]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
mtd: spi-nor: fsl-quadspi: add big-endian support
authorYao Yuan <yao.yuan@freescale.com>
Tue, 26 Jan 2016 07:23:55 +0000 (15:23 +0800)
committerBrian Norris <computersforpeace@gmail.com>
Mon, 7 Mar 2016 19:46:43 +0000 (11:46 -0800)
Add R/W functions for big- or little-endian registers:
The qSPI controller's endian is independent of the CPU core's endian.
So far, the qSPI have two versions for big-endian and little-endian.

Signed-off-by: Yuan Yao <yao.yuan@nxp.com>
Acked-by: Han xu <han.xu@freescale.com>
Acked-by: Han xu <han.xu@nxp.com>
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
drivers/mtd/spi-nor/fsl-quadspi.c

index 54640f1eb3a13caa772b003e624a4c61ae842171..04e8a93e1a3aa01f1d6107c117d13b9f7176cbc2 100644 (file)
@@ -275,6 +275,7 @@ struct fsl_qspi {
        u32 clk_rate;
        unsigned int chip_base_addr; /* We may support two chips. */
        bool has_second_chip;
+       bool big_endian;
        struct mutex lock;
        struct pm_qos_request pm_qos_req;
 };
@@ -299,6 +300,28 @@ static inline int needs_wakeup_wait_mode(struct fsl_qspi *q)
        return q->devtype_data->driver_data & QUADSPI_QUIRK_TKT245618;
 }
 
+/*
+ * R/W functions for big- or little-endian registers:
+ * The qSPI controller's endian is independent of the CPU core's endian.
+ * So far, although the CPU core is little-endian but the qSPI have two
+ * versions for big-endian and little-endian.
+ */
+static void qspi_writel(struct fsl_qspi *q, u32 val, void __iomem *addr)
+{
+       if (q->big_endian)
+               iowrite32be(val, addr);
+       else
+               iowrite32(val, addr);
+}
+
+static u32 qspi_readl(struct fsl_qspi *q, void __iomem *addr)
+{
+       if (q->big_endian)
+               return ioread32be(addr);
+       else
+               return ioread32(addr);
+}
+
 /*
  * An IC bug makes us to re-arrange the 32-bit data.
  * The following chips, such as IMX6SLX, have fixed this bug.
@@ -310,14 +333,14 @@ static inline u32 fsl_qspi_endian_xchg(struct fsl_qspi *q, u32 a)
 
 static inline void fsl_qspi_unlock_lut(struct fsl_qspi *q)
 {
-       writel(QUADSPI_LUTKEY_VALUE, q->iobase + QUADSPI_LUTKEY);
-       writel(QUADSPI_LCKER_UNLOCK, q->iobase + QUADSPI_LCKCR);
+       qspi_writel(q, QUADSPI_LUTKEY_VALUE, q->iobase + QUADSPI_LUTKEY);
+       qspi_writel(q, QUADSPI_LCKER_UNLOCK, q->iobase + QUADSPI_LCKCR);
 }
 
 static inline void fsl_qspi_lock_lut(struct fsl_qspi *q)
 {
-       writel(QUADSPI_LUTKEY_VALUE, q->iobase + QUADSPI_LUTKEY);
-       writel(QUADSPI_LCKER_LOCK, q->iobase + QUADSPI_LCKCR);
+       qspi_writel(q, QUADSPI_LUTKEY_VALUE, q->iobase + QUADSPI_LUTKEY);
+       qspi_writel(q, QUADSPI_LCKER_LOCK, q->iobase + QUADSPI_LCKCR);
 }
 
 static irqreturn_t fsl_qspi_irq_handler(int irq, void *dev_id)
@@ -326,8 +349,8 @@ static irqreturn_t fsl_qspi_irq_handler(int irq, void *dev_id)
        u32 reg;
 
        /* clear interrupt */
-       reg = readl(q->iobase + QUADSPI_FR);
-       writel(reg, q->iobase + QUADSPI_FR);
+       reg = qspi_readl(q, q->iobase + QUADSPI_FR);
+       qspi_writel(q, reg, q->iobase + QUADSPI_FR);
 
        if (reg & QUADSPI_FR_TFF_MASK)
                complete(&q->c);
@@ -348,7 +371,7 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
 
        /* Clear all the LUT table */
        for (i = 0; i < QUADSPI_LUT_NUM; i++)
-               writel(0, base + QUADSPI_LUT_BASE + i * 4);
+               qspi_writel(q, 0, base + QUADSPI_LUT_BASE + i * 4);
 
        /* Quad Read */
        lut_base = SEQID_QUAD_READ * 4;
@@ -364,14 +387,15 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
                dummy = 8;
        }
 
-       writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
+       qspi_writel(q, LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
                        base + QUADSPI_LUT(lut_base));
-       writel(LUT0(DUMMY, PAD1, dummy) | LUT1(FSL_READ, PAD4, rxfifo),
+       qspi_writel(q, LUT0(DUMMY, PAD1, dummy) | LUT1(FSL_READ, PAD4, rxfifo),
                        base + QUADSPI_LUT(lut_base + 1));
 
        /* Write enable */
        lut_base = SEQID_WREN * 4;
-       writel(LUT0(CMD, PAD1, SPINOR_OP_WREN), base + QUADSPI_LUT(lut_base));
+       qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_WREN),
+                       base + QUADSPI_LUT(lut_base));
 
        /* Page Program */
        lut_base = SEQID_PP * 4;
@@ -385,13 +409,15 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
                addrlen = ADDR32BIT;
        }
 
-       writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
+       qspi_writel(q, LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
                        base + QUADSPI_LUT(lut_base));
-       writel(LUT0(FSL_WRITE, PAD1, 0), base + QUADSPI_LUT(lut_base + 1));
+       qspi_writel(q, LUT0(FSL_WRITE, PAD1, 0),
+                       base + QUADSPI_LUT(lut_base + 1));
 
        /* Read Status */
        lut_base = SEQID_RDSR * 4;
-       writel(LUT0(CMD, PAD1, SPINOR_OP_RDSR) | LUT1(FSL_READ, PAD1, 0x1),
+       qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_RDSR) |
+                       LUT1(FSL_READ, PAD1, 0x1),
                        base + QUADSPI_LUT(lut_base));
 
        /* Erase a sector */
@@ -400,40 +426,46 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
        cmd = q->nor[0].erase_opcode;
        addrlen = q->nor_size <= SZ_16M ? ADDR24BIT : ADDR32BIT;
 
-       writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
+       qspi_writel(q, LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
                        base + QUADSPI_LUT(lut_base));
 
        /* Erase the whole chip */
        lut_base = SEQID_CHIP_ERASE * 4;
-       writel(LUT0(CMD, PAD1, SPINOR_OP_CHIP_ERASE),
+       qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_CHIP_ERASE),
                        base + QUADSPI_LUT(lut_base));
 
        /* READ ID */
        lut_base = SEQID_RDID * 4;
-       writel(LUT0(CMD, PAD1, SPINOR_OP_RDID) | LUT1(FSL_READ, PAD1, 0x8),
+       qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_RDID) |
+                       LUT1(FSL_READ, PAD1, 0x8),
                        base + QUADSPI_LUT(lut_base));
 
        /* Write Register */
        lut_base = SEQID_WRSR * 4;
-       writel(LUT0(CMD, PAD1, SPINOR_OP_WRSR) | LUT1(FSL_WRITE, PAD1, 0x2),
+       qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_WRSR) |
+                       LUT1(FSL_WRITE, PAD1, 0x2),
                        base + QUADSPI_LUT(lut_base));
 
        /* Read Configuration Register */
        lut_base = SEQID_RDCR * 4;
-       writel(LUT0(CMD, PAD1, SPINOR_OP_RDCR) | LUT1(FSL_READ, PAD1, 0x1),
+       qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_RDCR) |
+                       LUT1(FSL_READ, PAD1, 0x1),
                        base + QUADSPI_LUT(lut_base));
 
        /* Write disable */
        lut_base = SEQID_WRDI * 4;
-       writel(LUT0(CMD, PAD1, SPINOR_OP_WRDI), base + QUADSPI_LUT(lut_base));
+       qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_WRDI),
+                       base + QUADSPI_LUT(lut_base));
 
        /* Enter 4 Byte Mode (Micron) */
        lut_base = SEQID_EN4B * 4;
-       writel(LUT0(CMD, PAD1, SPINOR_OP_EN4B), base + QUADSPI_LUT(lut_base));
+       qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_EN4B),
+                       base + QUADSPI_LUT(lut_base));
 
        /* Enter 4 Byte Mode (Spansion) */
        lut_base = SEQID_BRWR * 4;
-       writel(LUT0(CMD, PAD1, SPINOR_OP_BRWR), base + QUADSPI_LUT(lut_base));
+       qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_BRWR),
+                       base + QUADSPI_LUT(lut_base));
 
        fsl_qspi_lock_lut(q);
 }
@@ -488,15 +520,16 @@ fsl_qspi_runcmd(struct fsl_qspi *q, u8 cmd, unsigned int addr, int len)
                        q->chip_base_addr, addr, len, cmd);
 
        /* save the reg */
-       reg = readl(base + QUADSPI_MCR);
+       reg = qspi_readl(q, base + QUADSPI_MCR);
 
-       writel(q->memmap_phy + q->chip_base_addr + addr, base + QUADSPI_SFAR);
-       writel(QUADSPI_RBCT_WMRK_MASK | QUADSPI_RBCT_RXBRD_USEIPS,
+       qspi_writel(q, q->memmap_phy + q->chip_base_addr + addr,
+                       base + QUADSPI_SFAR);
+       qspi_writel(q, QUADSPI_RBCT_WMRK_MASK | QUADSPI_RBCT_RXBRD_USEIPS,
                        base + QUADSPI_RBCT);
-       writel(reg | QUADSPI_MCR_CLR_RXF_MASK, base + QUADSPI_MCR);
+       qspi_writel(q, reg | QUADSPI_MCR_CLR_RXF_MASK, base + QUADSPI_MCR);
 
        do {
-               reg2 = readl(base + QUADSPI_SR);
+               reg2 = qspi_readl(q, base + QUADSPI_SR);
                if (reg2 & (QUADSPI_SR_IP_ACC_MASK | QUADSPI_SR_AHB_ACC_MASK)) {
                        udelay(1);
                        dev_dbg(q->dev, "The controller is busy, 0x%x\n", reg2);
@@ -507,21 +540,22 @@ fsl_qspi_runcmd(struct fsl_qspi *q, u8 cmd, unsigned int addr, int len)
 
        /* trigger the LUT now */
        seqid = fsl_qspi_get_seqid(q, cmd);
-       writel((seqid << QUADSPI_IPCR_SEQID_SHIFT) | len, base + QUADSPI_IPCR);
+       qspi_writel(q, (seqid << QUADSPI_IPCR_SEQID_SHIFT) | len,
+                       base + QUADSPI_IPCR);
 
        /* Wait for the interrupt. */
        if (!wait_for_completion_timeout(&q->c, msecs_to_jiffies(1000))) {
                dev_err(q->dev,
                        "cmd 0x%.2x timeout, addr@%.8x, FR:0x%.8x, SR:0x%.8x\n",
-                       cmd, addr, readl(base + QUADSPI_FR),
-                       readl(base + QUADSPI_SR));
+                       cmd, addr, qspi_readl(q, base + QUADSPI_FR),
+                       qspi_readl(q, base + QUADSPI_SR));
                err = -ETIMEDOUT;
        } else {
                err = 0;
        }
 
        /* restore the MCR */
-       writel(reg, base + QUADSPI_MCR);
+       qspi_writel(q, reg, base + QUADSPI_MCR);
 
        return err;
 }
@@ -533,7 +567,7 @@ static void fsl_qspi_read_data(struct fsl_qspi *q, int len, u8 *rxbuf)
        int i = 0;
 
        while (len > 0) {
-               tmp = readl(q->iobase + QUADSPI_RBDR + i * 4);
+               tmp = qspi_readl(q, q->iobase + QUADSPI_RBDR + i * 4);
                tmp = fsl_qspi_endian_xchg(q, tmp);
                dev_dbg(q->dev, "chip addr:0x%.8x, rcv:0x%.8x\n",
                                q->chip_base_addr, tmp);
@@ -561,9 +595,9 @@ static inline void fsl_qspi_invalid(struct fsl_qspi *q)
 {
        u32 reg;
 
-       reg = readl(q->iobase + QUADSPI_MCR);
+       reg = qspi_readl(q, q->iobase + QUADSPI_MCR);
        reg |= QUADSPI_MCR_SWRSTHD_MASK | QUADSPI_MCR_SWRSTSD_MASK;
-       writel(reg, q->iobase + QUADSPI_MCR);
+       qspi_writel(q, reg, q->iobase + QUADSPI_MCR);
 
        /*
         * The minimum delay : 1 AHB + 2 SFCK clocks.
@@ -572,7 +606,7 @@ static inline void fsl_qspi_invalid(struct fsl_qspi *q)
        udelay(1);
 
        reg &= ~(QUADSPI_MCR_SWRSTHD_MASK | QUADSPI_MCR_SWRSTSD_MASK);
-       writel(reg, q->iobase + QUADSPI_MCR);
+       qspi_writel(q, reg, q->iobase + QUADSPI_MCR);
 }
 
 static int fsl_qspi_nor_write(struct fsl_qspi *q, struct spi_nor *nor,
@@ -586,20 +620,20 @@ static int fsl_qspi_nor_write(struct fsl_qspi *q, struct spi_nor *nor,
                q->chip_base_addr, to, count);
 
        /* clear the TX FIFO. */
-       tmp = readl(q->iobase + QUADSPI_MCR);
-       writel(tmp | QUADSPI_MCR_CLR_TXF_MASK, q->iobase + QUADSPI_MCR);
+       tmp = qspi_readl(q, q->iobase + QUADSPI_MCR);
+       qspi_writel(q, tmp | QUADSPI_MCR_CLR_TXF_MASK, q->iobase + QUADSPI_MCR);
 
        /* fill the TX data to the FIFO */
        for (j = 0, i = ((count + 3) / 4); j < i; j++) {
                tmp = fsl_qspi_endian_xchg(q, *txbuf);
-               writel(tmp, q->iobase + QUADSPI_TBDR);
+               qspi_writel(q, tmp, q->iobase + QUADSPI_TBDR);
                txbuf++;
        }
 
        /* fill the TXFIFO upto 16 bytes for i.MX7d */
        if (needs_fill_txfifo(q))
                for (; i < 4; i++)
-                       writel(tmp, q->iobase + QUADSPI_TBDR);
+                       qspi_writel(q, tmp, q->iobase + QUADSPI_TBDR);
 
        /* Trigger it */
        ret = fsl_qspi_runcmd(q, opcode, to, count);
@@ -615,10 +649,10 @@ static void fsl_qspi_set_map_addr(struct fsl_qspi *q)
        int nor_size = q->nor_size;
        void __iomem *base = q->iobase;
 
-       writel(nor_size + q->memmap_phy, base + QUADSPI_SFA1AD);
-       writel(nor_size * 2 + q->memmap_phy, base + QUADSPI_SFA2AD);
-       writel(nor_size * 3 + q->memmap_phy, base + QUADSPI_SFB1AD);
-       writel(nor_size * 4 + q->memmap_phy, base + QUADSPI_SFB2AD);
+       qspi_writel(q, nor_size + q->memmap_phy, base + QUADSPI_SFA1AD);
+       qspi_writel(q, nor_size * 2 + q->memmap_phy, base + QUADSPI_SFA2AD);
+       qspi_writel(q, nor_size * 3 + q->memmap_phy, base + QUADSPI_SFB1AD);
+       qspi_writel(q, nor_size * 4 + q->memmap_phy, base + QUADSPI_SFB2AD);
 }
 
 /*
@@ -640,24 +674,26 @@ static void fsl_qspi_init_abh_read(struct fsl_qspi *q)
        int seqid;
 
        /* AHB configuration for access buffer 0/1/2 .*/
-       writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF0CR);
-       writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF1CR);
-       writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF2CR);
+       qspi_writel(q, QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF0CR);
+       qspi_writel(q, QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF1CR);
+       qspi_writel(q, QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF2CR);
        /*
         * Set ADATSZ with the maximum AHB buffer size to improve the
         * read performance.
         */
-       writel(QUADSPI_BUF3CR_ALLMST_MASK | ((q->devtype_data->ahb_buf_size / 8)
-                       << QUADSPI_BUF3CR_ADATSZ_SHIFT), base + QUADSPI_BUF3CR);
+       qspi_writel(q, QUADSPI_BUF3CR_ALLMST_MASK |
+                       ((q->devtype_data->ahb_buf_size / 8)
+                       << QUADSPI_BUF3CR_ADATSZ_SHIFT),
+                       base + QUADSPI_BUF3CR);
 
        /* We only use the buffer3 */
-       writel(0, base + QUADSPI_BUF0IND);
-       writel(0, base + QUADSPI_BUF1IND);
-       writel(0, base + QUADSPI_BUF2IND);
+       qspi_writel(q, 0, base + QUADSPI_BUF0IND);
+       qspi_writel(q, 0, base + QUADSPI_BUF1IND);
+       qspi_writel(q, 0, base + QUADSPI_BUF2IND);
 
        /* Set the default lut sequence for AHB Read. */
        seqid = fsl_qspi_get_seqid(q, q->nor[0].read_opcode);
-       writel(seqid << QUADSPI_BFGENCR_SEQID_SHIFT,
+       qspi_writel(q, seqid << QUADSPI_BFGENCR_SEQID_SHIFT,
                q->iobase + QUADSPI_BFGENCR);
 }
 
@@ -713,7 +749,7 @@ static int fsl_qspi_nor_setup(struct fsl_qspi *q)
                return ret;
 
        /* Reset the module */
-       writel(QUADSPI_MCR_SWRSTSD_MASK | QUADSPI_MCR_SWRSTHD_MASK,
+       qspi_writel(q, QUADSPI_MCR_SWRSTSD_MASK | QUADSPI_MCR_SWRSTHD_MASK,
                base + QUADSPI_MCR);
        udelay(1);
 
@@ -721,24 +757,24 @@ static int fsl_qspi_nor_setup(struct fsl_qspi *q)
        fsl_qspi_init_lut(q);
 
        /* Disable the module */
-       writel(QUADSPI_MCR_MDIS_MASK | QUADSPI_MCR_RESERVED_MASK,
+       qspi_writel(q, QUADSPI_MCR_MDIS_MASK | QUADSPI_MCR_RESERVED_MASK,
                        base + QUADSPI_MCR);
 
-       reg = readl(base + QUADSPI_SMPR);
-       writel(reg & ~(QUADSPI_SMPR_FSDLY_MASK
+       reg = qspi_readl(q, base + QUADSPI_SMPR);
+       qspi_writel(q, reg & ~(QUADSPI_SMPR_FSDLY_MASK
                        | QUADSPI_SMPR_FSPHS_MASK
                        | QUADSPI_SMPR_HSENA_MASK
                        | QUADSPI_SMPR_DDRSMP_MASK), base + QUADSPI_SMPR);
 
        /* Enable the module */
-       writel(QUADSPI_MCR_RESERVED_MASK | QUADSPI_MCR_END_CFG_MASK,
+       qspi_writel(q, QUADSPI_MCR_RESERVED_MASK | QUADSPI_MCR_END_CFG_MASK,
                        base + QUADSPI_MCR);
 
        /* clear all interrupt status */
-       writel(0xffffffff, q->iobase + QUADSPI_FR);
+       qspi_writel(q, 0xffffffff, q->iobase + QUADSPI_FR);
 
        /* enable the interrupt */
-       writel(QUADSPI_RSER_TFIE, q->iobase + QUADSPI_RSER);
+       qspi_writel(q, QUADSPI_RSER_TFIE, q->iobase + QUADSPI_RSER);
 
        return 0;
 }
@@ -954,6 +990,7 @@ static int fsl_qspi_probe(struct platform_device *pdev)
        if (IS_ERR(q->iobase))
                return PTR_ERR(q->iobase);
 
+       q->big_endian = of_property_read_bool(np, "big-endian");
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
                                        "QuadSPI-memory");
        if (!devm_request_mem_region(dev, res->start, resource_size(res),
@@ -1101,8 +1138,8 @@ static int fsl_qspi_remove(struct platform_device *pdev)
        }
 
        /* disable the hardware */
-       writel(QUADSPI_MCR_MDIS_MASK, q->iobase + QUADSPI_MCR);
-       writel(0x0, q->iobase + QUADSPI_RSER);
+       qspi_writel(q, QUADSPI_MCR_MDIS_MASK, q->iobase + QUADSPI_MCR);
+       qspi_writel(q, 0x0, q->iobase + QUADSPI_RSER);
 
        mutex_destroy(&q->lock);