[U-Boot] [PATCH v2 0/9] qspi: Add Quad and Dual mode support for Zynq QSPI

This series enables the Quad and dual modes support for zynq. It also contains fixes for issues found during testing of dual parallel and stacked modes.
Siva Durga Prasad Paladugu (9): spi: zynq_qspi: Add quad support for zynq qspi spi: zynq_qspi: Add support of Dual parallel and Dual stacked modes sf: Kconfig: Add SF_DUAL_FLASH config entry dts: zynq_zc706: update qspi node with is-dual and num-cs defconfig: zc706: Add dual modes support for zc706 spi: spi_flash: Correct flash size calculation spi: spi_flash: Correct bank select incase of dual stacked spi: spi_flash: Fix Bank selection calculation for Dual parallel spi: spi_flash: Set Quad enable bit of upper flash
arch/arm/dts/zynq-zc706.dts | 2 ++ configs/zynq_zc706_defconfig | 1 + drivers/mtd/spi/Kconfig | 8 ++++++ drivers/mtd/spi/spi_flash.c | 54 +++++++++++++++++++++++++++++++-------- drivers/spi/zynq_qspi.c | 61 ++++++++++++++++++++++++++++++++++++++++++++ include/spi_flash.h | 1 + 6 files changed, 117 insertions(+), 10 deletions(-)

Add quad commands supports for zynq qspi driver
Signed-off-by: Siva Durga Prasad Paladugu sivadur@xilinx.com --- drivers/spi/zynq_qspi.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
diff --git a/drivers/spi/zynq_qspi.c b/drivers/spi/zynq_qspi.c index b98663c..e636244 100644 --- a/drivers/spi/zynq_qspi.c +++ b/drivers/spi/zynq_qspi.c @@ -11,7 +11,9 @@ #include <dm.h> #include <malloc.h> #include <spi.h> +#include <spi_flash.h> #include <asm/io.h> +#include "../mtd/spi/sf_internal.h"
DECLARE_GLOBAL_DATA_PTR;
@@ -156,6 +158,17 @@ static void zynq_qspi_init_hw(struct zynq_qspi_priv *priv) writel(ZYNQ_QSPI_ENR_SPI_EN_MASK, ®s->enr); }
+static int zynq_qspi_child_pre_probe(struct udevice *bus) +{ + struct spi_slave *slave = dev_get_parent_priv(bus); + + slave->mode_rx = QUAD_OUTPUT_FAST; + slave->mode = SPI_TX_QUAD; + slave->no_all_quad = 1; + + return 0; +} + static int zynq_qspi_probe(struct udevice *bus) { struct zynq_qspi_platdata *plat = dev_get_platdata(bus); @@ -627,4 +640,5 @@ U_BOOT_DRIVER(zynq_qspi) = { .platdata_auto_alloc_size = sizeof(struct zynq_qspi_platdata), .priv_auto_alloc_size = sizeof(struct zynq_qspi_priv), .probe = zynq_qspi_probe, + .child_pre_probe = zynq_qspi_child_pre_probe, };

Add Dual parallel and dual stacked supports for zynq qspi driver. The is-dual property defines the dual parallel mode and num-cs, numbere of chip selects defines dual stacked mode if its value is 2
Signed-off-by: Siva Durga Prasad Paladugu sivadur@xilinx.com --- drivers/spi/zynq_qspi.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+)
diff --git a/drivers/spi/zynq_qspi.c b/drivers/spi/zynq_qspi.c index e636244..44057ba 100644 --- a/drivers/spi/zynq_qspi.c +++ b/drivers/spi/zynq_qspi.c @@ -52,6 +52,10 @@ DECLARE_GLOBAL_DATA_PTR; #define CONFIG_SYS_ZYNQ_QSPI_WAIT CONFIG_SYS_HZ/100 /* 10 ms */ #endif
+#define ZYNQ_QSPI_LCR_TWO_MEM_MASK BIT(30) /* QSPI Enable Bit Mask */ +#define ZYNQ_QSPI_LCR_SEP_BUS_MASK BIT(29) /* QSPI Enable Bit Mask */ +#define ZYNQ_QSPI_LCR_U_PAGE BIT(28) /* QSPI Upper memory set */ + /* zynq qspi register set */ struct zynq_qspi_regs { u32 cr; /* 0x00 */ @@ -96,6 +100,8 @@ struct zynq_qspi_priv { int bytes_to_transfer; int bytes_to_receive; unsigned int is_inst; + unsigned int is_dual; + unsigned int u_page; unsigned cs_change:1; };
@@ -154,6 +160,14 @@ static void zynq_qspi_init_hw(struct zynq_qspi_priv *priv) confr &= ~ZYNQ_QSPI_LQSPICFG_LQMODE_MASK; writel(confr, ®s->lqspicfg);
+ if (priv->is_dual == SF_DUAL_PARALLEL_FLASH) + writel(ZYNQ_QSPI_LCR_TWO_MEM_MASK | + ZYNQ_QSPI_LCR_SEP_BUS_MASK, + ®s->lqspicfg); + else if (priv->is_dual == SF_DUAL_STACKED_FLASH) + writel(ZYNQ_QSPI_LCR_TWO_MEM_MASK, + ®s->lqspicfg); + /* Enable SPI */ writel(ZYNQ_QSPI_ENR_SPI_EN_MASK, ®s->enr); } @@ -161,7 +175,9 @@ static void zynq_qspi_init_hw(struct zynq_qspi_priv *priv) static int zynq_qspi_child_pre_probe(struct udevice *bus) { struct spi_slave *slave = dev_get_parent_priv(bus); + struct zynq_qspi_priv *priv = dev_get_priv(bus->parent);
+ slave->option = priv->is_dual; slave->mode_rx = QUAD_OUTPUT_FAST; slave->mode = SPI_TX_QUAD; slave->no_all_quad = 1; @@ -173,10 +189,23 @@ static int zynq_qspi_probe(struct udevice *bus) { struct zynq_qspi_platdata *plat = dev_get_platdata(bus); struct zynq_qspi_priv *priv = dev_get_priv(bus); + const void *blob = gd->fdt_blob; + int node = bus->of_offset; + u8 is_dual = 0; + u8 num_cs = 0;
priv->regs = plat->regs; priv->fifo_depth = ZYNQ_QSPI_FIFO_DEPTH;
+ is_dual = fdtdec_get_int(blob, node, "is-dual", 0); + if (is_dual) { + priv->is_dual = SF_DUAL_PARALLEL_FLASH; + } else { + num_cs = fdtdec_get_int(blob, node, "num-cs", 1); + if (num_cs == 2) + priv->is_dual = SF_DUAL_STACKED_FLASH; + } + /* init the zynq spi hw */ zynq_qspi_init_hw(priv);
@@ -437,6 +466,7 @@ static int zynq_qspi_irq_poll(struct zynq_qspi_priv *priv) */ static int zynq_qspi_start_transfer(struct zynq_qspi_priv *priv) { + static u8 current_u_page; u32 data = 0; struct zynq_qspi_regs *regs = priv->regs;
@@ -446,6 +476,18 @@ static int zynq_qspi_start_transfer(struct zynq_qspi_priv *priv) priv->bytes_to_transfer = priv->len; priv->bytes_to_receive = priv->len;
+ if (priv->is_inst && (priv->is_dual == SF_DUAL_STACKED_FLASH) && + (current_u_page != priv->u_page)) { + if (priv->u_page) + writel(ZYNQ_QSPI_LCR_TWO_MEM_MASK | + ZYNQ_QSPI_LCR_U_PAGE, + ®s->lqspicfg); + else + writel(ZYNQ_QSPI_LCR_TWO_MEM_MASK, + ®s->lqspicfg); + current_u_page = priv->u_page; + } + if (priv->len < 4) zynq_qspi_fill_tx_fifo(priv, priv->len); else @@ -555,6 +597,11 @@ static int zynq_qspi_xfer(struct udevice *dev, unsigned int bitlen, else priv->cs_change = 0;
+ if (flags & SPI_XFER_U_PAGE) + priv->u_page = 1; + else + priv->u_page = 0; + zynq_qspi_transfer(priv);
return 0;

Add SF_DUAL_FLASH config entry with help description This is needed to support dual parallel and stacked modes.
Signed-off-by: Siva Durga Prasad Paladugu sivadur@xilinx.com --- drivers/mtd/spi/Kconfig | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig index 1f23c8e..be5fb78 100644 --- a/drivers/mtd/spi/Kconfig +++ b/drivers/mtd/spi/Kconfig @@ -128,6 +128,14 @@ config SPI_FLASH_MTD
If unsure, say N
+config SF_DUAL_FLASH + bool "SPI Flash Dual support" + depends on SPI_FLASH + help + Enables the dual modes support for spi flash layer, this is required + to handle dual parallel and stacked modes during sf read, write and + erase ops. + if SPL
config SPL_SPI_SUNXI

Update qspi node with properties is-dual and num-cs QSPI flash devices on zc706 connected in dual paralle mode hence is-dual is 1 and num-cs is 1. The property is-dual expalins the dual parallel connection mode The property num-cs defines number of chip selects whose value is 1 incase of dual parllel connection
Signed-off-by: Siva Durga Prasad Paladugu sivadur@xilinx.com --- arch/arm/dts/zynq-zc706.dts | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/arch/arm/dts/zynq-zc706.dts b/arch/arm/dts/zynq-zc706.dts index d04880a..ee58128 100644 --- a/arch/arm/dts/zynq-zc706.dts +++ b/arch/arm/dts/zynq-zc706.dts @@ -309,6 +309,8 @@ &qspi { u-boot,dm-pre-reloc; status = "okay"; + is-dual = <1>; + num-cs = <1>; };
&sdhci0 {

Add QSPI dual mode support for zc706 by enabling the config option SF_DUAL_FLASH
Signed-off-by: Siva Durga Prasad Paladugu sivadur@xilinx.com --- configs/zynq_zc706_defconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/configs/zynq_zc706_defconfig b/configs/zynq_zc706_defconfig index 8b24d90..e65d5c5 100644 --- a/configs/zynq_zc706_defconfig +++ b/configs/zynq_zc706_defconfig @@ -34,6 +34,7 @@ CONFIG_SPL_DM_SEQ_ALIAS=y CONFIG_ZYNQ_SDHCI=y CONFIG_SPI_FLASH=y CONFIG_SPI_FLASH_BAR=y +CONFIG_SF_DUAL_FLASH=y CONFIG_SPI_FLASH_SPANSION=y CONFIG_SPI_FLASH_STMICRO=y CONFIG_SPI_FLASH_WINBOND=y

Dont need to double the size while calculating the flash size as the sector size calculation already takes care of doubling the size incase of dual modes
Signed-off-by: Siva Durga Prasad Paladugu sivadur@xilinx.com --- drivers/mtd/spi/spi_flash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index 1be3e56..ef9b877 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -1167,7 +1167,7 @@ int spi_flash_scan(struct spi_flash *flash) } flash->page_size <<= flash->shift; flash->sector_size = params->sector_size << flash->shift; - flash->size = flash->sector_size * params->nr_sectors << flash->shift; + flash->size = flash->sector_size * params->nr_sectors; #ifdef CONFIG_SF_DUAL_FLASH if (flash->dual_flash & SF_DUAL_STACKED_FLASH) flash->size <<= 1;

Correct the bank selection issue incase of Dual stacked mode. This fix corrects the wrong bank selection if banks are accessed as below. 1. Access the bank2 in upper flash. 2. Access the bank1 in lower flash. 3. Now access the bank1 in upper flash. But here in the step3, the present code was accessing the bank2 in upper flash not bank1. This was because the code thinks the bank1 was already selected as part of step2 but it was not taking care of upper or lower flash.
Signed-off-by: Siva Durga Prasad Paladugu sivadur@xilinx.com --- drivers/mtd/spi/spi_flash.c | 20 +++++++++++++++++--- include/spi_flash.h | 1 + 2 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index ef9b877..404533b 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -146,12 +146,26 @@ static int write_evcr(struct spi_flash *flash, u8 evcr) #ifdef CONFIG_SPI_FLASH_BAR static int spi_flash_write_bar(struct spi_flash *flash, u32 offset) { - u8 cmd, bank_sel; + u8 cmd, bank_sel, upage_curr; int ret;
bank_sel = offset / (SPI_FLASH_16MB_BOUN << flash->shift); - if (bank_sel == flash->bank_curr) - goto bar_end; + + upage_curr = flash->spi->flags & SPI_XFER_U_PAGE; + + if (flash->dual_flash != SF_DUAL_STACKED_FLASH) { + if (flash->bank_curr == bank_sel) { + debug("SF: not require to enable bank%d\n", bank_sel); + goto bar_end; + } + } else if (flash->upage_prev == upage_curr) { + if (flash->bank_curr == bank_sel) { + debug("SF: not require to enable bank%d\n", bank_sel); + goto bar_end; + } + } else { + flash->upage_prev = upage_curr; + }
cmd = flash->bank_write_cmd; ret = spi_flash_write_common(flash, &cmd, 1, &bank_sel, 1); diff --git a/include/spi_flash.h b/include/spi_flash.h index d0ce9e7..83052e0 100644 --- a/include/spi_flash.h +++ b/include/spi_flash.h @@ -78,6 +78,7 @@ struct spi_flash { u8 bank_read_cmd; u8 bank_write_cmd; u8 bank_curr; + u8 upage_prev; #endif u8 erase_cmd; u8 read_cmd;

In Dual parallel connection the bank selection calculation should be performed using offset and not the calculated address
Signed-off-by: Siva Durga Prasad Paladugu sivadur@xilinx.com --- drivers/mtd/spi/spi_flash.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-)
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index 404533b..293b47b 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -340,7 +340,7 @@ int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd,
int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len) { - u32 erase_size, erase_addr; + u32 erase_size, erase_addr, bank_addr; u8 cmd[SPI_FLASH_CMD_LEN]; int ret = -1;
@@ -361,13 +361,16 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len) cmd[0] = flash->erase_cmd; while (len) { erase_addr = offset; + bank_addr = offset;
#ifdef CONFIG_SF_DUAL_FLASH if (flash->dual_flash > SF_SINGLE_FLASH) spi_flash_dual(flash, &erase_addr); + if (flash->dual_flash == SF_DUAL_STACKED_FLASH) + bank_addr = erase_addr; #endif #ifdef CONFIG_SPI_FLASH_BAR - ret = spi_flash_write_bar(flash, erase_addr); + ret = spi_flash_write_bar(flash, bank_addr); if (ret < 0) return ret; #endif @@ -394,7 +397,7 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, { struct spi_slave *spi = flash->spi; unsigned long byte_addr, page_size; - u32 write_addr; + u32 write_addr, bank_addr; size_t chunk_len, actual; u8 cmd[SPI_FLASH_CMD_LEN]; int ret = -1; @@ -412,13 +415,16 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, cmd[0] = flash->write_cmd; for (actual = 0; actual < len; actual += chunk_len) { write_addr = offset; + bank_addr = offset;
#ifdef CONFIG_SF_DUAL_FLASH if (flash->dual_flash > SF_SINGLE_FLASH) spi_flash_dual(flash, &write_addr); + if (flash->dual_flash == SF_DUAL_STACKED_FLASH) + bank_addr = write_addr; #endif #ifdef CONFIG_SPI_FLASH_BAR - ret = spi_flash_write_bar(flash, write_addr); + ret = spi_flash_write_bar(flash, bank_addr); if (ret < 0) return ret; #endif @@ -488,7 +494,7 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, { struct spi_slave *spi = flash->spi; u8 *cmd, cmdsz; - u32 remain_len, read_len, read_addr; + u32 remain_len, read_len, read_addr, bank_addr; int bank_sel = 0; int ret = -1;
@@ -516,13 +522,16 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, cmd[0] = flash->read_cmd; while (len) { read_addr = offset; + bank_addr = offset;
#ifdef CONFIG_SF_DUAL_FLASH if (flash->dual_flash > SF_SINGLE_FLASH) spi_flash_dual(flash, &read_addr); + if (flash->dual_flash == SF_DUAL_STACKED_FLASH) + bank_addr = read_addr; #endif #ifdef CONFIG_SPI_FLASH_BAR - ret = spi_flash_write_bar(flash, read_addr); + ret = spi_flash_write_bar(flash, bank_addr); if (ret < 0) return ret; bank_sel = flash->bank_curr;

Set quad enable for upper flash incase of Dual stacked mode.
Signed-off-by: Siva Durga Prasad Paladugu sivadur@xilinx.com --- drivers/mtd/spi/spi_flash.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index 293b47b..5a152db 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -1237,6 +1237,17 @@ int spi_flash_scan(struct spi_flash *flash) debug("SF: Fail to set QEB for %02x\n", idcode[0]); return -EINVAL; } +#ifdef CONFIG_SF_DUAL_FLASH + if (flash->dual_flash & SF_DUAL_STACKED_FLASH) { + flash->spi->flags |= SPI_XFER_U_PAGE; + if (set_quad_mode(flash, idcode[0])) { + debug("SF: Fail to set QEB Upper Flash %02x\n", + idcode[0]); + return 0; + } + flash->spi->flags &= ~SPI_XFER_U_PAGE; + } +#endif }
/* Read dummy_byte: dummy byte is determined based on the

On 19 July 2016 at 21:18, Siva Durga Prasad Paladugu siva.durga.paladugu@xilinx.com wrote:
This series enables the Quad and dual modes support for zynq. It also contains fixes for issues found during testing of dual parallel and stacked modes.
Siva Durga Prasad Paladugu (9): spi: zynq_qspi: Add quad support for zynq qspi spi: zynq_qspi: Add support of Dual parallel and Dual stacked modes sf: Kconfig: Add SF_DUAL_FLASH config entry dts: zynq_zc706: update qspi node with is-dual and num-cs defconfig: zc706: Add dual modes support for zc706 spi: spi_flash: Correct flash size calculation spi: spi_flash: Correct bank select incase of dual stacked spi: spi_flash: Fix Bank selection calculation for Dual parallel spi: spi_flash: Set Quad enable bit of upper flash
All these patches were talking to spi about flash attributes which wrong, I thought you might have know all these. spi-nor framework is dealing all these pitfalls, if possible please do work on that.
thanks!

Hi Jagan,
-----Original Message----- From: Jagan Teki [mailto:jagannadh.teki@gmail.com] Sent: Wednesday, July 27, 2016 1:47 PM To: Siva Durga Prasad Paladugu sivadur@xilinx.com Cc: u-boot@lists.denx.de; Michal Simek michals@xilinx.com; Siva Durga Prasad Paladugu sivadur@xilinx.com Subject: Re: [PATCH v2 0/9] qspi: Add Quad and Dual mode support for Zynq QSPI
On 19 July 2016 at 21:18, Siva Durga Prasad Paladugu siva.durga.paladugu@xilinx.com wrote:
This series enables the Quad and dual modes support for zynq. It also contains fixes for issues found during testing of dual parallel and stacked modes.
Siva Durga Prasad Paladugu (9): spi: zynq_qspi: Add quad support for zynq qspi spi: zynq_qspi: Add support of Dual parallel and Dual stacked modes sf: Kconfig: Add SF_DUAL_FLASH config entry dts: zynq_zc706: update qspi node with is-dual and num-cs defconfig: zc706: Add dual modes support for zc706 spi: spi_flash: Correct flash size calculation spi: spi_flash: Correct bank select incase of dual stacked spi: spi_flash: Fix Bank selection calculation for Dual parallel spi: spi_flash: Set Quad enable bit of upper flash
All these patches were talking to spi about flash attributes which wrong, I thought you might have know all these. spi-nor framework is dealing all these pitfalls, if possible please do work on that.
I didn’t find any spi-nor framework in mainline when I sent these patches that’s why these are like this. How could I send without aware of spi-nor framework.
Regards, Siva
thanks!
Jagan.

On 27 July 2016 at 14:28, Siva Durga Prasad Paladugu siva.durga.paladugu@xilinx.com wrote:
Hi Jagan,
-----Original Message----- From: Jagan Teki [mailto:jagannadh.teki@gmail.com] Sent: Wednesday, July 27, 2016 1:47 PM To: Siva Durga Prasad Paladugu sivadur@xilinx.com Cc: u-boot@lists.denx.de; Michal Simek michals@xilinx.com; Siva Durga Prasad Paladugu sivadur@xilinx.com Subject: Re: [PATCH v2 0/9] qspi: Add Quad and Dual mode support for Zynq QSPI
On 19 July 2016 at 21:18, Siva Durga Prasad Paladugu siva.durga.paladugu@xilinx.com wrote:
This series enables the Quad and dual modes support for zynq. It also contains fixes for issues found during testing of dual parallel and stacked modes.
Siva Durga Prasad Paladugu (9): spi: zynq_qspi: Add quad support for zynq qspi spi: zynq_qspi: Add support of Dual parallel and Dual stacked modes sf: Kconfig: Add SF_DUAL_FLASH config entry dts: zynq_zc706: update qspi node with is-dual and num-cs defconfig: zc706: Add dual modes support for zc706 spi: spi_flash: Correct flash size calculation spi: spi_flash: Correct bank select incase of dual stacked spi: spi_flash: Fix Bank selection calculation for Dual parallel spi: spi_flash: Set Quad enable bit of upper flash
All these patches were talking to spi about flash attributes which wrong, I thought you might have know all these. spi-nor framework is dealing all these pitfalls, if possible please do work on that.
I didn’t find any spi-nor framework in mainline when I sent these patches that’s why these are like this. How could I send without aware of spi-nor framework.
I'm just pointing an alternate approach, and either way please tune your approach better the one you added look not good to me.
participants (2)
-
Jagan Teki
-
Siva Durga Prasad Paladugu