X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=drivers%2Fspi%2Ffsl_qspi.c;h=e61c67b088bc7e267f44eaec916df7628b9fa5b4;hb=034e226bc77e6b2137acaa5094d9886c8bc9a07e;hp=542b6cfe355b3e3212f7cb59d5c49792e1333e4c;hpb=774da4b9aadeea4d6973a16debc02a6801ff9344;p=u-boot diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c index 542b6cfe35..e61c67b088 100644 --- a/drivers/spi/fsl_qspi.c +++ b/drivers/spi/fsl_qspi.c @@ -44,6 +44,8 @@ DECLARE_GLOBAL_DATA_PTR; #define SEQID_RDEAR 11 #define SEQID_WREAR 12 #endif +#define SEQID_WRAR 13 +#define SEQID_RDAR 14 /* QSPI CMD */ #define QSPI_CMD_PP 0x02 /* Page program (up to 256 bytes) */ @@ -63,6 +65,10 @@ DECLARE_GLOBAL_DATA_PTR; #define QSPI_CMD_BRRD 0x16 /* Bank register read */ #define QSPI_CMD_BRWR 0x17 /* Bank register write */ +/* Used for Spansion S25FS-S family flash only. */ +#define QSPI_CMD_RDAR 0x65 /* Read any device register */ +#define QSPI_CMD_WRAR 0x71 /* Write any device register */ + /* 4-byte address QSPI CMD - used on Spansion and some Macronix flashes */ #define QSPI_CMD_FAST_READ_4B 0x0c /* Read data bytes (high frequency) */ #define QSPI_CMD_PP_4B 0x12 /* Page program (up to 256 bytes) */ @@ -92,9 +98,9 @@ DECLARE_GLOBAL_DATA_PTR; struct fsl_qspi_platdata { u32 flags; u32 speed_hz; - u32 reg_base; - u32 amba_base; - u32 amba_total_size; + fdt_addr_t reg_base; + fdt_addr_t amba_base; + fdt_size_t amba_total_size; u32 flash_num; u32 num_chipselect; }; @@ -317,6 +323,33 @@ static void qspi_set_lut(struct fsl_qspi_priv *priv) PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) | PAD1(LUT_PAD1) | INSTR1(LUT_WRITE)); #endif + + /* + * Read any device register. + * Used for Spansion S25FS-S family flash only. + */ + lut_base = SEQID_RDAR * 4; + qspi_write32(priv->flags, ®s->lut[lut_base], + OPRND0(QSPI_CMD_RDAR) | PAD0(LUT_PAD1) | + INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) | + PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); + qspi_write32(priv->flags, ®s->lut[lut_base + 1], + OPRND0(8) | PAD0(LUT_PAD1) | INSTR0(LUT_DUMMY) | + OPRND1(1) | PAD1(LUT_PAD1) | + INSTR1(LUT_READ)); + + /* + * Write any device register. + * Used for Spansion S25FS-S family flash only. + */ + lut_base = SEQID_WRAR * 4; + qspi_write32(priv->flags, ®s->lut[lut_base], + OPRND0(QSPI_CMD_WRAR) | PAD0(LUT_PAD1) | + INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) | + PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); + qspi_write32(priv->flags, ®s->lut[lut_base + 1], + OPRND0(1) | PAD0(LUT_PAD1) | INSTR0(LUT_WRITE)); + /* Lock the LUT */ qspi_write32(priv->flags, ®s->lutkey, LUT_KEY_VALUE); qspi_write32(priv->flags, ®s->lckcr, QSPI_LCKCR_LOCK); @@ -353,6 +386,7 @@ static inline void qspi_ahb_read(struct fsl_qspi_priv *priv, u8 *rxbuf, int len) { struct fsl_qspi_regs *regs = priv->regs; u32 mcr_reg; + void *rx_addr = NULL; mcr_reg = qspi_read32(priv->flags, ®s->mcr); @@ -360,8 +394,9 @@ static inline void qspi_ahb_read(struct fsl_qspi_priv *priv, u8 *rxbuf, int len) QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK | QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE); + rx_addr = (void *)(uintptr_t)(priv->cur_amba_base + priv->sf_addr); /* Read out the data directly from the AHB buffer. */ - memcpy(rxbuf, (u8 *)(priv->cur_amba_base + priv->sf_addr), len); + memcpy(rxbuf, rx_addr, len); qspi_write32(priv->flags, ®s->mcr, mcr_reg); } @@ -477,8 +512,8 @@ static void qspi_op_rdbank(struct fsl_qspi_priv *priv, u8 *rxbuf, u32 len) static void qspi_op_rdid(struct fsl_qspi_priv *priv, u32 *rxbuf, u32 len) { struct fsl_qspi_regs *regs = priv->regs; - u32 mcr_reg, rbsr_reg, data; - int i, size; + u32 mcr_reg, rbsr_reg, data, size; + int i; mcr_reg = qspi_read32(priv->flags, ®s->mcr); qspi_write32(priv->flags, ®s->mcr, @@ -494,15 +529,15 @@ static void qspi_op_rdid(struct fsl_qspi_priv *priv, u32 *rxbuf, u32 len) ; i = 0; - size = len; - while ((RX_BUFFER_SIZE >= size) && (size > 0)) { + while ((RX_BUFFER_SIZE >= len) && (len > 0)) { rbsr_reg = qspi_read32(priv->flags, ®s->rbsr); if (rbsr_reg & QSPI_RBSR_RDBFL_MASK) { data = qspi_read32(priv->flags, ®s->rbdr[i]); data = qspi_endian_xchg(data); - memcpy(rxbuf, &data, 4); + size = (len < 4) ? len : 4; + memcpy(rxbuf, &data, size); + len -= size; rxbuf++; - size -= 4; i++; } } @@ -510,7 +545,6 @@ static void qspi_op_rdid(struct fsl_qspi_priv *priv, u32 *rxbuf, u32 len) qspi_write32(priv->flags, ®s->mcr, mcr_reg); } -#ifndef CONFIG_SYS_FSL_QSPI_AHB /* If not use AHB read, read data from ip interface */ static void qspi_op_read(struct fsl_qspi_priv *priv, u32 *rxbuf, u32 len) { @@ -518,6 +552,12 @@ static void qspi_op_read(struct fsl_qspi_priv *priv, u32 *rxbuf, u32 len) u32 mcr_reg, data; int i, size; u32 to_or_from; + u32 seqid; + + if (priv->cur_seqid == QSPI_CMD_RDAR) + seqid = SEQID_RDAR; + else + seqid = SEQID_FAST_READ; mcr_reg = qspi_read32(priv->flags, ®s->mcr); qspi_write32(priv->flags, ®s->mcr, @@ -536,7 +576,7 @@ static void qspi_op_read(struct fsl_qspi_priv *priv, u32 *rxbuf, u32 len) RX_BUFFER_SIZE : len; qspi_write32(priv->flags, ®s->ipcr, - (SEQID_FAST_READ << QSPI_IPCR_SEQID_SHIFT) | + (seqid << QSPI_IPCR_SEQID_SHIFT) | size); while (qspi_read32(priv->flags, ®s->sr) & QSPI_SR_BUSY_MASK) ; @@ -548,7 +588,10 @@ static void qspi_op_read(struct fsl_qspi_priv *priv, u32 *rxbuf, u32 len) while ((RX_BUFFER_SIZE >= size) && (size > 0)) { data = qspi_read32(priv->flags, ®s->rbdr[i]); data = qspi_endian_xchg(data); - memcpy(rxbuf, &data, 4); + if (size < 4) + memcpy(rxbuf, &data, size); + else + memcpy(rxbuf, &data, 4); rxbuf++; size -= 4; i++; @@ -560,7 +603,6 @@ static void qspi_op_read(struct fsl_qspi_priv *priv, u32 *rxbuf, u32 len) qspi_write32(priv->flags, ®s->mcr, mcr_reg); } -#endif static void qspi_op_write(struct fsl_qspi_priv *priv, u8 *txbuf, u32 len) { @@ -601,6 +643,8 @@ static void qspi_op_write(struct fsl_qspi_priv *priv, u8 *txbuf, u32 len) /* Default is page programming */ seqid = SEQID_PP; + if (priv->cur_seqid == QSPI_CMD_WRAR) + seqid = SEQID_WRAR; #ifdef CONFIG_SPI_FLASH_BAR if (priv->cur_seqid == QSPI_CMD_BRWR) seqid = SEQID_BRWR; @@ -639,7 +683,7 @@ static void qspi_op_write(struct fsl_qspi_priv *priv, u8 *txbuf, u32 len) qspi_write32(priv->flags, ®s->mcr, mcr_reg); } -static void qspi_op_rdsr(struct fsl_qspi_priv *priv, u32 *rxbuf) +static void qspi_op_rdsr(struct fsl_qspi_priv *priv, void *rxbuf, u32 len) { struct fsl_qspi_regs *regs = priv->regs; u32 mcr_reg, reg, data; @@ -662,7 +706,7 @@ static void qspi_op_rdsr(struct fsl_qspi_priv *priv, u32 *rxbuf) if (reg & QSPI_RBSR_RDBFL_MASK) { data = qspi_read32(priv->flags, ®s->rbdr[0]); data = qspi_endian_xchg(data); - memcpy(rxbuf, &data, 4); + memcpy(rxbuf, &data, len); qspi_write32(priv->flags, ®s->mcr, qspi_read32(priv->flags, ®s->mcr) | QSPI_MCR_CLR_RXF_MASK); @@ -725,13 +769,15 @@ int qspi_xfer(struct fsl_qspi_priv *priv, unsigned int bitlen, return 0; } - if (priv->cur_seqid == QSPI_CMD_FAST_READ) { + if (priv->cur_seqid == QSPI_CMD_FAST_READ || + priv->cur_seqid == QSPI_CMD_RDAR) { priv->sf_addr = swab32(txbuf) & OFFSET_BITS_MASK; } else if ((priv->cur_seqid == QSPI_CMD_SE) || (priv->cur_seqid == QSPI_CMD_BE_4K)) { priv->sf_addr = swab32(txbuf) & OFFSET_BITS_MASK; qspi_op_erase(priv); - } else if (priv->cur_seqid == QSPI_CMD_PP) { + } else if (priv->cur_seqid == QSPI_CMD_PP || + priv->cur_seqid == QSPI_CMD_WRAR) { wr_sfaddr = swab32(txbuf) & OFFSET_BITS_MASK; } else if ((priv->cur_seqid == QSPI_CMD_BRWR) || (priv->cur_seqid == QSPI_CMD_WREAR)) { @@ -748,10 +794,12 @@ int qspi_xfer(struct fsl_qspi_priv *priv, unsigned int bitlen, #else qspi_op_read(priv, din, bytes); #endif + } else if (priv->cur_seqid == QSPI_CMD_RDAR) { + qspi_op_read(priv, din, bytes); } else if (priv->cur_seqid == QSPI_CMD_RDID) qspi_op_rdid(priv, din, bytes); else if (priv->cur_seqid == QSPI_CMD_RDSR) - qspi_op_rdsr(priv, din); + qspi_op_rdsr(priv, din, bytes); #ifdef CONFIG_SPI_FLASH_BAR else if ((priv->cur_seqid == QSPI_CMD_BRRD) || (priv->cur_seqid == QSPI_CMD_RDEAR)) { @@ -817,6 +865,7 @@ static inline struct fsl_qspi *to_qspi_spi(struct spi_slave *slave) struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, unsigned int max_hz, unsigned int mode) { + u32 mcr_val; struct fsl_qspi *qspi; struct fsl_qspi_regs *regs; u32 total_size; @@ -848,8 +897,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, qspi->slave.max_write_size = TX_BUFFER_SIZE; + mcr_val = qspi_read32(qspi->priv.flags, ®s->mcr); qspi_write32(qspi->priv.flags, ®s->mcr, - QSPI_MCR_RESERVED_MASK | QSPI_MCR_MDIS_MASK); + QSPI_MCR_RESERVED_MASK | QSPI_MCR_MDIS_MASK | + (mcr_val & QSPI_MCR_END_CFD_MASK)); qspi_cfg_smpr(&qspi->priv, ~(QSPI_SMPR_FSDLY_MASK | QSPI_SMPR_DDRSMP_MASK | @@ -927,31 +978,55 @@ static int fsl_qspi_child_pre_probe(struct udevice *dev) static int fsl_qspi_probe(struct udevice *bus) { - u32 total_size; + u32 mcr_val; + u32 amba_size_per_chip; struct fsl_qspi_platdata *plat = dev_get_platdata(bus); struct fsl_qspi_priv *priv = dev_get_priv(bus); struct dm_spi_bus *dm_spi_bus; + int i; dm_spi_bus = bus->uclass_priv; dm_spi_bus->max_hz = plat->speed_hz; - priv->regs = (struct fsl_qspi_regs *)plat->reg_base; + priv->regs = (struct fsl_qspi_regs *)(uintptr_t)plat->reg_base; priv->flags = plat->flags; priv->speed_hz = plat->speed_hz; - priv->amba_base[0] = plat->amba_base; - priv->amba_total_size = plat->amba_total_size; + /* + * QSPI SFADR width is 32bits, the max dest addr is 4GB-1. + * AMBA memory zone should be located on the 0~4GB space + * even on a 64bits cpu. + */ + priv->amba_base[0] = (u32)plat->amba_base; + priv->amba_total_size = (u32)plat->amba_total_size; priv->flash_num = plat->flash_num; priv->num_chipselect = plat->num_chipselect; + mcr_val = qspi_read32(priv->flags, &priv->regs->mcr); qspi_write32(priv->flags, &priv->regs->mcr, - QSPI_MCR_RESERVED_MASK | QSPI_MCR_MDIS_MASK); + QSPI_MCR_RESERVED_MASK | QSPI_MCR_MDIS_MASK | + (mcr_val & QSPI_MCR_END_CFD_MASK)); qspi_cfg_smpr(priv, ~(QSPI_SMPR_FSDLY_MASK | QSPI_SMPR_DDRSMP_MASK | QSPI_SMPR_FSPHS_MASK | QSPI_SMPR_HSENA_MASK), 0); - total_size = FSL_QSPI_FLASH_SIZE * FSL_QSPI_FLASH_NUM; + /* + * Assign AMBA memory zone for every chipselect + * QuadSPI has two channels, every channel has two chipselects. + * If the property 'num-cs' in dts is 2, the AMBA memory will be divided + * into two parts and assign to every channel. This indicate that every + * channel only has one valid chipselect. + * If the property 'num-cs' in dts is 4, the AMBA memory will be divided + * into four parts and assign to every chipselect. + * Every channel will has two valid chipselects. + */ + amba_size_per_chip = priv->amba_total_size >> + (priv->num_chipselect >> 1); + for (i = 1 ; i < priv->num_chipselect ; i++) + priv->amba_base[i] = + amba_size_per_chip + priv->amba_base[i - 1]; + /* * Any read access to non-implemented addresses will provide * undefined results. @@ -963,13 +1038,32 @@ static int fsl_qspi_probe(struct udevice *bus) * that the complete memory map is assigned to only one flash device. */ qspi_write32(priv->flags, &priv->regs->sfa1ad, - FSL_QSPI_FLASH_SIZE | priv->amba_base[0]); - qspi_write32(priv->flags, &priv->regs->sfa2ad, - FSL_QSPI_FLASH_SIZE | priv->amba_base[0]); - qspi_write32(priv->flags, &priv->regs->sfb1ad, - total_size | priv->amba_base[0]); - qspi_write32(priv->flags, &priv->regs->sfb2ad, - total_size | priv->amba_base[0]); + priv->amba_base[0] + amba_size_per_chip); + switch (priv->num_chipselect) { + case 1: + break; + case 2: + qspi_write32(priv->flags, &priv->regs->sfa2ad, + priv->amba_base[1]); + qspi_write32(priv->flags, &priv->regs->sfb1ad, + priv->amba_base[1] + amba_size_per_chip); + qspi_write32(priv->flags, &priv->regs->sfb2ad, + priv->amba_base[1] + amba_size_per_chip); + break; + case 4: + qspi_write32(priv->flags, &priv->regs->sfa2ad, + priv->amba_base[2]); + qspi_write32(priv->flags, &priv->regs->sfb1ad, + priv->amba_base[3]); + qspi_write32(priv->flags, &priv->regs->sfb2ad, + priv->amba_base[3] + amba_size_per_chip); + break; + default: + debug("Error: Unsupported chipselect number %u!\n", + priv->num_chipselect); + qspi_module_disable(priv, 1); + return -EINVAL; + } qspi_set_lut(priv); @@ -984,27 +1078,30 @@ static int fsl_qspi_probe(struct udevice *bus) static int fsl_qspi_ofdata_to_platdata(struct udevice *bus) { - struct reg_data { - u32 addr; - u32 size; - } regs_data[2]; + struct fdt_resource res_regs, res_mem; struct fsl_qspi_platdata *plat = bus->platdata; const void *blob = gd->fdt_blob; - int node = bus->of_offset; + int node = dev_of_offset(bus); int ret, flash_num = 0, subnode; if (fdtdec_get_bool(blob, node, "big-endian")) plat->flags |= QSPI_FLAG_REGMAP_ENDIAN_BIG; - ret = fdtdec_get_int_array(blob, node, "reg", (u32 *)regs_data, - sizeof(regs_data)/sizeof(u32)); + ret = fdt_get_named_resource(blob, node, "reg", "reg-names", + "QuadSPI", &res_regs); + if (ret) { + debug("Error: can't get regs base addresses(ret = %d)!\n", ret); + return -ENOMEM; + } + ret = fdt_get_named_resource(blob, node, "reg", "reg-names", + "QuadSPI-memory", &res_mem); if (ret) { - debug("Error: can't get base addresses (ret = %d)!\n", ret); + debug("Error: can't get AMBA base addresses(ret = %d)!\n", ret); return -ENOMEM; } /* Count flash numbers */ - fdt_for_each_subnode(blob, subnode, node) + fdt_for_each_subnode(subnode, blob, node) ++flash_num; if (flash_num == 0) { @@ -1017,16 +1114,16 @@ static int fsl_qspi_ofdata_to_platdata(struct udevice *bus) plat->num_chipselect = fdtdec_get_int(blob, node, "num-cs", FSL_QSPI_MAX_CHIPSELECT_NUM); - plat->reg_base = regs_data[0].addr; - plat->amba_base = regs_data[1].addr; - plat->amba_total_size = regs_data[1].size; + plat->reg_base = res_regs.start; + plat->amba_base = res_mem.start; + plat->amba_total_size = res_mem.end - res_mem.start + 1; plat->flash_num = flash_num; - debug("%s: regs=<0x%x> <0x%x, 0x%x>, max-frequency=%d, endianess=%s\n", + debug("%s: regs=<0x%llx> <0x%llx, 0x%llx>, max-frequency=%d, endianess=%s\n", __func__, - plat->reg_base, - plat->amba_base, - plat->amba_total_size, + (u64)plat->reg_base, + (u64)plat->amba_base, + (u64)plat->amba_total_size, plat->speed_hz, plat->flags & QSPI_FLAG_REGMAP_ENDIAN_BIG ? "be" : "le" ); @@ -1055,8 +1152,7 @@ static int fsl_qspi_claim_bus(struct udevice *dev) bus = dev->parent; priv = dev_get_priv(bus); - priv->cur_amba_base = - priv->amba_base[0] + FSL_QSPI_FLASH_SIZE * slave_plat->cs; + priv->cur_amba_base = priv->amba_base[slave_plat->cs]; qspi_module_disable(priv, 0);