brintos

brintos / linux-shallow public Read only

0
0
Text · 6.2 KiB · b5ad711 Raw
273 lines · c
1// SPDX-License-Identifier: GPL-2.02/*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, u64 len)17{18	return -EOPNOTSUPP;19}20 21static int sst26vf_nor_unlock(struct spi_nor *nor, loff_t ofs, u64 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, u64 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 int sst26vf_nor_late_init(struct spi_nor *nor)53{54	nor->params->locking_ops = &sst26vf_nor_locking_ops;55 56	return 0;57}58 59static const struct spi_nor_fixups sst26vf_nor_fixups = {60	.late_init = sst26vf_nor_late_init,61};62 63static const struct flash_info sst_nor_parts[] = {64	{65		.id = SNOR_ID(0x62, 0x16, 0x12),66		.name = "sst25wf020a",67		.size = SZ_256K,68		.flags = SPI_NOR_HAS_LOCK,69		.no_sfdp_flags = SECT_4K,70	}, {71		.id = SNOR_ID(0x62, 0x16, 0x13),72		.name = "sst25wf040b",73		.size = SZ_512K,74		.flags = SPI_NOR_HAS_LOCK,75		.no_sfdp_flags = SECT_4K,76	}, {77		.id = SNOR_ID(0xbf, 0x25, 0x01),78		.name = "sst25wf512",79		.size = SZ_64K,80		.flags = SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE,81		.no_sfdp_flags = SECT_4K,82		.mfr_flags = SST_WRITE,83	}, {84		.id = SNOR_ID(0xbf, 0x25, 0x02),85		.name = "sst25wf010",86		.size = SZ_128K,87		.flags = SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE,88		.no_sfdp_flags = SECT_4K,89		.mfr_flags = SST_WRITE,90	}, {91		.id = SNOR_ID(0xbf, 0x25, 0x03),92		.name = "sst25wf020",93		.size = SZ_256K,94		.flags = SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE,95		.no_sfdp_flags = SECT_4K,96		.mfr_flags = SST_WRITE,97	}, {98		.id = SNOR_ID(0xbf, 0x25, 0x04),99		.name = "sst25wf040",100		.size = SZ_512K,101		.flags = SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE,102		.no_sfdp_flags = SECT_4K,103		.mfr_flags = SST_WRITE,104	}, {105		.id = SNOR_ID(0xbf, 0x25, 0x05),106		.name = "sst25wf080",107		.size = SZ_1M,108		.flags = SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE,109		.no_sfdp_flags = SECT_4K,110		.mfr_flags = SST_WRITE,111	}, {112		.id = SNOR_ID(0xbf, 0x25, 0x41),113		.name = "sst25vf016b",114		.size = SZ_2M,115		.flags = SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE,116		.no_sfdp_flags = SECT_4K,117		.mfr_flags = SST_WRITE,118	}, {119		.id = SNOR_ID(0xbf, 0x25, 0x4a),120		.name = "sst25vf032b",121		.size = SZ_4M,122		.flags = SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE,123		.no_sfdp_flags = SECT_4K,124		.mfr_flags = SST_WRITE,125	}, {126		.id = SNOR_ID(0xbf, 0x25, 0x4b),127		.name = "sst25vf064c",128		.size = SZ_8M,129		.flags = SPI_NOR_HAS_LOCK | SPI_NOR_4BIT_BP | SPI_NOR_SWP_IS_VOLATILE,130		.no_sfdp_flags = SECT_4K,131	}, {132		.id = SNOR_ID(0xbf, 0x25, 0x8d),133		.name = "sst25vf040b",134		.size = SZ_512K,135		.flags = SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE,136		.no_sfdp_flags = SECT_4K,137		.mfr_flags = SST_WRITE,138	}, {139		.id = SNOR_ID(0xbf, 0x25, 0x8e),140		.name = "sst25vf080b",141		.size = SZ_1M,142		.flags = SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE,143		.no_sfdp_flags = SECT_4K,144		.mfr_flags = SST_WRITE,145	}, {146		.id = SNOR_ID(0xbf, 0x26, 0x41),147		.name = "sst26vf016b",148		.size = SZ_2M,149		.no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ,150	}, {151		.id = SNOR_ID(0xbf, 0x26, 0x42),152		.name = "sst26vf032b",153		.flags = SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE,154		.fixups = &sst26vf_nor_fixups,155	}, {156		.id = SNOR_ID(0xbf, 0x26, 0x43),157		.name = "sst26vf064b",158		.size = SZ_8M,159		.flags = SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE,160		.no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,161		.fixups = &sst26vf_nor_fixups,162	}, {163		.id = SNOR_ID(0xbf, 0x26, 0x51),164		.name = "sst26wf016b",165		.size = SZ_2M,166		.no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,167	}168};169 170static int sst_nor_write_data(struct spi_nor *nor, loff_t to, size_t len,171			      const u_char *buf)172{173	u8 op = (len == 1) ? SPINOR_OP_BP : SPINOR_OP_AAI_WP;174	int ret;175 176	nor->program_opcode = op;177	ret = spi_nor_write_data(nor, to, 1, buf);178	if (ret < 0)179		return ret;180	WARN(ret != len, "While writing %zu byte written %i bytes\n", len, ret);181 182	return spi_nor_wait_till_ready(nor);183}184 185static int sst_nor_write(struct mtd_info *mtd, loff_t to, size_t len,186			 size_t *retlen, const u_char *buf)187{188	struct spi_nor *nor = mtd_to_spi_nor(mtd);189	size_t actual = 0;190	int ret;191 192	dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);193 194	ret = spi_nor_prep_and_lock(nor);195	if (ret)196		return ret;197 198	ret = spi_nor_write_enable(nor);199	if (ret)200		goto out;201 202	nor->sst_write_second = false;203 204	/* Start write from odd address. */205	if (to % 2) {206		/* write one byte. */207		ret = sst_nor_write_data(nor, to, 1, buf);208		if (ret < 0)209			goto out;210 211		to++;212		actual++;213	}214 215	/* Write out most of the data here. */216	for (; actual < len - 1; actual += 2) {217		/* write two bytes. */218		ret = sst_nor_write_data(nor, to, 2, buf + actual);219		if (ret < 0)220			goto out;221 222		to += 2;223		nor->sst_write_second = true;224	}225	nor->sst_write_second = false;226 227	ret = spi_nor_write_disable(nor);228	if (ret)229		goto out;230 231	ret = spi_nor_wait_till_ready(nor);232	if (ret)233		goto out;234 235	/* Write out trailing byte if it exists. */236	if (actual != len) {237		ret = spi_nor_write_enable(nor);238		if (ret)239			goto out;240 241		ret = sst_nor_write_data(nor, to, 1, buf + actual);242		if (ret < 0)243			goto out;244 245		actual += 1;246 247		ret = spi_nor_write_disable(nor);248	}249out:250	*retlen += actual;251	spi_nor_unlock_and_unprep(nor);252	return ret;253}254 255static int sst_nor_late_init(struct spi_nor *nor)256{257	if (nor->info->mfr_flags & SST_WRITE)258		nor->mtd._write = sst_nor_write;259 260	return 0;261}262 263static const struct spi_nor_fixups sst_nor_fixups = {264	.late_init = sst_nor_late_init,265};266 267const struct spi_nor_manufacturer spi_nor_sst = {268	.name = "sst",269	.parts = sst_nor_parts,270	.nparts = ARRAY_SIZE(sst_nor_parts),271	.fixups = &sst_nor_fixups,272};273