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

sst.c (5850B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) 2005, Intec Automation Inc.
      4 * Copyright (C) 2014, Freescale Semiconductor, Inc.
      5 */
      6
      7#include <linux/mtd/spi-nor.h>
      8
      9#include "core.h"
     10
     11/* SST flash_info mfr_flag. Used to specify SST byte programming. */
     12#define SST_WRITE		BIT(0)
     13
     14#define SST26VF_CR_BPNV		BIT(3)
     15
     16static int sst26vf_nor_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
     17{
     18	return -EOPNOTSUPP;
     19}
     20
     21static int sst26vf_nor_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
     22{
     23	int ret;
     24
     25	/* We only support unlocking the entire flash array. */
     26	if (ofs != 0 || len != nor->params->size)
     27		return -EINVAL;
     28
     29	ret = spi_nor_read_cr(nor, nor->bouncebuf);
     30	if (ret)
     31		return ret;
     32
     33	if (!(nor->bouncebuf[0] & SST26VF_CR_BPNV)) {
     34		dev_dbg(nor->dev, "Any block has been permanently locked\n");
     35		return -EINVAL;
     36	}
     37
     38	return spi_nor_global_block_unlock(nor);
     39}
     40
     41static int sst26vf_nor_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len)
     42{
     43	return -EOPNOTSUPP;
     44}
     45
     46static const struct spi_nor_locking_ops sst26vf_nor_locking_ops = {
     47	.lock = sst26vf_nor_lock,
     48	.unlock = sst26vf_nor_unlock,
     49	.is_locked = sst26vf_nor_is_locked,
     50};
     51
     52static void sst26vf_nor_late_init(struct spi_nor *nor)
     53{
     54	nor->params->locking_ops = &sst26vf_nor_locking_ops;
     55}
     56
     57static const struct spi_nor_fixups sst26vf_nor_fixups = {
     58	.late_init = sst26vf_nor_late_init,
     59};
     60
     61static const struct flash_info sst_nor_parts[] = {
     62	/* SST -- large erase sizes are "overlays", "sectors" are 4K */
     63	{ "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024,  8)
     64		FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
     65		NO_SFDP_FLAGS(SECT_4K)
     66		MFR_FLAGS(SST_WRITE) },
     67	{ "sst25vf080b", INFO(0xbf258e, 0, 64 * 1024, 16)
     68		FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
     69		NO_SFDP_FLAGS(SECT_4K)
     70		MFR_FLAGS(SST_WRITE) },
     71	{ "sst25vf016b", INFO(0xbf2541, 0, 64 * 1024, 32)
     72		FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
     73		NO_SFDP_FLAGS(SECT_4K)
     74		MFR_FLAGS(SST_WRITE) },
     75	{ "sst25vf032b", INFO(0xbf254a, 0, 64 * 1024, 64)
     76		FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
     77		NO_SFDP_FLAGS(SECT_4K)
     78		MFR_FLAGS(SST_WRITE) },
     79	{ "sst25vf064c", INFO(0xbf254b, 0, 64 * 1024, 128)
     80		FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_4BIT_BP |
     81		      SPI_NOR_SWP_IS_VOLATILE)
     82		NO_SFDP_FLAGS(SECT_4K) },
     83	{ "sst25wf512",  INFO(0xbf2501, 0, 64 * 1024,  1)
     84		FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
     85		NO_SFDP_FLAGS(SECT_4K)
     86		MFR_FLAGS(SST_WRITE) },
     87	{ "sst25wf010",  INFO(0xbf2502, 0, 64 * 1024,  2)
     88		FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
     89		NO_SFDP_FLAGS(SECT_4K)
     90		MFR_FLAGS(SST_WRITE) },
     91	{ "sst25wf020",  INFO(0xbf2503, 0, 64 * 1024,  4)
     92		FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
     93		NO_SFDP_FLAGS(SECT_4K)
     94		MFR_FLAGS(SST_WRITE) },
     95	{ "sst25wf020a", INFO(0x621612, 0, 64 * 1024,  4)
     96		FLAGS(SPI_NOR_HAS_LOCK)
     97		NO_SFDP_FLAGS(SECT_4K) },
     98	{ "sst25wf040b", INFO(0x621613, 0, 64 * 1024,  8)
     99		FLAGS(SPI_NOR_HAS_LOCK)
    100		NO_SFDP_FLAGS(SECT_4K) },
    101	{ "sst25wf040",  INFO(0xbf2504, 0, 64 * 1024,  8)
    102		FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
    103		NO_SFDP_FLAGS(SECT_4K)
    104		MFR_FLAGS(SST_WRITE) },
    105	{ "sst25wf080",  INFO(0xbf2505, 0, 64 * 1024, 16)
    106		FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
    107		NO_SFDP_FLAGS(SECT_4K)
    108		MFR_FLAGS(SST_WRITE) },
    109	{ "sst26wf016b", INFO(0xbf2651, 0, 64 * 1024, 32)
    110		NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
    111			      SPI_NOR_QUAD_READ) },
    112	{ "sst26vf016b", INFO(0xbf2641, 0, 64 * 1024, 32)
    113		NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ) },
    114	{ "sst26vf064b", INFO(0xbf2643, 0, 64 * 1024, 128)
    115		FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
    116		NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
    117		.fixups = &sst26vf_nor_fixups },
    118};
    119
    120static int sst_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
    121			 size_t *retlen, const u_char *buf)
    122{
    123	struct spi_nor *nor = mtd_to_spi_nor(mtd);
    124	size_t actual = 0;
    125	int ret;
    126
    127	dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
    128
    129	ret = spi_nor_lock_and_prep(nor);
    130	if (ret)
    131		return ret;
    132
    133	ret = spi_nor_write_enable(nor);
    134	if (ret)
    135		goto out;
    136
    137	nor->sst_write_second = false;
    138
    139	/* Start write from odd address. */
    140	if (to % 2) {
    141		nor->program_opcode = SPINOR_OP_BP;
    142
    143		/* write one byte. */
    144		ret = spi_nor_write_data(nor, to, 1, buf);
    145		if (ret < 0)
    146			goto out;
    147		WARN(ret != 1, "While writing 1 byte written %i bytes\n", ret);
    148		ret = spi_nor_wait_till_ready(nor);
    149		if (ret)
    150			goto out;
    151
    152		to++;
    153		actual++;
    154	}
    155
    156	/* Write out most of the data here. */
    157	for (; actual < len - 1; actual += 2) {
    158		nor->program_opcode = SPINOR_OP_AAI_WP;
    159
    160		/* write two bytes. */
    161		ret = spi_nor_write_data(nor, to, 2, buf + actual);
    162		if (ret < 0)
    163			goto out;
    164		WARN(ret != 2, "While writing 2 bytes written %i bytes\n", ret);
    165		ret = spi_nor_wait_till_ready(nor);
    166		if (ret)
    167			goto out;
    168		to += 2;
    169		nor->sst_write_second = true;
    170	}
    171	nor->sst_write_second = false;
    172
    173	ret = spi_nor_write_disable(nor);
    174	if (ret)
    175		goto out;
    176
    177	ret = spi_nor_wait_till_ready(nor);
    178	if (ret)
    179		goto out;
    180
    181	/* Write out trailing byte if it exists. */
    182	if (actual != len) {
    183		ret = spi_nor_write_enable(nor);
    184		if (ret)
    185			goto out;
    186
    187		nor->program_opcode = SPINOR_OP_BP;
    188		ret = spi_nor_write_data(nor, to, 1, buf + actual);
    189		if (ret < 0)
    190			goto out;
    191		WARN(ret != 1, "While writing 1 byte written %i bytes\n", ret);
    192		ret = spi_nor_wait_till_ready(nor);
    193		if (ret)
    194			goto out;
    195
    196		actual += 1;
    197
    198		ret = spi_nor_write_disable(nor);
    199	}
    200out:
    201	*retlen += actual;
    202	spi_nor_unlock_and_unprep(nor);
    203	return ret;
    204}
    205
    206static void sst_nor_late_init(struct spi_nor *nor)
    207{
    208	if (nor->info->mfr_flags & SST_WRITE)
    209		nor->mtd._write = sst_nor_write;
    210}
    211
    212static const struct spi_nor_fixups sst_nor_fixups = {
    213	.late_init = sst_nor_late_init,
    214};
    215
    216const struct spi_nor_manufacturer spi_nor_sst = {
    217	.name = "sst",
    218	.parts = sst_nor_parts,
    219	.nparts = ARRAY_SIZE(sst_nor_parts),
    220	.fixups = &sst_nor_fixups,
    221};