xref: /openbmc/u-boot/drivers/mtd/nand/spi/macronix.c (revision 592cd5defd4f71d34ffcbd8dd3326bc10f662e20)
16f041ccaSBoris Brezillon // SPDX-License-Identifier: GPL-2.0
26f041ccaSBoris Brezillon /*
36f041ccaSBoris Brezillon  * Copyright (c) 2018 Macronix
46f041ccaSBoris Brezillon  *
56f041ccaSBoris Brezillon  * Author: Boris Brezillon <boris.brezillon@bootlin.com>
66f041ccaSBoris Brezillon  */
76f041ccaSBoris Brezillon 
86f041ccaSBoris Brezillon #ifndef __UBOOT__
96f041ccaSBoris Brezillon #include <linux/device.h>
106f041ccaSBoris Brezillon #include <linux/kernel.h>
116f041ccaSBoris Brezillon #endif
126f041ccaSBoris Brezillon #include <linux/mtd/spinand.h>
136f041ccaSBoris Brezillon 
146f041ccaSBoris Brezillon #define SPINAND_MFR_MACRONIX		0xC2
156f041ccaSBoris Brezillon 
166f041ccaSBoris Brezillon static SPINAND_OP_VARIANTS(read_cache_variants,
176f041ccaSBoris Brezillon 		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
186f041ccaSBoris Brezillon 		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
196f041ccaSBoris Brezillon 		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
206f041ccaSBoris Brezillon 		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
216f041ccaSBoris Brezillon 
226f041ccaSBoris Brezillon static SPINAND_OP_VARIANTS(write_cache_variants,
236f041ccaSBoris Brezillon 		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
246f041ccaSBoris Brezillon 		SPINAND_PROG_LOAD(true, 0, NULL, 0));
256f041ccaSBoris Brezillon 
266f041ccaSBoris Brezillon static SPINAND_OP_VARIANTS(update_cache_variants,
276f041ccaSBoris Brezillon 		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
286f041ccaSBoris Brezillon 		SPINAND_PROG_LOAD(false, 0, NULL, 0));
296f041ccaSBoris Brezillon 
mx35lfxge4ab_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)30*515d0212SMiquel Raynal static int mx35lfxge4ab_ooblayout_ecc(struct mtd_info *mtd, int section,
316f041ccaSBoris Brezillon 				      struct mtd_oob_region *region)
326f041ccaSBoris Brezillon {
336f041ccaSBoris Brezillon 	return -ERANGE;
346f041ccaSBoris Brezillon }
356f041ccaSBoris Brezillon 
mx35lfxge4ab_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)36*515d0212SMiquel Raynal static int mx35lfxge4ab_ooblayout_free(struct mtd_info *mtd, int section,
376f041ccaSBoris Brezillon 				       struct mtd_oob_region *region)
386f041ccaSBoris Brezillon {
396f041ccaSBoris Brezillon 	if (section)
406f041ccaSBoris Brezillon 		return -ERANGE;
416f041ccaSBoris Brezillon 
426f041ccaSBoris Brezillon 	region->offset = 2;
436f041ccaSBoris Brezillon 	region->length = mtd->oobsize - 2;
446f041ccaSBoris Brezillon 
456f041ccaSBoris Brezillon 	return 0;
466f041ccaSBoris Brezillon }
476f041ccaSBoris Brezillon 
48*515d0212SMiquel Raynal static const struct mtd_ooblayout_ops mx35lfxge4ab_ooblayout = {
49*515d0212SMiquel Raynal 	.ecc = mx35lfxge4ab_ooblayout_ecc,
50*515d0212SMiquel Raynal 	.free = mx35lfxge4ab_ooblayout_free,
516f041ccaSBoris Brezillon };
526f041ccaSBoris Brezillon 
mx35lf1ge4ab_get_eccsr(struct spinand_device * spinand,u8 * eccsr)536f041ccaSBoris Brezillon static int mx35lf1ge4ab_get_eccsr(struct spinand_device *spinand, u8 *eccsr)
546f041ccaSBoris Brezillon {
556f041ccaSBoris Brezillon 	struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(0x7c, 1),
566f041ccaSBoris Brezillon 					  SPI_MEM_OP_NO_ADDR,
576f041ccaSBoris Brezillon 					  SPI_MEM_OP_DUMMY(1, 1),
586f041ccaSBoris Brezillon 					  SPI_MEM_OP_DATA_IN(1, eccsr, 1));
596f041ccaSBoris Brezillon 
606f041ccaSBoris Brezillon 	return spi_mem_exec_op(spinand->slave, &op);
616f041ccaSBoris Brezillon }
626f041ccaSBoris Brezillon 
mx35lf1ge4ab_ecc_get_status(struct spinand_device * spinand,u8 status)636f041ccaSBoris Brezillon static int mx35lf1ge4ab_ecc_get_status(struct spinand_device *spinand,
646f041ccaSBoris Brezillon 				       u8 status)
656f041ccaSBoris Brezillon {
666f041ccaSBoris Brezillon 	struct nand_device *nand = spinand_to_nand(spinand);
676f041ccaSBoris Brezillon 	u8 eccsr;
686f041ccaSBoris Brezillon 
696f041ccaSBoris Brezillon 	switch (status & STATUS_ECC_MASK) {
706f041ccaSBoris Brezillon 	case STATUS_ECC_NO_BITFLIPS:
716f041ccaSBoris Brezillon 		return 0;
726f041ccaSBoris Brezillon 
736f041ccaSBoris Brezillon 	case STATUS_ECC_UNCOR_ERROR:
746f041ccaSBoris Brezillon 		return -EBADMSG;
756f041ccaSBoris Brezillon 
766f041ccaSBoris Brezillon 	case STATUS_ECC_HAS_BITFLIPS:
776f041ccaSBoris Brezillon 		/*
786f041ccaSBoris Brezillon 		 * Let's try to retrieve the real maximum number of bitflips
796f041ccaSBoris Brezillon 		 * in order to avoid forcing the wear-leveling layer to move
806f041ccaSBoris Brezillon 		 * data around if it's not necessary.
816f041ccaSBoris Brezillon 		 */
826f041ccaSBoris Brezillon 		if (mx35lf1ge4ab_get_eccsr(spinand, &eccsr))
836f041ccaSBoris Brezillon 			return nand->eccreq.strength;
846f041ccaSBoris Brezillon 
856f041ccaSBoris Brezillon 		if (WARN_ON(eccsr > nand->eccreq.strength || !eccsr))
866f041ccaSBoris Brezillon 			return nand->eccreq.strength;
876f041ccaSBoris Brezillon 
886f041ccaSBoris Brezillon 		return eccsr;
896f041ccaSBoris Brezillon 
906f041ccaSBoris Brezillon 	default:
916f041ccaSBoris Brezillon 		break;
926f041ccaSBoris Brezillon 	}
936f041ccaSBoris Brezillon 
946f041ccaSBoris Brezillon 	return -EINVAL;
956f041ccaSBoris Brezillon }
966f041ccaSBoris Brezillon 
976f041ccaSBoris Brezillon static const struct spinand_info macronix_spinand_table[] = {
986f041ccaSBoris Brezillon 	SPINAND_INFO("MX35LF1GE4AB", 0x12,
996f041ccaSBoris Brezillon 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
1006f041ccaSBoris Brezillon 		     NAND_ECCREQ(4, 512),
1016f041ccaSBoris Brezillon 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
1026f041ccaSBoris Brezillon 					      &write_cache_variants,
1036f041ccaSBoris Brezillon 					      &update_cache_variants),
1046f041ccaSBoris Brezillon 		     SPINAND_HAS_QE_BIT,
105*515d0212SMiquel Raynal 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
1066f041ccaSBoris Brezillon 				     mx35lf1ge4ab_ecc_get_status)),
107*515d0212SMiquel Raynal 	SPINAND_INFO("MX35LF2GE4AB", 0x22,
108*515d0212SMiquel Raynal 		     NAND_MEMORG(1, 2048, 64, 64, 2048, 2, 1, 1),
109*515d0212SMiquel Raynal 		     NAND_ECCREQ(4, 512),
110*515d0212SMiquel Raynal 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
111*515d0212SMiquel Raynal 					      &write_cache_variants,
112*515d0212SMiquel Raynal 					      &update_cache_variants),
113*515d0212SMiquel Raynal 		     SPINAND_HAS_QE_BIT,
114*515d0212SMiquel Raynal 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
1156f041ccaSBoris Brezillon };
1166f041ccaSBoris Brezillon 
macronix_spinand_detect(struct spinand_device * spinand)1176f041ccaSBoris Brezillon static int macronix_spinand_detect(struct spinand_device *spinand)
1186f041ccaSBoris Brezillon {
1196f041ccaSBoris Brezillon 	u8 *id = spinand->id.data;
1206f041ccaSBoris Brezillon 	int ret;
1216f041ccaSBoris Brezillon 
1226f041ccaSBoris Brezillon 	/*
1236f041ccaSBoris Brezillon 	 * Macronix SPI NAND read ID needs a dummy byte, so the first byte in
1246f041ccaSBoris Brezillon 	 * raw_id is garbage.
1256f041ccaSBoris Brezillon 	 */
1266f041ccaSBoris Brezillon 	if (id[1] != SPINAND_MFR_MACRONIX)
1276f041ccaSBoris Brezillon 		return 0;
1286f041ccaSBoris Brezillon 
1296f041ccaSBoris Brezillon 	ret = spinand_match_and_init(spinand, macronix_spinand_table,
1306f041ccaSBoris Brezillon 				     ARRAY_SIZE(macronix_spinand_table),
1316f041ccaSBoris Brezillon 				     id[2]);
1326f041ccaSBoris Brezillon 	if (ret)
1336f041ccaSBoris Brezillon 		return ret;
1346f041ccaSBoris Brezillon 
1356f041ccaSBoris Brezillon 	return 1;
1366f041ccaSBoris Brezillon }
1376f041ccaSBoris Brezillon 
1386f041ccaSBoris Brezillon static const struct spinand_manufacturer_ops macronix_spinand_manuf_ops = {
1396f041ccaSBoris Brezillon 	.detect = macronix_spinand_detect,
1406f041ccaSBoris Brezillon };
1416f041ccaSBoris Brezillon 
1426f041ccaSBoris Brezillon const struct spinand_manufacturer macronix_spinand_manufacturer = {
1436f041ccaSBoris Brezillon 	.id = SPINAND_MFR_MACRONIX,
1446f041ccaSBoris Brezillon 	.name = "Macronix",
1456f041ccaSBoris Brezillon 	.ops = &macronix_spinand_manuf_ops,
1466f041ccaSBoris Brezillon };
147