|
@@ -192,6 +192,8 @@
|
|
|
#define SEQID_EN4B 10
|
|
|
#define SEQID_BRWR 11
|
|
|
|
|
|
+#define QUADSPI_MIN_IOMAP SZ_4M
|
|
|
+
|
|
|
enum fsl_qspi_devtype {
|
|
|
FSL_QUADSPI_VYBRID,
|
|
|
FSL_QUADSPI_IMX6SX,
|
|
@@ -223,8 +225,10 @@ struct fsl_qspi {
|
|
|
struct mtd_info mtd[FSL_QSPI_MAX_CHIP];
|
|
|
struct spi_nor nor[FSL_QSPI_MAX_CHIP];
|
|
|
void __iomem *iobase;
|
|
|
- void __iomem *ahb_base; /* Used when read from AHB bus */
|
|
|
+ void __iomem *ahb_addr;
|
|
|
u32 memmap_phy;
|
|
|
+ u32 memmap_offs;
|
|
|
+ u32 memmap_len;
|
|
|
struct clk *clk, *clk_en;
|
|
|
struct device *dev;
|
|
|
struct completion c;
|
|
@@ -732,11 +736,42 @@ static int fsl_qspi_read(struct spi_nor *nor, loff_t from,
|
|
|
struct fsl_qspi *q = nor->priv;
|
|
|
u8 cmd = nor->read_opcode;
|
|
|
|
|
|
- dev_dbg(q->dev, "cmd [%x],read from (0x%p, 0x%.8x, 0x%.8x),len:%d\n",
|
|
|
- cmd, q->ahb_base, q->chip_base_addr, (unsigned int)from, len);
|
|
|
+ /* if necessary,ioremap buffer before AHB read, */
|
|
|
+ if (!q->ahb_addr) {
|
|
|
+ q->memmap_offs = q->chip_base_addr + from;
|
|
|
+ q->memmap_len = len > QUADSPI_MIN_IOMAP ? len : QUADSPI_MIN_IOMAP;
|
|
|
+
|
|
|
+ q->ahb_addr = ioremap_nocache(
|
|
|
+ q->memmap_phy + q->memmap_offs,
|
|
|
+ q->memmap_len);
|
|
|
+ if (!q->ahb_addr) {
|
|
|
+ dev_err(q->dev, "ioremap failed\n");
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+ /* ioremap if the data requested is out of range */
|
|
|
+ } else if (q->chip_base_addr + from < q->memmap_offs
|
|
|
+ || q->chip_base_addr + from + len >
|
|
|
+ q->memmap_offs + q->memmap_len) {
|
|
|
+ iounmap(q->ahb_addr);
|
|
|
+
|
|
|
+ q->memmap_offs = q->chip_base_addr + from;
|
|
|
+ q->memmap_len = len > QUADSPI_MIN_IOMAP ? len : QUADSPI_MIN_IOMAP;
|
|
|
+ q->ahb_addr = ioremap_nocache(
|
|
|
+ q->memmap_phy + q->memmap_offs,
|
|
|
+ q->memmap_len);
|
|
|
+ if (!q->ahb_addr) {
|
|
|
+ dev_err(q->dev, "ioremap failed\n");
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ dev_dbg(q->dev, "cmd [%x],read from 0x%p, len:%d\n",
|
|
|
+ cmd, q->ahb_addr + q->chip_base_addr + from - q->memmap_offs,
|
|
|
+ len);
|
|
|
|
|
|
/* Read out the data directly from the AHB buffer.*/
|
|
|
- memcpy(buf, q->ahb_base + q->chip_base_addr + from, len);
|
|
|
+ memcpy(buf, q->ahb_addr + q->chip_base_addr + from - q->memmap_offs,
|
|
|
+ len);
|
|
|
|
|
|
*retlen += len;
|
|
|
return 0;
|
|
@@ -821,9 +856,11 @@ static int fsl_qspi_probe(struct platform_device *pdev)
|
|
|
|
|
|
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
|
|
"QuadSPI-memory");
|
|
|
- q->ahb_base = devm_ioremap_resource(dev, res);
|
|
|
- if (IS_ERR(q->ahb_base))
|
|
|
- return PTR_ERR(q->ahb_base);
|
|
|
+ if (!devm_request_mem_region(dev, res->start, resource_size(res),
|
|
|
+ res->name)) {
|
|
|
+ dev_err(dev, "can't request region for resource %pR\n", res);
|
|
|
+ return -EBUSY;
|
|
|
+ }
|
|
|
|
|
|
q->memmap_phy = res->start;
|
|
|
|
|
@@ -989,6 +1026,10 @@ static int fsl_qspi_remove(struct platform_device *pdev)
|
|
|
mutex_destroy(&q->lock);
|
|
|
clk_unprepare(q->clk);
|
|
|
clk_unprepare(q->clk_en);
|
|
|
+
|
|
|
+ if (q->ahb_addr)
|
|
|
+ iounmap(q->ahb_addr);
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|