mirror of
https://github.com/smaeul/u-boot.git
synced 2025-10-17 14:18:14 +01:00
spi: zynqmp_gqspi: Add support for IO mode
Add support for io-mode transfers. This is necessary for UBIFS to work properly with spi-nor devices. The driver will work in IO mode when "has-io-mode" is passed from device tree instead of DMA. Signed-off-by: Ashok Reddy Soma <ashok.reddy.soma@amd.com> Link: https://lore.kernel.org/r/20220825125906.11581-4-ashok.reddy.soma@amd.com Signed-off-by: Michal Simek <michal.simek@amd.com>
This commit is contained in:
parent
9e89e30d4d
commit
d91b0f4a18
@ -166,6 +166,7 @@ struct zynqmp_qspi_plat {
|
|||||||
struct zynqmp_qspi_dma_regs *dma_regs;
|
struct zynqmp_qspi_dma_regs *dma_regs;
|
||||||
u32 frequency;
|
u32 frequency;
|
||||||
u32 speed_hz;
|
u32 speed_hz;
|
||||||
|
unsigned int io_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct zynqmp_qspi_priv {
|
struct zynqmp_qspi_priv {
|
||||||
@ -174,6 +175,7 @@ struct zynqmp_qspi_priv {
|
|||||||
const void *tx_buf;
|
const void *tx_buf;
|
||||||
void *rx_buf;
|
void *rx_buf;
|
||||||
unsigned int len;
|
unsigned int len;
|
||||||
|
unsigned int io_mode;
|
||||||
int bytes_to_transfer;
|
int bytes_to_transfer;
|
||||||
int bytes_to_receive;
|
int bytes_to_receive;
|
||||||
const struct spi_mem_op *op;
|
const struct spi_mem_op *op;
|
||||||
@ -190,6 +192,8 @@ static int zynqmp_qspi_of_to_plat(struct udevice *bus)
|
|||||||
plat->dma_regs = (struct zynqmp_qspi_dma_regs *)
|
plat->dma_regs = (struct zynqmp_qspi_dma_regs *)
|
||||||
(dev_read_addr(bus) + GQSPI_DMA_REG_OFFSET);
|
(dev_read_addr(bus) + GQSPI_DMA_REG_OFFSET);
|
||||||
|
|
||||||
|
plat->io_mode = dev_read_bool(bus, "has-io-mode");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,8 +213,11 @@ static void zynqmp_qspi_init_hw(struct zynqmp_qspi_priv *priv)
|
|||||||
config_reg = readl(®s->confr);
|
config_reg = readl(®s->confr);
|
||||||
config_reg &= ~(GQSPI_GFIFO_STRT_MODE_MASK |
|
config_reg &= ~(GQSPI_GFIFO_STRT_MODE_MASK |
|
||||||
GQSPI_CONFIG_MODE_EN_MASK);
|
GQSPI_CONFIG_MODE_EN_MASK);
|
||||||
config_reg |= GQSPI_CONFIG_DMA_MODE | GQSPI_GFIFO_WP_HOLD |
|
config_reg |= GQSPI_GFIFO_WP_HOLD | GQSPI_DFLT_BAUD_RATE_DIV;
|
||||||
GQSPI_DFLT_BAUD_RATE_DIV | GQSPI_GFIFO_STRT_MODE_MASK;
|
config_reg |= GQSPI_GFIFO_STRT_MODE_MASK;
|
||||||
|
if (!priv->io_mode)
|
||||||
|
config_reg |= GQSPI_CONFIG_DMA_MODE;
|
||||||
|
|
||||||
writel(config_reg, ®s->confr);
|
writel(config_reg, ®s->confr);
|
||||||
|
|
||||||
writel(GQSPI_ENABLE_ENABLE_MASK, ®s->enbr);
|
writel(GQSPI_ENABLE_ENABLE_MASK, ®s->enbr);
|
||||||
@ -388,6 +395,7 @@ static int zynqmp_qspi_probe(struct udevice *bus)
|
|||||||
|
|
||||||
priv->regs = plat->regs;
|
priv->regs = plat->regs;
|
||||||
priv->dma_regs = plat->dma_regs;
|
priv->dma_regs = plat->dma_regs;
|
||||||
|
priv->io_mode = plat->io_mode;
|
||||||
|
|
||||||
ret = clk_get_by_index(bus, 0, &clk);
|
ret = clk_get_by_index(bus, 0, &clk);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@ -592,6 +600,66 @@ static int zynqmp_qspi_genfifo_fill_tx(struct zynqmp_qspi_priv *priv)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int zynqmp_qspi_start_io(struct zynqmp_qspi_priv *priv,
|
||||||
|
u32 gen_fifo_cmd, u32 *buf)
|
||||||
|
{
|
||||||
|
u32 len;
|
||||||
|
u32 actuallen = priv->len;
|
||||||
|
u32 config_reg, ier, isr;
|
||||||
|
u32 timeout = GQSPI_TIMEOUT;
|
||||||
|
struct zynqmp_qspi_regs *regs = priv->regs;
|
||||||
|
u32 last_bits;
|
||||||
|
u32 *traverse = buf;
|
||||||
|
|
||||||
|
while (priv->len) {
|
||||||
|
len = zynqmp_qspi_calc_exp(priv, &gen_fifo_cmd);
|
||||||
|
/* If exponent bit is set, reset immediate to be 2^len */
|
||||||
|
if (gen_fifo_cmd & GQSPI_GFIFO_EXP_MASK)
|
||||||
|
priv->bytes_to_receive = (1 << len);
|
||||||
|
else
|
||||||
|
priv->bytes_to_receive = len;
|
||||||
|
zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd);
|
||||||
|
debug("GFIFO_CMD_RX:0x%x\n", gen_fifo_cmd);
|
||||||
|
/* Manual start */
|
||||||
|
config_reg = readl(®s->confr);
|
||||||
|
config_reg |= GQSPI_STRT_GEN_FIFO;
|
||||||
|
writel(config_reg, ®s->confr);
|
||||||
|
/* Enable RX interrupts for IO mode */
|
||||||
|
ier = readl(®s->ier);
|
||||||
|
ier |= GQSPI_IXR_ALL_MASK;
|
||||||
|
writel(ier, ®s->ier);
|
||||||
|
while (priv->bytes_to_receive && timeout) {
|
||||||
|
isr = readl(®s->isr);
|
||||||
|
if (isr & GQSPI_IXR_RXNEMTY_MASK) {
|
||||||
|
if (priv->bytes_to_receive >= 4) {
|
||||||
|
*traverse = readl(®s->drxr);
|
||||||
|
traverse++;
|
||||||
|
priv->bytes_to_receive -= 4;
|
||||||
|
} else {
|
||||||
|
last_bits = readl(®s->drxr);
|
||||||
|
memcpy(traverse, &last_bits,
|
||||||
|
priv->bytes_to_receive);
|
||||||
|
priv->bytes_to_receive = 0;
|
||||||
|
}
|
||||||
|
timeout = GQSPI_TIMEOUT;
|
||||||
|
} else {
|
||||||
|
udelay(1);
|
||||||
|
timeout--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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("IO timeout: %d\n", readl(®s->isr));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int zynqmp_qspi_start_dma(struct zynqmp_qspi_priv *priv,
|
static int zynqmp_qspi_start_dma(struct zynqmp_qspi_priv *priv,
|
||||||
u32 gen_fifo_cmd, u32 *buf)
|
u32 gen_fifo_cmd, u32 *buf)
|
||||||
{
|
{
|
||||||
@ -649,10 +717,13 @@ static int zynqmp_qspi_genfifo_fill_rx(struct zynqmp_qspi_priv *priv)
|
|||||||
* Check if receive buffer is aligned to 4 byte and length
|
* Check if receive buffer is aligned to 4 byte and length
|
||||||
* is multiples of four byte as we are using dma to receive.
|
* is multiples of four byte as we are using dma to receive.
|
||||||
*/
|
*/
|
||||||
if (!((unsigned long)priv->rx_buf & (GQSPI_DMA_ALIGN - 1)) &&
|
if ((!((unsigned long)priv->rx_buf & (GQSPI_DMA_ALIGN - 1)) &&
|
||||||
!(actuallen % GQSPI_DMA_ALIGN)) {
|
!(actuallen % GQSPI_DMA_ALIGN)) || priv->io_mode) {
|
||||||
buf = (u32 *)priv->rx_buf;
|
buf = (u32 *)priv->rx_buf;
|
||||||
return zynqmp_qspi_start_dma(priv, gen_fifo_cmd, buf);
|
if (priv->io_mode)
|
||||||
|
return zynqmp_qspi_start_io(priv, gen_fifo_cmd, buf);
|
||||||
|
else
|
||||||
|
return zynqmp_qspi_start_dma(priv, gen_fifo_cmd, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
ALLOC_CACHE_ALIGN_BUFFER(u8, tmp, roundup(priv->len,
|
ALLOC_CACHE_ALIGN_BUFFER(u8, tmp, roundup(priv->len,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user