cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

micron.c (9397B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      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		0x2c
     14
     15#define MICRON_STATUS_ECC_MASK		GENMASK(7, 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 Die
     25 * Select Register (Address 0xD0).
     26 */
     27#define MICRON_DIE_SELECT_REG	0xD0
     28
     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 possible
    291	 * 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};