
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;