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

sst25l.c (9594B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * sst25l.c
      4 *
      5 * Driver for SST25L SPI Flash chips
      6 *
      7 * Copyright © 2009 Bluewater Systems Ltd
      8 * Author: Andre Renaud <andre@bluewatersys.com>
      9 * Author: Ryan Mallon
     10 *
     11 * Based on m25p80.c
     12 */
     13
     14#include <linux/module.h>
     15#include <linux/device.h>
     16#include <linux/mutex.h>
     17#include <linux/interrupt.h>
     18#include <linux/slab.h>
     19#include <linux/sched.h>
     20
     21#include <linux/mtd/mtd.h>
     22#include <linux/mtd/partitions.h>
     23
     24#include <linux/spi/spi.h>
     25#include <linux/spi/flash.h>
     26
     27/* Erases can take up to 3 seconds! */
     28#define MAX_READY_WAIT_JIFFIES	msecs_to_jiffies(3000)
     29
     30#define SST25L_CMD_WRSR		0x01	/* Write status register */
     31#define SST25L_CMD_WRDI		0x04	/* Write disable */
     32#define SST25L_CMD_RDSR		0x05	/* Read status register */
     33#define SST25L_CMD_WREN		0x06	/* Write enable */
     34#define SST25L_CMD_READ		0x03	/* High speed read */
     35
     36#define SST25L_CMD_EWSR		0x50	/* Enable write status register */
     37#define SST25L_CMD_SECTOR_ERASE	0x20	/* Erase sector */
     38#define SST25L_CMD_READ_ID	0x90	/* Read device ID */
     39#define SST25L_CMD_AAI_PROGRAM	0xaf	/* Auto address increment */
     40
     41#define SST25L_STATUS_BUSY	(1 << 0)	/* Chip is busy */
     42#define SST25L_STATUS_WREN	(1 << 1)	/* Write enabled */
     43#define SST25L_STATUS_BP0	(1 << 2)	/* Block protection 0 */
     44#define SST25L_STATUS_BP1	(1 << 3)	/* Block protection 1 */
     45
     46struct sst25l_flash {
     47	struct spi_device	*spi;
     48	struct mutex		lock;
     49	struct mtd_info		mtd;
     50};
     51
     52struct flash_info {
     53	const char		*name;
     54	uint16_t		device_id;
     55	unsigned		page_size;
     56	unsigned		nr_pages;
     57	unsigned		erase_size;
     58};
     59
     60#define to_sst25l_flash(x) container_of(x, struct sst25l_flash, mtd)
     61
     62static struct flash_info sst25l_flash_info[] = {
     63	{"sst25lf020a", 0xbf43, 256, 1024, 4096},
     64	{"sst25lf040a",	0xbf44,	256, 2048, 4096},
     65};
     66
     67static int sst25l_status(struct sst25l_flash *flash, int *status)
     68{
     69	struct spi_message m;
     70	struct spi_transfer t;
     71	unsigned char cmd_resp[2];
     72	int err;
     73
     74	spi_message_init(&m);
     75	memset(&t, 0, sizeof(struct spi_transfer));
     76
     77	cmd_resp[0] = SST25L_CMD_RDSR;
     78	cmd_resp[1] = 0xff;
     79	t.tx_buf = cmd_resp;
     80	t.rx_buf = cmd_resp;
     81	t.len = sizeof(cmd_resp);
     82	spi_message_add_tail(&t, &m);
     83	err = spi_sync(flash->spi, &m);
     84	if (err < 0)
     85		return err;
     86
     87	*status = cmd_resp[1];
     88	return 0;
     89}
     90
     91static int sst25l_write_enable(struct sst25l_flash *flash, int enable)
     92{
     93	unsigned char command[2];
     94	int status, err;
     95
     96	command[0] = enable ? SST25L_CMD_WREN : SST25L_CMD_WRDI;
     97	err = spi_write(flash->spi, command, 1);
     98	if (err)
     99		return err;
    100
    101	command[0] = SST25L_CMD_EWSR;
    102	err = spi_write(flash->spi, command, 1);
    103	if (err)
    104		return err;
    105
    106	command[0] = SST25L_CMD_WRSR;
    107	command[1] = enable ? 0 : SST25L_STATUS_BP0 | SST25L_STATUS_BP1;
    108	err = spi_write(flash->spi, command, 2);
    109	if (err)
    110		return err;
    111
    112	if (enable) {
    113		err = sst25l_status(flash, &status);
    114		if (err)
    115			return err;
    116		if (!(status & SST25L_STATUS_WREN))
    117			return -EROFS;
    118	}
    119
    120	return 0;
    121}
    122
    123static int sst25l_wait_till_ready(struct sst25l_flash *flash)
    124{
    125	unsigned long deadline;
    126	int status, err;
    127
    128	deadline = jiffies + MAX_READY_WAIT_JIFFIES;
    129	do {
    130		err = sst25l_status(flash, &status);
    131		if (err)
    132			return err;
    133		if (!(status & SST25L_STATUS_BUSY))
    134			return 0;
    135
    136		cond_resched();
    137	} while (!time_after_eq(jiffies, deadline));
    138
    139	return -ETIMEDOUT;
    140}
    141
    142static int sst25l_erase_sector(struct sst25l_flash *flash, uint32_t offset)
    143{
    144	unsigned char command[4];
    145	int err;
    146
    147	err = sst25l_write_enable(flash, 1);
    148	if (err)
    149		return err;
    150
    151	command[0] = SST25L_CMD_SECTOR_ERASE;
    152	command[1] = offset >> 16;
    153	command[2] = offset >> 8;
    154	command[3] = offset;
    155	err = spi_write(flash->spi, command, 4);
    156	if (err)
    157		return err;
    158
    159	err = sst25l_wait_till_ready(flash);
    160	if (err)
    161		return err;
    162
    163	return sst25l_write_enable(flash, 0);
    164}
    165
    166static int sst25l_erase(struct mtd_info *mtd, struct erase_info *instr)
    167{
    168	struct sst25l_flash *flash = to_sst25l_flash(mtd);
    169	uint32_t addr, end;
    170	int err;
    171
    172	/* Sanity checks */
    173	if ((uint32_t)instr->len % mtd->erasesize)
    174		return -EINVAL;
    175
    176	if ((uint32_t)instr->addr % mtd->erasesize)
    177		return -EINVAL;
    178
    179	addr = instr->addr;
    180	end = addr + instr->len;
    181
    182	mutex_lock(&flash->lock);
    183
    184	err = sst25l_wait_till_ready(flash);
    185	if (err) {
    186		mutex_unlock(&flash->lock);
    187		return err;
    188	}
    189
    190	while (addr < end) {
    191		err = sst25l_erase_sector(flash, addr);
    192		if (err) {
    193			mutex_unlock(&flash->lock);
    194			dev_err(&flash->spi->dev, "Erase failed\n");
    195			return err;
    196		}
    197
    198		addr += mtd->erasesize;
    199	}
    200
    201	mutex_unlock(&flash->lock);
    202
    203	return 0;
    204}
    205
    206static int sst25l_read(struct mtd_info *mtd, loff_t from, size_t len,
    207		       size_t *retlen, unsigned char *buf)
    208{
    209	struct sst25l_flash *flash = to_sst25l_flash(mtd);
    210	struct spi_transfer transfer[2];
    211	struct spi_message message;
    212	unsigned char command[4];
    213	int ret;
    214
    215	spi_message_init(&message);
    216	memset(&transfer, 0, sizeof(transfer));
    217
    218	command[0] = SST25L_CMD_READ;
    219	command[1] = from >> 16;
    220	command[2] = from >> 8;
    221	command[3] = from;
    222
    223	transfer[0].tx_buf = command;
    224	transfer[0].len = sizeof(command);
    225	spi_message_add_tail(&transfer[0], &message);
    226
    227	transfer[1].rx_buf = buf;
    228	transfer[1].len = len;
    229	spi_message_add_tail(&transfer[1], &message);
    230
    231	mutex_lock(&flash->lock);
    232
    233	/* Wait for previous write/erase to complete */
    234	ret = sst25l_wait_till_ready(flash);
    235	if (ret) {
    236		mutex_unlock(&flash->lock);
    237		return ret;
    238	}
    239
    240	spi_sync(flash->spi, &message);
    241
    242	if (retlen && message.actual_length > sizeof(command))
    243		*retlen += message.actual_length - sizeof(command);
    244
    245	mutex_unlock(&flash->lock);
    246	return 0;
    247}
    248
    249static int sst25l_write(struct mtd_info *mtd, loff_t to, size_t len,
    250			size_t *retlen, const unsigned char *buf)
    251{
    252	struct sst25l_flash *flash = to_sst25l_flash(mtd);
    253	int i, j, ret, bytes, copied = 0;
    254	unsigned char command[5];
    255
    256	if ((uint32_t)to % mtd->writesize)
    257		return -EINVAL;
    258
    259	mutex_lock(&flash->lock);
    260
    261	ret = sst25l_write_enable(flash, 1);
    262	if (ret)
    263		goto out;
    264
    265	for (i = 0; i < len; i += mtd->writesize) {
    266		ret = sst25l_wait_till_ready(flash);
    267		if (ret)
    268			goto out;
    269
    270		/* Write the first byte of the page */
    271		command[0] = SST25L_CMD_AAI_PROGRAM;
    272		command[1] = (to + i) >> 16;
    273		command[2] = (to + i) >> 8;
    274		command[3] = (to + i);
    275		command[4] = buf[i];
    276		ret = spi_write(flash->spi, command, 5);
    277		if (ret < 0)
    278			goto out;
    279		copied++;
    280
    281		/*
    282		 * Write the remaining bytes using auto address
    283		 * increment mode
    284		 */
    285		bytes = min_t(uint32_t, mtd->writesize, len - i);
    286		for (j = 1; j < bytes; j++, copied++) {
    287			ret = sst25l_wait_till_ready(flash);
    288			if (ret)
    289				goto out;
    290
    291			command[1] = buf[i + j];
    292			ret = spi_write(flash->spi, command, 2);
    293			if (ret)
    294				goto out;
    295		}
    296	}
    297
    298out:
    299	ret = sst25l_write_enable(flash, 0);
    300
    301	if (retlen)
    302		*retlen = copied;
    303
    304	mutex_unlock(&flash->lock);
    305	return ret;
    306}
    307
    308static struct flash_info *sst25l_match_device(struct spi_device *spi)
    309{
    310	struct flash_info *flash_info = NULL;
    311	struct spi_message m;
    312	struct spi_transfer t;
    313	unsigned char cmd_resp[6];
    314	int i, err;
    315	uint16_t id;
    316
    317	spi_message_init(&m);
    318	memset(&t, 0, sizeof(struct spi_transfer));
    319
    320	cmd_resp[0] = SST25L_CMD_READ_ID;
    321	cmd_resp[1] = 0;
    322	cmd_resp[2] = 0;
    323	cmd_resp[3] = 0;
    324	cmd_resp[4] = 0xff;
    325	cmd_resp[5] = 0xff;
    326	t.tx_buf = cmd_resp;
    327	t.rx_buf = cmd_resp;
    328	t.len = sizeof(cmd_resp);
    329	spi_message_add_tail(&t, &m);
    330	err = spi_sync(spi, &m);
    331	if (err < 0) {
    332		dev_err(&spi->dev, "error reading device id\n");
    333		return NULL;
    334	}
    335
    336	id = (cmd_resp[4] << 8) | cmd_resp[5];
    337
    338	for (i = 0; i < ARRAY_SIZE(sst25l_flash_info); i++)
    339		if (sst25l_flash_info[i].device_id == id)
    340			flash_info = &sst25l_flash_info[i];
    341
    342	if (!flash_info)
    343		dev_err(&spi->dev, "unknown id %.4x\n", id);
    344
    345	return flash_info;
    346}
    347
    348static int sst25l_probe(struct spi_device *spi)
    349{
    350	struct flash_info *flash_info;
    351	struct sst25l_flash *flash;
    352	struct flash_platform_data *data;
    353	int ret;
    354
    355	flash_info = sst25l_match_device(spi);
    356	if (!flash_info)
    357		return -ENODEV;
    358
    359	flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL);
    360	if (!flash)
    361		return -ENOMEM;
    362
    363	flash->spi = spi;
    364	mutex_init(&flash->lock);
    365	spi_set_drvdata(spi, flash);
    366
    367	data = dev_get_platdata(&spi->dev);
    368	if (data && data->name)
    369		flash->mtd.name = data->name;
    370
    371	flash->mtd.dev.parent   = &spi->dev;
    372	flash->mtd.type		= MTD_NORFLASH;
    373	flash->mtd.flags	= MTD_CAP_NORFLASH;
    374	flash->mtd.erasesize	= flash_info->erase_size;
    375	flash->mtd.writesize	= flash_info->page_size;
    376	flash->mtd.writebufsize	= flash_info->page_size;
    377	flash->mtd.size		= flash_info->page_size * flash_info->nr_pages;
    378	flash->mtd._erase	= sst25l_erase;
    379	flash->mtd._read		= sst25l_read;
    380	flash->mtd._write 	= sst25l_write;
    381
    382	dev_info(&spi->dev, "%s (%lld KiB)\n", flash_info->name,
    383		 (long long)flash->mtd.size >> 10);
    384
    385	pr_debug("mtd .name = %s, .size = 0x%llx (%lldMiB) "
    386	      ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n",
    387	      flash->mtd.name,
    388	      (long long)flash->mtd.size, (long long)(flash->mtd.size >> 20),
    389	      flash->mtd.erasesize, flash->mtd.erasesize / 1024,
    390	      flash->mtd.numeraseregions);
    391
    392
    393	ret = mtd_device_register(&flash->mtd, data ? data->parts : NULL,
    394				  data ? data->nr_parts : 0);
    395	if (ret)
    396		return -ENODEV;
    397
    398	return 0;
    399}
    400
    401static void sst25l_remove(struct spi_device *spi)
    402{
    403	struct sst25l_flash *flash = spi_get_drvdata(spi);
    404
    405	WARN_ON(mtd_device_unregister(&flash->mtd));
    406}
    407
    408static struct spi_driver sst25l_driver = {
    409	.driver = {
    410		.name	= "sst25l",
    411	},
    412	.probe		= sst25l_probe,
    413	.remove		= sst25l_remove,
    414};
    415
    416module_spi_driver(sst25l_driver);
    417
    418MODULE_DESCRIPTION("MTD SPI driver for SST25L Flash chips");
    419MODULE_AUTHOR("Andre Renaud <andre@bluewatersys.com>, "
    420	      "Ryan Mallon");
    421MODULE_LICENSE("GPL");