123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774 |
- From 60eee49f37b77bc2d5f46c5db5a5c24d0c31bd02 Mon Sep 17 00:00:00 2001
- From: Biwen Li <[email protected]>
- Date: Tue, 20 Nov 2018 15:36:57 +0800
- Subject: [PATCH] qspi: support layerscape
- This is an integrated patch of qspi for layerscape
- Signed-off-by: Abhimanyu Saini <[email protected]>
- Signed-off-by: Cyrille Pitchen <[email protected]>
- Signed-off-by: Neil Armstrong <[email protected]>
- Signed-off-by: Prabhakar Kushwaha <[email protected]>
- Signed-off-by: Suresh Gupta <[email protected]>
- Signed-off-by: Yogesh Gaur <[email protected]>
- Signed-off-by: Biwen Li <[email protected]>
- Signed-off-by: Yangbo Lu <[email protected]>
- ---
- .../devicetree/bindings/mtd/fsl-quadspi.txt | 31 ++
- drivers/mtd/spi-nor/fsl-quadspi.c | 444 +++++++++++-------
- drivers/mtd/spi-nor/spi-nor.c | 5 +
- 3 files changed, 320 insertions(+), 160 deletions(-)
- --- a/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt
- +++ b/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt
- @@ -7,6 +7,7 @@ Required properties:
- or
- "fsl,ls2080a-qspi" followed by "fsl,ls1021a-qspi",
- "fsl,ls1043a-qspi" followed by "fsl,ls1021a-qspi"
- + "fsl,ls2080a-qspi" followed by "fsl,ls1088a-qspi",
- - reg : the first contains the register location and length,
- the second contains the memory mapping address and length
- - reg-names: Should contain the reg names "QuadSPI" and "QuadSPI-memory"
- @@ -39,3 +40,33 @@ qspi0: quadspi@40044000 {
- ....
- };
- };
- +
- +qspi1: quadspi@20c0000 {
- + #address-cells = <1>;
- + #size-cells = <0>;
- + reg = <0x0 0x20c0000 0x0 0x10000>,
- + <0x0 0x20000000 0x0 0x10000000>;
- + reg-names = "QuadSPI", "QuadSPI-memory";
- + interrupts = <0 25 0x4>; /* Level high type */
- + clocks = <&clockgen 4 3>, <&clockgen 4 3>;
- + clock-names = "qspi_en", "qspi";
- + status = "okay";
- +
- + qflash0: s25fs512s@0 {
- + #address-cells = <1>;
- + #size-cells = <1>;
- + spi-max-frequency = <20000000>;
- + reg = <0>;
- + spi-rx-bus-width = <4>;
- + spi-tx-bus-width = <4>;
- + };
- +
- + qflash1: s25fs512s@1 {
- + #address-cells = <1>;
- + #size-cells = <1>;
- + spi-max-frequency = <20000000>;
- + reg = <1>;
- + spi-rx-bus-width = <4>;
- + spi-tx-bus-width = <4>;
- + };
- +};
- --- a/drivers/mtd/spi-nor/fsl-quadspi.c
- +++ b/drivers/mtd/spi-nor/fsl-quadspi.c
- @@ -41,6 +41,7 @@
- #define QUADSPI_QUIRK_TKT253890 (1 << 2)
- /* Controller cannot wake up from wait mode, TKT245618 */
- #define QUADSPI_QUIRK_TKT245618 (1 << 3)
- +#define QUADSPI_ADDR_REMAP (1 << 4)
-
- /* The registers */
- #define QUADSPI_MCR 0x00
- @@ -183,7 +184,7 @@
-
- /* Macros for constructing the LUT register. */
- #define LUT0(ins, pad, opr) \
- - (((opr) << OPRND0_SHIFT) | ((LUT_##pad) << PAD0_SHIFT) | \
- + (((opr) << OPRND0_SHIFT) | ((pad) << PAD0_SHIFT) | \
- ((LUT_##ins) << INSTR0_SHIFT))
-
- #define LUT1(ins, pad, opr) (LUT0(ins, pad, opr) << OPRND1_SHIFT)
- @@ -193,27 +194,29 @@
- #define QUADSPI_LUT_NUM 64
-
- /* SEQID -- we can have 16 seqids at most. */
- -#define SEQID_READ 0
- -#define SEQID_WREN 1
- -#define SEQID_WRDI 2
- -#define SEQID_RDSR 3
- -#define SEQID_SE 4
- -#define SEQID_CHIP_ERASE 5
- -#define SEQID_PP 6
- -#define SEQID_RDID 7
- -#define SEQID_WRSR 8
- -#define SEQID_RDCR 9
- -#define SEQID_EN4B 10
- -#define SEQID_BRWR 11
- +/* LUT0 programmed by bootloader, for run-time create entry for LUT seqid 1 */
- +#define SEQID_LUT0_BOOTLOADER 0
- +#define SEQID_LUT1_RUNTIME 1
- +#define SEQID_LUT2_AHBREAD 2
-
- #define QUADSPI_MIN_IOMAP SZ_4M
-
- +enum fsl_qspi_ops {
- + FSL_QSPI_OPS_READ = 0,
- + FSL_QSPI_OPS_WRITE,
- + FSL_QSPI_OPS_ERASE,
- + FSL_QSPI_OPS_READ_REG,
- + FSL_QSPI_OPS_WRITE_REG,
- + FSL_QSPI_OPS_WRITE_BUF_REG,
- +};
- +
- enum fsl_qspi_devtype {
- FSL_QUADSPI_VYBRID,
- FSL_QUADSPI_IMX6SX,
- FSL_QUADSPI_IMX7D,
- FSL_QUADSPI_IMX6UL,
- FSL_QUADSPI_LS1021A,
- + FSL_QUADSPI_LS2080A,
- };
-
- struct fsl_qspi_devtype_data {
- @@ -267,6 +270,15 @@ static struct fsl_qspi_devtype_data ls10
- .driver_data = 0,
- };
-
- +static const struct fsl_qspi_devtype_data ls2080a_data = {
- + .devtype = FSL_QUADSPI_LS2080A,
- + .rxfifo = 128,
- + .txfifo = 64,
- + .ahb_buf_size = 1024,
- + .driver_data = QUADSPI_QUIRK_TKT253890 | QUADSPI_ADDR_REMAP,
- +};
- +
- +
- #define FSL_QSPI_MAX_CHIP 4
- struct fsl_qspi {
- struct spi_nor nor[FSL_QSPI_MAX_CHIP];
- @@ -310,6 +322,22 @@ static inline int needs_wakeup_wait_mode
- }
-
- /*
- + * QSPI memory regions split into two parts: a 256MB region that is located
- + * in the least significant 4GB of the SoC address space and a 3.75GB region
- + * that is located above the least significant 4GB of the SoC address space.
- + *
- + * The 4GB QSPI address space map is shown below.
- + *
- + * SoC Address QSPI Address
- + * 0x00_2000_0000-0x00_2FFF_FFFF 0x00_0000_0000-0x00_0FFF_FFFF First 256MB
- + * 0x04_1000_0000-0x04_FFFF_FFFF 0x00_1000_0000-0x00_FFFF_FFFF Last 3.75GB
- + */
- +static inline int need_address_remap(struct fsl_qspi *q)
- +{
- + return q->devtype_data->driver_data & QUADSPI_ADDR_REMAP;
- +}
- +
- +/*
- * 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
- @@ -368,137 +396,160 @@ static irqreturn_t fsl_qspi_irq_handler(
- return IRQ_HANDLED;
- }
-
- -static void fsl_qspi_init_lut(struct fsl_qspi *q)
- +static inline s8 pad_count(s8 pad_val)
- {
- + s8 count = -1;
- +
- + if (!pad_val)
- + return 0;
- +
- + while (pad_val) {
- + pad_val >>= 1;
- + count++;
- + }
- + return count;
- +}
- +
- +/*
- + * Prepare LUT entry for the input cmd.
- + * Protocol info is present in instance of struct spi_nor, using which fields
- + * like cmd, data, addrlen along with pad info etc can be parsed.
- + */
- +static void fsl_qspi_prepare_lut(struct spi_nor *nor,
- + enum fsl_qspi_ops ops, u8 cmd)
- +{
- + struct fsl_qspi *q = nor->priv;
- void __iomem *base = q->iobase;
- int rxfifo = q->devtype_data->rxfifo;
- + int txfifo = q->devtype_data->txfifo;
- u32 lut_base;
- - int i;
- + u8 cmd_pad, addr_pad, data_pad, dummy_pad;
- + enum spi_nor_protocol protocol = 0;
- + u8 addrlen = 0;
- + u8 read_dm, opcode;
- + int stop_lut;
- +
- + read_dm = opcode = cmd_pad = addr_pad = data_pad = dummy_pad = 0;
- +
- + switch (ops) {
- + case FSL_QSPI_OPS_READ_REG:
- + case FSL_QSPI_OPS_WRITE_REG:
- + case FSL_QSPI_OPS_WRITE_BUF_REG:
- + opcode = cmd;
- + protocol = nor->reg_proto;
- + break;
- + case FSL_QSPI_OPS_READ:
- + opcode = cmd;
- + read_dm = nor->read_dummy;
- + protocol = nor->read_proto;
- + break;
- + case FSL_QSPI_OPS_WRITE:
- + opcode = cmd;
- + protocol = nor->write_proto;
- + break;
- + case FSL_QSPI_OPS_ERASE:
- + opcode = cmd;
- + break;
- + default:
- + dev_err(q->dev, "Unsupported operation 0x%.2x\n", ops);
- + return;
- + }
- +
- + if (protocol) {
- + cmd_pad = spi_nor_get_protocol_inst_nbits(protocol);
- + addr_pad = spi_nor_get_protocol_addr_nbits(protocol);
- + data_pad = spi_nor_get_protocol_data_nbits(protocol);
- + }
- +
- + dummy_pad = data_pad;
-
- - struct spi_nor *nor = &q->nor[0];
- - u8 addrlen = (nor->addr_width == 3) ? ADDR24BIT : ADDR32BIT;
- - u8 read_op = nor->read_opcode;
- - u8 read_dm = nor->read_dummy;
- + dev_dbg(q->dev, "ops:%x opcode:%x pad[cmd:%d, addr:%d, data:%d]\n",
- + ops, opcode, cmd_pad, addr_pad, data_pad);
-
- fsl_qspi_unlock_lut(q);
-
- - /* Clear all the LUT table */
- - for (i = 0; i < QUADSPI_LUT_NUM; i++)
- - qspi_writel(q, 0, base + QUADSPI_LUT_BASE + i * 4);
- -
- - /* Read */
- - lut_base = SEQID_READ * 4;
- -
- - qspi_writel(q, LUT0(CMD, PAD1, read_op) | LUT1(ADDR, PAD1, addrlen),
- - base + QUADSPI_LUT(lut_base));
- - qspi_writel(q, LUT0(DUMMY, PAD1, read_dm) |
- - LUT1(FSL_READ, PAD4, rxfifo),
- - base + QUADSPI_LUT(lut_base + 1));
- -
- - /* Write enable */
- - lut_base = SEQID_WREN * 4;
- - qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_WREN),
- - base + QUADSPI_LUT(lut_base));
- -
- - /* Page Program */
- - lut_base = SEQID_PP * 4;
- -
- - qspi_writel(q, LUT0(CMD, PAD1, nor->program_opcode) |
- - LUT1(ADDR, PAD1, addrlen),
- - base + QUADSPI_LUT(lut_base));
- - qspi_writel(q, LUT0(FSL_WRITE, PAD1, 0),
- - base + QUADSPI_LUT(lut_base + 1));
- -
- - /* Read Status */
- - lut_base = SEQID_RDSR * 4;
- - qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_RDSR) |
- - LUT1(FSL_READ, PAD1, 0x1),
- - base + QUADSPI_LUT(lut_base));
- -
- - /* Erase a sector */
- - lut_base = SEQID_SE * 4;
- -
- - qspi_writel(q, LUT0(CMD, PAD1, nor->erase_opcode) |
- - LUT1(ADDR, PAD1, addrlen),
- - base + QUADSPI_LUT(lut_base));
- -
- - /* Erase the whole chip */
- - lut_base = SEQID_CHIP_ERASE * 4;
- - qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_CHIP_ERASE),
- - base + QUADSPI_LUT(lut_base));
- -
- - /* READ ID */
- - lut_base = SEQID_RDID * 4;
- - 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;
- - 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;
- - 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;
- - qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_WRDI),
- - base + QUADSPI_LUT(lut_base));
- -
- - /* Enter 4 Byte Mode (Micron) */
- - lut_base = SEQID_EN4B * 4;
- - qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_EN4B),
- - base + QUADSPI_LUT(lut_base));
- -
- - /* Enter 4 Byte Mode (Spansion) */
- - lut_base = SEQID_BRWR * 4;
- - qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_BRWR),
- - base + QUADSPI_LUT(lut_base));
- + /* Dynamic LUT */
- + lut_base = SEQID_LUT1_RUNTIME * 4;
- + if (ops == FSL_QSPI_OPS_READ)
- + lut_base = SEQID_LUT2_AHBREAD * 4;
- +
- + /* default, STOP instruction to be programmed in (lut_base + 1) reg */
- + stop_lut = 1;
- + switch (ops) {
- + case FSL_QSPI_OPS_READ_REG:
- + qspi_writel(q, LUT0(CMD, pad_count(cmd_pad), opcode) |
- + LUT1(FSL_READ, pad_count(data_pad), rxfifo),
- + base + QUADSPI_LUT(lut_base));
- + break;
- + case FSL_QSPI_OPS_WRITE_REG:
- + qspi_writel(q, LUT0(CMD, pad_count(cmd_pad), opcode),
- + base + QUADSPI_LUT(lut_base));
- + break;
- + case FSL_QSPI_OPS_WRITE_BUF_REG:
- + qspi_writel(q, LUT0(CMD, pad_count(cmd_pad), opcode) |
- + LUT1(FSL_WRITE, pad_count(data_pad), txfifo),
- + base + QUADSPI_LUT(lut_base));
- + break;
- + case FSL_QSPI_OPS_READ:
- + case FSL_QSPI_OPS_WRITE:
- + case FSL_QSPI_OPS_ERASE:
- + /* Common for Read, Write and Erase ops. */
- +
- + addrlen = (nor->addr_width == 3) ? ADDR24BIT : ADDR32BIT;
- +
- + qspi_writel(q, LUT0(CMD, pad_count(cmd_pad), opcode) |
- + LUT1(ADDR, pad_count(addr_pad), addrlen),
- + base + QUADSPI_LUT(lut_base));
- + /*
- + * For Erase ops - Data and Dummy not required.
- + * For Write ops - Dummy not required.
- + */
-
- - fsl_qspi_lock_lut(q);
- -}
- + if (ops == FSL_QSPI_OPS_READ) {
-
- -/* Get the SEQID for the command */
- -static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd)
- -{
- - switch (cmd) {
- - case SPINOR_OP_READ_1_1_4:
- - case SPINOR_OP_READ_1_1_4_4B:
- - return SEQID_READ;
- - case SPINOR_OP_WREN:
- - return SEQID_WREN;
- - case SPINOR_OP_WRDI:
- - return SEQID_WRDI;
- - case SPINOR_OP_RDSR:
- - return SEQID_RDSR;
- - case SPINOR_OP_SE:
- - return SEQID_SE;
- - case SPINOR_OP_CHIP_ERASE:
- - return SEQID_CHIP_ERASE;
- - case SPINOR_OP_PP:
- - return SEQID_PP;
- - case SPINOR_OP_RDID:
- - return SEQID_RDID;
- - case SPINOR_OP_WRSR:
- - return SEQID_WRSR;
- - case SPINOR_OP_RDCR:
- - return SEQID_RDCR;
- - case SPINOR_OP_EN4B:
- - return SEQID_EN4B;
- - case SPINOR_OP_BRWR:
- - return SEQID_BRWR;
- + /*
- + * For cmds SPINOR_OP_READ and SPINOR_OP_READ_4B value
- + * of dummy cycles are 0.
- + */
- + if (read_dm)
- + qspi_writel(q,
- + LUT0(DUMMY, pad_count(dummy_pad),
- + read_dm) |
- + LUT1(FSL_READ, pad_count(data_pad),
- + rxfifo),
- + base + QUADSPI_LUT(lut_base + 1));
- + else
- + qspi_writel(q,
- + LUT0(FSL_READ, pad_count(data_pad),
- + rxfifo),
- + base + QUADSPI_LUT(lut_base + 1));
- +
- + stop_lut = 2;
- +
- + /* TODO Add condition to check if READ is IP/AHB. */
- +
- + /* For AHB read, add seqid in BFGENCR register. */
- + qspi_writel(q,
- + SEQID_LUT2_AHBREAD <<
- + QUADSPI_BFGENCR_SEQID_SHIFT,
- + q->iobase + QUADSPI_BFGENCR);
- + }
- +
- + if (ops == FSL_QSPI_OPS_WRITE) {
- + qspi_writel(q, LUT0(FSL_WRITE, pad_count(data_pad), 0),
- + base + QUADSPI_LUT(lut_base + 1));
- + stop_lut = 2;
- + }
- + break;
- default:
- - if (cmd == q->nor[0].erase_opcode)
- - return SEQID_SE;
- - dev_err(q->dev, "Unsupported cmd 0x%.2x\n", cmd);
- + dev_err(q->dev, "Unsupported operation 0x%.2x\n", ops);
- break;
- }
- - return -EINVAL;
- +
- + /* prepare LUT for STOP instruction. */
- + qspi_writel(q, 0, base + QUADSPI_LUT(lut_base + stop_lut));
- +
- + fsl_qspi_lock_lut(q);
- }
-
- static int
- @@ -508,6 +559,10 @@ fsl_qspi_runcmd(struct fsl_qspi *q, u8 c
- int seqid;
- u32 reg, reg2;
- int err;
- + u32 memmap_phyadd = q->memmap_phy;
- +
- + if (need_address_remap(q))
- + memmap_phyadd = 0;
-
- init_completion(&q->c);
- dev_dbg(q->dev, "to 0x%.8x:0x%.8x, len:%d, cmd:%.2x\n",
- @@ -516,7 +571,7 @@ fsl_qspi_runcmd(struct fsl_qspi *q, u8 c
- /* save the reg */
- reg = qspi_readl(q, base + QUADSPI_MCR);
-
- - qspi_writel(q, q->memmap_phy + q->chip_base_addr + addr,
- + qspi_writel(q, memmap_phyadd + q->chip_base_addr + addr,
- base + QUADSPI_SFAR);
- qspi_writel(q, QUADSPI_RBCT_WMRK_MASK | QUADSPI_RBCT_RXBRD_USEIPS,
- base + QUADSPI_RBCT);
- @@ -533,7 +588,7 @@ fsl_qspi_runcmd(struct fsl_qspi *q, u8 c
- } while (1);
-
- /* trigger the LUT now */
- - seqid = fsl_qspi_get_seqid(q, cmd);
- + seqid = SEQID_LUT1_RUNTIME;
- qspi_writel(q, (seqid << QUADSPI_IPCR_SEQID_SHIFT) | len,
- base + QUADSPI_IPCR);
-
- @@ -609,6 +664,7 @@ static ssize_t fsl_qspi_nor_write(struct
- {
- int ret, i, j;
- u32 tmp;
- + u8 byts;
-
- dev_dbg(q->dev, "to 0x%.8x:0x%.8x, len : %d\n",
- q->chip_base_addr, to, count);
- @@ -618,10 +674,18 @@ static ssize_t fsl_qspi_nor_write(struct
- qspi_writel(q, tmp | QUADSPI_MCR_CLR_TXF_MASK, q->iobase + QUADSPI_MCR);
-
- /* fill the TX data to the FIFO */
- + byts = count;
- for (j = 0, i = ((count + 3) / 4); j < i; j++) {
- - tmp = fsl_qspi_endian_xchg(q, *txbuf);
- + if(byts >= 4)
- + tmp = fsl_qspi_endian_xchg(q, *txbuf);
- + else {
- + memcpy(&tmp, txbuf, byts);
- + tmp = fsl_qspi_endian_xchg(q, tmp);
- + }
- +
- qspi_writel(q, tmp, q->iobase + QUADSPI_TBDR);
- txbuf++;
- + byts -= 4;
- }
-
- /* fill the TXFIFO upto 16 bytes for i.MX7d */
- @@ -642,11 +706,15 @@ static void fsl_qspi_set_map_addr(struct
- {
- int nor_size = q->nor_size;
- void __iomem *base = q->iobase;
- + u32 memmap_phyadd = q->memmap_phy;
- +
- + if (need_address_remap(q))
- + memmap_phyadd = 0;
-
- - 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);
- + qspi_writel(q, nor_size + memmap_phyadd, base + QUADSPI_SFA1AD);
- + qspi_writel(q, nor_size * 2 + memmap_phyadd, base + QUADSPI_SFA2AD);
- + qspi_writel(q, nor_size * 3 + memmap_phyadd, base + QUADSPI_SFB1AD);
- + qspi_writel(q, nor_size * 4 + memmap_phyadd, base + QUADSPI_SFB2AD);
- }
-
- /*
- @@ -662,7 +730,7 @@ static void fsl_qspi_set_map_addr(struct
- * causes the controller to clear the buffer, and use the sequence pointed
- * by the QUADSPI_BFGENCR[SEQID] to initiate a read from the flash.
- */
- -static void fsl_qspi_init_abh_read(struct fsl_qspi *q)
- +static void fsl_qspi_init_ahb_read(struct fsl_qspi *q)
- {
- void __iomem *base = q->iobase;
- int seqid;
- @@ -685,8 +753,8 @@ static void fsl_qspi_init_abh_read(struc
- 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);
- + /* Set dynamic LUT entry as lut sequence for AHB Read . */
- + seqid = SEQID_LUT2_AHBREAD;
- qspi_writel(q, seqid << QUADSPI_BFGENCR_SEQID_SHIFT,
- q->iobase + QUADSPI_BFGENCR);
- }
- @@ -729,7 +797,6 @@ static int fsl_qspi_nor_setup(struct fsl
- void __iomem *base = q->iobase;
- u32 reg;
- int ret;
- -
- /* disable and unprepare clock to avoid glitch pass to controller */
- fsl_qspi_clk_disable_unprep(q);
-
- @@ -747,9 +814,6 @@ static int fsl_qspi_nor_setup(struct fsl
- base + QUADSPI_MCR);
- udelay(1);
-
- - /* Init the LUT table. */
- - fsl_qspi_init_lut(q);
- -
- /* Disable the module */
- qspi_writel(q, QUADSPI_MCR_MDIS_MASK | QUADSPI_MCR_RESERVED_MASK,
- base + QUADSPI_MCR);
- @@ -770,6 +834,9 @@ static int fsl_qspi_nor_setup(struct fsl
- /* enable the interrupt */
- qspi_writel(q, QUADSPI_RSER_TFIE, q->iobase + QUADSPI_RSER);
-
- + /* Init for AHB read */
- + fsl_qspi_init_ahb_read(q);
- +
- return 0;
- }
-
- @@ -792,12 +859,6 @@ static int fsl_qspi_nor_setup_last(struc
- if (ret)
- return ret;
-
- - /* Init the LUT table again. */
- - fsl_qspi_init_lut(q);
- -
- - /* Init for AHB read */
- - fsl_qspi_init_abh_read(q);
- -
- return 0;
- }
-
- @@ -807,6 +868,7 @@ static const struct of_device_id fsl_qsp
- { .compatible = "fsl,imx7d-qspi", .data = (void *)&imx7d_data, },
- { .compatible = "fsl,imx6ul-qspi", .data = (void *)&imx6ul_data, },
- { .compatible = "fsl,ls1021a-qspi", .data = (void *)&ls1021a_data, },
- + { .compatible = "fsl,ls2080a-qspi", .data = &ls2080a_data, },
- { /* sentinel */ }
- };
- MODULE_DEVICE_TABLE(of, fsl_qspi_dt_ids);
- @@ -821,6 +883,7 @@ static int fsl_qspi_read_reg(struct spi_
- int ret;
- struct fsl_qspi *q = nor->priv;
-
- + fsl_qspi_prepare_lut(nor, FSL_QSPI_OPS_READ_REG, opcode);
- ret = fsl_qspi_runcmd(q, opcode, 0, len);
- if (ret)
- return ret;
- @@ -835,6 +898,8 @@ static int fsl_qspi_write_reg(struct spi
- int ret;
-
- if (!buf) {
- + /* Prepare LUT for WRITE_REG cmd with input BUF as NULL. */
- + fsl_qspi_prepare_lut(nor, FSL_QSPI_OPS_WRITE_REG, opcode);
- ret = fsl_qspi_runcmd(q, opcode, 0, 1);
- if (ret)
- return ret;
- @@ -843,6 +908,8 @@ static int fsl_qspi_write_reg(struct spi
- fsl_qspi_invalid(q);
-
- } else if (len > 0) {
- + /* Prepare LUT for WRITE_REG cmd with input BUF non-NULL. */
- + fsl_qspi_prepare_lut(nor, FSL_QSPI_OPS_WRITE_BUF_REG, opcode);
- ret = fsl_qspi_nor_write(q, nor, opcode, 0,
- (u32 *)buf, len);
- if (ret > 0)
- @@ -859,8 +926,11 @@ static ssize_t fsl_qspi_write(struct spi
- size_t len, const u_char *buf)
- {
- struct fsl_qspi *q = nor->priv;
- - ssize_t ret = fsl_qspi_nor_write(q, nor, nor->program_opcode, to,
- - (u32 *)buf, len);
- + ssize_t ret;
- +
- + fsl_qspi_prepare_lut(nor, FSL_QSPI_OPS_WRITE, nor->program_opcode);
- + ret = fsl_qspi_nor_write(q, nor, nor->program_opcode, to,
- + (u32 *)buf, len);
-
- /* invalid the data in the AHB buffer. */
- fsl_qspi_invalid(q);
- @@ -873,6 +943,8 @@ static ssize_t fsl_qspi_read(struct spi_
- struct fsl_qspi *q = nor->priv;
- u8 cmd = nor->read_opcode;
-
- + fsl_qspi_prepare_lut(nor, FSL_QSPI_OPS_READ, nor->read_opcode);
- +
- /* if necessary,ioremap buffer before AHB read, */
- if (!q->ahb_addr) {
- q->memmap_offs = q->chip_base_addr + from;
- @@ -907,8 +979,9 @@ static ssize_t fsl_qspi_read(struct spi_
- len);
-
- /* Read out the data directly from the AHB buffer.*/
- - memcpy(buf, q->ahb_addr + q->chip_base_addr + from - q->memmap_offs,
- - len);
- + memcpy_fromio(buf,
- + q->ahb_addr + q->chip_base_addr + from - q->memmap_offs,
- + len);
-
- return len;
- }
- @@ -921,6 +994,7 @@ static int fsl_qspi_erase(struct spi_nor
- dev_dbg(nor->dev, "%dKiB at 0x%08x:0x%08x\n",
- nor->mtd.erasesize / 1024, q->chip_base_addr, (u32)offs);
-
- + fsl_qspi_prepare_lut(nor, FSL_QSPI_OPS_ERASE, nor->erase_opcode);
- ret = fsl_qspi_runcmd(q, nor->erase_opcode, offs, 0);
- if (ret)
- return ret;
- @@ -958,17 +1032,14 @@ static void fsl_qspi_unprep(struct spi_n
-
- static int fsl_qspi_probe(struct platform_device *pdev)
- {
- - const struct spi_nor_hwcaps hwcaps = {
- - .mask = SNOR_HWCAPS_READ_1_1_4 |
- - SNOR_HWCAPS_PP,
- - };
- + struct spi_nor_hwcaps hwcaps;
- struct device_node *np = pdev->dev.of_node;
- struct device *dev = &pdev->dev;
- struct fsl_qspi *q;
- struct resource *res;
- struct spi_nor *nor;
- struct mtd_info *mtd;
- - int ret, i = 0;
- + int ret, i = 0, value;
-
- q = devm_kzalloc(dev, sizeof(*q), GFP_KERNEL);
- if (!q)
- @@ -1041,6 +1112,10 @@ static int fsl_qspi_probe(struct platfor
-
- /* iterate the subnodes. */
- for_each_available_child_of_node(dev->of_node, np) {
- + /* Reset hwcaps mask to minimal caps for the slave node. */
- + hwcaps.mask = SNOR_HWCAPS_READ | SNOR_HWCAPS_PP;
- + value = 0;
- +
- /* skip the holes */
- if (!q->has_second_chip)
- i *= 2;
- @@ -1070,6 +1145,51 @@ static int fsl_qspi_probe(struct platfor
- /* set the chip address for READID */
- fsl_qspi_set_base_addr(q, nor);
-
- + /*
- + * If spi-rx-bus-width and spi-tx-bus-width not defined assign
- + * default hardware capabilities SNOR_HWCAPS_READ_1_1_4 and
- + * SNOR_HWCAPS_PP supported by the Quad-SPI controller.
- + */
- + if (!of_property_read_u32(np, "spi-rx-bus-width", &value)) {
- + switch (value) {
- + case 1:
- + hwcaps.mask |= SNOR_HWCAPS_READ |
- + SNOR_HWCAPS_READ_FAST;
- + break;
- + case 2:
- + hwcaps.mask |= SNOR_HWCAPS_READ_1_1_2 |
- + SNOR_HWCAPS_READ_1_2_2;
- + break;
- + case 4:
- + hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4 |
- + SNOR_HWCAPS_READ_1_4_4;
- + break;
- + default:
- + dev_err(dev,
- + "spi-rx-bus-width %d not supported\n",
- + value);
- + break;
- + }
- + } else
- + hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4;
- +
- + if (!of_property_read_u32(np, "spi-tx-bus-width", &value)) {
- + switch (value) {
- + case 1:
- + hwcaps.mask |= SNOR_HWCAPS_PP;
- + break;
- + case 4:
- + hwcaps.mask |= SNOR_HWCAPS_PP_1_1_4 |
- + SNOR_HWCAPS_PP_1_4_4;
- + break;
- + default:
- + dev_err(dev,
- + "spi-tx-bus-width %d not supported\n",
- + value);
- + break;
- + }
- + }
- +
- ret = spi_nor_scan(nor, NULL, &hwcaps);
- if (ret)
- goto mutex_failed;
- @@ -1098,6 +1218,8 @@ static int fsl_qspi_probe(struct platfor
- if (nor->page_size > q->devtype_data->txfifo)
- nor->page_size = q->devtype_data->txfifo;
-
- + /*required for memory mapped AHB read*/
- + fsl_qspi_prepare_lut(nor, FSL_QSPI_OPS_READ, nor->read_opcode);
- i++;
- }
-
- @@ -1106,6 +1228,8 @@ static int fsl_qspi_probe(struct platfor
- if (ret)
- goto last_init_failed;
-
- +
- +
- fsl_qspi_clk_disable_unprep(q);
- return 0;
-
- --- a/drivers/mtd/spi-nor/spi-nor.c
- +++ b/drivers/mtd/spi-nor/spi-nor.c
- @@ -1147,6 +1147,11 @@ static const struct flash_info spi_nor_i
- { "w25x40", INFO(0xef3013, 0, 64 * 1024, 8, SECT_4K) },
- { "w25x80", INFO(0xef3014, 0, 64 * 1024, 16, SECT_4K) },
- { "w25x16", INFO(0xef3015, 0, 64 * 1024, 32, SECT_4K) },
- + {
- + "w25q16dw", INFO(0xef6015, 0, 64 * 1024, 32,
- + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
- + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
- + },
- { "w25x32", INFO(0xef3016, 0, 64 * 1024, 64, SECT_4K) },
- { "w25q20cl", INFO(0xef4012, 0, 64 * 1024, 4, SECT_4K) },
- { "w25q20bw", INFO(0xef5012, 0, 64 * 1024, 4, SECT_4K) },
|