[U-Boot] [PATCH v3 00/16] spi: zynq qspi support

These are the last two version patches links. https://patchwork.ozlabs.org/patch/302945/ https://patchwork.ozlabs.org/patch/264440/
This series adds zynq qspi controller driver in driver model and enabled support on relevent zynq boards and tested the same.
Branch to verify: $ git clone git://git.denx.de/u-boot-spi.git $ cd u-boot-spi $ git checkout -b spi-nor spi-nor
Changes for v3: - Added driver-model to zynq-qspi driver - devicetree support on zynq-qspi - Enabled qspi nodes on relevent board dts files - Enabled qspi driver on relevent board config files
Changes for v3: - Fixes with macro's addition
Jagan Teki (16): spi: Add zynq qspi controller driver dts: zynq: Add zynq qspi controller nodes doc: device-tree-bindings: spi: Add zynq qspi info dts: microzed: Enable zynq qspi controller node dts: zc702: Enable zynq qspi controller node dts: zc706: Enable zynq qspi controller node dts: zc770-xm010: Enable zynq qspi controller node dts: zed: Enable zynq qspi controller node configs: Enable legacy SPI flash interface support zynq-common: Enable zynq qspi controller support zynq-common: Enable Bank/Extended address register support configs: zynq: Enable zynq qspi controller spi: Kconfig: Add Zynq QSPI controller entry spi: zynq_spi: Add config reg shift named macros spi: zynq_spi: Rename baudrate divisor mask name spi: zynq_spi: Store cs value into private data
arch/arm/dts/zynq-7000.dtsi | 12 + arch/arm/dts/zynq-microzed.dts | 5 + arch/arm/dts/zynq-zc702.dts | 5 + arch/arm/dts/zynq-zc706.dts | 5 + arch/arm/dts/zynq-zc770-xm010.dts | 5 + arch/arm/dts/zynq-zed.dts | 5 + configs/zynq_microzed_defconfig | 2 + configs/zynq_zc702_defconfig | 2 + configs/zynq_zc706_defconfig | 2 + configs/zynq_zc70x_defconfig | 2 + configs/zynq_zc770_xm010_defconfig | 1 + configs/zynq_zed_defconfig | 2 + doc/device-tree-bindings/spi/spi-zynq-qspi.txt | 26 ++ drivers/spi/Kconfig | 9 + drivers/spi/Makefile | 1 + drivers/spi/zynq_qspi.c | 622 +++++++++++++++++++++++++ drivers/spi/zynq_spi.c | 20 +- include/configs/zynq-common.h | 10 + 18 files changed, 729 insertions(+), 7 deletions(-) create mode 100644 doc/device-tree-bindings/spi/spi-zynq-qspi.txt create mode 100644 drivers/spi/zynq_qspi.c

Added zynq qspi controller driver for Xilinx Zynq APSOC, this driver is driver-model driven with devicetree support.
=> sf probe SF: Detected S25FL128S_64K with page size 256 Bytes, erase size 64 KiB, total 16 MiB => mw.b 0x100 0xCC 0x1000000 => sf update 0x100 0x0 0x1000000 device 0 whole chip 16777216 bytes written, 0 bytes skipped in 59.842s, speed 289262 B/s => sf read 0x3000000 0x0 0x1000000 device 0 whole chip SF: 16777216 bytes @ 0x0 Read: OK => cmp.b 0x3000000 0x100 0x1000000 Total of 16777216 byte(s) were the same
Signed-off-by: Jagan Teki jteki@openedev.com Cc: Simon Glass sjg@chromium.org Cc: Michal Simek michal.simek@xilinx.com Cc: Siva Durga Prasad Paladugu sivadur@xilinx.com Tested-by: Jagan Teki jteki@openedev.com --- drivers/spi/Makefile | 1 + drivers/spi/zynq_qspi.c | 622 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 623 insertions(+) create mode 100644 drivers/spi/zynq_qspi.c
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index ee88aa1..f59312b 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -48,3 +48,4 @@ obj-$(CONFIG_TEGRA20_SLINK) += tegra20_slink.o obj-$(CONFIG_TI_QSPI) += ti_qspi.o obj-$(CONFIG_XILINX_SPI) += xilinx_spi.o obj-$(CONFIG_ZYNQ_SPI) += zynq_spi.o +obj-$(CONFIG_ZYNQ_QSPI) += zynq_qspi.o diff --git a/drivers/spi/zynq_qspi.c b/drivers/spi/zynq_qspi.c new file mode 100644 index 0000000..0ce6127 --- /dev/null +++ b/drivers/spi/zynq_qspi.c @@ -0,0 +1,622 @@ +/* + * (C) Copyright 2013 Xilinx, Inc. + * (C) Copyright 2015 Jagan Teki jteki@openedev.com + * + * Xilinx Zynq Quad-SPI(QSPI) controller driver (master mode only) + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <malloc.h> +#include <spi.h> +#include <asm/io.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* zynq qspi register bit masks ZYNQ_QSPI_<REG>_<BIT>_MASK */ +#define ZYNQ_QSPI_CR_IFMODE_MASK (1 << 31) /* Flash intrface mode*/ +#define ZYNQ_QSPI_CR_MSA_MASK (1 << 15) /* Manual start enb */ +#define ZYNQ_QSPI_CR_MCS_MASK (1 << 14) /* Manual chip select */ +#define ZYNQ_QSPI_CR_PCS_MASK (1 << 10) /* Peri chip select */ +#define ZYNQ_QSPI_CR_FW_MASK (0x3 << 6) /* FIFO width */ +#define ZYNQ_QSPI_CR_SS_MASK (0xF << 10) /* Slave Select */ +#define ZYNQ_QSPI_CR_BAUD_MASK (0x7 << 3) /* Baud rate div */ +#define ZYNQ_QSPI_CR_CPHA_MASK (1 << 2) /* Clock phase */ +#define ZYNQ_QSPI_CR_CPOL_MASK (1 << 1) /* Clock polarity */ +#define ZYNQ_QSPI_CR_MSTREN_MASK (1 << 0) /* Mode select */ +#define ZYNQ_QSPI_IXR_RXNEMPTY_MASK (1 << 4) /* RX_FIFO_not_empty */ +#define ZYNQ_QSPI_IXR_TXOW_MASK (1 << 2) /* TX_FIFO_not_full */ +#define ZYNQ_QSPI_IXR_ALL_MASK 0x7F /* All IXR bits */ +#define ZYNQ_QSPI_ENR_SPI_EN_MASK (1 << 0) /* SPI Enable */ + +/* zynq qspi Transmit Data Register */ +#define ZYNQ_QSPI_TXD_00_00_OFFSET 0x1C /* Transmit 4-byte inst */ +#define ZYNQ_QSPI_TXD_00_01_OFFSET 0x80 /* Transmit 1-byte inst */ +#define ZYNQ_QSPI_TXD_00_10_OFFSET 0x84 /* Transmit 2-byte inst */ +#define ZYNQ_QSPI_TXD_00_11_OFFSET 0x88 /* Transmit 3-byte inst */ + +#define ZYNQ_QSPI_TXFIFO_THRESHOLD 1 /* Tx FIFO threshold level*/ +#define ZYNQ_QSPI_RXFIFO_THRESHOLD 32 /* Rx FIFO threshold level */ + +#define ZYNQ_QSPI_CR_BAUD_MAX 8 /* Baud rate divisor max val */ +#define ZYNQ_QSPI_CR_BAUD_SHIFT 3 /* Baud rate divisor shift */ +#define ZYNQ_QSPI_CR_SS_SHIFT 10 /* Slave select shift */ + +#define ZYNQ_QSPI_FIFO_DEPTH 63 +#ifndef CONFIG_SYS_ZYNQ_QSPI_WAIT +#define CONFIG_SYS_ZYNQ_QSPI_WAIT CONFIG_SYS_HZ/100 /* 10 ms */ +#endif + +/* zynq qspi register set */ +struct zynq_qspi_regs { + u32 cr; /* 0x00 */ + u32 isr; /* 0x04 */ + u32 ier; /* 0x08 */ + u32 idr; /* 0x0C */ + u32 imr; /* 0x10 */ + u32 enr; /* 0x14 */ + u32 dr; /* 0x18 */ + u32 txd0r; /* 0x1C */ + u32 drxr; /* 0x20 */ + u32 sicr; /* 0x24 */ + u32 txftr; /* 0x28 */ + u32 rxftr; /* 0x2C */ + u32 gpior; /* 0x30 */ + u32 reserved0[19]; + u32 txd1r; /* 0x80 */ + u32 txd2r; /* 0x84 */ + u32 txd3r; /* 0x88 */ +}; + +/* zynq qspi platform data */ +struct zynq_qspi_platdata { + struct zynq_qspi_regs *regs; + u32 frequency; /* input frequency */ + u32 speed_hz; +}; + +/* zynq qspi priv */ +struct zynq_qspi_priv { + struct zynq_qspi_regs *regs; + u8 cs; + u8 mode; + u8 fifo_depth; + u32 freq; /* required frequency */ + const void *tx_buf; + void *rx_buf; + unsigned len; + int bytes_to_transfer; + int bytes_to_receive; + unsigned int is_inst; + unsigned cs_change:1; +}; + +static int zynq_qspi_ofdata_to_platdata(struct udevice *bus) +{ + struct zynq_qspi_platdata *plat = bus->platdata; + const void *blob = gd->fdt_blob; + int node = bus->of_offset; + + plat->regs = (struct zynq_qspi_regs *)fdtdec_get_addr(blob, + node, "reg"); + + /* FIXME: Use 166MHz as a suitable default */ + plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency", + 166666666); + plat->speed_hz = plat->frequency / 2; + + debug("%s: regs=%p max-frequency=%d\n", __func__, + plat->regs, plat->frequency); + + return 0; +} + +static void zynq_qspi_init_hw(struct zynq_qspi_priv *priv) +{ + struct zynq_qspi_regs *regs = priv->regs; + u32 confr; + + /* Disable QSPI */ + writel(~ZYNQ_QSPI_ENR_SPI_EN_MASK, ®s->enr); + + /* Disable Interrupts */ + writel(ZYNQ_QSPI_IXR_ALL_MASK, ®s->idr); + + /* Clear the TX and RX threshold reg */ + writel(ZYNQ_QSPI_TXFIFO_THRESHOLD, ®s->txftr); + writel(ZYNQ_QSPI_RXFIFO_THRESHOLD, ®s->rxftr); + + /* Clear the RX FIFO */ + while (readl(®s->isr) & ZYNQ_QSPI_IXR_RXNEMPTY_MASK) + readl(®s->drxr); + + /* Clear Interrupts */ + writel(ZYNQ_QSPI_IXR_ALL_MASK, ®s->isr); + + /* Manual slave select and Auto start */ + confr = readl(®s->cr); + confr &= ~ZYNQ_QSPI_CR_MSA_MASK; + confr |= ZYNQ_QSPI_CR_IFMODE_MASK | ZYNQ_QSPI_CR_MCS_MASK | + ZYNQ_QSPI_CR_PCS_MASK | ZYNQ_QSPI_CR_FW_MASK | + ZYNQ_QSPI_CR_MSTREN_MASK; + writel(confr, ®s->cr); + + /* Enable SPI */ + writel(ZYNQ_QSPI_ENR_SPI_EN_MASK, ®s->enr); +} + +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); + + priv->regs = plat->regs; + priv->fifo_depth = ZYNQ_QSPI_FIFO_DEPTH; + + /* init the zynq spi hw */ + zynq_qspi_init_hw(priv); + + return 0; +} + +/* + * zynq_qspi_read_data - Copy data to RX buffer + * @zqspi: Pointer to the zynq_qspi structure + * @data: The 32 bit variable where data is stored + * @size: Number of bytes to be copied from data to RX buffer + */ +static void zynq_qspi_read_data(struct zynq_qspi_priv *priv, u32 data, u8 size) +{ + u8 byte3; + + debug("%s: data 0x%04x rx_buf addr: 0x%08x size %d\n", __func__ , + data, (unsigned)(priv->rx_buf), size); + + if (priv->rx_buf) { + switch (size) { + case 1: + *((u8 *)priv->rx_buf) = data; + priv->rx_buf += 1; + break; + case 2: + *((u16 *)priv->rx_buf) = data; + priv->rx_buf += 2; + break; + case 3: + *((u16 *)priv->rx_buf) = data; + priv->rx_buf += 2; + byte3 = (u8)(data >> 16); + *((u8 *)priv->rx_buf) = byte3; + priv->rx_buf += 1; + break; + case 4: + /* Can not assume word aligned buffer */ + memcpy(priv->rx_buf, &data, size); + priv->rx_buf += 4; + break; + default: + /* This will never execute */ + break; + } + } + priv->bytes_to_receive -= size; + if (priv->bytes_to_receive < 0) + priv->bytes_to_receive = 0; +} + +/* + * zynq_qspi_write_data - Copy data from TX buffer + * @zqspi: Pointer to the zynq_qspi structure + * @data: Pointer to the 32 bit variable where data is to be copied + * @size: Number of bytes to be copied from TX buffer to data + */ +static void zynq_qspi_write_data(struct zynq_qspi_priv *priv, + u32 *data, u8 size) +{ + if (priv->tx_buf) { + switch (size) { + case 1: + *data = *((u8 *)priv->tx_buf); + priv->tx_buf += 1; + *data |= 0xFFFFFF00; + break; + case 2: + *data = *((u16 *)priv->tx_buf); + priv->tx_buf += 2; + *data |= 0xFFFF0000; + break; + case 3: + *data = *((u16 *)priv->tx_buf); + priv->tx_buf += 2; + *data |= (*((u8 *)priv->tx_buf) << 16); + priv->tx_buf += 1; + *data |= 0xFF000000; + break; + case 4: + /* Can not assume word aligned buffer */ + memcpy(data, priv->tx_buf, size); + priv->tx_buf += 4; + break; + default: + /* This will never execute */ + break; + } + } else { + *data = 0; + } + + debug("%s: data 0x%08x tx_buf addr: 0x%08x size %d\n", __func__, + *data, (u32)priv->tx_buf, size); + + priv->bytes_to_transfer -= size; + if (priv->bytes_to_transfer < 0) + priv->bytes_to_transfer = 0; +} + +static void zynq_qspi_chipselect(struct zynq_qspi_priv *priv, int is_on) +{ + u32 confr; + struct zynq_qspi_regs *regs = priv->regs; + + confr = readl(®s->cr); + + if (is_on) { + /* Select the slave */ + confr &= ~ZYNQ_QSPI_CR_SS_MASK; + confr |= (~(1 << priv->cs) << ZYNQ_QSPI_CR_SS_SHIFT) & + ZYNQ_QSPI_CR_SS_MASK; + } else + /* Deselect the slave */ + confr |= ZYNQ_QSPI_CR_SS_MASK; + + writel(confr, ®s->cr); +} + +/* + * zynq_qspi_fill_tx_fifo - Fills the TX FIFO with as many bytes as possible + * @zqspi: Pointer to the zynq_qspi structure + */ +static void zynq_qspi_fill_tx_fifo(struct zynq_qspi_priv *priv, u32 size) +{ + u32 data = 0; + u32 fifocount = 0; + unsigned len, offset; + struct zynq_qspi_regs *regs = priv->regs; + static const unsigned offsets[4] = { + ZYNQ_QSPI_TXD_00_00_OFFSET, ZYNQ_QSPI_TXD_00_01_OFFSET, + ZYNQ_QSPI_TXD_00_10_OFFSET, ZYNQ_QSPI_TXD_00_11_OFFSET }; + + while ((fifocount < size) && + (priv->bytes_to_transfer > 0)) { + if (priv->bytes_to_transfer >= 4) { + if (priv->tx_buf) { + memcpy(&data, priv->tx_buf, 4); + priv->tx_buf += 4; + } else { + data = 0; + } + writel(data, ®s->txd0r); + priv->bytes_to_transfer -= 4; + fifocount++; + } else { + /* Write TXD1, TXD2, TXD3 only if TxFIFO is empty. */ + if (!(readl(®s->isr) + & ZYNQ_QSPI_IXR_TXOW_MASK) && + !priv->rx_buf) + return; + len = priv->bytes_to_transfer; + zynq_qspi_write_data(priv, &data, len); + offset = (priv->rx_buf) ? offsets[0] : offsets[len]; + writel(data, ®s->cr + (offset / 4)); + } + } +} + +/* + * zynq_qspi_irq_poll - Interrupt service routine of the QSPI controller + * @zqspi: Pointer to the zynq_qspi structure + * + * This function handles TX empty and Mode Fault interrupts only. + * On TX empty interrupt this function reads the received data from RX FIFO and + * fills the TX FIFO if there is any data remaining to be transferred. + * On Mode Fault interrupt this function indicates that transfer is completed, + * the SPI subsystem will identify the error as the remaining bytes to be + * transferred is non-zero. + * + * returns: 0 for poll timeout + * 1 transfer operation complete + */ +static int zynq_qspi_irq_poll(struct zynq_qspi_priv *priv) +{ + struct zynq_qspi_regs *regs = priv->regs; + u32 rxindex = 0; + u32 rxcount; + u32 status, timeout; + + /* Poll until any of the interrupt status bits are set */ + timeout = get_timer(0); + do { + status = readl(®s->isr); + } while ((status == 0) && + (get_timer(timeout) < CONFIG_SYS_ZYNQ_QSPI_WAIT)); + + if (status == 0) { + printf("zynq_qspi_irq_poll: Timeout!\n"); + return -ETIMEDOUT; + } + + writel(status, ®s->isr); + + /* Disable all interrupts */ + writel(ZYNQ_QSPI_IXR_ALL_MASK, ®s->idr); + if ((status & ZYNQ_QSPI_IXR_TXOW_MASK) || + (status & ZYNQ_QSPI_IXR_RXNEMPTY_MASK)) { + /* + * This bit is set when Tx FIFO has < THRESHOLD entries. We have + * the THRESHOLD value set to 1, so this bit indicates Tx FIFO + * is empty + */ + rxcount = priv->bytes_to_receive - priv->bytes_to_transfer; + rxcount = (rxcount % 4) ? ((rxcount/4)+1) : (rxcount/4); + while ((rxindex < rxcount) && + (rxindex < ZYNQ_QSPI_RXFIFO_THRESHOLD)) { + /* Read out the data from the RX FIFO */ + u32 data; + data = readl(®s->drxr); + + if (priv->bytes_to_receive >= 4) { + if (priv->rx_buf) { + memcpy(priv->rx_buf, &data, 4); + priv->rx_buf += 4; + } + priv->bytes_to_receive -= 4; + } else { + zynq_qspi_read_data(priv, data, + priv->bytes_to_receive); + } + rxindex++; + } + + if (priv->bytes_to_transfer) { + /* There is more data to send */ + zynq_qspi_fill_tx_fifo(priv, + ZYNQ_QSPI_RXFIFO_THRESHOLD); + + writel(ZYNQ_QSPI_IXR_ALL_MASK, ®s->ier); + } else { + /* + * If transfer and receive is completed then only send + * complete signal + */ + if (!priv->bytes_to_receive) { + /* return operation complete */ + writel(ZYNQ_QSPI_IXR_ALL_MASK, + ®s->idr); + return 1; + } + } + } + + return 0; +} + +/* + * zynq_qspi_start_transfer - Initiates the QSPI transfer + * @qspi: Pointer to the spi_device structure + * @transfer: Pointer to the spi_transfer structure which provide information + * about next transfer parameters + * + * This function fills the TX FIFO, starts the QSPI transfer, and waits for the + * transfer to be completed. + * + * returns: Number of bytes transferred in the last transfer + */ +static int zynq_qspi_start_transfer(struct zynq_qspi_priv *priv) +{ + u32 data = 0; + struct zynq_qspi_regs *regs = priv->regs; + + debug("%s: qspi: 0x%08x transfer: 0x%08x len: %d\n", __func__, + (u32)priv, (u32)priv, priv->len); + + priv->bytes_to_transfer = priv->len; + priv->bytes_to_receive = priv->len; + + if (priv->len < 4) + zynq_qspi_fill_tx_fifo(priv, priv->len); + else + zynq_qspi_fill_tx_fifo(priv, priv->fifo_depth); + + writel(ZYNQ_QSPI_IXR_ALL_MASK, ®s->ier); + /* Start the transfer by enabling manual start bit */ + + /* wait for completion */ + do { + data = zynq_qspi_irq_poll(priv); + } while (data == 0); + + return (priv->len) - (priv->bytes_to_transfer); +} + +static int zynq_qspi_transfer(struct zynq_qspi_priv *priv) +{ + unsigned cs_change = 1; + int status = 0; + + while (1) { + /* Select the chip if required */ + if (cs_change) + zynq_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 = zynq_qspi_start_transfer(priv); + priv->is_inst = 0; + } + + if (status != priv->len) { + if (status > 0) + status = -EMSGSIZE; + debug("zynq_qspi_transfer:%d len:%d\n", + status, priv->len); + break; + } + status = 0; + + if (cs_change) + /* Deselect the chip */ + zynq_qspi_chipselect(priv, 0); + + break; + } + + return 0; +} + +static int zynq_qspi_claim_bus(struct udevice *dev) +{ + struct udevice *bus = dev->parent; + struct zynq_qspi_priv *priv = dev_get_priv(bus); + struct zynq_qspi_regs *regs = priv->regs; + + writel(ZYNQ_QSPI_ENR_SPI_EN_MASK, ®s->enr); + + return 0; +} + +static int zynq_qspi_release_bus(struct udevice *dev) +{ + struct udevice *bus = dev->parent; + struct zynq_qspi_priv *priv = dev_get_priv(bus); + struct zynq_qspi_regs *regs = priv->regs; + + writel(~ZYNQ_QSPI_ENR_SPI_EN_MASK, ®s->enr); + + return 0; +} + +static int zynq_qspi_xfer(struct udevice *dev, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + struct udevice *bus = dev->parent; + struct zynq_qspi_priv *priv = dev_get_priv(bus); + struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); + + priv->cs = slave_plat->cs; + priv->tx_buf = dout; + priv->rx_buf = din; + priv->len = bitlen / 8; + + debug("spi_xfer: bus:%i cs:%i bitlen:%i len:%i flags:%lx\n", + bus->seq, slave_plat->cs, bitlen, priv->len, flags); + + /* + * Festering sore. + * Assume that the beginning of a transfer with bits to + * transmit must contain a device command. + */ + if (dout && flags & SPI_XFER_BEGIN) + priv->is_inst = 1; + else + priv->is_inst = 0; + + if (flags & SPI_XFER_END) + priv->cs_change = 1; + else + priv->cs_change = 0; + + zynq_qspi_transfer(priv); + + return 0; +} + +static int zynq_qspi_set_speed(struct udevice *bus, uint speed) +{ + struct zynq_qspi_platdata *plat = bus->platdata; + struct zynq_qspi_priv *priv = dev_get_priv(bus); + struct zynq_qspi_regs *regs = priv->regs; + uint32_t confr; + u8 baud_rate_val = 0; + + if (speed > plat->frequency) + speed = plat->frequency; + + /* Set the clock frequency */ + confr = readl(®s->cr); + 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 < ZYNQ_QSPI_CR_BAUD_MAX) && + ((plat->frequency / + (2 << baud_rate_val)) > speed)) + baud_rate_val++; + + plat->speed_hz = speed / (2 << baud_rate_val); + } + confr &= ~ZYNQ_QSPI_CR_BAUD_MASK; + confr |= (baud_rate_val << ZYNQ_QSPI_CR_BAUD_SHIFT); + + writel(confr, ®s->cr); + priv->freq = speed; + + debug("zynq_spi_set_speed: regs=%p, mode=%d\n", priv->regs, priv->freq); + + return 0; +} + +static int zynq_qspi_set_mode(struct udevice *bus, uint mode) +{ + struct zynq_qspi_priv *priv = dev_get_priv(bus); + struct zynq_qspi_regs *regs = priv->regs; + uint32_t confr; + + /* Set the SPI Clock phase and polarities */ + confr = readl(®s->cr); + confr &= ~(ZYNQ_QSPI_CR_CPHA_MASK | ZYNQ_QSPI_CR_CPOL_MASK); + + if (priv->mode & SPI_CPHA) + confr |= ZYNQ_QSPI_CR_CPHA_MASK; + if (priv->mode & SPI_CPOL) + confr |= ZYNQ_QSPI_CR_CPOL_MASK; + + writel(confr, ®s->cr); + priv->mode = mode; + + debug("zynq_spi_set_mode: regs=%p, mode=%d\n", priv->regs, priv->mode); + + return 0; +} + +static const struct dm_spi_ops zynq_qspi_ops = { + .claim_bus = zynq_qspi_claim_bus, + .release_bus = zynq_qspi_release_bus, + .xfer = zynq_qspi_xfer, + .set_speed = zynq_qspi_set_speed, + .set_mode = zynq_qspi_set_mode, +}; + +static const struct udevice_id zynq_qspi_ids[] = { + { .compatible = "xlnx,zynq-qspi-1.0" }, + { } +}; + +U_BOOT_DRIVER(zynq_qspi) = { + .name = "zynq_qspi", + .id = UCLASS_SPI, + .of_match = zynq_qspi_ids, + .ops = &zynq_qspi_ops, + .ofdata_to_platdata = zynq_qspi_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct zynq_qspi_platdata), + .priv_auto_alloc_size = sizeof(struct zynq_qspi_priv), + .probe = zynq_qspi_probe, +};

On 17 August 2015 at 07:30, Jagan Teki jteki@openedev.com wrote:
Added zynq qspi controller driver for Xilinx Zynq APSOC, this driver is driver-model driven with devicetree support.
=> sf probe SF: Detected S25FL128S_64K with page size 256 Bytes, erase size 64 KiB, total 16 MiB => mw.b 0x100 0xCC 0x1000000 => sf update 0x100 0x0 0x1000000 device 0 whole chip 16777216 bytes written, 0 bytes skipped in 59.842s, speed 289262 B/s => sf read 0x3000000 0x0 0x1000000 device 0 whole chip SF: 16777216 bytes @ 0x0 Read: OK => cmp.b 0x3000000 0x100 0x1000000 Total of 16777216 byte(s) were the same
Signed-off-by: Jagan Teki jteki@openedev.com Cc: Simon Glass sjg@chromium.org Cc: Michal Simek michal.simek@xilinx.com Cc: Siva Durga Prasad Paladugu sivadur@xilinx.com Tested-by: Jagan Teki jteki@openedev.com
drivers/spi/Makefile | 1 + drivers/spi/zynq_qspi.c | 622 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 623 insertions(+) create mode 100644 drivers/spi/zynq_qspi.c
Reviewed-by: Simon Glass sjg@chromium.org

This patch adds zynq qspi controller nodes in zynq-7000.dtsi.
Signed-off-by: Jagan Teki jteki@openedev.com Cc: Simon Glass sjg@chromium.org Cc: Michal Simek michal.simek@xilinx.com Cc: Siva Durga Prasad Paladugu sivadur@xilinx.com Tested-by: Jagan Teki jteki@openedev.com --- arch/arm/dts/zynq-7000.dtsi | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/arch/arm/dts/zynq-7000.dtsi b/arch/arm/dts/zynq-7000.dtsi index 0b62cb0..84c15b5 100644 --- a/arch/arm/dts/zynq-7000.dtsi +++ b/arch/arm/dts/zynq-7000.dtsi @@ -191,6 +191,18 @@ #size-cells = <0>; };
+ qspi: spi@e000d000 { + clock-names = "ref_clk", "pclk"; + clocks = <&clkc 10>, <&clkc 43>; + compatible = "xlnx,zynq-qspi-1.0"; + status = "disabled"; + interrupt-parent = <&intc>; + interrupts = <0 19 4>; + reg = <0xe000d000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + }; + gem0: ethernet@e000b000 { compatible = "cdns,zynq-gem", "cdns,gem"; reg = <0xe000b000 0x1000>;

Added device-tree-binding information for zynq qspi controller driver.
Signed-off-by: Jagan Teki jteki@openedev.com Cc: Simon Glass sjg@chromium.org Cc: Michal Simek michal.simek@xilinx.com Cc: Siva Durga Prasad Paladugu sivadur@xilinx.com Tested-by: Jagan Teki jteki@openedev.com --- doc/device-tree-bindings/spi/spi-zynq-qspi.txt | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 doc/device-tree-bindings/spi/spi-zynq-qspi.txt
diff --git a/doc/device-tree-bindings/spi/spi-zynq-qspi.txt b/doc/device-tree-bindings/spi/spi-zynq-qspi.txt new file mode 100644 index 0000000..47472fd --- /dev/null +++ b/doc/device-tree-bindings/spi/spi-zynq-qspi.txt @@ -0,0 +1,26 @@ +Xilinx Zynq QSPI controller Device Tree Bindings +------------------------------------------------- + +Required properties: +- compatible : Should be "xlnx,zynq-qspi-1.0". +- reg : Physical base address and size of QSPI registers map. +- interrupts : Property with a value describing the interrupt + number. +- interrupt-parent : Must be core interrupt controller +- clock-names : List of input clock names - "ref_clk", "pclk" + (See clock bindings for details). +- clocks : Clock phandles (see clock bindings for details). + +Optional properties: +- num-cs : Number of chip selects used. + +Example: + qspi@e000d000 { + compatible = "xlnx,zynq-qspi-1.0"; + clock-names = "ref_clk", "pclk"; + clocks = <&clkc 10>, <&clkc 43>; + interrupt-parent = <&intc>; + interrupts = <0 19 4>; + num-cs = <1>; + reg = <0xe000d000 0x1000>; + } ;

Enabled zynq qspi controller node for microzed board, verified the same on spansion spi-nor flash.
Signed-off-by: Jagan Teki jteki@openedev.com Cc: Simon Glass sjg@chromium.org Cc: Michal Simek michal.simek@xilinx.com Cc: Siva Durga Prasad Paladugu sivadur@xilinx.com Tested-by: Jagan Teki jteki@openedev.com --- arch/arm/dts/zynq-microzed.dts | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/arch/arm/dts/zynq-microzed.dts b/arch/arm/dts/zynq-microzed.dts index c373a2c..d5e0050 100644 --- a/arch/arm/dts/zynq-microzed.dts +++ b/arch/arm/dts/zynq-microzed.dts @@ -14,6 +14,7 @@
aliases { serial0 = &uart1; + spi0 = &qspi; };
memory { @@ -21,3 +22,7 @@ reg = <0 0x40000000>; }; }; + +&qspi { + status = "okay"; +};

Enabled zynq qspi controller node for zc702 board.
Signed-off-by: Jagan Teki jteki@openedev.com Cc: Simon Glass sjg@chromium.org Cc: Michal Simek michal.simek@xilinx.com Cc: Siva Durga Prasad Paladugu sivadur@xilinx.com --- arch/arm/dts/zynq-zc702.dts | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/arch/arm/dts/zynq-zc702.dts b/arch/arm/dts/zynq-zc702.dts index 6691a8d..4d86960 100644 --- a/arch/arm/dts/zynq-zc702.dts +++ b/arch/arm/dts/zynq-zc702.dts @@ -17,6 +17,7 @@ ethernet0 = &gem0; i2c0 = &i2c0; serial0 = &uart1; + spi0 = &qspi; };
memory { @@ -380,6 +381,10 @@ pinctrl-0 = <&pinctrl_uart1_default>; };
+&qspi { + status = "okay"; +}; + &usb0 { status = "okay"; dr_mode = "host";

Enabled zynq qspi controller node for zc706 board.
Signed-off-by: Jagan Teki jteki@openedev.com Cc: Simon Glass sjg@chromium.org Cc: Michal Simek michal.simek@xilinx.com Cc: Siva Durga Prasad Paladugu sivadur@xilinx.com --- arch/arm/dts/zynq-zc706.dts | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/arch/arm/dts/zynq-zc706.dts b/arch/arm/dts/zynq-zc706.dts index cf7bce4..fc336ea 100644 --- a/arch/arm/dts/zynq-zc706.dts +++ b/arch/arm/dts/zynq-zc706.dts @@ -17,6 +17,7 @@ ethernet0 = &gem0; i2c0 = &i2c0; serial0 = &uart1; + spi0 = &qspi; };
memory { @@ -301,6 +302,10 @@ pinctrl-0 = <&pinctrl_uart1_default>; };
+&qspi { + status = "okay"; +}; + &usb0 { status = "okay"; dr_mode = "host";

Enabled zynq qspi controller node for zc770-xm010 board.
=> sf probe 0 -- bus0 for selecting spi controller => sf probe 1 -- bus1 for selecting qspi controller
Signed-off-by: Jagan Teki jteki@openedev.com Cc: Simon Glass sjg@chromium.org Cc: Michal Simek michal.simek@xilinx.com Cc: Siva Durga Prasad Paladugu sivadur@xilinx.com --- arch/arm/dts/zynq-zc770-xm010.dts | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/arch/arm/dts/zynq-zc770-xm010.dts b/arch/arm/dts/zynq-zc770-xm010.dts index da3a182..a5c9da5 100644 --- a/arch/arm/dts/zynq-zc770-xm010.dts +++ b/arch/arm/dts/zynq-zc770-xm010.dts @@ -17,6 +17,7 @@ i2c0 = &i2c0; serial0 = &uart1; spi0 = &spi1; + spi1 = &qspi; };
chosen { @@ -53,6 +54,10 @@ }; };
+&qspi { + status = "okay"; +}; + &can0 { status = "okay"; };

Enabled zynq qspi controller node for zed board.
Signed-off-by: Jagan Teki jteki@openedev.com Cc: Simon Glass sjg@chromium.org Cc: Michal Simek michal.simek@xilinx.com Cc: Siva Durga Prasad Paladugu sivadur@xilinx.com --- arch/arm/dts/zynq-zed.dts | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/arch/arm/dts/zynq-zed.dts b/arch/arm/dts/zynq-zed.dts index 5762576..3630490 100644 --- a/arch/arm/dts/zynq-zed.dts +++ b/arch/arm/dts/zynq-zed.dts @@ -16,6 +16,7 @@ aliases { ethernet0 = &gem0; serial0 = &uart1; + spi0 = &qspi; };
memory { @@ -56,6 +57,10 @@ status = "okay"; };
+&qspi { + status = "okay"; +}; + &usb0 { status = "okay"; dr_mode = "host";

Enable legacy spi-flash interface support for boards which supports qspi controller with connected spi-nor flash.
Signed-off-by: Jagan Teki jteki@openedev.com Cc: Simon Glass sjg@chromium.org Cc: Michal Simek michal.simek@xilinx.com Cc: Siva Durga Prasad Paladugu sivadur@xilinx.com Tested-by: Jagan Teki jteki@openedev.com --- configs/zynq_microzed_defconfig | 1 + configs/zynq_zc702_defconfig | 1 + configs/zynq_zc706_defconfig | 1 + configs/zynq_zc70x_defconfig | 1 + configs/zynq_zed_defconfig | 1 + 5 files changed, 5 insertions(+)
diff --git a/configs/zynq_microzed_defconfig b/configs/zynq_microzed_defconfig index c878924..838f8ae 100644 --- a/configs/zynq_microzed_defconfig +++ b/configs/zynq_microzed_defconfig @@ -10,3 +10,4 @@ CONFIG_FIT_SIGNATURE=y # CONFIG_CMD_IMLS is not set # CONFIG_CMD_FLASH is not set # CONFIG_CMD_SETEXPR is not set +CONFIG_SPI_FLASH=y diff --git a/configs/zynq_zc702_defconfig b/configs/zynq_zc702_defconfig index 5dde452..1aaa296 100644 --- a/configs/zynq_zc702_defconfig +++ b/configs/zynq_zc702_defconfig @@ -10,3 +10,4 @@ CONFIG_FIT_SIGNATURE=y # CONFIG_CMD_IMLS is not set # CONFIG_CMD_FLASH is not set # CONFIG_CMD_SETEXPR is not set +CONFIG_SPI_FLASH=y diff --git a/configs/zynq_zc706_defconfig b/configs/zynq_zc706_defconfig index 0f96d16..4f12fd2 100644 --- a/configs/zynq_zc706_defconfig +++ b/configs/zynq_zc706_defconfig @@ -10,3 +10,4 @@ CONFIG_FIT_SIGNATURE=y # CONFIG_CMD_IMLS is not set # CONFIG_CMD_FLASH is not set # CONFIG_CMD_SETEXPR is not set +CONFIG_SPI_FLASH=y diff --git a/configs/zynq_zc70x_defconfig b/configs/zynq_zc70x_defconfig index 525c538..856b9fd 100644 --- a/configs/zynq_zc70x_defconfig +++ b/configs/zynq_zc70x_defconfig @@ -10,3 +10,4 @@ CONFIG_FIT_SIGNATURE=y # CONFIG_CMD_IMLS is not set # CONFIG_CMD_FLASH is not set # CONFIG_CMD_SETEXPR is not set +CONFIG_SPI_FLASH=y diff --git a/configs/zynq_zed_defconfig b/configs/zynq_zed_defconfig index f3c63f9..a49b6bb 100644 --- a/configs/zynq_zed_defconfig +++ b/configs/zynq_zed_defconfig @@ -10,3 +10,4 @@ CONFIG_FIT_SIGNATURE=y # CONFIG_CMD_IMLS is not set # CONFIG_CMD_FLASH is not set # CONFIG_CMD_SETEXPR is not set +CONFIG_SPI_FLASH=y

This patch adds support for zynq qspi controller driver on zynq-common.h
Signed-off-by: Jagan Teki jteki@openedev.com Cc: Simon Glass sjg@chromium.org Cc: Michal Simek michal.simek@xilinx.com Cc: Siva Durga Prasad Paladugu sivadur@xilinx.com Tested-by: Jagan Teki jteki@openedev.com --- include/configs/zynq-common.h | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/include/configs/zynq-common.h b/include/configs/zynq-common.h index cc72c86..13903ec 100644 --- a/include/configs/zynq-common.h +++ b/include/configs/zynq-common.h @@ -72,6 +72,15 @@ # define CONFIG_CMD_SF #endif
+/* QSPI */ +#ifdef CONFIG_ZYNQ_QSPI +# define CONFIG_SF_DEFAULT_SPEED 30000000 +# define CONFIG_SPI_FLASH_SPANSION +# define CONFIG_SPI_FLASH_STMICRO +# define CONFIG_SPI_FLASH_WINBOND +# define CONFIG_CMD_SF +#endif + /* NOR */ #ifndef CONFIG_SYS_NO_FLASH # define CONFIG_SYS_FLASH_BASE 0xE2000000

Enabled SPI flash Bank/Extended address register support.
Bank/Extended address registers are used to access the flash which has size > 16MiB in 3-byte addressing.
Signed-off-by: Jagan Teki jteki@openedev.com --- include/configs/zynq-common.h | 1 + 1 file changed, 1 insertion(+)
diff --git a/include/configs/zynq-common.h b/include/configs/zynq-common.h index 13903ec..181d393 100644 --- a/include/configs/zynq-common.h +++ b/include/configs/zynq-common.h @@ -78,6 +78,7 @@ # define CONFIG_SPI_FLASH_SPANSION # define CONFIG_SPI_FLASH_STMICRO # define CONFIG_SPI_FLASH_WINBOND +# define CONFIG_SPI_FLASH_BAR # define CONFIG_CMD_SF #endif

Enable zynq qspi controller driver on respective zynq boards.
Signed-off-by: Jagan Teki jteki@openedev.com Cc: Simon Glass sjg@chromium.org Cc: Michal Simek michal.simek@xilinx.com Cc: Siva Durga Prasad Paladugu sivadur@xilinx.com Tested-by: Jagan Teki jteki@openedev.com --- configs/zynq_microzed_defconfig | 1 + configs/zynq_zc702_defconfig | 1 + configs/zynq_zc706_defconfig | 1 + configs/zynq_zc70x_defconfig | 1 + configs/zynq_zc770_xm010_defconfig | 1 + configs/zynq_zed_defconfig | 1 + 6 files changed, 6 insertions(+)
diff --git a/configs/zynq_microzed_defconfig b/configs/zynq_microzed_defconfig index 838f8ae..c055704 100644 --- a/configs/zynq_microzed_defconfig +++ b/configs/zynq_microzed_defconfig @@ -11,3 +11,4 @@ CONFIG_FIT_SIGNATURE=y # CONFIG_CMD_FLASH is not set # CONFIG_CMD_SETEXPR is not set CONFIG_SPI_FLASH=y +CONFIG_ZYNQ_QSPI=y diff --git a/configs/zynq_zc702_defconfig b/configs/zynq_zc702_defconfig index 1aaa296..a5812ce 100644 --- a/configs/zynq_zc702_defconfig +++ b/configs/zynq_zc702_defconfig @@ -11,3 +11,4 @@ CONFIG_FIT_SIGNATURE=y # CONFIG_CMD_FLASH is not set # CONFIG_CMD_SETEXPR is not set CONFIG_SPI_FLASH=y +CONFIG_ZYNQ_QSPI=y diff --git a/configs/zynq_zc706_defconfig b/configs/zynq_zc706_defconfig index 4f12fd2..a2fcaad 100644 --- a/configs/zynq_zc706_defconfig +++ b/configs/zynq_zc706_defconfig @@ -11,3 +11,4 @@ CONFIG_FIT_SIGNATURE=y # CONFIG_CMD_FLASH is not set # CONFIG_CMD_SETEXPR is not set CONFIG_SPI_FLASH=y +CONFIG_ZYNQ_QSPI=y diff --git a/configs/zynq_zc70x_defconfig b/configs/zynq_zc70x_defconfig index 856b9fd..20737c0 100644 --- a/configs/zynq_zc70x_defconfig +++ b/configs/zynq_zc70x_defconfig @@ -11,3 +11,4 @@ CONFIG_FIT_SIGNATURE=y # CONFIG_CMD_FLASH is not set # CONFIG_CMD_SETEXPR is not set CONFIG_SPI_FLASH=y +CONFIG_ZYNQ_QSPI=y diff --git a/configs/zynq_zc770_xm010_defconfig b/configs/zynq_zc770_xm010_defconfig index f1fc283..b824342 100644 --- a/configs/zynq_zc770_xm010_defconfig +++ b/configs/zynq_zc770_xm010_defconfig @@ -12,3 +12,4 @@ CONFIG_SYS_EXTRA_OPTIONS="ZC770_XM010" # CONFIG_CMD_FLASH is not set # CONFIG_CMD_SETEXPR is not set CONFIG_SPI_FLASH=y +CONFIG_ZYNQ_QSPI=y diff --git a/configs/zynq_zed_defconfig b/configs/zynq_zed_defconfig index a49b6bb..163eed1 100644 --- a/configs/zynq_zed_defconfig +++ b/configs/zynq_zed_defconfig @@ -11,3 +11,4 @@ CONFIG_FIT_SIGNATURE=y # CONFIG_CMD_FLASH is not set # CONFIG_CMD_SETEXPR is not set CONFIG_SPI_FLASH=y +CONFIG_ZYNQ_QSPI=y

Add Zynq QSPI controller Kconfig entry.
Signed-off-by: Jagan Teki jteki@openedev.com Cc: Simon Glass sjg@chromium.org Cc: Michal Simek michal.simek@xilinx.com Cc: Siva Durga Prasad Paladugu sivadur@xilinx.com --- drivers/spi/Kconfig | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index c84a7b7..facd94d 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -123,6 +123,15 @@ config ZYNQ_SPI access the SPI NOR flash on platforms embedding this Zynq SPI IP core.
+config ZYNQ_QSPI + bool "Zynq QSPI driver" + depends on ARCH_ZYNQ || TARGET_XILINX_ZYNQMP + help + Enable the Zynq Quad-SPI (QSPI) driver. This driver can be + used to access the SPI NOR flash on platforms embedding this + Zynq QSPI IP core. This IP is used to connect the flash in + 4-bit qspi, 8-bit dual stacked and shared 4-bit dual parallel. + endif # if DM_SPI
config FSL_ESPI

On 17 August 2015 at 07:30, Jagan Teki jteki@openedev.com wrote:
Add Zynq QSPI controller Kconfig entry.
Signed-off-by: Jagan Teki jteki@openedev.com Cc: Simon Glass sjg@chromium.org Cc: Michal Simek michal.simek@xilinx.com Cc: Siva Durga Prasad Paladugu sivadur@xilinx.com
drivers/spi/Kconfig | 9 +++++++++ 1 file changed, 9 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org

Update the numerical values for baudrate and chipselect with config reg shift named macro's
Signed-off-by: Jagan Teki jteki@openedev.com --- drivers/spi/zynq_spi.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/drivers/spi/zynq_spi.c b/drivers/spi/zynq_spi.c index b9cf335..817728c 100644 --- a/drivers/spi/zynq_spi.c +++ b/drivers/spi/zynq_spi.c @@ -28,6 +28,10 @@ DECLARE_GLOBAL_DATA_PTR; #define ZYNQ_SPI_IXR_ALL_MASK 0x7F /* All IXR bits */ #define ZYNQ_SPI_ENR_SPI_EN_MASK (1 << 0) /* SPI Enable */
+#define ZYNQ_SPI_CR_BAUD_MAX 8 /* Baud rate divisor max val */ +#define ZYNQ_SPI_CR_BAUD_SHIFT 3 /* Baud rate divisor shift */ +#define ZYNQ_SPI_CR_SS_SHIFT 10 /* Slave select shift */ + #define ZYNQ_SPI_FIFO_DEPTH 128 #ifndef CONFIG_SYS_ZYNQ_SPI_WAIT #define CONFIG_SYS_ZYNQ_SPI_WAIT (CONFIG_SYS_HZ/100) /* 10 ms */ @@ -139,7 +143,7 @@ static void spi_cs_activate(struct udevice *dev, uint cs) * xx01 - cs1 * x011 - cs2 */ - cr |= (~(0x1 << cs) << 10) & ZYNQ_SPI_CR_CS_MASK; + cr |= (~(0x1 << cs) << ZYNQ_SPI_CR_SS_SHIFT) & ZYNQ_SPI_CR_CS_MASK; writel(cr, ®s->cr); }
@@ -256,14 +260,14 @@ static int zynq_spi_set_speed(struct udevice *bus, uint speed) /* Set baudrate x8, if the freq is 0 */ baud_rate_val = 0x2; } else if (plat->speed_hz != speed) { - while ((baud_rate_val < 8) && + while ((baud_rate_val < ZYNQ_SPI_CR_BAUD_MAX) && ((plat->frequency / (2 << baud_rate_val)) > speed)) baud_rate_val++; plat->speed_hz = speed / (2 << baud_rate_val); } confr &= ~ZYNQ_SPI_CR_BRD_MASK; - confr |= (baud_rate_val << 3); + confr |= (baud_rate_val << ZYNQ_SPI_CR_BAUD_SHIFT);
writel(confr, ®s->cr); priv->freq = speed;

Rename ZYNQ_SPI_CR_BRD_MASK to ZYNQ_SPI_CR_BAUD_MASK for more readable.
Signed-off-by: Jagan Teki jteki@openedev.com --- drivers/spi/zynq_spi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/spi/zynq_spi.c b/drivers/spi/zynq_spi.c index 817728c..70d7716 100644 --- a/drivers/spi/zynq_spi.c +++ b/drivers/spi/zynq_spi.c @@ -19,7 +19,7 @@ DECLARE_GLOBAL_DATA_PTR; #define ZYNQ_SPI_CR_MSA_MASK (1 << 15) /* Manual start enb */ #define ZYNQ_SPI_CR_MCS_MASK (1 << 14) /* Manual chip select */ #define ZYNQ_SPI_CR_CS_MASK (0xF << 10) /* Chip select */ -#define ZYNQ_SPI_CR_BRD_MASK (0x7 << 3) /* Baud rate div */ +#define ZYNQ_SPI_CR_BAUD_MASK (0x7 << 3) /* Baud rate div */ #define ZYNQ_SPI_CR_CPHA_MASK (1 << 2) /* Clock phase */ #define ZYNQ_SPI_CR_CPOL_MASK (1 << 1) /* Clock polarity */ #define ZYNQ_SPI_CR_MSTREN_MASK (1 << 0) /* Mode select */ @@ -266,7 +266,7 @@ static int zynq_spi_set_speed(struct udevice *bus, uint speed) baud_rate_val++; plat->speed_hz = speed / (2 << baud_rate_val); } - confr &= ~ZYNQ_SPI_CR_BRD_MASK; + confr &= ~ZYNQ_SPI_CR_BAUD_MASK; confr |= (baud_rate_val << ZYNQ_SPI_CR_BAUD_SHIFT);
writel(confr, ®s->cr);

Store cs value into private data and use it while activating chipselect instead of passing through function.
Signed-off-by: Jagan Teki jteki@openedev.com --- drivers/spi/zynq_spi.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/spi/zynq_spi.c b/drivers/spi/zynq_spi.c index 70d7716..70ddd7f 100644 --- a/drivers/spi/zynq_spi.c +++ b/drivers/spi/zynq_spi.c @@ -61,6 +61,7 @@ struct zynq_spi_platdata { /* zynq spi priv */ struct zynq_spi_priv { struct zynq_spi_regs *regs; + u8 cs; u8 mode; u8 fifo_depth; u32 freq; /* required frequency */ @@ -128,7 +129,7 @@ static int zynq_spi_probe(struct udevice *bus) return 0; }
-static void spi_cs_activate(struct udevice *dev, uint cs) +static void spi_cs_activate(struct udevice *dev) { struct udevice *bus = dev->parent; struct zynq_spi_priv *priv = dev_get_priv(bus); @@ -143,7 +144,7 @@ static void spi_cs_activate(struct udevice *dev, uint cs) * xx01 - cs1 * x011 - cs2 */ - cr |= (~(0x1 << cs) << ZYNQ_SPI_CR_SS_SHIFT) & ZYNQ_SPI_CR_CS_MASK; + cr |= (~(1 << priv->cs) << ZYNQ_SPI_CR_SS_SHIFT) & ZYNQ_SPI_CR_CS_MASK; writel(cr, ®s->cr); }
@@ -199,8 +200,9 @@ static int zynq_spi_xfer(struct udevice *dev, unsigned int bitlen, return -1; }
+ priv->cs = slave_plat->cs; if (flags & SPI_XFER_BEGIN) - spi_cs_activate(dev, slave_plat->cs); + spi_cs_activate(dev);
while (rx_len > 0) { /* Write the data into TX FIFO - tx threshold is fifo_depth */
participants (2)
-
Jagan Teki
-
Simon Glass