brintos

brintos / linux-shallow public Read only

0
0
Text · 3.8 KiB · 7936ea5 Raw
154 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Author: Mario Kicherer <dev@kicherer.org>4 */5 6#include <linux/device.h>7#include <linux/kernel.h>8#include <linux/mtd/spinand.h>9 10#define SPINAND_MFR_ALLIANCEMEMORY	0x5211 12#define AM_STATUS_ECC_BITMASK		(3 << 4)13 14#define AM_STATUS_ECC_NONE_DETECTED	(0 << 4)15#define AM_STATUS_ECC_CORRECTED		(1 << 4)16#define AM_STATUS_ECC_ERRORED		(2 << 4)17#define AM_STATUS_ECC_MAX_CORRECTED	(3 << 4)18 19static SPINAND_OP_VARIANTS(read_cache_variants,20		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),21		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),22		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),23		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),24		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),25		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));26 27static SPINAND_OP_VARIANTS(write_cache_variants,28			   SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),29			   SPINAND_PROG_LOAD(true, 0, NULL, 0));30 31static SPINAND_OP_VARIANTS(update_cache_variants,32			   SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),33			   SPINAND_PROG_LOAD(false, 0, NULL, 0));34 35static int am_get_eccsize(struct mtd_info *mtd)36{37	if (mtd->oobsize == 64)38		return 0x20;39	else if (mtd->oobsize == 128)40		return 0x38;41	else if (mtd->oobsize == 256)42		return 0x70;43	else44		return -EINVAL;45}46 47static int am_ooblayout_ecc(struct mtd_info *mtd, int section,48			    struct mtd_oob_region *region)49{50	int ecc_bytes;51 52	ecc_bytes = am_get_eccsize(mtd);53	if (ecc_bytes < 0)54		return ecc_bytes;55 56	region->offset = mtd->oobsize - ecc_bytes;57	region->length = ecc_bytes;58 59	return 0;60}61 62static int am_ooblayout_free(struct mtd_info *mtd, int section,63			     struct mtd_oob_region *region)64{65	int ecc_bytes;66 67	if (section)68		return -ERANGE;69 70	ecc_bytes = am_get_eccsize(mtd);71	if (ecc_bytes < 0)72		return ecc_bytes;73 74	/*75	 * It is unclear how many bytes are used for the bad block marker. We76	 * reserve the common two bytes here.77	 *78	 * The free area in this kind of flash is divided into chunks where the79	 * first 4 bytes of each chunk are unprotected. The number of chunks80	 * depends on the specific model. The models with 4096+256 bytes pages81	 * have 8 chunks, the others 4 chunks.82	 */83 84	region->offset = 2;85	region->length = mtd->oobsize - 2 - ecc_bytes;86 87	return 0;88}89 90static const struct mtd_ooblayout_ops am_ooblayout = {91	.ecc = am_ooblayout_ecc,92	.free = am_ooblayout_free,93};94 95static int am_ecc_get_status(struct spinand_device *spinand, u8 status)96{97	switch (status & AM_STATUS_ECC_BITMASK) {98	case AM_STATUS_ECC_NONE_DETECTED:99		return 0;100 101	case AM_STATUS_ECC_CORRECTED:102		/*103		 * use oobsize to determine the flash model and the maximum of104		 * correctable errors and return maximum - 1 by convention105		 */106		if (spinand->base.mtd.oobsize == 64)107			return 3;108		else109			return 7;110 111	case AM_STATUS_ECC_ERRORED:112		return -EBADMSG;113 114	case AM_STATUS_ECC_MAX_CORRECTED:115		/*116		 * use oobsize to determine the flash model and the maximum of117		 * correctable errors118		 */119		if (spinand->base.mtd.oobsize == 64)120			return 4;121		else122			return 8;123 124	default:125		break;126	}127 128	return -EINVAL;129}130 131static const struct spinand_info alliancememory_spinand_table[] = {132	SPINAND_INFO("AS5F34G04SND",133		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x2f),134		     NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 1, 1, 1),135		     NAND_ECCREQ(4, 512),136		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,137					      &write_cache_variants,138					      &update_cache_variants),139		     SPINAND_HAS_QE_BIT,140		     SPINAND_ECCINFO(&am_ooblayout,141				     am_ecc_get_status)),142};143 144static const struct spinand_manufacturer_ops alliancememory_spinand_manuf_ops = {145};146 147const struct spinand_manufacturer alliancememory_spinand_manufacturer = {148	.id = SPINAND_MFR_ALLIANCEMEMORY,149	.name = "AllianceMemory",150	.chips = alliancememory_spinand_table,151	.nchips = ARRAY_SIZE(alliancememory_spinand_table),152	.ops = &alliancememory_spinand_manuf_ops,153};154