blob: 6d643a8000dd6672149b10312bfea735844176ce [file] [log] [blame]
Boris Brezillonfa465252018-08-16 17:30:15 +02001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2018 Macronix
4 *
5 * Author: Boris Brezillon <boris.brezillon@bootlin.com>
6 */
7
8#ifndef __UBOOT__
Simon Glass9bc15642020-02-03 07:36:16 -07009#include <malloc.h>
Boris Brezillonfa465252018-08-16 17:30:15 +020010#include <linux/device.h>
11#include <linux/kernel.h>
12#endif
Simon Glassc06c1be2020-05-10 11:40:08 -060013#include <linux/bug.h>
Boris Brezillonfa465252018-08-16 17:30:15 +020014#include <linux/mtd/spinand.h>
15
16#define SPINAND_MFR_MACRONIX 0xC2
Haolin Libd45aab2021-09-05 22:41:41 +080017#define MACRONIX_ECCSR_MASK 0x0F
18
Boris Brezillonfa465252018-08-16 17:30:15 +020019
20static SPINAND_OP_VARIANTS(read_cache_variants,
21 SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
22 SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
23 SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
24 SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
25
26static SPINAND_OP_VARIANTS(write_cache_variants,
27 SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
28 SPINAND_PROG_LOAD(true, 0, NULL, 0));
29
30static SPINAND_OP_VARIANTS(update_cache_variants,
31 SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
32 SPINAND_PROG_LOAD(false, 0, NULL, 0));
33
Miquel Raynal02b49792018-08-16 17:30:16 +020034static int mx35lfxge4ab_ooblayout_ecc(struct mtd_info *mtd, int section,
Boris Brezillonfa465252018-08-16 17:30:15 +020035 struct mtd_oob_region *region)
36{
37 return -ERANGE;
38}
39
Miquel Raynal02b49792018-08-16 17:30:16 +020040static int mx35lfxge4ab_ooblayout_free(struct mtd_info *mtd, int section,
Boris Brezillonfa465252018-08-16 17:30:15 +020041 struct mtd_oob_region *region)
42{
43 if (section)
44 return -ERANGE;
45
46 region->offset = 2;
47 region->length = mtd->oobsize - 2;
48
49 return 0;
50}
51
Miquel Raynal02b49792018-08-16 17:30:16 +020052static const struct mtd_ooblayout_ops mx35lfxge4ab_ooblayout = {
53 .ecc = mx35lfxge4ab_ooblayout_ecc,
Simon Glass62fd1a42020-02-03 07:35:56 -070054 .rfree = mx35lfxge4ab_ooblayout_free,
Boris Brezillonfa465252018-08-16 17:30:15 +020055};
56
57static int mx35lf1ge4ab_get_eccsr(struct spinand_device *spinand, u8 *eccsr)
58{
59 struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(0x7c, 1),
60 SPI_MEM_OP_NO_ADDR,
61 SPI_MEM_OP_DUMMY(1, 1),
62 SPI_MEM_OP_DATA_IN(1, eccsr, 1));
63
Haolin Libd45aab2021-09-05 22:41:41 +080064 int ret = spi_mem_exec_op(spinand->slave, &op);
65
66 if (ret)
67 return ret;
68
69 *eccsr &= MACRONIX_ECCSR_MASK;
70 return 0;
Boris Brezillonfa465252018-08-16 17:30:15 +020071}
72
73static int mx35lf1ge4ab_ecc_get_status(struct spinand_device *spinand,
74 u8 status)
75{
76 struct nand_device *nand = spinand_to_nand(spinand);
77 u8 eccsr;
78
79 switch (status & STATUS_ECC_MASK) {
80 case STATUS_ECC_NO_BITFLIPS:
81 return 0;
82
83 case STATUS_ECC_UNCOR_ERROR:
84 return -EBADMSG;
85
86 case STATUS_ECC_HAS_BITFLIPS:
87 /*
88 * Let's try to retrieve the real maximum number of bitflips
89 * in order to avoid forcing the wear-leveling layer to move
90 * data around if it's not necessary.
91 */
92 if (mx35lf1ge4ab_get_eccsr(spinand, &eccsr))
93 return nand->eccreq.strength;
94
95 if (WARN_ON(eccsr > nand->eccreq.strength || !eccsr))
96 return nand->eccreq.strength;
97
98 return eccsr;
99
100 default:
101 break;
102 }
103
104 return -EINVAL;
105}
106
107static const struct spinand_info macronix_spinand_table[] = {
108 SPINAND_INFO("MX35LF1GE4AB", 0x12,
109 NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
110 NAND_ECCREQ(4, 512),
111 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
112 &write_cache_variants,
113 &update_cache_variants),
114 SPINAND_HAS_QE_BIT,
Miquel Raynal02b49792018-08-16 17:30:16 +0200115 SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
Boris Brezillonfa465252018-08-16 17:30:15 +0200116 mx35lf1ge4ab_ecc_get_status)),
Miquel Raynal02b49792018-08-16 17:30:16 +0200117 SPINAND_INFO("MX35LF2GE4AB", 0x22,
118 NAND_MEMORG(1, 2048, 64, 64, 2048, 2, 1, 1),
119 NAND_ECCREQ(4, 512),
120 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
121 &write_cache_variants,
122 &update_cache_variants),
123 SPINAND_HAS_QE_BIT,
124 SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
Jaime Liao4b017b92021-06-07 16:19:15 +0800125 SPINAND_INFO("MX35UF4GE4AD", 0xb7,
126 NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
127 NAND_ECCREQ(8, 512),
128 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
129 &write_cache_variants,
130 &update_cache_variants),
131 SPINAND_HAS_QE_BIT,
132 SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
133 mx35lf1ge4ab_ecc_get_status)),
134 SPINAND_INFO("MX35UF2GE4AD", 0xa6,
135 NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
136 NAND_ECCREQ(8, 512),
137 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
138 &write_cache_variants,
139 &update_cache_variants),
140 SPINAND_HAS_QE_BIT,
141 SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
142 mx35lf1ge4ab_ecc_get_status)),
143 SPINAND_INFO("MX35UF2GE4AC", 0xa2,
144 NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1),
145 NAND_ECCREQ(4, 512),
146 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
147 &write_cache_variants,
148 &update_cache_variants),
149 SPINAND_HAS_QE_BIT,
150 SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
151 mx35lf1ge4ab_ecc_get_status)),
152 SPINAND_INFO("MX35UF1GE4AD", 0x96,
153 NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
154 NAND_ECCREQ(8, 512),
155 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
156 &write_cache_variants,
157 &update_cache_variants),
158 SPINAND_HAS_QE_BIT,
159 SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
160 mx35lf1ge4ab_ecc_get_status)),
161 SPINAND_INFO("MX35UF1GE4AC", 0x92,
162 NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
163 NAND_ECCREQ(4, 512),
164 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
165 &write_cache_variants,
166 &update_cache_variants),
167 SPINAND_HAS_QE_BIT,
168 SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
169 mx35lf1ge4ab_ecc_get_status)),
170
Boris Brezillonfa465252018-08-16 17:30:15 +0200171};
172
173static int macronix_spinand_detect(struct spinand_device *spinand)
174{
175 u8 *id = spinand->id.data;
176 int ret;
177
178 /*
179 * Macronix SPI NAND read ID needs a dummy byte, so the first byte in
180 * raw_id is garbage.
181 */
182 if (id[1] != SPINAND_MFR_MACRONIX)
183 return 0;
184
185 ret = spinand_match_and_init(spinand, macronix_spinand_table,
186 ARRAY_SIZE(macronix_spinand_table),
187 id[2]);
188 if (ret)
189 return ret;
190
191 return 1;
192}
193
194static const struct spinand_manufacturer_ops macronix_spinand_manuf_ops = {
195 .detect = macronix_spinand_detect,
196};
197
198const struct spinand_manufacturer macronix_spinand_manufacturer = {
199 .id = SPINAND_MFR_MACRONIX,
200 .name = "Macronix",
201 .ops = &macronix_spinand_manuf_ops,
202};