Commit f173f26a authored by Vignesh Raghavendra's avatar Vignesh Raghavendra Committed by Tudor Ambarus

mtd: spi-nor: always use bounce buffer for register read/writes

spi-mem layer expects all buffers passed to it to be DMA'able. But
spi-nor layer mostly allocates buffers on stack for reading/writing to
registers and therefore are not DMA'able. Introduce bounce buffer to be
used to read/write to registers. This ensures that buffer passed to
spi-mem layer during register read/writes is DMA'able. With this change
nor->cmd-buf is no longer used, so drop it.
Signed-off-by: default avatarVignesh Raghavendra <vigneshr@ti.com>
Reviewed-by: default avatarBoris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: default avatarTudor Ambarus <tudor.ambarus@microchip.com>
parent 5f9e832c
...@@ -296,15 +296,14 @@ struct flash_info { ...@@ -296,15 +296,14 @@ struct flash_info {
static int read_sr(struct spi_nor *nor) static int read_sr(struct spi_nor *nor)
{ {
int ret; int ret;
u8 val;
ret = nor->read_reg(nor, SPINOR_OP_RDSR, &val, 1); ret = nor->read_reg(nor, SPINOR_OP_RDSR, nor->bouncebuf, 1);
if (ret < 0) { if (ret < 0) {
pr_err("error %d reading SR\n", (int) ret); pr_err("error %d reading SR\n", (int) ret);
return ret; return ret;
} }
return val; return nor->bouncebuf[0];
} }
/* /*
...@@ -315,15 +314,14 @@ static int read_sr(struct spi_nor *nor) ...@@ -315,15 +314,14 @@ static int read_sr(struct spi_nor *nor)
static int read_fsr(struct spi_nor *nor) static int read_fsr(struct spi_nor *nor)
{ {
int ret; int ret;
u8 val;
ret = nor->read_reg(nor, SPINOR_OP_RDFSR, &val, 1); ret = nor->read_reg(nor, SPINOR_OP_RDFSR, nor->bouncebuf, 1);
if (ret < 0) { if (ret < 0) {
pr_err("error %d reading FSR\n", ret); pr_err("error %d reading FSR\n", ret);
return ret; return ret;
} }
return val; return nor->bouncebuf[0];
} }
/* /*
...@@ -334,15 +332,14 @@ static int read_fsr(struct spi_nor *nor) ...@@ -334,15 +332,14 @@ static int read_fsr(struct spi_nor *nor)
static int read_cr(struct spi_nor *nor) static int read_cr(struct spi_nor *nor)
{ {
int ret; int ret;
u8 val;
ret = nor->read_reg(nor, SPINOR_OP_RDCR, &val, 1); ret = nor->read_reg(nor, SPINOR_OP_RDCR, nor->bouncebuf, 1);
if (ret < 0) { if (ret < 0) {
dev_err(nor->dev, "error %d reading CR\n", ret); dev_err(nor->dev, "error %d reading CR\n", ret);
return ret; return ret;
} }
return val; return nor->bouncebuf[0];
} }
/* /*
...@@ -351,8 +348,8 @@ static int read_cr(struct spi_nor *nor) ...@@ -351,8 +348,8 @@ static int read_cr(struct spi_nor *nor)
*/ */
static int write_sr(struct spi_nor *nor, u8 val) static int write_sr(struct spi_nor *nor, u8 val)
{ {
nor->cmd_buf[0] = val; nor->bouncebuf[0] = val;
return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1); return nor->write_reg(nor, SPINOR_OP_WRSR, nor->bouncebuf, 1);
} }
/* /*
...@@ -500,31 +497,31 @@ static int set_4byte(struct spi_nor *nor, bool enable) ...@@ -500,31 +497,31 @@ static int set_4byte(struct spi_nor *nor, bool enable)
* We must clear the register to enable normal behavior. * We must clear the register to enable normal behavior.
*/ */
write_enable(nor); write_enable(nor);
nor->cmd_buf[0] = 0; nor->bouncebuf[0] = 0;
nor->write_reg(nor, SPINOR_OP_WREAR, nor->cmd_buf, 1); nor->write_reg(nor, SPINOR_OP_WREAR,
nor->bouncebuf, 1);
write_disable(nor); write_disable(nor);
} }
return status; return status;
default: default:
/* Spansion style */ /* Spansion style */
nor->cmd_buf[0] = enable << 7; nor->bouncebuf[0] = enable << 7;
return nor->write_reg(nor, SPINOR_OP_BRWR, nor->cmd_buf, 1); return nor->write_reg(nor, SPINOR_OP_BRWR, nor->bouncebuf, 1);
} }
} }
static int s3an_sr_ready(struct spi_nor *nor) static int s3an_sr_ready(struct spi_nor *nor)
{ {
int ret; int ret;
u8 val;
ret = nor->read_reg(nor, SPINOR_OP_XRDSR, &val, 1); ret = nor->read_reg(nor, SPINOR_OP_XRDSR, nor->bouncebuf, 1);
if (ret < 0) { if (ret < 0) {
dev_err(nor->dev, "error %d reading XRDSR\n", (int) ret); dev_err(nor->dev, "error %d reading XRDSR\n", (int) ret);
return ret; return ret;
} }
return !!(val & XSR_RDY); return !!(nor->bouncebuf[0] & XSR_RDY);
} }
static int spi_nor_sr_ready(struct spi_nor *nor) static int spi_nor_sr_ready(struct spi_nor *nor)
...@@ -683,7 +680,6 @@ static loff_t spi_nor_s3an_addr_convert(struct spi_nor *nor, unsigned int addr) ...@@ -683,7 +680,6 @@ static loff_t spi_nor_s3an_addr_convert(struct spi_nor *nor, unsigned int addr)
*/ */
static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr) static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr)
{ {
u8 buf[SPI_NOR_MAX_ADDR_WIDTH];
int i; int i;
if (nor->flags & SNOR_F_S3AN_ADDR_DEFAULT) if (nor->flags & SNOR_F_S3AN_ADDR_DEFAULT)
...@@ -697,11 +693,12 @@ static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr) ...@@ -697,11 +693,12 @@ static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr)
* control * control
*/ */
for (i = nor->addr_width - 1; i >= 0; i--) { for (i = nor->addr_width - 1; i >= 0; i--) {
buf[i] = addr & 0xff; nor->bouncebuf[i] = addr & 0xff;
addr >>= 8; addr >>= 8;
} }
return nor->write_reg(nor, nor->erase_opcode, buf, nor->addr_width); return nor->write_reg(nor, nor->erase_opcode, nor->bouncebuf,
nor->addr_width);
} }
/** /**
...@@ -1485,9 +1482,11 @@ static int macronix_quad_enable(struct spi_nor *nor) ...@@ -1485,9 +1482,11 @@ static int macronix_quad_enable(struct spi_nor *nor)
*/ */
static int spansion_quad_enable(struct spi_nor *nor) static int spansion_quad_enable(struct spi_nor *nor)
{ {
u8 sr_cr[2] = {0, CR_QUAD_EN_SPAN}; u8 *sr_cr = nor->bouncebuf;
int ret; int ret;
sr_cr[0] = 0;
sr_cr[1] = CR_QUAD_EN_SPAN;
ret = write_sr_cr(nor, sr_cr); ret = write_sr_cr(nor, sr_cr);
if (ret) if (ret)
return ret; return ret;
...@@ -1517,7 +1516,7 @@ static int spansion_quad_enable(struct spi_nor *nor) ...@@ -1517,7 +1516,7 @@ static int spansion_quad_enable(struct spi_nor *nor)
*/ */
static int spansion_no_read_cr_quad_enable(struct spi_nor *nor) static int spansion_no_read_cr_quad_enable(struct spi_nor *nor)
{ {
u8 sr_cr[2]; u8 *sr_cr = nor->bouncebuf;
int ret; int ret;
/* Keep the current value of the Status Register. */ /* Keep the current value of the Status Register. */
...@@ -1548,7 +1547,7 @@ static int spansion_no_read_cr_quad_enable(struct spi_nor *nor) ...@@ -1548,7 +1547,7 @@ static int spansion_no_read_cr_quad_enable(struct spi_nor *nor)
static int spansion_read_cr_quad_enable(struct spi_nor *nor) static int spansion_read_cr_quad_enable(struct spi_nor *nor)
{ {
struct device *dev = nor->dev; struct device *dev = nor->dev;
u8 sr_cr[2]; u8 *sr_cr = nor->bouncebuf;
int ret; int ret;
/* Check current Quad Enable bit value. */ /* Check current Quad Enable bit value. */
...@@ -1599,22 +1598,22 @@ static int spansion_read_cr_quad_enable(struct spi_nor *nor) ...@@ -1599,22 +1598,22 @@ static int spansion_read_cr_quad_enable(struct spi_nor *nor)
*/ */
static int sr2_bit7_quad_enable(struct spi_nor *nor) static int sr2_bit7_quad_enable(struct spi_nor *nor)
{ {
u8 sr2; u8 *sr2 = nor->bouncebuf;
int ret; int ret;
/* Check current Quad Enable bit value. */ /* Check current Quad Enable bit value. */
ret = nor->read_reg(nor, SPINOR_OP_RDSR2, &sr2, 1); ret = nor->read_reg(nor, SPINOR_OP_RDSR2, sr2, 1);
if (ret) if (ret)
return ret; return ret;
if (sr2 & SR2_QUAD_EN_BIT7) if (*sr2 & SR2_QUAD_EN_BIT7)
return 0; return 0;
/* Update the Quad Enable bit. */ /* Update the Quad Enable bit. */
sr2 |= SR2_QUAD_EN_BIT7; *sr2 |= SR2_QUAD_EN_BIT7;
write_enable(nor); write_enable(nor);
ret = nor->write_reg(nor, SPINOR_OP_WRSR2, &sr2, 1); ret = nor->write_reg(nor, SPINOR_OP_WRSR2, sr2, 1);
if (ret < 0) { if (ret < 0) {
dev_err(nor->dev, "error while writing status register 2\n"); dev_err(nor->dev, "error while writing status register 2\n");
return -EINVAL; return -EINVAL;
...@@ -1627,8 +1626,8 @@ static int sr2_bit7_quad_enable(struct spi_nor *nor) ...@@ -1627,8 +1626,8 @@ static int sr2_bit7_quad_enable(struct spi_nor *nor)
} }
/* Read back and check it. */ /* Read back and check it. */
ret = nor->read_reg(nor, SPINOR_OP_RDSR2, &sr2, 1); ret = nor->read_reg(nor, SPINOR_OP_RDSR2, sr2, 1);
if (!(ret > 0 && (sr2 & SR2_QUAD_EN_BIT7))) { if (!(ret > 0 && (*sr2 & SR2_QUAD_EN_BIT7))) {
dev_err(nor->dev, "SR2 Quad bit not set\n"); dev_err(nor->dev, "SR2 Quad bit not set\n");
return -EINVAL; return -EINVAL;
} }
...@@ -1687,7 +1686,7 @@ static int spi_nor_spansion_clear_sr_bp(struct spi_nor *nor) ...@@ -1687,7 +1686,7 @@ static int spi_nor_spansion_clear_sr_bp(struct spi_nor *nor)
{ {
int ret; int ret;
u8 mask = SR_BP2 | SR_BP1 | SR_BP0; u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
u8 sr_cr[2] = {0}; u8 *sr_cr = nor->bouncebuf;
/* Check current Quad Enable bit value. */ /* Check current Quad Enable bit value. */
ret = read_cr(nor); ret = read_cr(nor);
...@@ -2177,7 +2176,7 @@ static const struct flash_info spi_nor_ids[] = { ...@@ -2177,7 +2176,7 @@ static const struct flash_info spi_nor_ids[] = {
static const struct flash_info *spi_nor_read_id(struct spi_nor *nor) static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
{ {
int tmp; int tmp;
u8 id[SPI_NOR_MAX_ID_LEN]; u8 *id = nor->bouncebuf;
const struct flash_info *info; const struct flash_info *info;
tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN); tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN);
...@@ -2393,9 +2392,8 @@ static int spi_nor_check(struct spi_nor *nor) ...@@ -2393,9 +2392,8 @@ static int spi_nor_check(struct spi_nor *nor)
static int s3an_nor_scan(struct spi_nor *nor) static int s3an_nor_scan(struct spi_nor *nor)
{ {
int ret; int ret;
u8 val;
ret = nor->read_reg(nor, SPINOR_OP_XRDSR, &val, 1); ret = nor->read_reg(nor, SPINOR_OP_XRDSR, nor->bouncebuf, 1);
if (ret < 0) { if (ret < 0) {
dev_err(nor->dev, "error %d reading XRDSR\n", (int) ret); dev_err(nor->dev, "error %d reading XRDSR\n", (int) ret);
return ret; return ret;
...@@ -2417,7 +2415,7 @@ static int s3an_nor_scan(struct spi_nor *nor) ...@@ -2417,7 +2415,7 @@ static int s3an_nor_scan(struct spi_nor *nor)
* The current addressing mode can be read from the XRDSR register * The current addressing mode can be read from the XRDSR register
* and should not be changed, because is a destructive operation. * and should not be changed, because is a destructive operation.
*/ */
if (val & XSR_PAGESIZE) { if (nor->bouncebuf[0] & XSR_PAGESIZE) {
/* Flash in Power of 2 mode */ /* Flash in Power of 2 mode */
nor->page_size = (nor->page_size == 264) ? 256 : 512; nor->page_size = (nor->page_size == 264) ? 256 : 512;
nor->mtd.writebufsize = nor->page_size; nor->mtd.writebufsize = nor->page_size;
...@@ -4121,6 +4119,16 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, ...@@ -4121,6 +4119,16 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
nor->read_proto = SNOR_PROTO_1_1_1; nor->read_proto = SNOR_PROTO_1_1_1;
nor->write_proto = SNOR_PROTO_1_1_1; nor->write_proto = SNOR_PROTO_1_1_1;
/*
* We need the bounce buffer early to read/write registers when going
* through the spi-mem layer (buffers have to be DMA-able).
*/
nor->bouncebuf_size = PAGE_SIZE;
nor->bouncebuf = devm_kmalloc(dev, nor->bouncebuf_size,
GFP_KERNEL);
if (!nor->bouncebuf)
return -ENOMEM;
if (name) if (name)
info = spi_nor_match_id(name); info = spi_nor_match_id(name);
/* Try to auto-detect if chip name wasn't specified or not found */ /* Try to auto-detect if chip name wasn't specified or not found */
......
...@@ -344,6 +344,9 @@ struct flash_info; ...@@ -344,6 +344,9 @@ struct flash_info;
* @mtd: point to a mtd_info structure * @mtd: point to a mtd_info structure
* @lock: the lock for the read/write/erase/lock/unlock operations * @lock: the lock for the read/write/erase/lock/unlock operations
* @dev: point to a spi device, or a spi nor controller device. * @dev: point to a spi device, or a spi nor controller device.
* @bouncebuf: bounce buffer used when the buffer passed by the MTD
* layer is not DMA-able
* @bouncebuf_size: size of the bounce buffer
* @info: spi-nor part JDEC MFR id and other info * @info: spi-nor part JDEC MFR id and other info
* @page_size: the page size of the SPI NOR * @page_size: the page size of the SPI NOR
* @addr_width: number of address bytes * @addr_width: number of address bytes
...@@ -356,7 +359,6 @@ struct flash_info; ...@@ -356,7 +359,6 @@ struct flash_info;
* @read_proto: the SPI protocol for read operations * @read_proto: the SPI protocol for read operations
* @write_proto: the SPI protocol for write operations * @write_proto: the SPI protocol for write operations
* @reg_proto the SPI protocol for read_reg/write_reg/erase operations * @reg_proto the SPI protocol for read_reg/write_reg/erase operations
* @cmd_buf: used by the write_reg
* @erase_map: the erase map of the SPI NOR * @erase_map: the erase map of the SPI NOR
* @prepare: [OPTIONAL] do some preparations for the * @prepare: [OPTIONAL] do some preparations for the
* read/write/erase/lock/unlock operations * read/write/erase/lock/unlock operations
...@@ -382,6 +384,8 @@ struct spi_nor { ...@@ -382,6 +384,8 @@ struct spi_nor {
struct mtd_info mtd; struct mtd_info mtd;
struct mutex lock; struct mutex lock;
struct device *dev; struct device *dev;
u8 *bouncebuf;
size_t bouncebuf_size;
const struct flash_info *info; const struct flash_info *info;
u32 page_size; u32 page_size;
u8 addr_width; u8 addr_width;
...@@ -394,7 +398,6 @@ struct spi_nor { ...@@ -394,7 +398,6 @@ struct spi_nor {
enum spi_nor_protocol reg_proto; enum spi_nor_protocol reg_proto;
bool sst_write_second; bool sst_write_second;
u32 flags; u32 flags;
u8 cmd_buf[SPI_NOR_MAX_CMD_SIZE];
struct spi_nor_erase_map erase_map; struct spi_nor_erase_map erase_map;
int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops); int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment