xref: /linux/drivers/mtd/nand/spi/skyhigh.c (revision 08de7f9d4d39fd9aa5e747a13acc891214fa2d5f)
11a50e361STakahiro Kuwano // SPDX-License-Identifier: GPL-2.0
21a50e361STakahiro Kuwano /*
31a50e361STakahiro Kuwano  * Copyright (c) 2024 SkyHigh Memory Limited
41a50e361STakahiro Kuwano  *
51a50e361STakahiro Kuwano  * Author: Takahiro Kuwano <takahiro.kuwano@infineon.com>
61a50e361STakahiro Kuwano  * Co-Author: KR Kim <kr.kim@skyhighmemory.com>
71a50e361STakahiro Kuwano  */
81a50e361STakahiro Kuwano 
91a50e361STakahiro Kuwano #include <linux/device.h>
101a50e361STakahiro Kuwano #include <linux/kernel.h>
111a50e361STakahiro Kuwano #include <linux/mtd/spinand.h>
121a50e361STakahiro Kuwano 
131a50e361STakahiro Kuwano #define SPINAND_MFR_SKYHIGH			0x01
141a50e361STakahiro Kuwano #define SKYHIGH_STATUS_ECC_1TO2_BITFLIPS	(1 << 4)
151a50e361STakahiro Kuwano #define SKYHIGH_STATUS_ECC_3TO6_BITFLIPS	(2 << 4)
161a50e361STakahiro Kuwano #define SKYHIGH_STATUS_ECC_UNCOR_ERROR		(3 << 4)
171a50e361STakahiro Kuwano #define SKYHIGH_CONFIG_PROTECT_EN		BIT(1)
181a50e361STakahiro Kuwano 
191a50e361STakahiro Kuwano static SPINAND_OP_VARIANTS(read_cache_variants,
201a50e361STakahiro Kuwano 		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 4, NULL, 0),
211a50e361STakahiro Kuwano 		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
221a50e361STakahiro Kuwano 		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 2, NULL, 0),
231a50e361STakahiro Kuwano 		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
24*98b34d52SMiquel Raynal 		SPINAND_PAGE_READ_FROM_CACHE_FAST_OP(0, 1, NULL, 0),
25*98b34d52SMiquel Raynal 		SPINAND_PAGE_READ_FROM_CACHE_OP(0, 1, NULL, 0));
261a50e361STakahiro Kuwano 
271a50e361STakahiro Kuwano static SPINAND_OP_VARIANTS(write_cache_variants,
281a50e361STakahiro Kuwano 		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
291a50e361STakahiro Kuwano 		SPINAND_PROG_LOAD(true, 0, NULL, 0));
301a50e361STakahiro Kuwano 
311a50e361STakahiro Kuwano static SPINAND_OP_VARIANTS(update_cache_variants,
321a50e361STakahiro Kuwano 		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
331a50e361STakahiro Kuwano 		SPINAND_PROG_LOAD(false, 0, NULL, 0));
341a50e361STakahiro Kuwano 
351a50e361STakahiro Kuwano static int skyhigh_spinand_ooblayout_ecc(struct mtd_info *mtd, int section,
361a50e361STakahiro Kuwano 					 struct mtd_oob_region *region)
371a50e361STakahiro Kuwano {
381a50e361STakahiro Kuwano 	/* ECC bytes are stored in hidden area. */
391a50e361STakahiro Kuwano 	return -ERANGE;
401a50e361STakahiro Kuwano }
411a50e361STakahiro Kuwano 
421a50e361STakahiro Kuwano static int skyhigh_spinand_ooblayout_free(struct mtd_info *mtd, int section,
431a50e361STakahiro Kuwano 					  struct mtd_oob_region *region)
441a50e361STakahiro Kuwano {
451a50e361STakahiro Kuwano 	if (section)
461a50e361STakahiro Kuwano 		return -ERANGE;
471a50e361STakahiro Kuwano 
481a50e361STakahiro Kuwano 	/* ECC bytes are stored in hidden area. Reserve 2 bytes for the BBM. */
491a50e361STakahiro Kuwano 	region->offset = 2;
501a50e361STakahiro Kuwano 	region->length = mtd->oobsize - 2;
511a50e361STakahiro Kuwano 
521a50e361STakahiro Kuwano 	return 0;
531a50e361STakahiro Kuwano }
541a50e361STakahiro Kuwano 
551a50e361STakahiro Kuwano static const struct mtd_ooblayout_ops skyhigh_spinand_ooblayout = {
561a50e361STakahiro Kuwano 	.ecc = skyhigh_spinand_ooblayout_ecc,
571a50e361STakahiro Kuwano 	.free = skyhigh_spinand_ooblayout_free,
581a50e361STakahiro Kuwano };
591a50e361STakahiro Kuwano 
601a50e361STakahiro Kuwano static int skyhigh_spinand_ecc_get_status(struct spinand_device *spinand,
611a50e361STakahiro Kuwano 					  u8 status)
621a50e361STakahiro Kuwano {
631a50e361STakahiro Kuwano 	switch (status & STATUS_ECC_MASK) {
641a50e361STakahiro Kuwano 	case STATUS_ECC_NO_BITFLIPS:
651a50e361STakahiro Kuwano 		return 0;
661a50e361STakahiro Kuwano 
671a50e361STakahiro Kuwano 	case SKYHIGH_STATUS_ECC_UNCOR_ERROR:
681a50e361STakahiro Kuwano 		return -EBADMSG;
691a50e361STakahiro Kuwano 
701a50e361STakahiro Kuwano 	case SKYHIGH_STATUS_ECC_1TO2_BITFLIPS:
711a50e361STakahiro Kuwano 		return 2;
721a50e361STakahiro Kuwano 
731a50e361STakahiro Kuwano 	case SKYHIGH_STATUS_ECC_3TO6_BITFLIPS:
741a50e361STakahiro Kuwano 		return 6;
751a50e361STakahiro Kuwano 
761a50e361STakahiro Kuwano 	default:
771a50e361STakahiro Kuwano 		break;
781a50e361STakahiro Kuwano 	}
791a50e361STakahiro Kuwano 
801a50e361STakahiro Kuwano 	return -EINVAL;
811a50e361STakahiro Kuwano }
821a50e361STakahiro Kuwano 
831a50e361STakahiro Kuwano static const struct spinand_info skyhigh_spinand_table[] = {
841a50e361STakahiro Kuwano 	SPINAND_INFO("S35ML01G301",
851a50e361STakahiro Kuwano 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x15),
861a50e361STakahiro Kuwano 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
871a50e361STakahiro Kuwano 		     NAND_ECCREQ(6, 32),
881a50e361STakahiro Kuwano 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
891a50e361STakahiro Kuwano 					      &write_cache_variants,
901a50e361STakahiro Kuwano 					      &update_cache_variants),
911a50e361STakahiro Kuwano 		     SPINAND_NO_RAW_ACCESS,
921a50e361STakahiro Kuwano 		     SPINAND_ECCINFO(&skyhigh_spinand_ooblayout,
931a50e361STakahiro Kuwano 				     skyhigh_spinand_ecc_get_status)),
941a50e361STakahiro Kuwano 	SPINAND_INFO("S35ML01G300",
951a50e361STakahiro Kuwano 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14),
961a50e361STakahiro Kuwano 		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
971a50e361STakahiro Kuwano 		     NAND_ECCREQ(6, 32),
981a50e361STakahiro Kuwano 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
991a50e361STakahiro Kuwano 					      &write_cache_variants,
1001a50e361STakahiro Kuwano 					      &update_cache_variants),
1011a50e361STakahiro Kuwano 		     SPINAND_NO_RAW_ACCESS,
1021a50e361STakahiro Kuwano 		     SPINAND_ECCINFO(&skyhigh_spinand_ooblayout,
1031a50e361STakahiro Kuwano 				     skyhigh_spinand_ecc_get_status)),
1041a50e361STakahiro Kuwano 	SPINAND_INFO("S35ML02G300",
1051a50e361STakahiro Kuwano 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x25),
1061a50e361STakahiro Kuwano 		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
1071a50e361STakahiro Kuwano 		     NAND_ECCREQ(6, 32),
1081a50e361STakahiro Kuwano 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
1091a50e361STakahiro Kuwano 					      &write_cache_variants,
1101a50e361STakahiro Kuwano 					      &update_cache_variants),
1111a50e361STakahiro Kuwano 		     SPINAND_NO_RAW_ACCESS,
1121a50e361STakahiro Kuwano 		     SPINAND_ECCINFO(&skyhigh_spinand_ooblayout,
1131a50e361STakahiro Kuwano 				     skyhigh_spinand_ecc_get_status)),
1141a50e361STakahiro Kuwano 	SPINAND_INFO("S35ML04G300",
1151a50e361STakahiro Kuwano 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35),
1161a50e361STakahiro Kuwano 		     NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 2, 1, 1),
1171a50e361STakahiro Kuwano 		     NAND_ECCREQ(6, 32),
1181a50e361STakahiro Kuwano 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
1191a50e361STakahiro Kuwano 					      &write_cache_variants,
1201a50e361STakahiro Kuwano 					      &update_cache_variants),
1211a50e361STakahiro Kuwano 		     SPINAND_NO_RAW_ACCESS,
1221a50e361STakahiro Kuwano 		     SPINAND_ECCINFO(&skyhigh_spinand_ooblayout,
1231a50e361STakahiro Kuwano 				     skyhigh_spinand_ecc_get_status)),
1241a50e361STakahiro Kuwano };
1251a50e361STakahiro Kuwano 
1261a50e361STakahiro Kuwano static int skyhigh_spinand_init(struct spinand_device *spinand)
1271a50e361STakahiro Kuwano {
1281a50e361STakahiro Kuwano 	/*
1291a50e361STakahiro Kuwano 	 * Config_Protect_En (bit 1 in Block Lock register) must be set to 1
1301a50e361STakahiro Kuwano 	 * before writing other bits. Do it here before core unlocks all blocks
1311a50e361STakahiro Kuwano 	 * by writing block protection bits.
1321a50e361STakahiro Kuwano 	 */
1331a50e361STakahiro Kuwano 	return spinand_write_reg_op(spinand, REG_BLOCK_LOCK,
1341a50e361STakahiro Kuwano 				    SKYHIGH_CONFIG_PROTECT_EN);
1351a50e361STakahiro Kuwano }
1361a50e361STakahiro Kuwano 
1371a50e361STakahiro Kuwano static const struct spinand_manufacturer_ops skyhigh_spinand_manuf_ops = {
1381a50e361STakahiro Kuwano 	.init = skyhigh_spinand_init,
1391a50e361STakahiro Kuwano };
1401a50e361STakahiro Kuwano 
1411a50e361STakahiro Kuwano const struct spinand_manufacturer skyhigh_spinand_manufacturer = {
1421a50e361STakahiro Kuwano 	.id = SPINAND_MFR_SKYHIGH,
1431a50e361STakahiro Kuwano 	.name = "SkyHigh",
1441a50e361STakahiro Kuwano 	.chips = skyhigh_spinand_table,
1451a50e361STakahiro Kuwano 	.nchips = ARRAY_SIZE(skyhigh_spinand_table),
1461a50e361STakahiro Kuwano 	.ops = &skyhigh_spinand_manuf_ops,
1471a50e361STakahiro Kuwano };
148