[U-Boot] [PATCH v3 1/2] spi: zynqmp_gqspi: Add support for ZynqMP qspi driver
Siva Durga Prasad Paladugu
sivadur at xilinx.com
Wed May 9 07:50:00 UTC 2018
Hi,
> -----Original Message-----
> From: Jagan Teki [mailto:jagannadh.teki at gmail.com]
> Sent: Wednesday, May 09, 2018 1:12 PM
> To: Siva Durga Prasad Paladugu <sivadur at xilinx.com>
> Cc: Jagan Teki <jagan at amarulasolutions.com>; U-Boot-Denx <u-
> boot at lists.denx.de>; michal.simek at xilinx.com
> Subject: Re: [U-Boot] [PATCH v3 1/2] spi: zynqmp_gqspi: Add support for
> ZynqMP qspi driver
>
> On Wed, May 9, 2018 at 12:33 PM, Siva Durga Prasad Paladugu
> <sivadur at xilinx.com> wrote:
> > Hi Jagan,
> >
> >> -----Original Message-----
> >> From: Jagan Teki [mailto:jagan at amarulasolutions.com]
> >> Sent: Wednesday, May 09, 2018 12:01 PM
> >> To: Siva Durga Prasad Paladugu <sivadur at xilinx.com>
> >> Cc: U-Boot-Denx <u-boot at lists.denx.de>; michal.simek at xilinx.com
> >> Subject: Re: [PATCH v3 1/2] spi: zynqmp_gqspi: Add support for
> ZynqMP
> >> qspi driver
> >>
> >> On Tue, May 8, 2018 at 3:43 PM, Siva Durga Prasad Paladugu
> >> <siva.durga.paladugu at xilinx.com> wrote:
> >> > This patch adds qspi driver support for ZynqMP SoC. This driver is
> >> > responsible for communicating with qspi flash devices.
> >> >
> >> > Signed-off-by: Siva Durga Prasad Paladugu
> >> > <siva.durga.paladugu at xilinx.com>
> >> > ---
> >> > Changes for v3:
> >> > - Renamed all macros, functions, files and configs as per comment
> >> > - Used wait_for_bit wherever required
> >> > - Removed unnecessary header inclusion
> >> >
> >> > Changes for v2:
> >> > - Rebased on top of latest master
> >> > - Moved macro definitions to .h file as per comment
> >> > - Fixed magic values with macros as per comment
> >> > ---
> >> > arch/arm/include/asm/arch-zynqmp/zynqmp_gqspi.h | 154 ++++++
> >> > drivers/spi/Kconfig | 7 +
> >> > drivers/spi/Makefile | 1 +
> >> > drivers/spi/zynqmp_gqspi.c | 670
> >> ++++++++++++++++++++++++
> >> > 4 files changed, 832 insertions(+) create mode 100644
> >> > arch/arm/include/asm/arch-
> >> zynqmp/zynqmp_gqspi.h
> >> > create mode 100644 drivers/spi/zynqmp_gqspi.c
> >> >
> >> > diff --git a/arch/arm/include/asm/arch-zynqmp/zynqmp_gqspi.h
> >> > b/arch/arm/include/asm/arch-zynqmp/zynqmp_gqspi.h
> >>
> >> already asked you to move this header code in driver .c file
> >
> > You might have missed my reply to your earlier comment on this. These
> > were moved to .h based on comment from Lukasz in v1.
> > I don’t have any issue in having them anywhere. Let me know your choice.
>
> I'm trying to align Linux code, better to move like that and make sure to use
> similar macros.
>
> >
[snip]
> >> > +static void zynqmp_qspi_genfifo_cmd(struct zynqmp_qspi_priv
> *priv) {
> >> > + u8 command = 1;
> >> > + u32 gen_fifo_cmd;
> >> > + u32 bytecount = 0;
> >> > +
> >> > + while (priv->len) {
> >> > + gen_fifo_cmd = zynqmp_qspi_bus_select(priv);
> >> > + gen_fifo_cmd |= GQSPI_GFIFO_TX;
> >> > +
> >> > + if (command) {
> >> > + command = 0;
> >> > + last_cmd = *(u8 *)priv->tx_buf;
> >> > + }
> >>
> >> don't understand this code can you explain? command assigned 1 it
> >> will not updated anywhere?
> >
> > I want to store last command sent. As the first byte in loop only
> > contains command, it ensures it fills only for one time and next time it
> may contain data to be sent along with command.
> > Command initialized to 1 while declaring it above(u8 command = 1).
>
> Ok the first TX buf has command and reused in tx and rx fifo, how come to
> use use same in rx fifo? why is is last_cmd it is first_cmd?
This holds the command that was sent last to the device before we use in tx/rx fill, hence used this name.
Thanks,
Siva
>
>
> >
> >>
> >> > +
> >> > + gen_fifo_cmd |= GQSPI_SPI_MODE_SPI;
> >> > + gen_fifo_cmd |= *(u8 *)priv->tx_buf;
> >> > + bytecount++;
> >> > + priv->len--;
> >> > + priv->tx_buf = (u8 *)priv->tx_buf + 1;
> >> > +
> >> > + debug("GFIFO_CMD_Cmd = 0x%x\n", gen_fifo_cmd);
> >> > +
> >> > + zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd);
> >> > + }
> >> > +}
> >> > +
> >> > +static u32 zynqmp_qspi_calc_exp(struct zynqmp_qspi_priv *priv,
> >> > + u32 *gen_fifo_cmd) {
> >> > + u32 expval = 8;
> >> > + u32 len;
> >> > +
> >> > + while (1) {
> >> > + if (priv->len > 255) {
> >>
> >> what is 255 here?
> > When length is greater than 2^8 then we should fill length in different
> way, hence this check.
> > I will anyway use macro for better readability.
>
> make sure to write proper comments on why?
>
> >
> >>
> >> > + if (priv->len & (1 << expval)) {
> >> > + *gen_fifo_cmd &= ~GQSPI_GFIFO_IMD_MASK;
> >> > + *gen_fifo_cmd |= GQSPI_GFIFO_EXP_MASK;
> >> > + *gen_fifo_cmd |= expval;
> >> > + priv->len -= (1 << expval);
> >> > + return expval;
> >> > + }
> >> > + expval++;
> >> > + } else {
> >> > + *gen_fifo_cmd &= ~(GQSPI_GFIFO_IMD_MASK |
> >> > + GQSPI_GFIFO_EXP_MASK);
> >> > + *gen_fifo_cmd |= (u8)priv->len;
> >> > + len = (u8)priv->len;
> >> > + priv->len = 0;
> >> > + return len;
> >> > + }
> >> > + }
> >> > +}
> >> > +
> >> > +static int zynqmp_qspi_genfifo_fill_tx(struct zynqmp_qspi_priv
> >> > +*priv) {
> >> > + u32 gen_fifo_cmd;
> >> > + u32 len;
> >> > + int ret = 0;
> >> > +
> >> > + gen_fifo_cmd = zynqmp_qspi_bus_select(priv);
> >> > + gen_fifo_cmd |= GQSPI_GFIFO_TX |
> >> > + GQSPI_GFIFO_DATA_XFR_MASK;
> >> > +
> >> > + if (last_cmd == QUAD_PAGE_PROGRAM_CMD)
> >> > + gen_fifo_cmd |= GQSPI_SPI_MODE_QSPI;
> >> > + else
> >> > + gen_fifo_cmd |= GQSPI_SPI_MODE_SPI;
> >> > +
> >> > + while (priv->len) {
> >> > + len = zynqmp_qspi_calc_exp(priv, &gen_fifo_cmd);
> >> > + zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd);
> >> > +
> >> > + debug("GFIFO_CMD_TX:0x%x\n", gen_fifo_cmd);
> >> > +
> >> > + if (gen_fifo_cmd & GQSPI_GFIFO_EXP_MASK)
> >> > + ret = zynqmp_qspi_fill_tx_fifo(priv,
> >> > + 1 << len);
> >> > + else
> >> > + ret = zynqmp_qspi_fill_tx_fifo(priv,
> >> > + len);
> >> > +
> >> > + if (ret)
> >> > + return ret;
> >> > + }
> >> > + return ret;
> >> > +}
> >> > +
> >> > +static int zynqmp_qspi_start_dma(struct zynqmp_qspi_priv *priv,
> >> > + u32 gen_fifo_cmd, u32 *buf) {
> >> > + u32 addr;
> >> > + u32 size, len;
> >> > + u32 actuallen = priv->len;
> >> > + int ret = 0;
> >> > + struct zynqmp_qspi_dma_regs *dma_regs = priv->dma_regs;
> >> > +
> >> > + writel((unsigned long)buf, &dma_regs->dmadst);
> >> > + writel(roundup(priv->len, 4), &dma_regs->dmasize);
> >> > + writel(GQSPI_DMA_DST_I_STS_MASK, &dma_regs->dmaier);
> >> > + addr = (unsigned long)buf;
> >> > + size = roundup(priv->len, ARCH_DMA_MINALIGN);
> >> > + flush_dcache_range(addr, addr + size);
> >> > +
> >> > + while (priv->len) {
> >> > + len = zynqmp_qspi_calc_exp(priv, &gen_fifo_cmd);
> >> > + if (!(gen_fifo_cmd & GQSPI_GFIFO_EXP_MASK) &&
> >> > + (len % 4)) {
> >> > + gen_fifo_cmd &= ~(0xFF);
> >> > + gen_fifo_cmd |= (len / 4 + 1) * 4;
> >>
> >> Need macros for these numerics
> > Ok
> >>
> >> > + }
> >> > + zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd);
> >> > +
> >> > + debug("GFIFO_CMD_RX:0x%x\n", gen_fifo_cmd);
> >> > + }
> >> > +
> >> > + ret = wait_for_bit_le32(&dma_regs->dmaisr,
> >> GQSPI_DMA_DST_I_STS_DONE,
> >> > + 1, GQSPI_TIMEOUT, 1);
> >> > + if (ret) {
> >> > + printf("DMA Timeout:0x%x\n", readl(&dma_regs->dmaisr));
> >> > + return -1;
> >> > + }
> >> > +
> >> > + writel(GQSPI_DMA_DST_I_STS_DONE, &dma_regs->dmaisr);
> >> > +
> >> > + 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 (buf != priv->rx_buf)
> >> > + memcpy(priv->rx_buf, buf, actuallen);
> >> > +
> >> > + return 0;
> >> > +}
> >> > +
> >> > +static int zynqmp_qspi_genfifo_fill_rx(struct zynqmp_qspi_priv
> >> > +*priv) {
> >> > + u32 gen_fifo_cmd;
> >> > + u32 *buf;
> >> > + u32 actuallen = priv->len;
> >> > +
> >> > + gen_fifo_cmd = zynqmp_qspi_bus_select(priv);
> >> > + gen_fifo_cmd |= GQSPI_GFIFO_RX |
> >> > + GQSPI_GFIFO_DATA_XFR_MASK;
> >> > +
> >> > + if (last_cmd == QUAD_OUT_READ_CMD)
> >> > + gen_fifo_cmd |= GQSPI_SPI_MODE_QSPI;
> >> > + else if (last_cmd == DUAL_OUTPUT_FASTRD_CMD)
> >> > + gen_fifo_cmd |= GQSPI_SPI_MODE_DUAL_SPI;
> >> > + else
> >> > + gen_fifo_cmd |= GQSPI_SPI_MODE_SPI;
> >> > +
> >> > + /*
> >> > + * Check if receive buffer is aligned to 4 byte and length
> >> > + * is multiples of four byte as we are using dma to receive.
> >> > + */
> >> > + if (!((unsigned long)priv->rx_buf & (GQSPI_DMA_ALIGN - 1)) &&
> >> > + !(actuallen % GQSPI_DMA_ALIGN)) {
> >> > + buf = (u32 *)priv->rx_buf;
> >> > + return zynqmp_qspi_start_dma(priv, gen_fifo_cmd, buf);
> >> > + }
> >> > +
> >> > + ALLOC_CACHE_ALIGN_BUFFER(u8, tmp, roundup(priv->len,
> >> > + GQSPI_DMA_ALIGN));
> >> > + buf = (u32 *)tmp;
> >> > + return zynqmp_qspi_start_dma(priv, gen_fifo_cmd, buf); }
> >> > +
> >> > +static int zynqmp_qspi_start_transfer(struct zynqmp_qspi_priv
> >> > +*priv) {
> >> > + int ret = 0;
> >> > +
> >> > + if (priv->is_inst) {
> >> > + if (priv->tx_buf)
> >> > + zynqmp_qspi_genfifo_cmd(priv);
> >> > + else
> >> > + ret = -1;
> >> > + } else {
> >> > + 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_transfer(struct zynqmp_qspi_priv *priv) {
> >> > + static unsigned int cs_change = 1;
> >> > + int status = 0;
> >> > +
> >> > + debug("%s\n", __func__);
> >> > +
> >> > + while (1) {
> >> > + /* Select the chip if required */
> >> > + if (cs_change)
> >> > + zynqmp_qspi_chipselect(priv, 1);
> >> > +
> >> > + cs_change = priv->cs_change;
> >> > +
> >> > + if (!priv->tx_buf && !priv->rx_buf && priv->len) {
> >> > + status = -1;
> >> > + break;
> >> > + }
> >> > +
> >> > + /* Request the transfer */
> >> > + if (priv->len) {
> >> > + status = zynqmp_qspi_start_transfer(priv);
> >> > + priv->is_inst = 0;
> >> > + if (status < 0)
> >> > + break;
> >> > + }
> >> > +
> >> > + if (cs_change)
> >> > + /* Deselect the chip */
> >> > + zynqmp_qspi_chipselect(priv, 0);
> >> > + break;
> >> > + }
> >> > +
> >> > + return status;
> >> > +}
> >> > +
> >> > +static int zynqmp_qspi_claim_bus(struct udevice *dev) {
> >> > + struct udevice *bus = dev->parent;
> >> > + struct zynqmp_qspi_priv *priv = dev_get_priv(bus);
> >> > + struct zynqmp_qspi_regs *regs = priv->regs;
> >> > +
> >> > + debug("%s\n", __func__);
> >>
> >> drop this.
> > I didn’t see any problem in having, its just for debugging.
> > If you don’t like I can remove.
>
> Yes drop it.
More information about the U-Boot
mailing list