diff --git a/drivers/mtd/spi-nor/cadence-quadspi.c b/drivers/mtd/spi-nor/cadence-quadspi.c index c7bf4d523f9c..4b8e9183489a 100644 --- a/drivers/mtd/spi-nor/cadence-quadspi.c +++ b/drivers/mtd/spi-nor/cadence-quadspi.c @@ -58,6 +58,7 @@ struct cqspi_flash_pdata { u8 data_width; u8 cs; bool registered; + bool use_direct_mode; }; struct cqspi_st { @@ -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; @@ -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) @@ -890,6 +893,8 @@ 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); @@ -900,7 +905,10 @@ static ssize_t cqspi_write(struct spi_nor *nor, loff_t to, if (ret) return ret; - ret = cqspi_indirect_write_execute(nor, to, 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; @@ -910,6 +918,8 @@ 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); @@ -920,7 +930,10 @@ static ssize_t cqspi_read(struct spi_nor *nor, loff_t from, if (ret) return ret; - ret = cqspi_indirect_read_execute(nor, buf, from, 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; @@ -1055,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 */ @@ -1077,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); } @@ -1152,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; @@ -1211,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);