1c219aedbSJon Lin // SPDX-License-Identifier: GPL-2.0
2c219aedbSJon Lin /*
3c219aedbSJon Lin * Copyright (c) 2020 Rockchip Electronics Co., Ltd
4c219aedbSJon Lin *
5c219aedbSJon Lin * Authors:
6c219aedbSJon Lin * Dingqiang Lin <jon.lin@rock-chips.com>
7c219aedbSJon Lin */
8c219aedbSJon Lin
9c219aedbSJon Lin #ifndef __UBOOT__
10c219aedbSJon Lin #include <linux/device.h>
11c219aedbSJon Lin #include <linux/kernel.h>
12c219aedbSJon Lin #endif
13c219aedbSJon Lin #include <linux/mtd/spinand.h>
14c219aedbSJon Lin
15c219aedbSJon Lin #define SPINAND_MFR_DOSILICON 0xE5
16c219aedbSJon Lin
17666736e0SJon Lin #define DOSICON_STATUS_ECC_MASK GENMASK(6, 4)
183825dbadSJon Lin #define DOSICON_STATUS_ECC_NO_BITFLIPS (0 << 4)
193825dbadSJon Lin #define DOSICON_STATUS_ECC_1TO3_BITFLIPS (1 << 4)
203825dbadSJon Lin #define DOSICON_STATUS_ECC_4TO6_BITFLIPS (3 << 4)
213825dbadSJon Lin #define DOSICON_STATUS_ECC_7TO8_BITFLIPS (5 << 4)
223825dbadSJon Lin
23c219aedbSJon Lin static SPINAND_OP_VARIANTS(read_cache_variants,
24c219aedbSJon Lin SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
25c219aedbSJon Lin SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
26c219aedbSJon Lin SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
27c219aedbSJon Lin SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
28c219aedbSJon Lin SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
29c219aedbSJon Lin SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
30c219aedbSJon Lin
31c219aedbSJon Lin static SPINAND_OP_VARIANTS(write_cache_variants,
32c219aedbSJon Lin SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
33c219aedbSJon Lin SPINAND_PROG_LOAD(true, 0, NULL, 0));
34c219aedbSJon Lin
35c219aedbSJon Lin static SPINAND_OP_VARIANTS(update_cache_variants,
36c219aedbSJon Lin SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
37c219aedbSJon Lin SPINAND_PROG_LOAD(false, 0, NULL, 0));
38c219aedbSJon Lin
ds35xxga_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)39c219aedbSJon Lin static int ds35xxga_ooblayout_ecc(struct mtd_info *mtd, int section,
40c219aedbSJon Lin struct mtd_oob_region *region)
41c219aedbSJon Lin {
42c219aedbSJon Lin if (section > 3)
43c219aedbSJon Lin return -ERANGE;
44c219aedbSJon Lin
45c219aedbSJon Lin region->offset = (16 * section) + 8;
46c219aedbSJon Lin region->length = 8;
47c219aedbSJon Lin
48c219aedbSJon Lin return 0;
49c219aedbSJon Lin }
50c219aedbSJon Lin
ds35xxga_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)51c219aedbSJon Lin static int ds35xxga_ooblayout_free(struct mtd_info *mtd, int section,
52c219aedbSJon Lin struct mtd_oob_region *region)
53c219aedbSJon Lin {
54c219aedbSJon Lin if (section > 3)
55c219aedbSJon Lin return -ERANGE;
56c219aedbSJon Lin
57c219aedbSJon Lin region->offset = (16 * section) + 2;
58c219aedbSJon Lin region->length = 6;
59c219aedbSJon Lin
60c219aedbSJon Lin return 0;
61c219aedbSJon Lin }
62c219aedbSJon Lin
63c219aedbSJon Lin static const struct mtd_ooblayout_ops ds35xxga_ooblayout = {
64c219aedbSJon Lin .ecc = ds35xxga_ooblayout_ecc,
65c219aedbSJon Lin .rfree = ds35xxga_ooblayout_free,
66c219aedbSJon Lin };
67c219aedbSJon Lin
ds35xxgb_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)683825dbadSJon Lin static int ds35xxgb_ooblayout_ecc(struct mtd_info *mtd, int section,
693825dbadSJon Lin struct mtd_oob_region *region)
703825dbadSJon Lin {
713825dbadSJon Lin if (section)
723825dbadSJon Lin return -ERANGE;
733825dbadSJon Lin
743825dbadSJon Lin region->offset = 64;
753825dbadSJon Lin region->length = 64;
763825dbadSJon Lin
773825dbadSJon Lin return 0;
783825dbadSJon Lin }
793825dbadSJon Lin
ds35xxgb_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)803825dbadSJon Lin static int ds35xxgb_ooblayout_free(struct mtd_info *mtd, int section,
813825dbadSJon Lin struct mtd_oob_region *region)
823825dbadSJon Lin {
833825dbadSJon Lin if (section)
843825dbadSJon Lin return -ERANGE;
853825dbadSJon Lin
863825dbadSJon Lin /* Reserve 1 bytes for the BBM. */
873825dbadSJon Lin region->offset = 1;
883825dbadSJon Lin region->length = 63;
893825dbadSJon Lin
903825dbadSJon Lin return 0;
913825dbadSJon Lin }
923825dbadSJon Lin
933825dbadSJon Lin static const struct mtd_ooblayout_ops ds35xxgb_ooblayout = {
943825dbadSJon Lin .ecc = ds35xxgb_ooblayout_ecc,
953825dbadSJon Lin .rfree = ds35xxgb_ooblayout_free,
963825dbadSJon Lin };
973825dbadSJon Lin
ds35xxgb_ecc_get_status(struct spinand_device * spinand,u8 status)983825dbadSJon Lin static int ds35xxgb_ecc_get_status(struct spinand_device *spinand,
993825dbadSJon Lin u8 status)
1003825dbadSJon Lin {
1013825dbadSJon Lin switch (status & DOSICON_STATUS_ECC_MASK) {
1023825dbadSJon Lin case STATUS_ECC_NO_BITFLIPS:
1033825dbadSJon Lin return 0;
1043825dbadSJon Lin
1053825dbadSJon Lin case STATUS_ECC_UNCOR_ERROR:
1063825dbadSJon Lin return -EBADMSG;
1073825dbadSJon Lin
1083825dbadSJon Lin case DOSICON_STATUS_ECC_1TO3_BITFLIPS:
1093825dbadSJon Lin return 3;
1103825dbadSJon Lin
1113825dbadSJon Lin case DOSICON_STATUS_ECC_4TO6_BITFLIPS:
1123825dbadSJon Lin return 6;
1133825dbadSJon Lin
1143825dbadSJon Lin case DOSICON_STATUS_ECC_7TO8_BITFLIPS:
1153825dbadSJon Lin return 8;
1163825dbadSJon Lin
1173825dbadSJon Lin default:
1183825dbadSJon Lin break;
1193825dbadSJon Lin }
1203825dbadSJon Lin
1213825dbadSJon Lin return -EINVAL;
1223825dbadSJon Lin }
1233825dbadSJon Lin
124c219aedbSJon Lin static const struct spinand_info dosilicon_spinand_table[] = {
12581afcfe1SJon Lin SPINAND_INFO("DS35X1GA",
12681afcfe1SJon Lin SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x71),
127c219aedbSJon Lin NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
128c219aedbSJon Lin NAND_ECCREQ(4, 512),
129c219aedbSJon Lin SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
130c219aedbSJon Lin &write_cache_variants,
131c219aedbSJon Lin &update_cache_variants),
132c219aedbSJon Lin SPINAND_HAS_QE_BIT,
133c219aedbSJon Lin SPINAND_ECCINFO(&ds35xxga_ooblayout, NULL)),
13481afcfe1SJon Lin SPINAND_INFO("DS35Q2GA",
13581afcfe1SJon Lin SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x72),
136d38748a7SJon Lin NAND_MEMORG(1, 2048, 64, 64, 2048, 2, 1, 1),
137d38748a7SJon Lin NAND_ECCREQ(4, 512),
138d38748a7SJon Lin SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
139d38748a7SJon Lin &write_cache_variants,
140d38748a7SJon Lin &update_cache_variants),
141d38748a7SJon Lin SPINAND_HAS_QE_BIT,
142d38748a7SJon Lin SPINAND_ECCINFO(&ds35xxga_ooblayout, NULL)),
14381afcfe1SJon Lin SPINAND_INFO("DS35M1GA",
14481afcfe1SJon Lin SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x21),
1453825dbadSJon Lin NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
1463825dbadSJon Lin NAND_ECCREQ(4, 512),
1473825dbadSJon Lin SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
1483825dbadSJon Lin &write_cache_variants,
1493825dbadSJon Lin &update_cache_variants),
1503825dbadSJon Lin SPINAND_HAS_QE_BIT,
1513825dbadSJon Lin SPINAND_ECCINFO(&ds35xxga_ooblayout, NULL)),
152dc631be6SJon Lin SPINAND_INFO("DS35M2GA",
153dc631be6SJon Lin SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x22),
154dc631be6SJon Lin NAND_MEMORG(1, 2048, 64, 64, 2048, 2, 1, 1),
155dc631be6SJon Lin NAND_ECCREQ(4, 512),
156dc631be6SJon Lin SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
157dc631be6SJon Lin &write_cache_variants,
158dc631be6SJon Lin &update_cache_variants),
159dc631be6SJon Lin SPINAND_HAS_QE_BIT,
160dc631be6SJon Lin SPINAND_ECCINFO(&ds35xxga_ooblayout, NULL)),
16181afcfe1SJon Lin SPINAND_INFO("DS35Q2GB",
16281afcfe1SJon Lin SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xF2),
1633825dbadSJon Lin NAND_MEMORG(1, 2048, 128, 64, 2048, 2, 1, 1),
1643825dbadSJon Lin NAND_ECCREQ(8, 512),
1653825dbadSJon Lin SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
1663825dbadSJon Lin &write_cache_variants,
1673825dbadSJon Lin &update_cache_variants),
1683825dbadSJon Lin SPINAND_HAS_QE_BIT,
1693825dbadSJon Lin SPINAND_ECCINFO(&ds35xxgb_ooblayout,
1703825dbadSJon Lin ds35xxgb_ecc_get_status)),
171dc631be6SJon Lin SPINAND_INFO("DS35M1GB",
172dc631be6SJon Lin SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xA1),
173d1ad35e5SJon Lin NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
174d1ad35e5SJon Lin NAND_ECCREQ(8, 512),
175d1ad35e5SJon Lin SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
176d1ad35e5SJon Lin &write_cache_variants,
177d1ad35e5SJon Lin &update_cache_variants),
178d1ad35e5SJon Lin SPINAND_HAS_QE_BIT,
179d1ad35e5SJon Lin SPINAND_ECCINFO(&ds35xxgb_ooblayout,
180d1ad35e5SJon Lin ds35xxgb_ecc_get_status)),
181d1ad35e5SJon Lin SPINAND_INFO("DS35Q1GB",
182d1ad35e5SJon Lin SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xF1),
183d1ad35e5SJon Lin NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
184d1ad35e5SJon Lin NAND_ECCREQ(8, 512),
185d1ad35e5SJon Lin SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
186d1ad35e5SJon Lin &write_cache_variants,
187d1ad35e5SJon Lin &update_cache_variants),
188d1ad35e5SJon Lin SPINAND_HAS_QE_BIT,
189d1ad35e5SJon Lin SPINAND_ECCINFO(&ds35xxgb_ooblayout,
190d1ad35e5SJon Lin ds35xxgb_ecc_get_status)),
191d1ad35e5SJon Lin SPINAND_INFO("DS35Q4GM",
192d1ad35e5SJon Lin SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xF4),
193d1ad35e5SJon Lin NAND_MEMORG(1, 2048, 128, 64, 4096, 2, 1, 1),
194dc631be6SJon Lin NAND_ECCREQ(8, 512),
195dc631be6SJon Lin SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
196dc631be6SJon Lin &write_cache_variants,
197dc631be6SJon Lin &update_cache_variants),
198dc631be6SJon Lin SPINAND_HAS_QE_BIT,
199dc631be6SJon Lin SPINAND_ECCINFO(&ds35xxgb_ooblayout,
200dc631be6SJon Lin ds35xxgb_ecc_get_status)),
201c765acc0SJon Lin SPINAND_INFO("DS35Q12B",
202c765acc0SJon Lin SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xF5),
203c765acc0SJon Lin NAND_MEMORG(1, 2048, 128, 64, 512, 1, 1, 1),
204c765acc0SJon Lin NAND_ECCREQ(8, 512),
205c765acc0SJon Lin SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
206c765acc0SJon Lin &write_cache_variants,
207c765acc0SJon Lin &update_cache_variants),
208c765acc0SJon Lin SPINAND_HAS_QE_BIT,
209c765acc0SJon Lin SPINAND_ECCINFO(&ds35xxgb_ooblayout,
210c765acc0SJon Lin ds35xxgb_ecc_get_status)),
211c765acc0SJon Lin SPINAND_INFO("DS35M12B",
212c765acc0SJon Lin SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xA5),
213c765acc0SJon Lin NAND_MEMORG(1, 2048, 128, 64, 512, 1, 1, 1),
214c765acc0SJon Lin NAND_ECCREQ(8, 512),
215c765acc0SJon Lin SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
216c765acc0SJon Lin &write_cache_variants,
217c765acc0SJon Lin &update_cache_variants),
218c765acc0SJon Lin SPINAND_HAS_QE_BIT,
219c765acc0SJon Lin SPINAND_ECCINFO(&ds35xxgb_ooblayout,
220c765acc0SJon Lin ds35xxgb_ecc_get_status)),
221dc84ac99SJon Lin SPINAND_INFO("DS35Q1GD-IB",
222dc84ac99SJon Lin SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x51),
223dc84ac99SJon Lin NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
224dc84ac99SJon Lin NAND_ECCREQ(8, 512),
225dc84ac99SJon Lin SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
226dc84ac99SJon Lin &write_cache_variants,
227dc84ac99SJon Lin &update_cache_variants),
228dc84ac99SJon Lin SPINAND_HAS_QE_BIT,
229dc84ac99SJon Lin SPINAND_ECCINFO(&ds35xxgb_ooblayout, ds35xxgb_ecc_get_status)),
2303407dbc7SJon Lin SPINAND_INFO("DS35M4GB-IB",
2313407dbc7SJon Lin SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x64),
2323407dbc7SJon Lin NAND_MEMORG(1, 2048, 128, 64, 4096, 1, 1, 1),
2333407dbc7SJon Lin NAND_ECCREQ(8, 512),
2343407dbc7SJon Lin SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
2353407dbc7SJon Lin &write_cache_variants,
2363407dbc7SJon Lin &update_cache_variants),
2373407dbc7SJon Lin SPINAND_HAS_QE_BIT,
2383407dbc7SJon Lin SPINAND_ECCINFO(&ds35xxgb_ooblayout, ds35xxgb_ecc_get_status)),
2393407dbc7SJon Lin SPINAND_INFO("DS35Q4GB-IB",
2403407dbc7SJon Lin SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xB4),
2413407dbc7SJon Lin NAND_MEMORG(1, 2048, 128, 64, 4096, 1, 1, 1),
2423407dbc7SJon Lin NAND_ECCREQ(8, 512),
2433407dbc7SJon Lin SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
2443407dbc7SJon Lin &write_cache_variants,
2453407dbc7SJon Lin &update_cache_variants),
2463407dbc7SJon Lin SPINAND_HAS_QE_BIT,
2473407dbc7SJon Lin SPINAND_ECCINFO(&ds35xxgb_ooblayout, ds35xxgb_ecc_get_status)),
2483407dbc7SJon Lin SPINAND_INFO("DS35Q12C-IB",
2493407dbc7SJon Lin SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x75),
2503407dbc7SJon Lin NAND_MEMORG(1, 2048, 128, 64, 512, 1, 1, 1),
2513407dbc7SJon Lin NAND_ECCREQ(8, 512),
2523407dbc7SJon Lin SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
2533407dbc7SJon Lin &write_cache_variants,
2543407dbc7SJon Lin &update_cache_variants),
2553407dbc7SJon Lin SPINAND_HAS_QE_BIT,
2563407dbc7SJon Lin SPINAND_ECCINFO(&ds35xxgb_ooblayout, ds35xxgb_ecc_get_status)),
2573407dbc7SJon Lin SPINAND_INFO("DS35M12C-IB",
2583407dbc7SJon Lin SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x25),
2593407dbc7SJon Lin NAND_MEMORG(1, 2048, 128, 64, 512, 1, 1, 1),
2603407dbc7SJon Lin NAND_ECCREQ(8, 512),
2613407dbc7SJon Lin SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
2623407dbc7SJon Lin &write_cache_variants,
2633407dbc7SJon Lin &update_cache_variants),
2643407dbc7SJon Lin SPINAND_HAS_QE_BIT,
2653407dbc7SJon Lin SPINAND_ECCINFO(&ds35xxgb_ooblayout, ds35xxgb_ecc_get_status)),
266*72eb20ffSJon Lin SPINAND_INFO("DS35Q2GBS",
267*72eb20ffSJon Lin SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xB2),
268*72eb20ffSJon Lin NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
269*72eb20ffSJon Lin NAND_ECCREQ(8, 512),
270*72eb20ffSJon Lin SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
271*72eb20ffSJon Lin &write_cache_variants,
272*72eb20ffSJon Lin &update_cache_variants),
273*72eb20ffSJon Lin SPINAND_HAS_QE_BIT,
274*72eb20ffSJon Lin SPINAND_ECCINFO(&ds35xxgb_ooblayout, ds35xxgb_ecc_get_status)),
275c219aedbSJon Lin };
276c219aedbSJon Lin
277c219aedbSJon Lin static const struct spinand_manufacturer_ops dosilicon_spinand_manuf_ops = {
278c219aedbSJon Lin };
279c219aedbSJon Lin
280c219aedbSJon Lin const struct spinand_manufacturer dosilicon_spinand_manufacturer = {
281c219aedbSJon Lin .id = SPINAND_MFR_DOSILICON,
282c219aedbSJon Lin .name = "dosilicon",
28381afcfe1SJon Lin .chips = dosilicon_spinand_table,
28481afcfe1SJon Lin .nchips = ARRAY_SIZE(dosilicon_spinand_table),
285c219aedbSJon Lin .ops = &dosilicon_spinand_manuf_ops,
286c219aedbSJon Lin };
287