blob: 08f7d69d8c64c930cc12a54fc67e10d0912113ed [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[] = {
Mikhail Kshevetskiy72010312023-01-10 12:58:38 +0100108 SPINAND_INFO("MX35LF1GE4AB",
109 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x12),
Boris Brezillonfa465252018-08-16 17:30:15 +0200110 NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
111 NAND_ECCREQ(4, 512),
112 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
113 &write_cache_variants,
114 &update_cache_variants),
115 SPINAND_HAS_QE_BIT,
Miquel Raynal02b49792018-08-16 17:30:16 +0200116 SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
Boris Brezillonfa465252018-08-16 17:30:15 +0200117 mx35lf1ge4ab_ecc_get_status)),
Mikhail Kshevetskiy72010312023-01-10 12:58:38 +0100118 SPINAND_INFO("MX35LF2GE4AB",
119 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x22),
Miquel Raynal02b49792018-08-16 17:30:16 +0200120 NAND_MEMORG(1, 2048, 64, 64, 2048, 2, 1, 1),
121 NAND_ECCREQ(4, 512),
122 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
123 &write_cache_variants,
124 &update_cache_variants),
125 SPINAND_HAS_QE_BIT,
126 SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
Mikhail Kshevetskiy72010312023-01-10 12:58:38 +0100127 SPINAND_INFO("MX35UF4GE4AD",
128 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb7),
Jaime Liao4b017b92021-06-07 16:19:15 +0800129 NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
130 NAND_ECCREQ(8, 512),
131 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
132 &write_cache_variants,
133 &update_cache_variants),
134 SPINAND_HAS_QE_BIT,
135 SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
136 mx35lf1ge4ab_ecc_get_status)),
Mikhail Kshevetskiy72010312023-01-10 12:58:38 +0100137 SPINAND_INFO("MX35UF2GE4AD",
138 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa6),
Jaime Liao4b017b92021-06-07 16:19:15 +0800139 NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
140 NAND_ECCREQ(8, 512),
141 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
142 &write_cache_variants,
143 &update_cache_variants),
144 SPINAND_HAS_QE_BIT,
145 SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
146 mx35lf1ge4ab_ecc_get_status)),
Mikhail Kshevetskiy72010312023-01-10 12:58:38 +0100147 SPINAND_INFO("MX35UF2GE4AC",
148 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa2),
Jaime Liao4b017b92021-06-07 16:19:15 +0800149 NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1),
150 NAND_ECCREQ(4, 512),
151 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
152 &write_cache_variants,
153 &update_cache_variants),
154 SPINAND_HAS_QE_BIT,
155 SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
156 mx35lf1ge4ab_ecc_get_status)),
Mikhail Kshevetskiy72010312023-01-10 12:58:38 +0100157 SPINAND_INFO("MX35UF1GE4AD",
158 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x96),
Jaime Liao4b017b92021-06-07 16:19:15 +0800159 NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
160 NAND_ECCREQ(8, 512),
161 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
162 &write_cache_variants,
163 &update_cache_variants),
164 SPINAND_HAS_QE_BIT,
165 SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
166 mx35lf1ge4ab_ecc_get_status)),
Mikhail Kshevetskiy72010312023-01-10 12:58:38 +0100167 SPINAND_INFO("MX35UF1GE4AC",
168 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x92),
Jaime Liao4b017b92021-06-07 16:19:15 +0800169 NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
170 NAND_ECCREQ(4, 512),
171 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
172 &write_cache_variants,
173 &update_cache_variants),
174 SPINAND_HAS_QE_BIT,
175 SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
176 mx35lf1ge4ab_ecc_get_status)),
177
Boris Brezillonfa465252018-08-16 17:30:15 +0200178};
179
Boris Brezillonfa465252018-08-16 17:30:15 +0200180static const struct spinand_manufacturer_ops macronix_spinand_manuf_ops = {
Boris Brezillonfa465252018-08-16 17:30:15 +0200181};
182
183const struct spinand_manufacturer macronix_spinand_manufacturer = {
184 .id = SPINAND_MFR_MACRONIX,
185 .name = "Macronix",
Mikhail Kshevetskiy72010312023-01-10 12:58:38 +0100186 .chips = macronix_spinand_table,
187 .nchips = ARRAY_SIZE(macronix_spinand_table),
Boris Brezillonfa465252018-08-16 17:30:15 +0200188 .ops = &macronix_spinand_manuf_ops,
189};