xref: /rk3399_rockchip-uboot/drivers/mtd/nand/spi/gigadevice.c (revision f90b37db51e94492843ba992f5e8231766bfa105)
16eb4b036SStefan Roese // SPDX-License-Identifier: GPL-2.0
26eb4b036SStefan Roese /*
36eb4b036SStefan Roese  * Copyright (C) 2018 Stefan Roese <sr@denx.de>
46eb4b036SStefan Roese  *
56eb4b036SStefan Roese  * Derived from drivers/mtd/nand/spi/micron.c
66eb4b036SStefan Roese  *   Copyright (c) 2016-2017 Micron Technology, Inc.
76eb4b036SStefan Roese  */
86eb4b036SStefan Roese 
96eb4b036SStefan Roese #ifndef __UBOOT__
106eb4b036SStefan Roese #include <linux/device.h>
116eb4b036SStefan Roese #include <linux/kernel.h>
126eb4b036SStefan Roese #endif
136eb4b036SStefan Roese #include <linux/mtd/spinand.h>
146eb4b036SStefan Roese 
15a7b78be4SStefan Roese #define SPINAND_MFR_GIGADEVICE			0xC8
166eb4b036SStefan Roese 
173a9e6261SJon Lin #define GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS	(1 << 4)
183a9e6261SJon Lin #define GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS	(3 << 4)
193a9e6261SJon Lin 
203a9e6261SJon Lin #define GD5FXGQ5XE_STATUS_ECC_1_4_BITFLIPS	(1 << 4)
213a9e6261SJon Lin #define GD5FXGQ5XE_STATUS_ECC_4_BITFLIPS	(3 << 4)
223a9e6261SJon Lin 
233a9e6261SJon Lin #define GD5FXGQXXEXXG_REG_STATUS2		0xf0
243a9e6261SJon Lin 
253a9e6261SJon Lin #define GD5FXGQ4UXFXXG_STATUS_ECC_MASK		(7 << 4)
263a9e6261SJon Lin #define GD5FXGQ4UXFXXG_STATUS_ECC_NO_BITFLIPS	(0 << 4)
273a9e6261SJon Lin #define GD5FXGQ4UXFXXG_STATUS_ECC_1_3_BITFLIPS	(1 << 4)
283a9e6261SJon Lin #define GD5FXGQ4UXFXXG_STATUS_ECC_UNCOR_ERROR	(7 << 4)
296eb4b036SStefan Roese 
306eb4b036SStefan Roese static SPINAND_OP_VARIANTS(read_cache_variants,
313a9e6261SJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
326eb4b036SStefan Roese 		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
336eb4b036SStefan Roese 		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
346eb4b036SStefan Roese 		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
356eb4b036SStefan Roese 		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
366eb4b036SStefan Roese 		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
376eb4b036SStefan Roese 
383a9e6261SJon Lin static SPINAND_OP_VARIANTS(read_cache_variants_f,
393a9e6261SJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
403a9e6261SJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_X4_OP_3A(0, 1, NULL, 0),
413a9e6261SJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
423a9e6261SJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_X2_OP_3A(0, 1, NULL, 0),
433a9e6261SJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_OP_3A(true, 0, 1, NULL, 0),
443a9e6261SJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_OP_3A(false, 0, 0, NULL, 0));
453a9e6261SJon Lin 
464ae7a4efSJon Lin static SPINAND_OP_VARIANTS(read_cache_variants_1gq5,
474ae7a4efSJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
484ae7a4efSJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
494ae7a4efSJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
504ae7a4efSJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
514ae7a4efSJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
524ae7a4efSJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
534ae7a4efSJon Lin 
544ae7a4efSJon Lin static SPINAND_OP_VARIANTS(read_cache_variants_2gq5,
554ae7a4efSJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 4, NULL, 0),
564ae7a4efSJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
574ae7a4efSJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 2, NULL, 0),
584ae7a4efSJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
594ae7a4efSJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
604ae7a4efSJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
614ae7a4efSJon Lin 
626eb4b036SStefan Roese static SPINAND_OP_VARIANTS(write_cache_variants,
636eb4b036SStefan Roese 		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
646eb4b036SStefan Roese 		SPINAND_PROG_LOAD(true, 0, NULL, 0));
656eb4b036SStefan Roese 
666eb4b036SStefan Roese static SPINAND_OP_VARIANTS(update_cache_variants,
676eb4b036SStefan Roese 		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
686eb4b036SStefan Roese 		SPINAND_PROG_LOAD(false, 0, NULL, 0));
696eb4b036SStefan Roese 
gd5fxgq4xa_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)703a9e6261SJon Lin static int gd5fxgq4xa_ooblayout_ecc(struct mtd_info *mtd, int section,
713a9e6261SJon Lin 				  struct mtd_oob_region *region)
723a9e6261SJon Lin {
733a9e6261SJon Lin 	if (section > 3)
743a9e6261SJon Lin 		return -ERANGE;
753a9e6261SJon Lin 
763a9e6261SJon Lin 	region->offset = (16 * section) + 8;
773a9e6261SJon Lin 	region->length = 8;
783a9e6261SJon Lin 
793a9e6261SJon Lin 	return 0;
803a9e6261SJon Lin }
813a9e6261SJon Lin 
gd5fxgq4xa_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)823a9e6261SJon Lin static int gd5fxgq4xa_ooblayout_free(struct mtd_info *mtd, int section,
833a9e6261SJon Lin 				   struct mtd_oob_region *region)
843a9e6261SJon Lin {
853a9e6261SJon Lin 	if (section > 3)
863a9e6261SJon Lin 		return -ERANGE;
873a9e6261SJon Lin 
883a9e6261SJon Lin 	if (section) {
893a9e6261SJon Lin 		region->offset = 16 * section;
903a9e6261SJon Lin 		region->length = 8;
913a9e6261SJon Lin 	} else {
923a9e6261SJon Lin 		/* section 0 has one byte reserved for bad block mark */
933a9e6261SJon Lin 		region->offset = 1;
943a9e6261SJon Lin 		region->length = 7;
953a9e6261SJon Lin 	}
963a9e6261SJon Lin 	return 0;
973a9e6261SJon Lin }
983a9e6261SJon Lin 
993a9e6261SJon Lin static const struct mtd_ooblayout_ops gd5fxgq4xa_ooblayout = {
1003a9e6261SJon Lin 	.ecc = gd5fxgq4xa_ooblayout_ecc,
1013a9e6261SJon Lin 	.rfree = gd5fxgq4xa_ooblayout_free,
1023a9e6261SJon Lin };
1033a9e6261SJon Lin 
gd5fxgq4xa_ecc_get_status(struct spinand_device * spinand,u8 status)1043a9e6261SJon Lin static int gd5fxgq4xa_ecc_get_status(struct spinand_device *spinand,
1053a9e6261SJon Lin 					 u8 status)
1063a9e6261SJon Lin {
1073a9e6261SJon Lin 	switch (status & STATUS_ECC_MASK) {
1083a9e6261SJon Lin 	case STATUS_ECC_NO_BITFLIPS:
1093a9e6261SJon Lin 		return 0;
1103a9e6261SJon Lin 
1113a9e6261SJon Lin 	case GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS:
1123a9e6261SJon Lin 		/* 1-7 bits are flipped. return the maximum. */
1133a9e6261SJon Lin 		return 7;
1143a9e6261SJon Lin 
1153a9e6261SJon Lin 	case GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS:
1163a9e6261SJon Lin 		return 8;
1173a9e6261SJon Lin 
1183a9e6261SJon Lin 	case STATUS_ECC_UNCOR_ERROR:
1193a9e6261SJon Lin 		return -EBADMSG;
1203a9e6261SJon Lin 
1213a9e6261SJon Lin 	default:
1223a9e6261SJon Lin 		break;
1233a9e6261SJon Lin 	}
1243a9e6261SJon Lin 
1253a9e6261SJon Lin 	return -EINVAL;
1263a9e6261SJon Lin }
1273a9e6261SJon Lin 
gd5fxgqx_variant2_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)1283a9e6261SJon Lin static int gd5fxgqx_variant2_ooblayout_ecc(struct mtd_info *mtd, int section,
1296eb4b036SStefan Roese 				       struct mtd_oob_region *region)
1306eb4b036SStefan Roese {
1316eb4b036SStefan Roese 	if (section)
1326eb4b036SStefan Roese 		return -ERANGE;
1336eb4b036SStefan Roese 
1346eb4b036SStefan Roese 	region->offset = 64;
1356eb4b036SStefan Roese 	region->length = 64;
1366eb4b036SStefan Roese 
1376eb4b036SStefan Roese 	return 0;
1386eb4b036SStefan Roese }
1396eb4b036SStefan Roese 
gd5fxgqx_variant2_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)1403a9e6261SJon Lin static int gd5fxgqx_variant2_ooblayout_free(struct mtd_info *mtd, int section,
1416eb4b036SStefan Roese 					struct mtd_oob_region *region)
1426eb4b036SStefan Roese {
1436eb4b036SStefan Roese 	if (section)
1446eb4b036SStefan Roese 		return -ERANGE;
1456eb4b036SStefan Roese 
146a7b78be4SStefan Roese 	/* Reserve 1 bytes for the BBM. */
147a7b78be4SStefan Roese 	region->offset = 1;
148a7b78be4SStefan Roese 	region->length = 63;
1496eb4b036SStefan Roese 
1506eb4b036SStefan Roese 	return 0;
1516eb4b036SStefan Roese }
1526eb4b036SStefan Roese 
1533a9e6261SJon Lin /* Valid for Q4/Q5 and Q6 (untested) devices */
1543a9e6261SJon Lin static const struct mtd_ooblayout_ops gd5fxgqx_variant2_ooblayout = {
1553a9e6261SJon Lin 	.ecc = gd5fxgqx_variant2_ooblayout_ecc,
1563a9e6261SJon Lin 	.rfree = gd5fxgqx_variant2_ooblayout_free,
1573a9e6261SJon Lin };
1583a9e6261SJon Lin 
gd5fxgq4xc_ooblayout_256_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * oobregion)1593a9e6261SJon Lin static int gd5fxgq4xc_ooblayout_256_ecc(struct mtd_info *mtd, int section,
1603a9e6261SJon Lin 					struct mtd_oob_region *oobregion)
1613a9e6261SJon Lin {
1623a9e6261SJon Lin 	if (section)
1633a9e6261SJon Lin 		return -ERANGE;
1643a9e6261SJon Lin 
1653a9e6261SJon Lin 	oobregion->offset = 128;
1663a9e6261SJon Lin 	oobregion->length = 128;
1673a9e6261SJon Lin 
1683a9e6261SJon Lin 	return 0;
1693a9e6261SJon Lin }
1703a9e6261SJon Lin 
gd5fxgq4xc_ooblayout_256_free(struct mtd_info * mtd,int section,struct mtd_oob_region * oobregion)1713a9e6261SJon Lin static int gd5fxgq4xc_ooblayout_256_free(struct mtd_info *mtd, int section,
1723a9e6261SJon Lin 					 struct mtd_oob_region *oobregion)
1733a9e6261SJon Lin {
1743a9e6261SJon Lin 	if (section)
1753a9e6261SJon Lin 		return -ERANGE;
1763a9e6261SJon Lin 
1773a9e6261SJon Lin 	oobregion->offset = 1;
1783a9e6261SJon Lin 	oobregion->length = 127;
1793a9e6261SJon Lin 
1803a9e6261SJon Lin 	return 0;
1813a9e6261SJon Lin }
1823a9e6261SJon Lin 
1833a9e6261SJon Lin static const struct mtd_ooblayout_ops gd5fxgq4xc_oob_256_ops = {
1843a9e6261SJon Lin 	.ecc = gd5fxgq4xc_ooblayout_256_ecc,
1853a9e6261SJon Lin 	.rfree = gd5fxgq4xc_ooblayout_256_free,
1863a9e6261SJon Lin };
1873a9e6261SJon Lin 
gd5fxgqx_variant3_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)1883a9e6261SJon Lin static int gd5fxgqx_variant3_ooblayout_ecc(struct mtd_info *mtd, int section,
1893a9e6261SJon Lin 				       struct mtd_oob_region *region)
1903a9e6261SJon Lin {
1913a9e6261SJon Lin 	return -ERANGE;
1923a9e6261SJon Lin }
1933a9e6261SJon Lin 
gd5fxgqx_variant3_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)1943a9e6261SJon Lin static int gd5fxgqx_variant3_ooblayout_free(struct mtd_info *mtd, int section,
1953a9e6261SJon Lin 					struct mtd_oob_region *region)
1963a9e6261SJon Lin {
1973a9e6261SJon Lin 	if (section)
1983a9e6261SJon Lin 		return -ERANGE;
1993a9e6261SJon Lin 
2003a9e6261SJon Lin 	/* Reserve 1 bytes for the BBM. */
2013a9e6261SJon Lin 	region->offset = 1;
2023a9e6261SJon Lin 	region->length = 63;
2033a9e6261SJon Lin 
2043a9e6261SJon Lin 	return 0;
2053a9e6261SJon Lin }
2063a9e6261SJon Lin 
2073a9e6261SJon Lin static const struct mtd_ooblayout_ops gd5fxgqx_variant3_ooblayout = {
2083a9e6261SJon Lin 	.ecc = gd5fxgqx_variant3_ooblayout_ecc,
2093a9e6261SJon Lin 	.rfree = gd5fxgqx_variant3_ooblayout_free,
2103a9e6261SJon Lin };
2113a9e6261SJon Lin 
gd5fxgq4uexxg_ecc_get_status(struct spinand_device * spinand,u8 status)2123a9e6261SJon Lin static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand,
2136eb4b036SStefan Roese 					u8 status)
2146eb4b036SStefan Roese {
215a7b78be4SStefan Roese 	u8 status2;
2163a9e6261SJon Lin 	struct spi_mem_op op = SPINAND_GET_FEATURE_OP(GD5FXGQXXEXXG_REG_STATUS2,
217a7b78be4SStefan Roese 						      &status2);
218a7b78be4SStefan Roese 	int ret;
2196eb4b036SStefan Roese 
220a7b78be4SStefan Roese 	switch (status & STATUS_ECC_MASK) {
2216eb4b036SStefan Roese 	case STATUS_ECC_NO_BITFLIPS:
2226eb4b036SStefan Roese 		return 0;
2236eb4b036SStefan Roese 
2243a9e6261SJon Lin 	case GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS:
225a7b78be4SStefan Roese 		/*
226a7b78be4SStefan Roese 		 * Read status2 register to determine a more fine grained
227a7b78be4SStefan Roese 		 * bit error status
228a7b78be4SStefan Roese 		 */
229a7b78be4SStefan Roese 		ret = spi_mem_exec_op(spinand->slave, &op);
230a7b78be4SStefan Roese 		if (ret)
231a7b78be4SStefan Roese 			return ret;
2326eb4b036SStefan Roese 
233a7b78be4SStefan Roese 		/*
234a7b78be4SStefan Roese 		 * 4 ... 7 bits are flipped (1..4 can't be detected, so
235a7b78be4SStefan Roese 		 * report the maximum of 4 in this case
236a7b78be4SStefan Roese 		 */
237a7b78be4SStefan Roese 		/* bits sorted this way (3...0): ECCS1,ECCS0,ECCSE1,ECCSE0 */
238a7b78be4SStefan Roese 		return ((status & STATUS_ECC_MASK) >> 2) |
239a7b78be4SStefan Roese 			((status2 & STATUS_ECC_MASK) >> 4);
240a7b78be4SStefan Roese 
2413a9e6261SJon Lin 	case GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS:
2426eb4b036SStefan Roese 		return 8;
2436eb4b036SStefan Roese 
2446eb4b036SStefan Roese 	case STATUS_ECC_UNCOR_ERROR:
2456eb4b036SStefan Roese 		return -EBADMSG;
2466eb4b036SStefan Roese 
2476eb4b036SStefan Roese 	default:
2486eb4b036SStefan Roese 		break;
2496eb4b036SStefan Roese 	}
2506eb4b036SStefan Roese 
2516eb4b036SStefan Roese 	return -EINVAL;
2526eb4b036SStefan Roese }
2536eb4b036SStefan Roese 
gd5fxgq5xexxg_ecc_get_status(struct spinand_device * spinand,u8 status)25414ce3c6dSJon Lin static int gd5fxgq5xexxg_ecc_get_status(struct spinand_device *spinand,
255ad65dd86SJon Lin 					u8 status)
256ad65dd86SJon Lin {
257ad65dd86SJon Lin 	u8 status2;
2583a9e6261SJon Lin 	struct spi_mem_op op = SPINAND_GET_FEATURE_OP(GD5FXGQXXEXXG_REG_STATUS2,
259ad65dd86SJon Lin 						      &status2);
260ad65dd86SJon Lin 	int ret;
261ad65dd86SJon Lin 
262ad65dd86SJon Lin 	switch (status & STATUS_ECC_MASK) {
263ad65dd86SJon Lin 	case STATUS_ECC_NO_BITFLIPS:
264ad65dd86SJon Lin 		return 0;
265ad65dd86SJon Lin 
2663a9e6261SJon Lin 	case GD5FXGQ5XE_STATUS_ECC_1_4_BITFLIPS:
267ad65dd86SJon Lin 		/*
268ad65dd86SJon Lin 		 * Read status2 register to determine a more fine grained
269ad65dd86SJon Lin 		 * bit error status
270ad65dd86SJon Lin 		 */
271ad65dd86SJon Lin 		ret = spi_mem_exec_op(spinand->slave, &op);
272ad65dd86SJon Lin 		if (ret)
273ad65dd86SJon Lin 			return ret;
274ad65dd86SJon Lin 
275ad65dd86SJon Lin 		/*
2763a9e6261SJon Lin 		 * 1 ... 4 bits are flipped (and corrected)
277ad65dd86SJon Lin 		 */
2783a9e6261SJon Lin 		/* bits sorted this way (1...0): ECCSE1, ECCSE0 */
2793a9e6261SJon Lin 		return ((status2 & STATUS_ECC_MASK) >> 4) + 1;
280ad65dd86SJon Lin 
281ad65dd86SJon Lin 	case STATUS_ECC_UNCOR_ERROR:
282ad65dd86SJon Lin 		return -EBADMSG;
283ad65dd86SJon Lin 
284ad65dd86SJon Lin 	default:
285ad65dd86SJon Lin 		break;
286ad65dd86SJon Lin 	}
287ad65dd86SJon Lin 
288ad65dd86SJon Lin 	return -EINVAL;
289ad65dd86SJon Lin }
290ad65dd86SJon Lin 
gd5fxgq4ufxxg_ecc_get_status(struct spinand_device * spinand,u8 status)2913a9e6261SJon Lin static int gd5fxgq4ufxxg_ecc_get_status(struct spinand_device *spinand,
2923a9e6261SJon Lin 					u8 status)
2938781c285SJon Lin {
2943a9e6261SJon Lin 	switch (status & GD5FXGQ4UXFXXG_STATUS_ECC_MASK) {
2953a9e6261SJon Lin 	case GD5FXGQ4UXFXXG_STATUS_ECC_NO_BITFLIPS:
2968781c285SJon Lin 		return 0;
2973a9e6261SJon Lin 
2983a9e6261SJon Lin 	case GD5FXGQ4UXFXXG_STATUS_ECC_1_3_BITFLIPS:
2993a9e6261SJon Lin 		return 3;
3003a9e6261SJon Lin 
3013a9e6261SJon Lin 	case GD5FXGQ4UXFXXG_STATUS_ECC_UNCOR_ERROR:
3023a9e6261SJon Lin 		return -EBADMSG;
3033a9e6261SJon Lin 
3043a9e6261SJon Lin 	default: /* (2 << 4) through (6 << 4) are 4-8 corrected errors */
3053a9e6261SJon Lin 		return ((status & GD5FXGQ4UXFXXG_STATUS_ECC_MASK) >> 4) + 2;
3068781c285SJon Lin 	}
3078781c285SJon Lin 
3083a9e6261SJon Lin 	return -EINVAL;
3093a9e6261SJon Lin }
3108781c285SJon Lin 
3116eb4b036SStefan Roese static const struct spinand_info gigadevice_spinand_table[] = {
3123a9e6261SJon Lin 	SPINAND_INFO("GD5F1GQ4xA",
3133a9e6261SJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf1),
3143a9e6261SJon Lin 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
3153a9e6261SJon Lin 		     NAND_ECCREQ(8, 512),
3163a9e6261SJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
3173a9e6261SJon Lin 					      &write_cache_variants,
3183a9e6261SJon Lin 					      &update_cache_variants),
3193a9e6261SJon Lin 		     SPINAND_HAS_QE_BIT,
3203a9e6261SJon Lin 		     SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
3213a9e6261SJon Lin 				     gd5fxgq4xa_ecc_get_status)),
3223a9e6261SJon Lin 	SPINAND_INFO("GD5F2GQ4xA",
3233a9e6261SJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf2),
3243a9e6261SJon Lin 		     NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1),
3253a9e6261SJon Lin 		     NAND_ECCREQ(8, 512),
3263a9e6261SJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
3273a9e6261SJon Lin 					      &write_cache_variants,
3283a9e6261SJon Lin 					      &update_cache_variants),
3293a9e6261SJon Lin 		     SPINAND_HAS_QE_BIT,
3303a9e6261SJon Lin 		     SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
3313a9e6261SJon Lin 				     gd5fxgq4xa_ecc_get_status)),
3323a9e6261SJon Lin 	SPINAND_INFO("GD5F4GQ4xA",
3333a9e6261SJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf4),
3343a9e6261SJon Lin 		     NAND_MEMORG(1, 2048, 64, 64, 4096, 1, 1, 1),
3353a9e6261SJon Lin 		     NAND_ECCREQ(8, 512),
3363a9e6261SJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
3373a9e6261SJon Lin 					      &write_cache_variants,
3383a9e6261SJon Lin 					      &update_cache_variants),
3393a9e6261SJon Lin 		     SPINAND_HAS_QE_BIT,
3403a9e6261SJon Lin 		     SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
3413a9e6261SJon Lin 				     gd5fxgq4xa_ecc_get_status)),
3423a9e6261SJon Lin 	SPINAND_INFO("GD5F4GQ4RC",
3433a9e6261SJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xa4, 0x68),
3443a9e6261SJon Lin 		     NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
3453a9e6261SJon Lin 		     NAND_ECCREQ(8, 512),
3463a9e6261SJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f,
3473a9e6261SJon Lin 					      &write_cache_variants,
3483a9e6261SJon Lin 					      &update_cache_variants),
3493a9e6261SJon Lin 		     SPINAND_HAS_QE_BIT,
3503a9e6261SJon Lin 		     SPINAND_ECCINFO(&gd5fxgq4xc_oob_256_ops,
3513a9e6261SJon Lin 				     gd5fxgq4ufxxg_ecc_get_status)),
3523a9e6261SJon Lin 	SPINAND_INFO("GD5F4GQ4UC",
3533a9e6261SJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xb4, 0x68),
3543a9e6261SJon Lin 		     NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
3553a9e6261SJon Lin 		     NAND_ECCREQ(8, 512),
3563a9e6261SJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f,
3573a9e6261SJon Lin 					      &write_cache_variants,
3583a9e6261SJon Lin 					      &update_cache_variants),
3593a9e6261SJon Lin 		     SPINAND_HAS_QE_BIT,
3603a9e6261SJon Lin 		     SPINAND_ECCINFO(&gd5fxgq4xc_oob_256_ops,
3613a9e6261SJon Lin 				     gd5fxgq4ufxxg_ecc_get_status)),
36281afcfe1SJon Lin 	SPINAND_INFO("GD5F1GQ4UExxG",
36381afcfe1SJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xd1),
3646eb4b036SStefan Roese 		     NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
365a7b78be4SStefan Roese 		     NAND_ECCREQ(8, 512),
3666eb4b036SStefan Roese 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
3676eb4b036SStefan Roese 					      &write_cache_variants,
3686eb4b036SStefan Roese 					      &update_cache_variants),
369cb560f19SJon Lin 		     SPINAND_HAS_QE_BIT,
3703a9e6261SJon Lin 		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
3713a9e6261SJon Lin 				     gd5fxgq4uexxg_ecc_get_status)),
3724ae7a4efSJon Lin 	SPINAND_INFO("GD5F1GQ4RExxG",
3734ae7a4efSJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xc1),
3744ae7a4efSJon Lin 		     NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
3754ae7a4efSJon Lin 		     NAND_ECCREQ(8, 512),
3764ae7a4efSJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
3774ae7a4efSJon Lin 					      &write_cache_variants,
3784ae7a4efSJon Lin 					      &update_cache_variants),
3794ae7a4efSJon Lin 		     SPINAND_HAS_QE_BIT,
3804ae7a4efSJon Lin 		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
3814ae7a4efSJon Lin 				     gd5fxgq4uexxg_ecc_get_status)),
3824ae7a4efSJon Lin 	SPINAND_INFO("GD5F2GQ4UExxG",
3834ae7a4efSJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xd2),
3844ae7a4efSJon Lin 		     NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
3854ae7a4efSJon Lin 		     NAND_ECCREQ(8, 512),
3864ae7a4efSJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
3874ae7a4efSJon Lin 					      &write_cache_variants,
3884ae7a4efSJon Lin 					      &update_cache_variants),
3894ae7a4efSJon Lin 		     SPINAND_HAS_QE_BIT,
3904ae7a4efSJon Lin 		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
3914ae7a4efSJon Lin 				     gd5fxgq4uexxg_ecc_get_status)),
3924ae7a4efSJon Lin 	SPINAND_INFO("GD5F2GQ4RExxG",
3934ae7a4efSJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xc2),
3944ae7a4efSJon Lin 		     NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
3954ae7a4efSJon Lin 		     NAND_ECCREQ(8, 512),
3964ae7a4efSJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
3974ae7a4efSJon Lin 					      &write_cache_variants,
3984ae7a4efSJon Lin 					      &update_cache_variants),
3994ae7a4efSJon Lin 		     SPINAND_HAS_QE_BIT,
4004ae7a4efSJon Lin 		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
4014ae7a4efSJon Lin 				     gd5fxgq4uexxg_ecc_get_status)),
4023a9e6261SJon Lin 	SPINAND_INFO("GD5F1GQ4UFxxG",
4033a9e6261SJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xb1, 0x48),
4043a9e6261SJon Lin 		     NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
4053a9e6261SJon Lin 		     NAND_ECCREQ(8, 512),
4063a9e6261SJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f,
4073a9e6261SJon Lin 					      &write_cache_variants,
4083a9e6261SJon Lin 					      &update_cache_variants),
4093a9e6261SJon Lin 		     SPINAND_HAS_QE_BIT,
4103a9e6261SJon Lin 		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
4113a9e6261SJon Lin 				     gd5fxgq4ufxxg_ecc_get_status)),
41281afcfe1SJon Lin 	SPINAND_INFO("GD5F1GQ5UExxG",
4133a9e6261SJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x51),
41414ce3c6dSJon Lin 		     NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
41514ce3c6dSJon Lin 		     NAND_ECCREQ(4, 512),
41614ce3c6dSJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
41714ce3c6dSJon Lin 					      &write_cache_variants,
41814ce3c6dSJon Lin 					      &update_cache_variants),
41914ce3c6dSJon Lin 		     SPINAND_HAS_QE_BIT,
4203a9e6261SJon Lin 		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
42114ce3c6dSJon Lin 				     gd5fxgq5xexxg_ecc_get_status)),
4224ae7a4efSJon Lin 	SPINAND_INFO("GD5F1GQ5RExxG",
423dbba95bbSJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x41, 0xC8),
4244ae7a4efSJon Lin 		     NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
425ad65dd86SJon Lin 		     NAND_ECCREQ(4, 512),
4264ae7a4efSJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5,
427ad65dd86SJon Lin 					      &write_cache_variants,
428ad65dd86SJon Lin 					      &update_cache_variants),
429ad65dd86SJon Lin 		     SPINAND_HAS_QE_BIT,
4303a9e6261SJon Lin 		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
43114ce3c6dSJon Lin 				     gd5fxgq5xexxg_ecc_get_status)),
4324ae7a4efSJon Lin 	SPINAND_INFO("GD5F2GQ5UExxG",
4334ae7a4efSJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x52),
4344ae7a4efSJon Lin 		     NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
4354ae7a4efSJon Lin 		     NAND_ECCREQ(4, 512),
4364ae7a4efSJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_2gq5,
4374ae7a4efSJon Lin 					      &write_cache_variants,
4384ae7a4efSJon Lin 					      &update_cache_variants),
4394ae7a4efSJon Lin 		     SPINAND_HAS_QE_BIT,
4404ae7a4efSJon Lin 		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
4414ae7a4efSJon Lin 				     gd5fxgq5xexxg_ecc_get_status)),
4424ae7a4efSJon Lin 	SPINAND_INFO("GD5F2GQ5RExxG",
4434ae7a4efSJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x42),
4444ae7a4efSJon Lin 		     NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
4454ae7a4efSJon Lin 		     NAND_ECCREQ(4, 512),
4464ae7a4efSJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_2gq5,
4474ae7a4efSJon Lin 					      &write_cache_variants,
4484ae7a4efSJon Lin 					      &update_cache_variants),
4494ae7a4efSJon Lin 		     SPINAND_HAS_QE_BIT,
4504ae7a4efSJon Lin 		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
4514ae7a4efSJon Lin 				     gd5fxgq5xexxg_ecc_get_status)),
4524ae7a4efSJon Lin 	SPINAND_INFO("GD5F4GQ6UExxG",
4534ae7a4efSJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x55),
4544ae7a4efSJon Lin 		     NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 2, 1),
4554ae7a4efSJon Lin 		     NAND_ECCREQ(4, 512),
4564ae7a4efSJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_2gq5,
4574ae7a4efSJon Lin 					      &write_cache_variants,
4584ae7a4efSJon Lin 					      &update_cache_variants),
4594ae7a4efSJon Lin 		     SPINAND_HAS_QE_BIT,
4604ae7a4efSJon Lin 		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
4614ae7a4efSJon Lin 				     gd5fxgq5xexxg_ecc_get_status)),
4624ae7a4efSJon Lin 	SPINAND_INFO("GD5F4GQ6RExxG",
4634ae7a4efSJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x45),
4644ae7a4efSJon Lin 		     NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 2, 1),
4654ae7a4efSJon Lin 		     NAND_ECCREQ(4, 512),
4664ae7a4efSJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_2gq5,
4674ae7a4efSJon Lin 					      &write_cache_variants,
4684ae7a4efSJon Lin 					      &update_cache_variants),
4694ae7a4efSJon Lin 		     SPINAND_HAS_QE_BIT,
4704ae7a4efSJon Lin 		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
4714ae7a4efSJon Lin 				     gd5fxgq5xexxg_ecc_get_status)),
4724ae7a4efSJon Lin 	SPINAND_INFO("GD5F1GM7UExxG",
4734ae7a4efSJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x91),
4744ae7a4efSJon Lin 		     NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
4754ae7a4efSJon Lin 		     NAND_ECCREQ(8, 512),
4764ae7a4efSJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5,
4774ae7a4efSJon Lin 					      &write_cache_variants,
4784ae7a4efSJon Lin 					      &update_cache_variants),
4794ae7a4efSJon Lin 		     SPINAND_HAS_QE_BIT,
4804ae7a4efSJon Lin 		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
4814ae7a4efSJon Lin 				     gd5fxgq4uexxg_ecc_get_status)),
4824ae7a4efSJon Lin 	SPINAND_INFO("GD5F1GM7RExxG",
4834ae7a4efSJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x81),
4844ae7a4efSJon Lin 		     NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
4854ae7a4efSJon Lin 		     NAND_ECCREQ(8, 512),
4864ae7a4efSJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5,
4874ae7a4efSJon Lin 					      &write_cache_variants,
4884ae7a4efSJon Lin 					      &update_cache_variants),
4894ae7a4efSJon Lin 		     SPINAND_HAS_QE_BIT,
4904ae7a4efSJon Lin 		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
4914ae7a4efSJon Lin 				     gd5fxgq4uexxg_ecc_get_status)),
4924ae7a4efSJon Lin 	SPINAND_INFO("GD5F2GM7UExxG",
4934ae7a4efSJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x92),
494b191872fSJon Lin 		     NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
495b191872fSJon Lin 		     NAND_ECCREQ(8, 512),
4964ae7a4efSJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5,
497b191872fSJon Lin 					      &write_cache_variants,
498b191872fSJon Lin 					      &update_cache_variants),
499b191872fSJon Lin 		     SPINAND_HAS_QE_BIT,
5003a9e6261SJon Lin 		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
5014ae7a4efSJon Lin 				     gd5fxgq4uexxg_ecc_get_status)),
5024ae7a4efSJon Lin 	SPINAND_INFO("GD5F2GM7RExxG",
5034ae7a4efSJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x82),
5044ae7a4efSJon Lin 		     NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
5054ae7a4efSJon Lin 		     NAND_ECCREQ(8, 512),
5064ae7a4efSJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5,
5074ae7a4efSJon Lin 					      &write_cache_variants,
5084ae7a4efSJon Lin 					      &update_cache_variants),
5094ae7a4efSJon Lin 		     SPINAND_HAS_QE_BIT,
5104ae7a4efSJon Lin 		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
5114ae7a4efSJon Lin 				     gd5fxgq4uexxg_ecc_get_status)),
5124ae7a4efSJon Lin 	SPINAND_INFO("GD5F4GM8UExxG",
5134ae7a4efSJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x95),
5141f161166SJon Lin 		     NAND_MEMORG(1, 2048, 128, 64, 4096, 1, 1, 1),
5154ae7a4efSJon Lin 		     NAND_ECCREQ(8, 512),
5164ae7a4efSJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5,
5171f161166SJon Lin 					      &write_cache_variants,
5181f161166SJon Lin 					      &update_cache_variants),
5191f161166SJon Lin 		     SPINAND_HAS_QE_BIT,
5203a9e6261SJon Lin 		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
5214ae7a4efSJon Lin 				     gd5fxgq4uexxg_ecc_get_status)),
5224ae7a4efSJon Lin 	SPINAND_INFO("GD5F4GM8RExxG",
5234ae7a4efSJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x85),
5244ae7a4efSJon Lin 		     NAND_MEMORG(1, 2048, 128, 64, 4096, 1, 1, 1),
5254ae7a4efSJon Lin 		     NAND_ECCREQ(8, 512),
5264ae7a4efSJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5,
5274ae7a4efSJon Lin 					      &write_cache_variants,
5284ae7a4efSJon Lin 					      &update_cache_variants),
5294ae7a4efSJon Lin 		     SPINAND_HAS_QE_BIT,
5304ae7a4efSJon Lin 		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
5314ae7a4efSJon Lin 				     gd5fxgq4uexxg_ecc_get_status)),
53281afcfe1SJon Lin 	SPINAND_INFO("GD5F1GQ4UExxH",
53381afcfe1SJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xd9),
5348781c285SJon Lin 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
5358781c285SJon Lin 		     NAND_ECCREQ(8, 512),
5368781c285SJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
5378781c285SJon Lin 					      &write_cache_variants,
5388781c285SJon Lin 					      &update_cache_variants),
5398781c285SJon Lin 		     SPINAND_HAS_QE_BIT,
5403a9e6261SJon Lin 		     SPINAND_ECCINFO(&gd5fxgqx_variant3_ooblayout,
5413a9e6261SJon Lin 				     gd5fxgq4xa_ecc_get_status)),
542*f90b37dbSJon Lin 	SPINAND_INFO("GD5F1GM9UEYIGY",
543*f90b37dbSJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x91),
544*f90b37dbSJon Lin 		     NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
545*f90b37dbSJon Lin 		     NAND_ECCREQ(8, 512),
546*f90b37dbSJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
547*f90b37dbSJon Lin 					      &write_cache_variants,
548*f90b37dbSJon Lin 					      &update_cache_variants),
549*f90b37dbSJon Lin 		     SPINAND_HAS_QE_BIT,
550*f90b37dbSJon Lin 		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, gd5fxgq4xa_ecc_get_status)),
5516eb4b036SStefan Roese };
5526eb4b036SStefan Roese 
gigadevice_spinand_set_ds(struct spinand_device * spinand,u8 ds_io)553988e2486SJon Lin static int gigadevice_spinand_set_ds(struct spinand_device *spinand, u8 ds_io)
554988e2486SJon Lin {
555988e2486SJon Lin 	struct spi_mem_op op = SPINAND_SET_FEATURE_OP(0xD0,
556988e2486SJon Lin 						      spinand->scratchbuf);
557988e2486SJon Lin 
558988e2486SJon Lin 	*spinand->scratchbuf = (ds_io & 0x3) << 5;
559988e2486SJon Lin 	return spi_mem_exec_op(spinand->slave, &op);
560988e2486SJon Lin }
561988e2486SJon Lin 
gigadevice_spinand_init(struct spinand_device * spinand)562988e2486SJon Lin static int gigadevice_spinand_init(struct spinand_device *spinand)
563988e2486SJon Lin {
564988e2486SJon Lin 	/* GD5F1GQ5UExxG */
565988e2486SJon Lin 	if (spinand->id.data[1] == 0x51)
566988e2486SJon Lin 		gigadevice_spinand_set_ds(spinand, 3);
567988e2486SJon Lin 
568988e2486SJon Lin 	return 0;
569988e2486SJon Lin }
570988e2486SJon Lin 
5716eb4b036SStefan Roese static const struct spinand_manufacturer_ops gigadevice_spinand_manuf_ops = {
572988e2486SJon Lin 	.init = gigadevice_spinand_init,
5736eb4b036SStefan Roese };
5746eb4b036SStefan Roese 
5756eb4b036SStefan Roese const struct spinand_manufacturer gigadevice_spinand_manufacturer = {
5766eb4b036SStefan Roese 	.id = SPINAND_MFR_GIGADEVICE,
5776eb4b036SStefan Roese 	.name = "GigaDevice",
57881afcfe1SJon Lin 	.chips = gigadevice_spinand_table,
57981afcfe1SJon Lin 	.nchips = ARRAY_SIZE(gigadevice_spinand_table),
5806eb4b036SStefan Roese 	.ops = &gigadevice_spinand_manuf_ops,
5816eb4b036SStefan Roese };
582