103d86fc3SJon Lin // SPDX-License-Identifier: GPL-2.0
203d86fc3SJon Lin /*
34b3d79dcSJon Lin * Copyright (c) 2020-2021 Rockchip Electronics Co., Ltd
403d86fc3SJon Lin *
503d86fc3SJon Lin * Authors:
64b3d79dcSJon Lin * Dingqiang Lin <jon.lin@rock-chips.com>
703d86fc3SJon Lin */
803d86fc3SJon Lin
903d86fc3SJon Lin #ifndef __UBOOT__
1003d86fc3SJon Lin #include <linux/device.h>
1103d86fc3SJon Lin #include <linux/kernel.h>
1203d86fc3SJon Lin #endif
1303d86fc3SJon Lin #include <linux/mtd/spinand.h>
1403d86fc3SJon Lin
1503d86fc3SJon Lin #define SPINAND_MFR_FMSH 0xA1
1603d86fc3SJon Lin
1703d86fc3SJon Lin static SPINAND_OP_VARIANTS(read_cache_variants,
1803d86fc3SJon Lin SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
1903d86fc3SJon Lin SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
2003d86fc3SJon Lin SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
2103d86fc3SJon Lin SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
2203d86fc3SJon Lin SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
2303d86fc3SJon Lin SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
2403d86fc3SJon Lin
2503d86fc3SJon Lin static SPINAND_OP_VARIANTS(write_cache_variants,
2603d86fc3SJon Lin SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
2703d86fc3SJon Lin SPINAND_PROG_LOAD(true, 0, NULL, 0));
2803d86fc3SJon Lin
2903d86fc3SJon Lin static SPINAND_OP_VARIANTS(update_cache_variants,
3003d86fc3SJon Lin SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
3103d86fc3SJon Lin SPINAND_PROG_LOAD(false, 0, NULL, 0));
3203d86fc3SJon Lin
fm25s01a_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)3303d86fc3SJon Lin static int fm25s01a_ooblayout_ecc(struct mtd_info *mtd, int section,
3403d86fc3SJon Lin struct mtd_oob_region *region)
3503d86fc3SJon Lin {
3603d86fc3SJon Lin return -ERANGE;
3703d86fc3SJon Lin }
3803d86fc3SJon Lin
fm25s01a_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)3903d86fc3SJon Lin static int fm25s01a_ooblayout_free(struct mtd_info *mtd, int section,
4003d86fc3SJon Lin struct mtd_oob_region *region)
4103d86fc3SJon Lin {
4203d86fc3SJon Lin if (section)
4303d86fc3SJon Lin return -ERANGE;
4403d86fc3SJon Lin
4503d86fc3SJon Lin region->offset = 2;
4603d86fc3SJon Lin region->length = 62;
4703d86fc3SJon Lin
4803d86fc3SJon Lin return 0;
4903d86fc3SJon Lin }
5003d86fc3SJon Lin
5103d86fc3SJon Lin static const struct mtd_ooblayout_ops fm25s01a_ooblayout = {
5203d86fc3SJon Lin .ecc = fm25s01a_ooblayout_ecc,
5303d86fc3SJon Lin .rfree = fm25s01a_ooblayout_free,
5403d86fc3SJon Lin };
5503d86fc3SJon Lin
fm25s01_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)564cab706eSJon Lin static int fm25s01_ooblayout_ecc(struct mtd_info *mtd, int section,
574cab706eSJon Lin struct mtd_oob_region *region)
584cab706eSJon Lin {
594cab706eSJon Lin if (section)
604cab706eSJon Lin return -ERANGE;
614cab706eSJon Lin
624cab706eSJon Lin region->offset = 64;
634cab706eSJon Lin region->length = 64;
644cab706eSJon Lin
654cab706eSJon Lin return 0;
664cab706eSJon Lin }
674cab706eSJon Lin
fm25s01_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)684cab706eSJon Lin static int fm25s01_ooblayout_free(struct mtd_info *mtd, int section,
694cab706eSJon Lin struct mtd_oob_region *region)
704cab706eSJon Lin {
714cab706eSJon Lin if (section)
724cab706eSJon Lin return -ERANGE;
734cab706eSJon Lin
744cab706eSJon Lin region->offset = 2;
754cab706eSJon Lin region->length = 62;
764cab706eSJon Lin
774cab706eSJon Lin return 0;
784cab706eSJon Lin }
794cab706eSJon Lin
804cab706eSJon Lin static const struct mtd_ooblayout_ops fm25s01_ooblayout = {
814cab706eSJon Lin .ecc = fm25s01_ooblayout_ecc,
824cab706eSJon Lin .rfree = fm25s01_ooblayout_free,
834cab706eSJon Lin };
844cab706eSJon Lin
850a478b05SJon Lin /*
860a478b05SJon Lin * ecc bits: 0xC0[4,6]
870a478b05SJon Lin * [0b000], No bit errors were detected;
880a478b05SJon Lin * [0b001] and [0b011], 1~6 Bit errors were detected and corrected. Not
890a478b05SJon Lin * reach Flipping Bits;
900a478b05SJon Lin * [0b101], Bit error count equals the bit flip
910a478b05SJon Lin * detection threshold
920a478b05SJon Lin * [0b010], Multiple bit errors were detected and
930a478b05SJon Lin * not corrected.
940a478b05SJon Lin * others, Reserved.
950a478b05SJon Lin */
fm25s01bi3_ecc_ecc_get_status(struct spinand_device * spinand,u8 status)960a478b05SJon Lin static int fm25s01bi3_ecc_ecc_get_status(struct spinand_device *spinand,
970a478b05SJon Lin u8 status)
980a478b05SJon Lin {
990a478b05SJon Lin struct nand_device *nand = spinand_to_nand(spinand);
1000a478b05SJon Lin u8 eccsr = (status & GENMASK(6, 4)) >> 4;
1010a478b05SJon Lin
1020a478b05SJon Lin if (eccsr <= 1 || eccsr == 3)
1030a478b05SJon Lin return eccsr;
1040a478b05SJon Lin else if (eccsr == 5)
1050a478b05SJon Lin return nand->eccreq.strength;
1060a478b05SJon Lin else
1070a478b05SJon Lin return -EBADMSG;
1080a478b05SJon Lin }
1090a478b05SJon Lin
fm25g0xd_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)110*b83ea03aSJon Lin static int fm25g0xd_ooblayout_ecc(struct mtd_info *mtd, int section,
111*b83ea03aSJon Lin struct mtd_oob_region *region)
112*b83ea03aSJon Lin {
113*b83ea03aSJon Lin if (section > 3)
114*b83ea03aSJon Lin return -ERANGE;
115*b83ea03aSJon Lin
116*b83ea03aSJon Lin region->offset = (16 * section) + 8;
117*b83ea03aSJon Lin region->length = 8;
118*b83ea03aSJon Lin
119*b83ea03aSJon Lin return 0;
120*b83ea03aSJon Lin }
121*b83ea03aSJon Lin
fm25g0xd_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)122*b83ea03aSJon Lin static int fm25g0xd_ooblayout_free(struct mtd_info *mtd, int section,
123*b83ea03aSJon Lin struct mtd_oob_region *region)
124*b83ea03aSJon Lin {
125*b83ea03aSJon Lin if (section > 3)
126*b83ea03aSJon Lin return -ERANGE;
127*b83ea03aSJon Lin
128*b83ea03aSJon Lin region->offset = (16 * section) + 2;
129*b83ea03aSJon Lin region->length = 6;
130*b83ea03aSJon Lin
131*b83ea03aSJon Lin return 0;
132*b83ea03aSJon Lin }
133*b83ea03aSJon Lin
134*b83ea03aSJon Lin static const struct mtd_ooblayout_ops fm25g0xd_ooblayout = {
135*b83ea03aSJon Lin .ecc = fm25g0xd_ooblayout_ecc,
136*b83ea03aSJon Lin .rfree = fm25g0xd_ooblayout_free,
137*b83ea03aSJon Lin };
138*b83ea03aSJon Lin
139*b83ea03aSJon Lin /*
140*b83ea03aSJon Lin * ecc bits: 0xC0[4,6]
141*b83ea03aSJon Lin * [0x0], No bit errors were detected;
142*b83ea03aSJon Lin * [0x001, 0x011], Bit errors were detected and corrected. Not
143*b83ea03aSJon Lin * reach Flipping Bits;
144*b83ea03aSJon Lin * [0x100], Bit error count equals the bit flip
145*b83ea03aSJon Lin * detectionthreshold
146*b83ea03aSJon Lin * [0x101, 0x110], Reserved;
147*b83ea03aSJon Lin * [0x111], Multiple bit errors were detected and
148*b83ea03aSJon Lin * not corrected.
149*b83ea03aSJon Lin */
fm25g0xd_ecc_get_status(struct spinand_device * spinand,u8 status)150*b83ea03aSJon Lin static int fm25g0xd_ecc_get_status(struct spinand_device *spinand,
151*b83ea03aSJon Lin u8 status)
152*b83ea03aSJon Lin {
153*b83ea03aSJon Lin struct nand_device *nand = spinand_to_nand(spinand);
154*b83ea03aSJon Lin u8 eccsr = (status & GENMASK(6, 4)) >> 4;
155*b83ea03aSJon Lin
156*b83ea03aSJon Lin if (eccsr <= 3)
157*b83ea03aSJon Lin return 0;
158*b83ea03aSJon Lin else if (eccsr == 4)
159*b83ea03aSJon Lin return nand->eccreq.strength;
160*b83ea03aSJon Lin else
161*b83ea03aSJon Lin return -EBADMSG;
162*b83ea03aSJon Lin }
163*b83ea03aSJon Lin
16403d86fc3SJon Lin static const struct spinand_info fmsh_spinand_table[] = {
16581afcfe1SJon Lin SPINAND_INFO("FM25S01A",
16681afcfe1SJon Lin SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE4),
16703d86fc3SJon Lin NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
16803d86fc3SJon Lin NAND_ECCREQ(1, 512),
16903d86fc3SJon Lin SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
17003d86fc3SJon Lin &write_cache_variants,
17103d86fc3SJon Lin &update_cache_variants),
17203d86fc3SJon Lin 0,
17303d86fc3SJon Lin SPINAND_ECCINFO(&fm25s01a_ooblayout, NULL)),
17481afcfe1SJon Lin SPINAND_INFO("FM25S02A",
17581afcfe1SJon Lin SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE5),
176cc7b616dSJon Lin NAND_MEMORG(1, 2048, 64, 64, 2048, 2, 1, 1),
1773ac03e83SJon Lin NAND_ECCREQ(1, 512),
1783ac03e83SJon Lin SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
1793ac03e83SJon Lin &write_cache_variants,
1803ac03e83SJon Lin &update_cache_variants),
181e86e3b35SJon Lin SPINAND_HAS_QE_BIT,
1823ac03e83SJon Lin SPINAND_ECCINFO(&fm25s01a_ooblayout, NULL)),
18381afcfe1SJon Lin SPINAND_INFO("FM25S01",
18481afcfe1SJon Lin SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xA1),
185e86e3b35SJon Lin NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
1864cab706eSJon Lin NAND_ECCREQ(1, 512),
1874cab706eSJon Lin SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
1884cab706eSJon Lin &write_cache_variants,
1894cab706eSJon Lin &update_cache_variants),
1904cab706eSJon Lin 0,
1914cab706eSJon Lin SPINAND_ECCINFO(&fm25s01_ooblayout, NULL)),
1920c23f8d7SJon Lin SPINAND_INFO("FM25LS01",
1930c23f8d7SJon Lin SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xA5),
194e86e3b35SJon Lin NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
1950c23f8d7SJon Lin NAND_ECCREQ(1, 512),
1960c23f8d7SJon Lin SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
1970c23f8d7SJon Lin &write_cache_variants,
1980c23f8d7SJon Lin &update_cache_variants),
1990c23f8d7SJon Lin 0,
2000c23f8d7SJon Lin SPINAND_ECCINFO(&fm25s01_ooblayout, NULL)),
2010a478b05SJon Lin SPINAND_INFO("FM25S01BI3",
2020a478b05SJon Lin SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xD4),
203e86e3b35SJon Lin NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
2040a478b05SJon Lin NAND_ECCREQ(8, 512),
2050a478b05SJon Lin SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
2060a478b05SJon Lin &write_cache_variants,
2070a478b05SJon Lin &update_cache_variants),
2080a478b05SJon Lin SPINAND_HAS_QE_BIT,
2090a478b05SJon Lin SPINAND_ECCINFO(&fm25s01_ooblayout, fm25s01bi3_ecc_ecc_get_status)),
21077f0bee3SJon Lin SPINAND_INFO("FM25S02BI3-DND-A-G3",
21177f0bee3SJon Lin SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xD6),
21277f0bee3SJon Lin NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
21377f0bee3SJon Lin NAND_ECCREQ(8, 512),
21477f0bee3SJon Lin SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
21577f0bee3SJon Lin &write_cache_variants,
21677f0bee3SJon Lin &update_cache_variants),
21777f0bee3SJon Lin SPINAND_HAS_QE_BIT,
21877f0bee3SJon Lin SPINAND_ECCINFO(&fm25s01_ooblayout, fm25s01bi3_ecc_ecc_get_status)),
219*b83ea03aSJon Lin SPINAND_INFO("FM25G02D",
220*b83ea03aSJon Lin SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xF2),
221*b83ea03aSJon Lin NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1),
222*b83ea03aSJon Lin NAND_ECCREQ(4, 512),
223*b83ea03aSJon Lin SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
224*b83ea03aSJon Lin &write_cache_variants,
225*b83ea03aSJon Lin &update_cache_variants),
226*b83ea03aSJon Lin SPINAND_HAS_QE_BIT,
227*b83ea03aSJon Lin SPINAND_ECCINFO(&fm25g0xd_ooblayout, fm25g0xd_ecc_get_status)),
22803d86fc3SJon Lin };
22903d86fc3SJon Lin
23003d86fc3SJon Lin static const struct spinand_manufacturer_ops fmsh_spinand_manuf_ops = {
23103d86fc3SJon Lin };
23203d86fc3SJon Lin
23303d86fc3SJon Lin const struct spinand_manufacturer fmsh_spinand_manufacturer = {
23403d86fc3SJon Lin .id = SPINAND_MFR_FMSH,
23503d86fc3SJon Lin .name = "FMSH",
23681afcfe1SJon Lin .chips = fmsh_spinand_table,
23781afcfe1SJon Lin .nchips = ARRAY_SIZE(fmsh_spinand_table),
23803d86fc3SJon Lin .ops = &fmsh_spinand_manuf_ops,
23903d86fc3SJon Lin };
240