From b0c383a6877ffe969536a80f9bcf3f2ad41e2533 Mon Sep 17 00:00:00 2001 From: Siva Durga Prasad Paladugu Date: Thu, 6 Aug 2015 19:29:25 +0530 Subject: [PATCH] spi: zynqmp_qspi: Changes to support QSPI driver model Changes to support QSPI driver model for zynqMP and enable QSPI again. Signed-off-by: Siva Durga Prasad Paladugu Signed-off-by: Michal Simek --- configs/xilinx_zynqmp_ep_defconfig | 1 + configs/xilinx_zynqmp_mini_qspi_defconfig | 1 + drivers/spi/zynqmp_qspi.c | 558 +++++++++++----------- 3 files changed, 290 insertions(+), 270 deletions(-) diff --git a/configs/xilinx_zynqmp_ep_defconfig b/configs/xilinx_zynqmp_ep_defconfig index 7205d58ff8a..ea7d6356249 100644 --- a/configs/xilinx_zynqmp_ep_defconfig +++ b/configs/xilinx_zynqmp_ep_defconfig @@ -1,5 +1,6 @@ CONFIG_ARM=y CONFIG_ARCH_ZYNQMP=y +CONFIG_ZYNQMP_QSPI=y CONFIG_NAND_ARASAN=y CONFIG_ZYNQMP_USB=y CONFIG_SYS_TEXT_BASE=0x8000000 diff --git a/configs/xilinx_zynqmp_mini_qspi_defconfig b/configs/xilinx_zynqmp_mini_qspi_defconfig index 9efefa21152..c2e58c799b9 100644 --- a/configs/xilinx_zynqmp_mini_qspi_defconfig +++ b/configs/xilinx_zynqmp_mini_qspi_defconfig @@ -2,6 +2,7 @@ CONFIG_ARM=y CONFIG_ARCH_ZYNQMP=y CONFIG_TARGET_ZYNQMP_MINI=y CONFIG_SECURE_IOU=y +CONFIG_ZYNQMP_QSPI=y CONFIG_SYS_TEXT_BASE=0xFFFC0000 CONFIG_DEFAULT_DEVICE_TREE="zynqmp-ep108" CONFIG_FIT=y diff --git a/drivers/spi/zynqmp_qspi.c b/drivers/spi/zynqmp_qspi.c index 2fdfdbab14b..842ab666888 100644 --- a/drivers/spi/zynqmp_qspi.c +++ b/drivers/spi/zynqmp_qspi.c @@ -64,6 +64,7 @@ #define ZYNQMP_QSPI_STRT_GEN_FIFO (1 << 28) #define ZYNQMP_QSPI_GEN_FIFO_STRT_MOD (1 << 29) #define ZYNQMP_QSPI_GFIFO_WP_HOLD (1 << 19) +#define ZYNQMP_QSPI_BAUD_DIV_MASK (7 << 3) #define ZYNQMP_QSPI_DFLT_BAUD_RATE_DIV (1 << 3) #define ZYNQMP_QSPI_GFIFO_ALL_INT_MASK 0xFBE #define ZYNQMP_QSPI_DMA_DST_I_STS_DONE (1 << 1) @@ -125,16 +126,21 @@ struct zynqmp_qspi_dma_regs { u32 dmadstmsb; /* 0x28 */ }; -#define zynqmp_qspi_base \ - ((struct zynqmp_qspi_regs *)(ZYNQMP_QSPI_BASEADDR + 0x100)) -#define zynqmp_qspi_dma \ - ((struct zynqmp_qspi_dma_regs *)(ZYNQMP_QSPI_BASEADDR + 0x800)) - -struct zynqmp_qspi { - u32 input_clk_hz; +struct zynqmp_qspi_platdata { + struct zynqmp_qspi_regs *regs; + struct zynqmp_qspi_dma_regs *dma_regs; + u32 frequency; u32 speed_hz; - const void *txbuf; - void *rxbuf; +}; + +struct zynqmp_qspi_priv { + struct zynqmp_qspi_regs *regs; + struct zynqmp_qspi_dma_regs *dma_regs; + u8 mode; + u32 freq; + const void *tx_buf; + void *rx_buf; + unsigned len; int bytes_to_transfer; int bytes_to_receive; unsigned int is_inst; @@ -142,75 +148,69 @@ struct zynqmp_qspi { unsigned int u_page; unsigned int bus; unsigned int stripe; + unsigned cs_change:1; }; -struct spi_device { - struct zynqmp_qspi master; - u32 max_speed_hz; - u8 chip_select; - u8 mode; -}; +static u8 last_cmd; -struct spi_transfer { - const void *tx_buf; - void *rx_buf; - unsigned len; - unsigned cs_change:1; - u16 delay_usecs; - u32 speed_hz; -}; +static int zynqmp_qspi_ofdata_to_platdata(struct udevice *bus) +{ + struct zynqmp_qspi_platdata *plat = bus->platdata; -struct zynqmp_qspi_slave { - struct spi_slave slave; - struct spi_device qspi; -}; -#define to_zynqmp_qspi_slave(s) container_of(s, struct zynqmp_qspi_slave, slave) + debug("%s\n", __func__); + plat->regs = (struct zynqmp_qspi_regs *)(ZYNQMP_QSPI_BASEADDR + 0x100); + plat->dma_regs = (struct zynqmp_qspi_dma_regs *)(ZYNQMP_QSPI_BASEADDR + + 0x800); + plat->frequency = 166666666; + plat->speed_hz = plat->frequency / 2; -static u8 last_cmd; + return 0; +} -static void zynqmp_qspi_init_hw(int is_dual, unsigned int cs) +static void zynqmp_qspi_init_hw(struct zynqmp_qspi_priv *priv) { u32 config_reg; + struct zynqmp_qspi_regs *regs = priv->regs; - writel(ZYNQMP_QSPI_GFIFO_SELECT, &zynqmp_qspi_base->gqspisel); - writel(ZYNQMP_QSPI_GFIFO_ALL_INT_MASK, &zynqmp_qspi_base->idisr); - writel(ZYNQMP_QSPI_FIFO_THRESHOLD, &zynqmp_qspi_base->txftr); - writel(ZYNQMP_QSPI_FIFO_THRESHOLD, &zynqmp_qspi_base->rxftr); - writel(ZYNQMP_QSPI_GFIFO_ALL_INT_MASK, &zynqmp_qspi_base->isr); + writel(ZYNQMP_QSPI_GFIFO_SELECT, ®s->gqspisel); + writel(ZYNQMP_QSPI_GFIFO_ALL_INT_MASK, ®s->idisr); + writel(ZYNQMP_QSPI_FIFO_THRESHOLD, ®s->txftr); + writel(ZYNQMP_QSPI_FIFO_THRESHOLD, ®s->rxftr); + writel(ZYNQMP_QSPI_GFIFO_ALL_INT_MASK, ®s->isr); - config_reg = readl(&zynqmp_qspi_base->confr); + config_reg = readl(®s->confr); config_reg &= ~(ZYNQMP_QSPI_GFIFO_STRT_MODE_MASK | ZYNQMP_QSPI_CONFIG_MODE_EN_MASK); config_reg |= ZYNQMP_QSPI_CONFIG_DMA_MODE | ZYNQMP_QSPI_GFIFO_WP_HOLD | ZYNQMP_QSPI_DFLT_BAUD_RATE_DIV; - writel(config_reg, &zynqmp_qspi_base->confr); + writel(config_reg, ®s->confr); - writel(ZYNQMP_QSPI_ENABLE_ENABLE_MASK, &zynqmp_qspi_base->enbr); + writel(ZYNQMP_QSPI_ENABLE_ENABLE_MASK, ®s->enbr); } -static u32 zynqmp_qspi_bus_select(struct spi_device *qspi) +static u32 zynqmp_qspi_bus_select(struct zynqmp_qspi_priv *priv) { u32 gqspi_fifo_reg = 0; - if (qspi->master.is_dual == SF_DUAL_PARALLEL_FLASH) { - if (qspi->master.bus == SPI_XFER_ON_BOTH) + if (priv->is_dual == SF_DUAL_PARALLEL_FLASH) { + if (priv->bus == SPI_XFER_ON_BOTH) gqspi_fifo_reg = ZYNQMP_QSPI_GFIFO_LOW_BUS | ZYNQMP_QSPI_GFIFO_UP_BUS | ZYNQMP_QSPI_GFIFO_CS_UPPER | ZYNQMP_QSPI_GFIFO_CS_LOWER; - else if (qspi->master.bus == SPI_XFER_ON_LOWER) + else if (priv->bus == SPI_XFER_ON_LOWER) gqspi_fifo_reg = ZYNQMP_QSPI_GFIFO_LOW_BUS | ZYNQMP_QSPI_GFIFO_CS_UPPER | ZYNQMP_QSPI_GFIFO_CS_LOWER; - else if (qspi->master.bus == SPI_XFER_ON_UPPER) + else if (priv->bus == SPI_XFER_ON_UPPER) gqspi_fifo_reg = ZYNQMP_QSPI_GFIFO_UP_BUS | ZYNQMP_QSPI_GFIFO_CS_LOWER | ZYNQMP_QSPI_GFIFO_CS_UPPER; else - printf("Wrong Bus selection:0x%x\n", qspi->master.bus); + debug("Wrong Bus selection:0x%x\n", priv->bus); } else { - if (qspi->master.u_page) + if (priv->u_page) gqspi_fifo_reg = ZYNQMP_QSPI_GFIFO_LOW_BUS | ZYNQMP_QSPI_GFIFO_CS_UPPER; else @@ -220,19 +220,20 @@ static u32 zynqmp_qspi_bus_select(struct spi_device *qspi) return gqspi_fifo_reg; } -static void zynqmp_qspi_chipselect(struct spi_device *qspi, int is_on) +static void zynqmp_qspi_chipselect(struct zynqmp_qspi_priv *priv, int is_on) { u32 gqspi_fifo_reg = 0; + struct zynqmp_qspi_regs *regs = priv->regs; if (is_on) { - gqspi_fifo_reg = zynqmp_qspi_bus_select(qspi); + gqspi_fifo_reg = zynqmp_qspi_bus_select(priv); gqspi_fifo_reg |= ZYNQMP_QSPI_SPI_MODE_SPI | ZYNQMP_QSPI_IMD_DATA_CS_ASSERT; } else { - if (qspi->master.is_dual == SF_DUAL_PARALLEL_FLASH) + if (priv->is_dual == SF_DUAL_PARALLEL_FLASH) gqspi_fifo_reg = ZYNQMP_QSPI_GFIFO_UP_BUS | ZYNQMP_QSPI_GFIFO_LOW_BUS; - else if (qspi->master.u_page) + else if (priv->u_page) gqspi_fifo_reg = ZYNQMP_QSPI_GFIFO_UP_BUS; else gqspi_fifo_reg = ZYNQMP_QSPI_GFIFO_LOW_BUS; @@ -241,46 +242,141 @@ static void zynqmp_qspi_chipselect(struct spi_device *qspi, int is_on) debug("GFIFO_CMD_CS: 0x%x\n", gqspi_fifo_reg); - writel(gqspi_fifo_reg, &zynqmp_qspi_base->genfifo); + writel(gqspi_fifo_reg, ®s->genfifo); } -static int zynqmp_qspi_setup_transfer(struct spi_device *qspi, - struct spi_transfer *transfer) +static int zynqmp_qspi_set_speed(struct udevice *bus, uint speed) { - u32 config_reg; + struct zynqmp_qspi_platdata *plat = bus->platdata; + struct zynqmp_qspi_priv *priv = dev_get_priv(bus); + struct zynqmp_qspi_regs *regs = priv->regs; + uint32_t confr; + u8 baud_rate_val = 0; + + debug("%s\n", __func__); + if (speed > plat->frequency) + speed = plat->frequency; + + /* Set the clock frequency */ + confr = readl(®s->confr); + if (speed == 0) { + /* Set baudrate x8, if the freq is 0 */ + baud_rate_val = 0x2; + } else if (plat->speed_hz != speed) { + while ((baud_rate_val < 8) && + ((plat->frequency / + (2 << baud_rate_val)) > speed)) + baud_rate_val++; + + plat->speed_hz = speed / (2 << baud_rate_val); + } + confr &= ~ZYNQMP_QSPI_BAUD_DIV_MASK; + confr |= (baud_rate_val << 3); + + priv->freq = speed; + + debug("regs=%p, mode=%d\n", priv->regs, priv->freq); + + return 0; +} - if (qspi->mode & ~MODEBITS) { - printf("%s: Unsupported mode bits %x\n", - __func__, qspi->mode & ~MODEBITS); +static int zynqmp_qspi_child_pre_probe(struct udevice *bus) +{ + struct spi_slave *slave = dev_get_parentdata(bus); + struct zynqmp_qspi_priv *priv = dev_get_priv(bus->parent); + + slave->option = priv->is_dual; + slave->op_mode_rx = SPI_OPM_RX_QOF; + slave->op_mode_tx = SPI_OPM_TX_QPP; + + return 0; +} + +static void zynqmp_qspi_check_is_dual_flash(struct zynqmp_qspi_priv *priv) +{ + int is_dual = -1; + int lower_mio = 0, upper_mio = 0, upper_mio_cs1 = 0; + + lower_mio = zynq_slcr_get_mio_pin_status("qspi0"); + if (lower_mio == ZYNQMP_QSPI_MIO_NUM_QSPI0) + priv->is_dual = SF_SINGLE_FLASH; + + upper_mio_cs1 = zynq_slcr_get_mio_pin_status("qspi1_cs"); + if ((lower_mio == ZYNQMP_QSPI_MIO_NUM_QSPI0) && + (upper_mio_cs1 == ZYNQMP_QSPI_MIO_NUM_QSPI1_CS)) + priv->is_dual = SF_DUAL_STACKED_FLASH; + + upper_mio = zynq_slcr_get_mio_pin_status("qspi1"); + if ((lower_mio == ZYNQMP_QSPI_MIO_NUM_QSPI0) && + (upper_mio_cs1 == ZYNQMP_QSPI_MIO_NUM_QSPI1_CS) && + (upper_mio == ZYNQMP_QSPI_MIO_NUM_QSPI1)) + priv->is_dual = SF_DUAL_PARALLEL_FLASH; +} + +static int zynqmp_qspi_probe(struct udevice *bus) +{ + struct zynqmp_qspi_platdata *plat = dev_get_platdata(bus); + struct zynqmp_qspi_priv *priv = dev_get_priv(bus); + + debug("zynqmp_qspi_probe: bus:%p, priv:%p \n", bus, priv); + + priv->regs = plat->regs; + priv->dma_regs = plat->dma_regs; + zynqmp_qspi_check_is_dual_flash(priv); + + if (priv->is_dual == -1) { + debug("%s: No QSPI device detected based on MIO settings\n", + __func__); return -1; } - config_reg = readl(&zynqmp_qspi_base->confr); + /* init the zynq spi hw */ + zynqmp_qspi_init_hw(priv); + + return 0; +} + +static int zynqmp_qspi_set_mode(struct udevice *bus, uint mode) +{ + struct zynqmp_qspi_priv *priv = dev_get_priv(bus); + struct zynqmp_qspi_regs *regs = priv->regs; + uint32_t confr; + + debug("%s\n", __func__); + /* Set the SPI Clock phase and polarities */ + confr = readl(®s->confr); + confr &= ~(ZYNQMP_QSPI_CONFIG_CPHA_MASK | + ZYNQMP_QSPI_CONFIG_CPOL_MASK); + + if (priv->mode & SPI_CPHA) + confr |= ZYNQMP_QSPI_CONFIG_CPHA_MASK; + if (priv->mode & SPI_CPOL) + confr |= ZYNQMP_QSPI_CONFIG_CPOL_MASK; + + //writel(confr, ®s->confr); + priv->mode = mode; - /* Set the QSPI clock phase and clock polarity */ - config_reg &= (~ZYNQMP_QSPI_CONFIG_CPHA_MASK) & - (~ZYNQMP_QSPI_CONFIG_CPOL_MASK); - if (qspi->mode & SPI_CPHA) - config_reg |= ZYNQMP_QSPI_CONFIG_CPHA_MASK; - if (qspi->mode & SPI_CPOL) - config_reg |= ZYNQMP_QSPI_CONFIG_CPOL_MASK; + debug("regs=%p, mode=%d\n", priv->regs, priv->mode); return 0; } -static int zynqmp_qspi_fill_tx_fifo(u32 *buf, u32 size) + +static int zynqmp_qspi_fill_tx_fifo(struct zynqmp_qspi_priv *priv, u32 size) { u32 data; u32 timeout = 10000000; + struct zynqmp_qspi_regs *regs = priv->regs; + u32 *buf = (u32 *)priv->tx_buf; - debug("TxFIFO: 0x%x, size: 0x%x\n", readl(&zynqmp_qspi_base->isr), + debug("TxFIFO: 0x%x, size: 0x%x\n", readl(®s->isr), size); while (size && timeout) { - if (readl(&zynqmp_qspi_base->isr) & + if (readl(®s->isr) & ZYNQMP_QSPI_IXR_TXNFULL_MASK) { if (size >= 4) { - writel(*buf, &zynqmp_qspi_base->txd0r); + writel(*buf, ®s->txd0r); buf++; size -= 4; } else { @@ -303,7 +399,7 @@ static int zynqmp_qspi_fill_tx_fifo(u32 *buf, u32 size) data |= 0xFF000000; break; } - writel(data, &zynqmp_qspi_base->txd0r); + writel(data, ®s->txd0r); size = 0; } } else { @@ -311,80 +407,80 @@ static int zynqmp_qspi_fill_tx_fifo(u32 *buf, u32 size) } } if (!timeout) { - printf("zynqmp_qspi_fill_tx_fifo: Timeout\n"); + debug("zynqmp_qspi_fill_tx_fifo: Timeout\n"); return -1; } return 0; } -static void zynqmp_qspi_genfifo_cmd(struct spi_device *qspi, - struct spi_transfer *transfer) +static void zynqmp_qspi_genfifo_cmd(struct zynqmp_qspi_priv *priv) { u8 command = 1; u32 gen_fifo_cmd; u32 bytecount = 0; + struct zynqmp_qspi_regs *regs = priv->regs; - while (transfer->len) { - gen_fifo_cmd = zynqmp_qspi_bus_select(qspi); + while (priv->len) { + gen_fifo_cmd = zynqmp_qspi_bus_select(priv); gen_fifo_cmd |= ZYNQMP_QSPI_GFIFO_TX; if (command) { command = 0; - last_cmd = *(u8 *)transfer->tx_buf; + last_cmd = *(u8 *)priv->tx_buf; } gen_fifo_cmd |= ZYNQMP_QSPI_SPI_MODE_SPI; - gen_fifo_cmd |= *(u8 *)transfer->tx_buf; + gen_fifo_cmd |= *(u8 *)priv->tx_buf; bytecount++; - transfer->len--; - transfer->tx_buf = (u8 *)transfer->tx_buf + 1; + priv->len--; + priv->tx_buf = (u8 *)priv->tx_buf + 1; debug("GFIFO_CMD_Cmd = 0x%x\n", gen_fifo_cmd); - writel(gen_fifo_cmd, &zynqmp_qspi_base->genfifo); + writel(gen_fifo_cmd, ®s->genfifo); } } -static u32 zynqmp_qspi_calc_exp(struct spi_transfer *transfer, +static u32 zynqmp_qspi_calc_exp(struct zynqmp_qspi_priv *priv, u32 *gen_fifo_cmd) { u32 expval = 8; u32 len; while (1) { - if (transfer->len > 255) { - if (transfer->len & (1 << expval)) { + if (priv->len > 255) { + if (priv->len & (1 << expval)) { *gen_fifo_cmd &= ~ZYNQMP_QSPI_GFIFO_IMD_MASK; *gen_fifo_cmd |= ZYNQMP_QSPI_GFIFO_EXP_MASK; *gen_fifo_cmd |= expval; - transfer->len -= (1 << expval); + priv->len -= (1 << expval); return expval; } expval++; } else { *gen_fifo_cmd &= ~(ZYNQMP_QSPI_GFIFO_IMD_MASK | ZYNQMP_QSPI_GFIFO_EXP_MASK); - *gen_fifo_cmd |= (u8)transfer->len; - len = (u8)transfer->len; - transfer->len = 0; + *gen_fifo_cmd |= (u8)priv->len; + len = (u8)priv->len; + priv->len = 0; return len; } } } -static int zynqmp_qspi_genfifo_fill_tx(struct spi_device *qspi, - struct spi_transfer *transfer) +static int zynqmp_qspi_genfifo_fill_tx(struct zynqmp_qspi_priv *priv) { u32 gen_fifo_cmd; u32 len; int ret = 0; + struct zynqmp_qspi_regs *regs = priv->regs; - gen_fifo_cmd = zynqmp_qspi_bus_select(qspi); + gen_fifo_cmd = zynqmp_qspi_bus_select(priv); gen_fifo_cmd |= ZYNQMP_QSPI_GFIFO_TX | ZYNQMP_QSPI_GFIFO_DATA_XFR_MASK; - if (qspi->master.stripe) + if (priv->stripe) gen_fifo_cmd |= ZYNQMP_QSPI_GFIFO_STRIPE_MASK; if (last_cmd == QUAD_PAGE_PROGRAM_CMD) @@ -392,17 +488,17 @@ static int zynqmp_qspi_genfifo_fill_tx(struct spi_device *qspi, else gen_fifo_cmd |= ZYNQMP_QSPI_SPI_MODE_SPI; - while (transfer->len) { - len = zynqmp_qspi_calc_exp(transfer, &gen_fifo_cmd); - writel(gen_fifo_cmd, &zynqmp_qspi_base->genfifo); + while (priv->len) { + len = zynqmp_qspi_calc_exp(priv, &gen_fifo_cmd); + writel(gen_fifo_cmd, ®s->genfifo); debug("GFIFO_CMD_TX:0x%x\n", gen_fifo_cmd); if (gen_fifo_cmd & ZYNQMP_QSPI_GFIFO_EXP_MASK) - ret = zynqmp_qspi_fill_tx_fifo((u32 *)transfer->tx_buf, + ret = zynqmp_qspi_fill_tx_fifo(priv, 1 << len); else - ret = zynqmp_qspi_fill_tx_fifo((u32 *)transfer->tx_buf, + ret = zynqmp_qspi_fill_tx_fifo(priv, len); if (ret) @@ -411,17 +507,18 @@ static int zynqmp_qspi_genfifo_fill_tx(struct spi_device *qspi, return ret; } -static int zynqmp_qspi_genfifo_fill_rx(struct spi_device *qspi, - struct spi_transfer *transfer) +static int zynqmp_qspi_genfifo_fill_rx(struct zynqmp_qspi_priv *priv) { u32 gen_fifo_cmd; u32 *buf; u32 addr; u32 size, len; u32 timeout = 10000000; - u32 actuallen = transfer->len; + u32 actuallen = priv->len; + struct zynqmp_qspi_regs *regs = priv->regs; + struct zynqmp_qspi_dma_regs *dma_regs = priv->dma_regs; - gen_fifo_cmd = zynqmp_qspi_bus_select(qspi); + gen_fifo_cmd = zynqmp_qspi_bus_select(priv); gen_fifo_cmd |= ZYNQMP_QSPI_GFIFO_RX | ZYNQMP_QSPI_GFIFO_DATA_XFR_MASK; @@ -430,252 +527,151 @@ static int zynqmp_qspi_genfifo_fill_rx(struct spi_device *qspi, else gen_fifo_cmd |= ZYNQMP_QSPI_SPI_MODE_SPI; - if (qspi->master.stripe) + if (priv->stripe) gen_fifo_cmd |= ZYNQMP_QSPI_GFIFO_STRIPE_MASK; - if (!((u32)transfer->rx_buf & 0x3) && !(actuallen % 4)) { - buf = (u32 *)transfer->rx_buf; + if (!((u32)priv->rx_buf & 0x3) && !(actuallen % 4)) { + buf = (u32 *)priv->rx_buf; } else { - ALLOC_CACHE_ALIGN_BUFFER(u8, tmp, roundup(transfer->len, 4)); + ALLOC_CACHE_ALIGN_BUFFER(u8, tmp, roundup(priv->len, 4)); buf = (u32 *)tmp; } - writel((u32)buf, &zynqmp_qspi_dma->dmadst); - writel(roundup(transfer->len, 4), &zynqmp_qspi_dma->dmasize); - writel(ZYNQMP_QSPI_DMA_DST_I_STS_MASK, &zynqmp_qspi_dma->dmaier); + writel((u32)buf, &dma_regs->dmadst); + writel(roundup(priv->len, 4), &dma_regs->dmasize); + writel(ZYNQMP_QSPI_DMA_DST_I_STS_MASK, &dma_regs->dmaier); addr = (u32)buf; - size = roundup(transfer->len, ARCH_DMA_MINALIGN); + size = roundup(priv->len, ARCH_DMA_MINALIGN); flush_dcache_range(addr, addr+size); - while (transfer->len) { - len = zynqmp_qspi_calc_exp(transfer, &gen_fifo_cmd); + while (priv->len) { + len = zynqmp_qspi_calc_exp(priv, &gen_fifo_cmd); if (!(gen_fifo_cmd & ZYNQMP_QSPI_GFIFO_EXP_MASK) && (len % 4)) { gen_fifo_cmd &= ~(0xFF); gen_fifo_cmd |= (len/4 + 1) * 4; } - writel(gen_fifo_cmd, &zynqmp_qspi_base->genfifo); + writel(gen_fifo_cmd, ®s->genfifo); debug("GFIFO_CMD_RX:0x%x\n", gen_fifo_cmd); } while (timeout) { - if (readl(&zynqmp_qspi_dma->dmaisr) & + if (readl(&dma_regs->dmaisr) & ZYNQMP_QSPI_DMA_DST_I_STS_DONE) { writel(ZYNQMP_QSPI_DMA_DST_I_STS_DONE, - &zynqmp_qspi_dma->dmaisr); + &dma_regs->dmaisr); break; } timeout--; } - debug("buf:0x%lx, txbuf:0x%lx, *buf:0x%x len: 0x%x\n", - (unsigned long)buf, (unsigned long)transfer->rx_buf, *buf, + debug("buf:0x%lx, rxbuf:0x%lx, *buf:0x%x len: 0x%x\n", + (unsigned long)buf, (unsigned long)priv->rx_buf, *buf, actuallen); if (!timeout) { - printf("DMA Timeout:0x%x\n", readl(&zynqmp_qspi_dma->dmaisr)); + debug("DMA Timeout:0x%x\n", readl(&dma_regs->dmaisr)); return -1; } - if (buf != transfer->rx_buf) - memcpy(transfer->rx_buf, buf, actuallen); + if (buf != priv->rx_buf) + memcpy(priv->rx_buf, buf, actuallen); return 0; } -static int zynqmp_qspi_start_transfer(struct spi_device *qspi, - struct spi_transfer *transfer) +static int zynqmp_qspi_start_transfer(struct zynqmp_qspi_priv *priv) { int ret = 0; - if (qspi->master.is_inst) { - if (transfer->tx_buf) - zynqmp_qspi_genfifo_cmd(qspi, transfer); + if (priv->is_inst) { + if (priv->tx_buf) + zynqmp_qspi_genfifo_cmd(priv); else ret = -1; } else { - if (transfer->tx_buf) - ret = zynqmp_qspi_genfifo_fill_tx(qspi, transfer); - else if (transfer->rx_buf) - ret = zynqmp_qspi_genfifo_fill_rx(qspi, transfer); + if (priv->tx_buf) + ret = zynqmp_qspi_genfifo_fill_tx(priv); + else if (priv->rx_buf) + ret = zynqmp_qspi_genfifo_fill_rx(priv); else ret = -1; } return ret; } -static int zynqmp_qspi_check_is_dual_flash(void) -{ - int is_dual = -1; - int lower_mio = 0, upper_mio = 0, upper_mio_cs1 = 0; - - lower_mio = zynq_slcr_get_mio_pin_status("qspi0"); - if (lower_mio == ZYNQMP_QSPI_MIO_NUM_QSPI0) - is_dual = SF_SINGLE_FLASH; - - upper_mio_cs1 = zynq_slcr_get_mio_pin_status("qspi1_cs"); - if ((lower_mio == ZYNQMP_QSPI_MIO_NUM_QSPI0) && - (upper_mio_cs1 == ZYNQMP_QSPI_MIO_NUM_QSPI1_CS)) - is_dual = SF_DUAL_STACKED_FLASH; - - upper_mio = zynq_slcr_get_mio_pin_status("qspi1"); - if ((lower_mio == ZYNQMP_QSPI_MIO_NUM_QSPI0) && - (upper_mio_cs1 == ZYNQMP_QSPI_MIO_NUM_QSPI1_CS) && - (upper_mio == ZYNQMP_QSPI_MIO_NUM_QSPI1)) - is_dual = SF_DUAL_PARALLEL_FLASH; - - return is_dual; -} - -static int zynqmp_qspi_transfer(struct spi_device *qspi, - struct spi_transfer *transfer) +static int zynqmp_qspi_transfer(struct zynqmp_qspi_priv *priv) { - struct zynqmp_qspi *zqspi = &qspi->master; static unsigned cs_change = 1; int status = 0; debug("%s\n", __func__); while (1) { - if (transfer->speed_hz) { - status = zynqmp_qspi_setup_transfer(qspi, transfer); - if (status < 0) - break; - } - /* Select the chip if required */ if (cs_change) - zynqmp_qspi_chipselect(qspi, 1); + zynqmp_qspi_chipselect(priv, 1); - cs_change = transfer->cs_change; + cs_change = priv->cs_change; - if (!transfer->tx_buf && !transfer->rx_buf && transfer->len) { + if (!priv->tx_buf && !priv->rx_buf && priv->len) { status = -1; break; } /* Request the transfer */ - if (transfer->len) { - status = zynqmp_qspi_start_transfer(qspi, transfer); - zqspi->is_inst = 0; + if (priv->len) { + status = zynqmp_qspi_start_transfer(priv); + priv->is_inst = 0; if (status < 0) break; } - if (transfer->delay_usecs) - udelay(transfer->delay_usecs); - if (cs_change) /* Deselect the chip */ - zynqmp_qspi_chipselect(qspi, 0); + zynqmp_qspi_chipselect(priv, 0); break; } - zynqmp_qspi_setup_transfer(qspi, NULL); - return status; } -int spi_cs_is_valid(unsigned int bus, unsigned int cs) -{ - /* 1 bus with 2 chipselect */ - return bus == 0 && cs < 2; -} - -void spi_cs_activate(struct spi_slave *slave) +static int zynqmp_qspi_claim_bus(struct udevice *dev) { - debug("%s: slave 0x%08lx\n", __func__, (unsigned long)slave); -} - -void spi_cs_deactivate(struct spi_slave *slave) -{ - debug("%s: slave 0x%08lx\n", __func__, (unsigned long)slave); -} + struct udevice *bus = dev->parent; + struct zynqmp_qspi_priv *priv = dev_get_priv(bus); + struct zynqmp_qspi_regs *regs = priv->regs; -void spi_init(void) -{ debug("%s\n", __func__); -} - -struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, - unsigned int max_hz, unsigned int mode) -{ - int is_dual = SF_SINGLE_FLASH; - struct zynqmp_qspi_slave *qspi; - - debug("%s: bus: %d cs: %d max_hz: %d mode: %d\n", - __func__, bus, cs, max_hz, mode); - - if (!spi_cs_is_valid(bus, cs)) - return NULL; - - is_dual = zynqmp_qspi_check_is_dual_flash(); - - if (is_dual == -1) { - printf("%s: No QSPI device detected based on MIO settings\n", - __func__); - return NULL; - } - - zynqmp_qspi_init_hw(is_dual, cs); - - qspi = spi_alloc_slave(struct zynqmp_qspi_slave, bus, cs); - if (!qspi) { - printf("%s: Fail to allocate zynqmp_qspi_slave\n", __func__); - return NULL; - } + writel(ZYNQMP_QSPI_ENABLE_ENABLE_MASK, ®s->enbr); - debug("Defaulting to 200000000 Hz qspi clk"); - qspi->qspi.master.input_clk_hz = 200000000; - - qspi->slave.option = is_dual; - qspi->slave.op_mode_rx = SPI_OPM_RX_QOF; - qspi->slave.op_mode_tx = SPI_OPM_TX_QPP; - qspi->qspi.master.speed_hz = qspi->qspi.master.input_clk_hz / 2; - qspi->qspi.max_speed_hz = (max_hz < qspi->qspi.master.speed_hz) ? - max_hz : qspi->qspi.master.speed_hz; - qspi->qspi.master.is_dual = is_dual; - qspi->qspi.mode = mode; - qspi->qspi.chip_select = 0; - zynqmp_qspi_setup_transfer(&qspi->qspi, NULL); - - return &qspi->slave; + return 0; } -void spi_free_slave(struct spi_slave *slave) +static int zynqmp_qspi_release_bus(struct udevice *dev) { - struct zynqmp_qspi_slave *qspi; - - debug("%s: slave: 0x%08lx\n", __func__, (unsigned long)slave); + struct udevice *bus = dev->parent; + struct zynqmp_qspi_priv *priv = dev_get_priv(bus); + struct zynqmp_qspi_regs *regs = priv->regs; - qspi = to_zynqmp_qspi_slave(slave); - free(qspi); -} + debug("%s\n", __func__); + writel(~ZYNQMP_QSPI_ENABLE_ENABLE_MASK, ®s->enbr); -int spi_claim_bus(struct spi_slave *slave) -{ - debug("%s: slave: 0x%08lx\n", __func__, (unsigned long)slave); return 0; } -void spi_release_bus(struct spi_slave *slave) -{ - debug("%s: slave: 0x%08lx\n", __func__, (unsigned long)slave); -} - -int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, +int zynqmp_qspi_xfer(struct udevice *dev, unsigned int bitlen, const void *dout, void *din, unsigned long flags) { - struct zynqmp_qspi_slave *qspi; - struct spi_transfer transfer; + struct udevice *bus = dev->parent; + struct zynqmp_qspi_priv *priv = dev_get_priv(bus); - debug("%s: slave: 0x%08lx bitlen: %d dout: 0x%08lx ", __func__, - (unsigned long)slave, bitlen, (unsigned long)dout); + debug("%s: priv: 0x%08lx bitlen: %d dout: 0x%08lx ", __func__, + (unsigned long)priv, bitlen, (unsigned long)dout); debug("din: 0x%08lx flags: 0x%lx\n", (unsigned long)din, flags); - qspi = (struct zynqmp_qspi_slave *)slave; - transfer.tx_buf = dout; - transfer.rx_buf = din; - transfer.len = bitlen / 8; + priv->tx_buf = dout; + priv->rx_buf = din; + priv->len = bitlen / 8; /* * Festering sore. @@ -683,34 +679,56 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, * transmit must contain a device command. */ if (dout && flags & SPI_XFER_BEGIN) - qspi->qspi.master.is_inst = 1; + priv->is_inst = 1; else - qspi->qspi.master.is_inst = 0; + priv->is_inst = 0; if (flags & SPI_XFER_END) - transfer.cs_change = 1; + priv->cs_change = 1; else - transfer.cs_change = 0; + priv->cs_change = 0; if (flags & SPI_XFER_U_PAGE) - qspi->qspi.master.u_page = 1; + priv->u_page = 1; else - qspi->qspi.master.u_page = 0; + priv->u_page = 0; - qspi->qspi.master.stripe = 0; - qspi->qspi.master.bus = 0; - if (qspi->slave.option == SF_DUAL_PARALLEL_FLASH) { - qspi->qspi.master.is_dual = SF_DUAL_PARALLEL_FLASH; + priv->stripe = 0; + priv->bus = 0; + + if (priv->is_dual == SF_DUAL_PARALLEL_FLASH) { if (flags & SPI_XFER_MASK) - qspi->qspi.master.bus = (flags & SPI_XFER_MASK) >> 8; + priv->bus = (flags & SPI_XFER_MASK) >> 8; if (flags & SPI_XFER_STRIPE) - qspi->qspi.master.stripe = 1; + priv->stripe = 1; } - transfer.delay_usecs = 0; - transfer.speed_hz = qspi->qspi.max_speed_hz; - - zynqmp_qspi_transfer(&qspi->qspi, &transfer); + zynqmp_qspi_transfer(priv); return 0; } + +static const struct dm_spi_ops zynqmp_qspi_ops = { + .claim_bus = zynqmp_qspi_claim_bus, + .release_bus = zynqmp_qspi_release_bus, + .xfer = zynqmp_qspi_xfer, + .set_speed = zynqmp_qspi_set_speed, + .set_mode = zynqmp_qspi_set_mode, +}; + +static const struct udevice_id zynqmp_qspi_ids[] = { + { .compatible = "xlnx,zynqmp-qspi-1.0" }, + { } +}; + +U_BOOT_DRIVER(zynqmp_qspi) = { + .name = "zynqmp_qspi", + .id = UCLASS_SPI, + .of_match = zynqmp_qspi_ids, + .ops = &zynqmp_qspi_ops, + .ofdata_to_platdata = zynqmp_qspi_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct zynqmp_qspi_platdata), + .priv_auto_alloc_size = sizeof(struct zynqmp_qspi_priv), + .probe = zynqmp_qspi_probe, + .child_pre_probe = zynqmp_qspi_child_pre_probe, +}; -- 2.47.3