xref: /rk3399_rockchip-uboot/drivers/mtd/nand/spi/biwin.c (revision 81afcfe1f95ac45ca73ae8b8dd7c330fb6ed9d81)
18c4105ccSJon Lin // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
28c4105ccSJon Lin /*
38c4105ccSJon Lin  * Copyright (c) 2021 Rockchip Electronics Co., Ltd.
48c4105ccSJon Lin  */
58c4105ccSJon Lin 
68c4105ccSJon Lin #ifndef __UBOOT__
78c4105ccSJon Lin #include <linux/device.h>
88c4105ccSJon Lin #include <linux/kernel.h>
98c4105ccSJon Lin #endif
108c4105ccSJon Lin #include <linux/mtd/spinand.h>
118c4105ccSJon Lin 
128c4105ccSJon Lin #define SPINAND_MFR_BIWIN		0xBC
138c4105ccSJon Lin 
148c4105ccSJon Lin #define BIWIN_CFG_BUF_READ		BIT(3)
158c4105ccSJon Lin #define BIWIN_STATUS_ECC_HAS_BITFLIPS_T	(3 << 4)
168c4105ccSJon Lin 
178c4105ccSJon Lin static SPINAND_OP_VARIANTS(read_cache_variants,
188c4105ccSJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
198c4105ccSJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
208c4105ccSJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
218c4105ccSJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
228c4105ccSJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
238c4105ccSJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
248c4105ccSJon Lin 
258c4105ccSJon Lin static SPINAND_OP_VARIANTS(write_cache_variants,
268c4105ccSJon Lin 		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
278c4105ccSJon Lin 		SPINAND_PROG_LOAD(true, 0, NULL, 0));
288c4105ccSJon Lin 
298c4105ccSJon Lin static SPINAND_OP_VARIANTS(update_cache_variants,
308c4105ccSJon Lin 		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
318c4105ccSJon Lin 		SPINAND_PROG_LOAD(false, 0, NULL, 0));
328c4105ccSJon Lin 
bwjx08k_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)338c4105ccSJon Lin static int bwjx08k_ooblayout_ecc(struct mtd_info *mtd, int section,
348c4105ccSJon Lin 				 struct mtd_oob_region *region)
358c4105ccSJon Lin {
368c4105ccSJon Lin 	if (section > 3)
378c4105ccSJon Lin 		return -ERANGE;
388c4105ccSJon Lin 
398c4105ccSJon Lin 	region->offset = (16 * section) + 12;
408c4105ccSJon Lin 	region->length = 4;
418c4105ccSJon Lin 
428c4105ccSJon Lin 	return 0;
438c4105ccSJon Lin }
448c4105ccSJon Lin 
bwjx08k_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)458c4105ccSJon Lin static int bwjx08k_ooblayout_free(struct mtd_info *mtd, int section,
468c4105ccSJon Lin 				  struct mtd_oob_region *region)
478c4105ccSJon Lin {
488c4105ccSJon Lin 	if (section > 3)
498c4105ccSJon Lin 		return -ERANGE;
508c4105ccSJon Lin 
518c4105ccSJon Lin 	region->offset = (16 * section) + 2;
528c4105ccSJon Lin 	region->length = 10;
538c4105ccSJon Lin 
548c4105ccSJon Lin 	return 0;
558c4105ccSJon Lin }
568c4105ccSJon Lin 
578c4105ccSJon Lin static const struct mtd_ooblayout_ops bwjx08k_ooblayout = {
588c4105ccSJon Lin 	.ecc = bwjx08k_ooblayout_ecc,
598c4105ccSJon Lin 	.rfree = bwjx08k_ooblayout_free,
608c4105ccSJon Lin };
618c4105ccSJon Lin 
bwjx08k_ecc_get_status(struct spinand_device * spinand,u8 status)628c4105ccSJon Lin static int bwjx08k_ecc_get_status(struct spinand_device *spinand,
638c4105ccSJon Lin 				  u8 status)
648c4105ccSJon Lin {
658c4105ccSJon Lin 	struct nand_device *nand = spinand_to_nand(spinand);
668c4105ccSJon Lin 
678c4105ccSJon Lin 	switch (status & STATUS_ECC_MASK) {
688c4105ccSJon Lin 	case STATUS_ECC_NO_BITFLIPS:
698c4105ccSJon Lin 		return 0;
708c4105ccSJon Lin 
718c4105ccSJon Lin 	case STATUS_ECC_UNCOR_ERROR:
728c4105ccSJon Lin 		return -EBADMSG;
738c4105ccSJon Lin 
748c4105ccSJon Lin 	case STATUS_ECC_HAS_BITFLIPS:
758c4105ccSJon Lin 		return 1;
768c4105ccSJon Lin 
778c4105ccSJon Lin 	default:
788c4105ccSJon Lin 		return nand->eccreq.strength;
798c4105ccSJon Lin 	}
808c4105ccSJon Lin 
818c4105ccSJon Lin 	return -EINVAL;
828c4105ccSJon Lin }
838c4105ccSJon Lin 
848c4105ccSJon Lin /* Another set for the same id[2] devices in one series */
858c4105ccSJon Lin static const struct spinand_info biwin_spinand_table[] = {
86*81afcfe1SJon Lin 	SPINAND_INFO("BWJX08K",
87*81afcfe1SJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xB3),
888c4105ccSJon Lin 		     NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1),
898c4105ccSJon Lin 		     NAND_ECCREQ(8, 512),
908c4105ccSJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
918c4105ccSJon Lin 					      &write_cache_variants,
928c4105ccSJon Lin 					      &update_cache_variants),
938c4105ccSJon Lin 		     SPINAND_HAS_QE_BIT,
948c4105ccSJon Lin 		     SPINAND_ECCINFO(&bwjx08k_ooblayout,
958c4105ccSJon Lin 				     bwjx08k_ecc_get_status)),
968c4105ccSJon Lin };
978c4105ccSJon Lin 
988c4105ccSJon Lin static const struct spinand_manufacturer_ops biwin_spinand_manuf_ops = {
998c4105ccSJon Lin };
1008c4105ccSJon Lin 
1018c4105ccSJon Lin const struct spinand_manufacturer biwin_spinand_manufacturer = {
1028c4105ccSJon Lin 	.id = SPINAND_MFR_BIWIN,
1038c4105ccSJon Lin 	.name = "BIWIN",
104*81afcfe1SJon Lin 	.chips = biwin_spinand_table,
105*81afcfe1SJon Lin 	.nchips = ARRAY_SIZE(biwin_spinand_table),
1068c4105ccSJon Lin 	.ops = &biwin_spinand_manuf_ops,
1078c4105ccSJon Lin };
108