Skip to content

Commit

Permalink
Merge tag 'spi-nor/for-4.16' of git://git.infradead.org/linux-mtd int…
Browse files Browse the repository at this point in the history
…o mtd/next

Pull spi-nor changes from Cyrille Pitchen:

"
  This pull-request contains the following notable changes:

  Core changes:
  * Add support to new ISSI and Cypress/Spansion memory parts.
  * Fix support of Micron memories by checking error bits in the FSR.
  * Fix update of block-protection bits by reading back the SR.
  * Restore the internal state of the SPI flash memory when removing the
    device.

  Driver changes:
  * Maintenance for Freescale, Intel and Metiatek drivers.
  * Add support of the direct access mode for the Cadence QSPI controller.
"
  • Loading branch information
Boris Brezillon committed Jan 29, 2018
2 parents 0aede42 + 23bae78 commit c8f22b0
Show file tree
Hide file tree
Showing 9 changed files with 246 additions and 164 deletions.
2 changes: 1 addition & 1 deletion Documentation/devicetree/bindings/mtd/fsl-quadspi.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Required properties:
- reg-names: Should contain the reg names "QuadSPI" and "QuadSPI-memory"
- interrupts : Should contain the interrupt for the device
- clocks : The clocks needed by the QuadSPI controller
- clock-names : the name of the clocks
- clock-names : Should contain the name of the clocks: "qspi_en" and "qspi".

Optional properties:
- fsl,qspi-has-second-chip: The controller has two buses, bus A and bus B.
Expand Down
3 changes: 3 additions & 0 deletions Documentation/mtd/spi-nor.txt
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,6 @@ The main API is spi_nor_scan(). Before you call the hook, a driver should
initialize the necessary fields for spi_nor{}. Please see
drivers/mtd/spi-nor/spi-nor.c for detail. Please also refer to fsl-quadspi.c
when you want to write a new driver for a SPI NOR controller.
Another API is spi_nor_restore(), this is used to restore the status of SPI
flash chip such as addressing mode. Call it whenever detach the driver from
device or reboot the system.
9 changes: 9 additions & 0 deletions drivers/mtd/devices/m25p80.c
Original file line number Diff line number Diff line change
Expand Up @@ -307,10 +307,18 @@ static int m25p_remove(struct spi_device *spi)
{
struct m25p *flash = spi_get_drvdata(spi);

spi_nor_restore(&flash->spi_nor);

/* Clean up MTD stuff. */
return mtd_device_unregister(&flash->spi_nor.mtd);
}

static void m25p_shutdown(struct spi_device *spi)
{
struct m25p *flash = spi_get_drvdata(spi);

spi_nor_restore(&flash->spi_nor);
}
/*
* Do NOT add to this array without reading the following:
*
Expand Down Expand Up @@ -386,6 +394,7 @@ static struct spi_driver m25p80_driver = {
.id_table = m25p_ids,
.probe = m25p_probe,
.remove = m25p_remove,
.shutdown = m25p_shutdown,

/* REVISIT: many of these chips have deep power-down modes, which
* should clearly be entered on suspend() to minimize power use.
Expand Down
55 changes: 39 additions & 16 deletions drivers/mtd/spi-nor/cadence-quadspi.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ struct cqspi_flash_pdata {
u8 data_width;
u8 cs;
bool registered;
bool use_direct_mode;
};

struct cqspi_st {
Expand All @@ -68,6 +69,7 @@ struct cqspi_st {

void __iomem *iobase;
void __iomem *ahb_base;
resource_size_t ahb_size;
struct completion transfer_complete;
struct mutex bus_mutex;

Expand Down Expand Up @@ -103,6 +105,7 @@ struct cqspi_st {
/* Register map */
#define CQSPI_REG_CONFIG 0x00
#define CQSPI_REG_CONFIG_ENABLE_MASK BIT(0)
#define CQSPI_REG_CONFIG_ENB_DIR_ACC_CTRL BIT(7)
#define CQSPI_REG_CONFIG_DECODE_MASK BIT(9)
#define CQSPI_REG_CONFIG_CHIPSELECT_LSB 10
#define CQSPI_REG_CONFIG_DMA_MASK BIT(15)
Expand Down Expand Up @@ -450,17 +453,14 @@ static int cqspi_command_write_addr(struct spi_nor *nor,
return cqspi_exec_flash_cmd(cqspi, reg);
}

static int cqspi_indirect_read_setup(struct spi_nor *nor,
const unsigned int from_addr)
static int cqspi_read_setup(struct spi_nor *nor)
{
struct cqspi_flash_pdata *f_pdata = nor->priv;
struct cqspi_st *cqspi = f_pdata->cqspi;
void __iomem *reg_base = cqspi->iobase;
unsigned int dummy_clk = 0;
unsigned int reg;

writel(from_addr, reg_base + CQSPI_REG_INDIRECTRDSTARTADDR);

reg = nor->read_opcode << CQSPI_REG_RD_INSTR_OPCODE_LSB;
reg |= cqspi_calc_rdreg(nor, nor->read_opcode);

Expand Down Expand Up @@ -493,8 +493,8 @@ static int cqspi_indirect_read_setup(struct spi_nor *nor,
return 0;
}

static int cqspi_indirect_read_execute(struct spi_nor *nor,
u8 *rxbuf, const unsigned n_rx)
static int cqspi_indirect_read_execute(struct spi_nor *nor, u8 *rxbuf,
loff_t from_addr, const size_t n_rx)
{
struct cqspi_flash_pdata *f_pdata = nor->priv;
struct cqspi_st *cqspi = f_pdata->cqspi;
Expand All @@ -504,6 +504,7 @@ static int cqspi_indirect_read_execute(struct spi_nor *nor,
unsigned int bytes_to_read = 0;
int ret = 0;

writel(from_addr, reg_base + CQSPI_REG_INDIRECTRDSTARTADDR);
writel(remaining, reg_base + CQSPI_REG_INDIRECTRDBYTES);

/* Clear all interrupts. */
Expand Down Expand Up @@ -570,8 +571,7 @@ static int cqspi_indirect_read_execute(struct spi_nor *nor,
return ret;
}

static int cqspi_indirect_write_setup(struct spi_nor *nor,
const unsigned int to_addr)
static int cqspi_write_setup(struct spi_nor *nor)
{
unsigned int reg;
struct cqspi_flash_pdata *f_pdata = nor->priv;
Expand All @@ -584,17 +584,15 @@ static int cqspi_indirect_write_setup(struct spi_nor *nor,
reg = cqspi_calc_rdreg(nor, nor->program_opcode);
writel(reg, reg_base + CQSPI_REG_RD_INSTR);

writel(to_addr, reg_base + CQSPI_REG_INDIRECTWRSTARTADDR);

reg = readl(reg_base + CQSPI_REG_SIZE);
reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
reg |= (nor->addr_width - 1);
writel(reg, reg_base + CQSPI_REG_SIZE);
return 0;
}

static int cqspi_indirect_write_execute(struct spi_nor *nor,
const u8 *txbuf, const unsigned n_tx)
static int cqspi_indirect_write_execute(struct spi_nor *nor, loff_t to_addr,
const u8 *txbuf, const size_t n_tx)
{
const unsigned int page_size = nor->page_size;
struct cqspi_flash_pdata *f_pdata = nor->priv;
Expand All @@ -604,6 +602,7 @@ static int cqspi_indirect_write_execute(struct spi_nor *nor,
unsigned int write_bytes;
int ret;

writel(to_addr, reg_base + CQSPI_REG_INDIRECTWRSTARTADDR);
writel(remaining, reg_base + CQSPI_REG_INDIRECTWRBYTES);

/* Clear all interrupts. */
Expand Down Expand Up @@ -894,17 +893,22 @@ static int cqspi_set_protocol(struct spi_nor *nor, const int read)
static ssize_t cqspi_write(struct spi_nor *nor, loff_t to,
size_t len, const u_char *buf)
{
struct cqspi_flash_pdata *f_pdata = nor->priv;
struct cqspi_st *cqspi = f_pdata->cqspi;
int ret;

ret = cqspi_set_protocol(nor, 0);
if (ret)
return ret;

ret = cqspi_indirect_write_setup(nor, to);
ret = cqspi_write_setup(nor);
if (ret)
return ret;

ret = cqspi_indirect_write_execute(nor, buf, len);
if (f_pdata->use_direct_mode)
memcpy_toio(cqspi->ahb_base + to, buf, len);
else
ret = cqspi_indirect_write_execute(nor, to, buf, len);
if (ret)
return ret;

Expand All @@ -914,17 +918,22 @@ static ssize_t cqspi_write(struct spi_nor *nor, loff_t to,
static ssize_t cqspi_read(struct spi_nor *nor, loff_t from,
size_t len, u_char *buf)
{
struct cqspi_flash_pdata *f_pdata = nor->priv;
struct cqspi_st *cqspi = f_pdata->cqspi;
int ret;

ret = cqspi_set_protocol(nor, 1);
if (ret)
return ret;

ret = cqspi_indirect_read_setup(nor, from);
ret = cqspi_read_setup(nor);
if (ret)
return ret;

ret = cqspi_indirect_read_execute(nor, buf, len);
if (f_pdata->use_direct_mode)
memcpy_fromio(buf, cqspi->ahb_base + from, len);
else
ret = cqspi_indirect_read_execute(nor, buf, from, len);
if (ret)
return ret;

Expand Down Expand Up @@ -1059,6 +1068,8 @@ static int cqspi_of_get_pdata(struct platform_device *pdev)

static void cqspi_controller_init(struct cqspi_st *cqspi)
{
u32 reg;

cqspi_controller_enable(cqspi, 0);

/* Configure the remap address register, no remap */
Expand All @@ -1081,6 +1092,11 @@ static void cqspi_controller_init(struct cqspi_st *cqspi)
writel(cqspi->fifo_depth * cqspi->fifo_width / 8,
cqspi->iobase + CQSPI_REG_INDIRECTWRWATERMARK);

/* Enable Direct Access Controller */
reg = readl(cqspi->iobase + CQSPI_REG_CONFIG);
reg |= CQSPI_REG_CONFIG_ENB_DIR_ACC_CTRL;
writel(reg, cqspi->iobase + CQSPI_REG_CONFIG);

cqspi_controller_enable(cqspi, 1);
}

Expand Down Expand Up @@ -1156,6 +1172,12 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi, struct device_node *np)
goto err;

f_pdata->registered = true;

if (mtd->size <= cqspi->ahb_size) {
f_pdata->use_direct_mode = true;
dev_dbg(nor->dev, "using direct mode for %s\n",
mtd->name);
}
}

return 0;
Expand Down Expand Up @@ -1215,6 +1237,7 @@ static int cqspi_probe(struct platform_device *pdev)
dev_err(dev, "Cannot remap AHB address.\n");
return PTR_ERR(cqspi->ahb_base);
}
cqspi->ahb_size = resource_size(res_ahb);

init_completion(&cqspi->transfer_complete);

Expand Down
8 changes: 4 additions & 4 deletions drivers/mtd/spi-nor/fsl-quadspi.c
Original file line number Diff line number Diff line change
Expand Up @@ -801,10 +801,10 @@ static int fsl_qspi_nor_setup_last(struct fsl_qspi *q)
}

static const struct of_device_id fsl_qspi_dt_ids[] = {
{ .compatible = "fsl,vf610-qspi", .data = (void *)&vybrid_data, },
{ .compatible = "fsl,imx6sx-qspi", .data = (void *)&imx6sx_data, },
{ .compatible = "fsl,imx7d-qspi", .data = (void *)&imx7d_data, },
{ .compatible = "fsl,imx6ul-qspi", .data = (void *)&imx6ul_data, },
{ .compatible = "fsl,vf610-qspi", .data = &vybrid_data, },
{ .compatible = "fsl,imx6sx-qspi", .data = &imx6sx_data, },
{ .compatible = "fsl,imx7d-qspi", .data = &imx7d_data, },
{ .compatible = "fsl,imx6ul-qspi", .data = &imx6ul_data, },
{ .compatible = "fsl,ls1021a-qspi", .data = (void *)&ls1021a_data, },
{ /* sentinel */ }
};
Expand Down
6 changes: 0 additions & 6 deletions drivers/mtd/spi-nor/intel-spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,6 @@
* @erase_64k: 64k erase supported
* @opcodes: Opcodes which are supported. This are programmed by BIOS
* before it locks down the controller.
* @preopcodes: Preopcodes which are supported.
*/
struct intel_spi {
struct device *dev;
Expand All @@ -155,7 +154,6 @@ struct intel_spi {
bool swseq_erase;
bool erase_64k;
u8 opcodes[8];
u8 preopcodes[2];
};

static bool writeable;
Expand Down Expand Up @@ -400,10 +398,6 @@ static int intel_spi_init(struct intel_spi *ispi)
ispi->opcodes[i] = opmenu0 >> i * 8;
ispi->opcodes[i + 4] = opmenu1 >> i * 8;
}

val = readl(ispi->sregs + PREOP_OPTYPE);
ispi->preopcodes[0] = val;
ispi->preopcodes[1] = val >> 8;
}
}

Expand Down
Loading

0 comments on commit c8f22b0

Please sign in to comment.