123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400 |
- From c58b398221d88ac0db29c3bb7522a4f48dfa102c Mon Sep 17 00:00:00 2001
- From: Yuan Yao <yao.yuan@freescale.com>
- Date: Tue, 17 Nov 2015 16:13:47 +0800
- Subject: [PATCH 087/113] mtd: spi-nor: fsl-quadspi: add big-endian support
- 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>
- ---
- drivers/mtd/spi-nor/fsl-quadspi.c | 157 +++++++++++++++++++++++--------------
- 1 file changed, 97 insertions(+), 60 deletions(-)
- --- a/drivers/mtd/spi-nor/fsl-quadspi.c
- +++ b/drivers/mtd/spi-nor/fsl-quadspi.c
- @@ -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;
- };
- @@ -300,6 +301,28 @@ static inline int needs_wakeup_wait_mode
- }
-
- /*
- + * 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(s
-
- 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(
- 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
-
- /* 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
- 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
- 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
- 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 c
- 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 c
-
- /* 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 fs
- 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(stru
- {
- 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(stru
- 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
- 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
- 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(struc
- 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
- 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
- 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 platfor
- 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 platfo
- }
-
- /* 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);
-
|