brintos

brintos / linux-shallow public Read only

0
0
Text · 9.2 KiB · 12601bc Raw
310 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2016-2017 Micron Technology, Inc.4 *5 * Authors:6 *	Peter Pan <peterpandong@micron.com>7 */8 9#include <linux/device.h>10#include <linux/kernel.h>11#include <linux/mtd/spinand.h>12 13#define SPINAND_MFR_MICRON		0x2c14 15#define MICRON_STATUS_ECC_MASK		GENMASK(6, 4)16#define MICRON_STATUS_ECC_NO_BITFLIPS	(0 << 4)17#define MICRON_STATUS_ECC_1TO3_BITFLIPS	(1 << 4)18#define MICRON_STATUS_ECC_4TO6_BITFLIPS	(3 << 4)19#define MICRON_STATUS_ECC_7TO8_BITFLIPS	(5 << 4)20 21#define MICRON_CFG_CR			BIT(0)22 23/*24 * As per datasheet, die selection is done by the 6th bit of Die25 * Select Register (Address 0xD0).26 */27#define MICRON_DIE_SELECT_REG	0xD028 29#define MICRON_SELECT_DIE(x)	((x) << 6)30 31static SPINAND_OP_VARIANTS(quadio_read_cache_variants,32		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),33		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),34		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),35		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),36		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),37		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));38 39static SPINAND_OP_VARIANTS(x4_write_cache_variants,40		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),41		SPINAND_PROG_LOAD(true, 0, NULL, 0));42 43static SPINAND_OP_VARIANTS(x4_update_cache_variants,44		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),45		SPINAND_PROG_LOAD(false, 0, NULL, 0));46 47/* Micron  MT29F2G01AAAED Device */48static SPINAND_OP_VARIANTS(x4_read_cache_variants,49			   SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),50			   SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),51			   SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),52			   SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));53 54static SPINAND_OP_VARIANTS(x1_write_cache_variants,55			   SPINAND_PROG_LOAD(true, 0, NULL, 0));56 57static SPINAND_OP_VARIANTS(x1_update_cache_variants,58			   SPINAND_PROG_LOAD(false, 0, NULL, 0));59 60static int micron_8_ooblayout_ecc(struct mtd_info *mtd, int section,61				  struct mtd_oob_region *region)62{63	if (section)64		return -ERANGE;65 66	region->offset = mtd->oobsize / 2;67	region->length = mtd->oobsize / 2;68 69	return 0;70}71 72static int micron_8_ooblayout_free(struct mtd_info *mtd, int section,73				   struct mtd_oob_region *region)74{75	if (section)76		return -ERANGE;77 78	/* Reserve 2 bytes for the BBM. */79	region->offset = 2;80	region->length = (mtd->oobsize / 2) - 2;81 82	return 0;83}84 85static const struct mtd_ooblayout_ops micron_8_ooblayout = {86	.ecc = micron_8_ooblayout_ecc,87	.free = micron_8_ooblayout_free,88};89 90static int micron_4_ooblayout_ecc(struct mtd_info *mtd, int section,91				  struct mtd_oob_region *region)92{93	struct spinand_device *spinand = mtd_to_spinand(mtd);94 95	if (section >= spinand->base.memorg.pagesize /96			mtd->ecc_step_size)97		return -ERANGE;98 99	region->offset = (section * 16) + 8;100	region->length = 8;101 102	return 0;103}104 105static int micron_4_ooblayout_free(struct mtd_info *mtd, int section,106				   struct mtd_oob_region *region)107{108	struct spinand_device *spinand = mtd_to_spinand(mtd);109 110	if (section >= spinand->base.memorg.pagesize /111			mtd->ecc_step_size)112		return -ERANGE;113 114	if (section) {115		region->offset = 16 * section;116		region->length = 8;117	} else {118		/* section 0 has two bytes reserved for the BBM */119		region->offset = 2;120		region->length = 6;121	}122 123	return 0;124}125 126static const struct mtd_ooblayout_ops micron_4_ooblayout = {127	.ecc = micron_4_ooblayout_ecc,128	.free = micron_4_ooblayout_free,129};130 131static int micron_select_target(struct spinand_device *spinand,132				unsigned int target)133{134	struct spi_mem_op op = SPINAND_SET_FEATURE_OP(MICRON_DIE_SELECT_REG,135						      spinand->scratchbuf);136 137	if (target > 1)138		return -EINVAL;139 140	*spinand->scratchbuf = MICRON_SELECT_DIE(target);141 142	return spi_mem_exec_op(spinand->spimem, &op);143}144 145static int micron_8_ecc_get_status(struct spinand_device *spinand,146				   u8 status)147{148	switch (status & MICRON_STATUS_ECC_MASK) {149	case STATUS_ECC_NO_BITFLIPS:150		return 0;151 152	case STATUS_ECC_UNCOR_ERROR:153		return -EBADMSG;154 155	case MICRON_STATUS_ECC_1TO3_BITFLIPS:156		return 3;157 158	case MICRON_STATUS_ECC_4TO6_BITFLIPS:159		return 6;160 161	case MICRON_STATUS_ECC_7TO8_BITFLIPS:162		return 8;163 164	default:165		break;166	}167 168	return -EINVAL;169}170 171static const struct spinand_info micron_spinand_table[] = {172	/* M79A 2Gb 3.3V */173	SPINAND_INFO("MT29F2G01ABAGD",174		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24),175		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),176		     NAND_ECCREQ(8, 512),177		     SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,178					      &x4_write_cache_variants,179					      &x4_update_cache_variants),180		     0,181		     SPINAND_ECCINFO(&micron_8_ooblayout,182				     micron_8_ecc_get_status)),183	/* M79A 2Gb 1.8V */184	SPINAND_INFO("MT29F2G01ABBGD",185		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x25),186		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),187		     NAND_ECCREQ(8, 512),188		     SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,189					      &x4_write_cache_variants,190					      &x4_update_cache_variants),191		     0,192		     SPINAND_ECCINFO(&micron_8_ooblayout,193				     micron_8_ecc_get_status)),194	/* M78A 1Gb 3.3V */195	SPINAND_INFO("MT29F1G01ABAFD",196		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14),197		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),198		     NAND_ECCREQ(8, 512),199		     SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,200					      &x4_write_cache_variants,201					      &x4_update_cache_variants),202		     0,203		     SPINAND_ECCINFO(&micron_8_ooblayout,204				     micron_8_ecc_get_status)),205	/* M78A 1Gb 1.8V */206	SPINAND_INFO("MT29F1G01ABAFD",207		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x15),208		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),209		     NAND_ECCREQ(8, 512),210		     SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,211					      &x4_write_cache_variants,212					      &x4_update_cache_variants),213		     0,214		     SPINAND_ECCINFO(&micron_8_ooblayout,215				     micron_8_ecc_get_status)),216	/* M79A 4Gb 3.3V */217	SPINAND_INFO("MT29F4G01ADAGD",218		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x36),219		     NAND_MEMORG(1, 2048, 128, 64, 2048, 80, 2, 1, 2),220		     NAND_ECCREQ(8, 512),221		     SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,222					      &x4_write_cache_variants,223					      &x4_update_cache_variants),224		     0,225		     SPINAND_ECCINFO(&micron_8_ooblayout,226				     micron_8_ecc_get_status),227		     SPINAND_SELECT_TARGET(micron_select_target)),228	/* M70A 4Gb 3.3V */229	SPINAND_INFO("MT29F4G01ABAFD",230		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x34),231		     NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),232		     NAND_ECCREQ(8, 512),233		     SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,234					      &x4_write_cache_variants,235					      &x4_update_cache_variants),236		     SPINAND_HAS_CR_FEAT_BIT,237		     SPINAND_ECCINFO(&micron_8_ooblayout,238				     micron_8_ecc_get_status)),239	/* M70A 4Gb 1.8V */240	SPINAND_INFO("MT29F4G01ABBFD",241		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35),242		     NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),243		     NAND_ECCREQ(8, 512),244		     SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,245					      &x4_write_cache_variants,246					      &x4_update_cache_variants),247		     SPINAND_HAS_CR_FEAT_BIT,248		     SPINAND_ECCINFO(&micron_8_ooblayout,249				     micron_8_ecc_get_status)),250	/* M70A 8Gb 3.3V */251	SPINAND_INFO("MT29F8G01ADAFD",252		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x46),253		     NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 2),254		     NAND_ECCREQ(8, 512),255		     SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,256					      &x4_write_cache_variants,257					      &x4_update_cache_variants),258		     SPINAND_HAS_CR_FEAT_BIT,259		     SPINAND_ECCINFO(&micron_8_ooblayout,260				     micron_8_ecc_get_status),261		     SPINAND_SELECT_TARGET(micron_select_target)),262	/* M70A 8Gb 1.8V */263	SPINAND_INFO("MT29F8G01ADBFD",264		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x47),265		     NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 2),266		     NAND_ECCREQ(8, 512),267		     SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,268					      &x4_write_cache_variants,269					      &x4_update_cache_variants),270		     SPINAND_HAS_CR_FEAT_BIT,271		     SPINAND_ECCINFO(&micron_8_ooblayout,272				     micron_8_ecc_get_status),273		     SPINAND_SELECT_TARGET(micron_select_target)),274	/* M69A 2Gb 3.3V */275	SPINAND_INFO("MT29F2G01AAAED",276		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x9F),277		     NAND_MEMORG(1, 2048, 64, 64, 2048, 80, 2, 1, 1),278		     NAND_ECCREQ(4, 512),279		     SPINAND_INFO_OP_VARIANTS(&x4_read_cache_variants,280					      &x1_write_cache_variants,281					      &x1_update_cache_variants),282		     0,283		     SPINAND_ECCINFO(&micron_4_ooblayout, NULL)),284};285 286static int micron_spinand_init(struct spinand_device *spinand)287{288	/*289	 * M70A device series enable Continuous Read feature at Power-up,290	 * which is not supported. Disable this bit to avoid any possible291	 * failure.292	 */293	if (spinand->flags & SPINAND_HAS_CR_FEAT_BIT)294		return spinand_upd_cfg(spinand, MICRON_CFG_CR, 0);295 296	return 0;297}298 299static const struct spinand_manufacturer_ops micron_spinand_manuf_ops = {300	.init = micron_spinand_init,301};302 303const struct spinand_manufacturer micron_spinand_manufacturer = {304	.id = SPINAND_MFR_MICRON,305	.name = "Micron",306	.chips = micron_spinand_table,307	.nchips = ARRAY_SIZE(micron_spinand_table),308	.ops = &micron_spinand_manuf_ops,309};310