xref: /rk3399_rockchip-uboot/drivers/mtd/nand/spi/etron.c (revision 382644d447c5e4ca28f639e59e7fc91bfdb4f184)
1bb28334dSJon Lin // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
29c409da6SJon Lin /*
3bb28334dSJon Lin  * Copyright (c) 2021 Rockchip Electronics Co., Ltd.
49c409da6SJon Lin  */
59c409da6SJon Lin 
69c409da6SJon Lin #ifndef __UBOOT__
79c409da6SJon Lin #include <linux/device.h>
89c409da6SJon Lin #include <linux/kernel.h>
99c409da6SJon Lin #endif
109c409da6SJon Lin #include <linux/mtd/spinand.h>
119c409da6SJon Lin 
129c409da6SJon Lin #define SPINAND_MFR_ETRON		0xD5
139c409da6SJon Lin 
149c409da6SJon Lin static SPINAND_OP_VARIANTS(read_cache_variants,
159c409da6SJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
169c409da6SJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
179c409da6SJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
189c409da6SJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
199c409da6SJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
209c409da6SJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
219c409da6SJon Lin 
229c409da6SJon Lin static SPINAND_OP_VARIANTS(write_cache_variants,
239c409da6SJon Lin 		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
249c409da6SJon Lin 		SPINAND_PROG_LOAD(true, 0, NULL, 0));
259c409da6SJon Lin 
269c409da6SJon Lin static SPINAND_OP_VARIANTS(update_cache_variants,
279c409da6SJon Lin 		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
289c409da6SJon Lin 		SPINAND_PROG_LOAD(false, 0, NULL, 0));
299c409da6SJon Lin 
em73c044vcf_oh_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)309c409da6SJon Lin static int em73c044vcf_oh_ooblayout_ecc(struct mtd_info *mtd, int section,
319c409da6SJon Lin 					struct mtd_oob_region *region)
329c409da6SJon Lin {
339c409da6SJon Lin 	if (section > 3)
349c409da6SJon Lin 		return -ERANGE;
359c409da6SJon Lin 
369c409da6SJon Lin 	region->offset = (16 * section) + 8;
379c409da6SJon Lin 	region->length = 8;
389c409da6SJon Lin 
399c409da6SJon Lin 	return 0;
409c409da6SJon Lin }
419c409da6SJon Lin 
em73c044vcf_oh_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)429c409da6SJon Lin static int em73c044vcf_oh_ooblayout_free(struct mtd_info *mtd, int section,
439c409da6SJon Lin 					 struct mtd_oob_region *region)
449c409da6SJon Lin {
459c409da6SJon Lin 	if (section > 3)
469c409da6SJon Lin 		return -ERANGE;
479c409da6SJon Lin 
489c409da6SJon Lin 	region->offset = (16 * section) + 2;
499c409da6SJon Lin 	region->length = 6;
509c409da6SJon Lin 
519c409da6SJon Lin 	return 0;
529c409da6SJon Lin }
539c409da6SJon Lin 
549c409da6SJon Lin static const struct mtd_ooblayout_ops em73c044vcf_oh_ooblayout = {
559c409da6SJon Lin 	.ecc = em73c044vcf_oh_ooblayout_ecc,
569c409da6SJon Lin 	.rfree = em73c044vcf_oh_ooblayout_free,
579c409da6SJon Lin };
589c409da6SJon Lin 
em73c044vcf_oh_ecc_get_status(struct spinand_device * spinand,u8 status)599c409da6SJon Lin static int em73c044vcf_oh_ecc_get_status(struct spinand_device *spinand,
609c409da6SJon Lin 					 u8 status)
619c409da6SJon Lin {
629c409da6SJon Lin 	struct nand_device *nand = spinand_to_nand(spinand);
639c409da6SJon Lin 
649c409da6SJon Lin 	switch (status & STATUS_ECC_MASK) {
659c409da6SJon Lin 	case STATUS_ECC_NO_BITFLIPS:
669c409da6SJon Lin 		return 0;
679c409da6SJon Lin 
689c409da6SJon Lin 	case STATUS_ECC_UNCOR_ERROR:
699c409da6SJon Lin 		return -EBADMSG;
709c409da6SJon Lin 
719c409da6SJon Lin 	case STATUS_ECC_HAS_BITFLIPS:
729c409da6SJon Lin 		return 1;
739c409da6SJon Lin 
749c409da6SJon Lin 	default:
759c409da6SJon Lin 		return nand->eccreq.strength;
769c409da6SJon Lin 	}
779c409da6SJon Lin 
789c409da6SJon Lin 	return -EINVAL;
799c409da6SJon Lin }
809c409da6SJon Lin 
em73e044vce_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)812be1152dSJon Lin static int em73e044vce_ooblayout_ecc(struct mtd_info *mtd, int section,
822be1152dSJon Lin 				     struct mtd_oob_region *region)
832be1152dSJon Lin {
842be1152dSJon Lin 	if (section)
852be1152dSJon Lin 		return -ERANGE;
862be1152dSJon Lin 
872be1152dSJon Lin 	region->offset = mtd->oobsize / 2;
882be1152dSJon Lin 	region->length = mtd->oobsize / 2;
892be1152dSJon Lin 
902be1152dSJon Lin 	return 0;
912be1152dSJon Lin }
922be1152dSJon Lin 
em73e044vce_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)932be1152dSJon Lin static int em73e044vce_ooblayout_free(struct mtd_info *mtd, int section,
942be1152dSJon Lin 				      struct mtd_oob_region *region)
952be1152dSJon Lin {
962be1152dSJon Lin 	if (section)
972be1152dSJon Lin 		return -ERANGE;
982be1152dSJon Lin 
992be1152dSJon Lin 	region->offset = 2;
1002be1152dSJon Lin 	region->length = mtd->oobsize / 2 - 2;
1012be1152dSJon Lin 
1022be1152dSJon Lin 	return 0;
1032be1152dSJon Lin }
1042be1152dSJon Lin 
1052be1152dSJon Lin static const struct mtd_ooblayout_ops em73e044vce_ooblayout = {
1062be1152dSJon Lin 	.ecc = em73e044vce_ooblayout_ecc,
1072be1152dSJon Lin 	.rfree = em73e044vce_ooblayout_free,
1082be1152dSJon Lin };
1092be1152dSJon Lin 
em73e044vce_oh_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)110*382644d4SJon Lin static int em73e044vce_oh_ooblayout_ecc(struct mtd_info *mtd, int section,
111*382644d4SJon Lin 					struct mtd_oob_region *region)
112*382644d4SJon Lin {
113*382644d4SJon Lin 	if (section > 3)
114*382644d4SJon Lin 		return -ERANGE;
115*382644d4SJon Lin 
116*382644d4SJon Lin 	region->offset = (32 * section) + 18;
117*382644d4SJon Lin 	region->length = 14;
118*382644d4SJon Lin 
119*382644d4SJon Lin 	return 0;
120*382644d4SJon Lin }
121*382644d4SJon Lin 
em73e044vce_oh_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)122*382644d4SJon Lin static int em73e044vce_oh_ooblayout_free(struct mtd_info *mtd, int section,
123*382644d4SJon Lin 					 struct mtd_oob_region *region)
124*382644d4SJon Lin {
125*382644d4SJon Lin 	if (section > 3)
126*382644d4SJon Lin 		return -ERANGE;
127*382644d4SJon Lin 
128*382644d4SJon Lin 	region->offset = (32 * section) + 2;
129*382644d4SJon Lin 	region->length = 16;
130*382644d4SJon Lin 
131*382644d4SJon Lin 	return 0;
132*382644d4SJon Lin }
133*382644d4SJon Lin 
134*382644d4SJon Lin static const struct mtd_ooblayout_ops em73e044vce_oh_ooblayout = {
135*382644d4SJon Lin 	.ecc = em73e044vce_oh_ooblayout_ecc,
136*382644d4SJon Lin 	.rfree = em73e044vce_oh_ooblayout_free,
137*382644d4SJon Lin };
138*382644d4SJon Lin 
1399c409da6SJon Lin static const struct spinand_info etron_spinand_table[] = {
14081afcfe1SJon Lin 	SPINAND_INFO("EM73C044VCF-0H",
14120cb2c76SJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x36),
1429c409da6SJon Lin 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
1439c409da6SJon Lin 		     NAND_ECCREQ(4, 512),
1449c409da6SJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
1459c409da6SJon Lin 					      &write_cache_variants,
1469c409da6SJon Lin 					      &update_cache_variants),
1479c409da6SJon Lin 		     SPINAND_HAS_QE_BIT,
1489c409da6SJon Lin 		     SPINAND_ECCINFO(&em73c044vcf_oh_ooblayout,
1499c409da6SJon Lin 				     em73c044vcf_oh_ecc_get_status)),
1502be1152dSJon Lin 	SPINAND_INFO("EM73E044VCE-H",
1512be1152dSJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x3B),
1522be1152dSJon Lin 		     NAND_MEMORG(1, 2048, 128, 64, 4096, 1, 1, 1),
1532be1152dSJon Lin 		     NAND_ECCREQ(8, 512),
1542be1152dSJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
1552be1152dSJon Lin 					      &write_cache_variants,
1562be1152dSJon Lin 					      &update_cache_variants),
1572be1152dSJon Lin 		     SPINAND_HAS_QE_BIT,
1582be1152dSJon Lin 		     SPINAND_ECCINFO(&em73e044vce_ooblayout, em73c044vcf_oh_ecc_get_status)),
159*382644d4SJon Lin 	SPINAND_INFO("EM73E044VCE-OH",
160*382644d4SJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x40),
161*382644d4SJon Lin 		     NAND_MEMORG(1, 2048, 128, 64, 4096, 1, 1, 1),
162*382644d4SJon Lin 		     NAND_ECCREQ(8, 512),
163*382644d4SJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
164*382644d4SJon Lin 					      &write_cache_variants,
165*382644d4SJon Lin 					      &update_cache_variants),
166*382644d4SJon Lin 		     SPINAND_HAS_QE_BIT,
167*382644d4SJon Lin 		     SPINAND_ECCINFO(&em73e044vce_oh_ooblayout, em73c044vcf_oh_ecc_get_status)),
1689c409da6SJon Lin };
1699c409da6SJon Lin 
1709c409da6SJon Lin static const struct spinand_manufacturer_ops etron_spinand_manuf_ops = {
1719c409da6SJon Lin };
1729c409da6SJon Lin 
1739c409da6SJon Lin const struct spinand_manufacturer etron_spinand_manufacturer = {
1749c409da6SJon Lin 	.id = SPINAND_MFR_ETRON,
1759c409da6SJon Lin 	.name = "Etron",
17681afcfe1SJon Lin 	.chips = etron_spinand_table,
17781afcfe1SJon Lin 	.nchips = ARRAY_SIZE(etron_spinand_table),
1789c409da6SJon Lin 	.ops = &etron_spinand_manuf_ops,
1799c409da6SJon Lin };
180