#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)
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;
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
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;
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 {
data |= 0xFF000000;
break;
}
- writel(data, &zynqmp_qspi_base->txd0r);
+ writel(data, ®s->txd0r);
size = 0;
}
} else {
}
}
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)
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)
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;
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.
* 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,
+};