xref: /rk3399_rockchip-uboot/drivers/mtd/nand/spi/fmsh.c (revision b83ea03a04c439afef575e85de5830ab9eb1be10)
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