summaryrefslogtreecommitdiff
path: root/drivers/spi/zynq_qspi.c
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2022-07-26 08:32:37 -0400
committerTom Rini <trini@konsulko.com>2022-07-26 08:32:37 -0400
commite5f6fecda4a606acd2417fb537f331e37c757fa5 (patch)
tree852732e3a6aed34836e1e6650eda62cbbe02eeb2 /drivers/spi/zynq_qspi.c
parent6e15cda270a060cf87c6c643a1cc3da65ffb242d (diff)
parent2a75bc1303b34e88745fcecfeacbe94f2a4bd1e2 (diff)
Merge tag 'xilinx-for-v2022.10-rc2' of https://source.denx.de/u-boot/custodians/u-boot-microblaze
Xilinx changes for v2022.10-rc2 fpga: - Convert SYS_FPGA_CHECK_CTRLC and SYS_FPGA_PROG_FEEDBACK to Kconfig - Add support for secure bitstream loading spi: - xilinx_spi: Add support for memopers and supports_op - zynq_qspi: Add support for supports_op/child_pre_probe - zynq_qspi: Fix dummy cycle and qspi speed calculations xilinx: - Get rid of #stream-id-cells - Use fixed partitions for SOM - Add support for UUID reading from FRU - Use strlcpy instead of strncpy - Add reset driver support for ZynqMP and Versal - Enable power domain driver in ZynqMP and Versal zynqmp: - Do no place BSS at 0 which have issue with NULL pointer - Enable SLG gpio driver - Disable LMB for mini configurations - Remove duplicate PMIO_NODE_ID_BASE macro versal: - Add xlnx-versal-resets.h header mmc: - zynq_sdhci: Fix macro for MMC HS relocate-rela: - Fix support for BE hosts - Define all macros for e_machine and reloc types misc: - Get rid of guard macros from ARM and RISC-V lmb: - Add support for disabling LMB serial: - zynq: Fix baudrate calculation tests: - Mark bind tests to run only on sandbox - List also dm uclass and devres
Diffstat (limited to 'drivers/spi/zynq_qspi.c')
-rw-r--r--drivers/spi/zynq_qspi.c73
1 files changed, 65 insertions, 8 deletions
diff --git a/drivers/spi/zynq_qspi.c b/drivers/spi/zynq_qspi.c
index b69d992b28a..00e3ffcd1df 100644
--- a/drivers/spi/zynq_qspi.c
+++ b/drivers/spi/zynq_qspi.c
@@ -94,6 +94,7 @@ struct zynq_qspi_priv {
u8 mode;
u8 fifo_depth;
u32 freq; /* required frequency */
+ u32 max_hz;
const void *tx_buf;
void *rx_buf;
unsigned len;
@@ -174,6 +175,16 @@ static void zynq_qspi_init_hw(struct zynq_qspi_priv *priv)
writel(ZYNQ_QSPI_ENR_SPI_EN_MASK, &regs->enr);
}
+static int zynq_qspi_child_pre_probe(struct udevice *bus)
+{
+ struct spi_slave *slave = dev_get_parent_priv(bus);
+ struct zynq_qspi_priv *priv = dev_get_priv(bus->parent);
+
+ priv->max_hz = slave->max_hz;
+
+ return 0;
+}
+
static int zynq_qspi_probe(struct udevice *bus)
{
struct zynq_qspi_plat *plat = dev_get_plat(bus);
@@ -611,15 +622,12 @@ static int zynq_qspi_set_speed(struct udevice *bus, uint speed)
uint32_t confr;
u8 baud_rate_val = 0;
- if (speed > plat->frequency)
- speed = plat->frequency;
+ if (!speed || speed > priv->max_hz)
+ speed = priv->max_hz;
/* Set the clock frequency */
confr = readl(&regs->cr);
- if (speed == 0) {
- /* Set baudrate x8, if the freq is 0 */
- baud_rate_val = 0x2;
- } else if (plat->speed_hz != speed) {
+ if (plat->speed_hz != speed) {
while ((baud_rate_val < ZYNQ_QSPI_CR_BAUD_MAX) &&
((plat->frequency /
(2 << baud_rate_val)) > speed))
@@ -668,6 +676,7 @@ static int zynq_qspi_exec_op(struct spi_slave *slave,
const struct spi_mem_op *op)
{
int op_len, pos = 0, ret, i;
+ u32 dummy_bytes = 0;
unsigned int flag = 0;
const u8 *tx_buf = NULL;
u8 *rx_buf = NULL;
@@ -680,6 +689,11 @@ static int zynq_qspi_exec_op(struct spi_slave *slave,
}
op_len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;
+ if (op->dummy.nbytes) {
+ op_len = op->cmd.nbytes + op->addr.nbytes +
+ op->dummy.nbytes / op->dummy.buswidth;
+ dummy_bytes = op->dummy.nbytes / op->dummy.buswidth;
+ }
u8 op_buf[op_len];
@@ -693,8 +707,8 @@ static int zynq_qspi_exec_op(struct spi_slave *slave,
pos += op->addr.nbytes;
}
- if (op->dummy.nbytes)
- memset(op_buf + pos, 0xff, op->dummy.nbytes);
+ if (dummy_bytes)
+ memset(op_buf + pos, 0xff, dummy_bytes);
/* 1st transfer: opcode + address + dummy cycles */
/* Make sure to set END bit if no tx or rx data messages follow */
@@ -719,8 +733,50 @@ static int zynq_qspi_exec_op(struct spi_slave *slave,
return 0;
}
+static int zynq_qspi_check_buswidth(struct spi_slave *slave, u8 width)
+{
+ u32 mode = slave->mode;
+
+ switch (width) {
+ case 1:
+ return 0;
+ case 2:
+ if (mode & SPI_RX_DUAL)
+ return 0;
+ break;
+ case 4:
+ if (mode & SPI_RX_QUAD)
+ return 0;
+ break;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+bool zynq_qspi_mem_exec_op(struct spi_slave *slave,
+ const struct spi_mem_op *op)
+{
+ if (zynq_qspi_check_buswidth(slave, op->cmd.buswidth))
+ return false;
+
+ if (op->addr.nbytes &&
+ zynq_qspi_check_buswidth(slave, op->addr.buswidth))
+ return false;
+
+ if (op->dummy.nbytes &&
+ zynq_qspi_check_buswidth(slave, op->dummy.buswidth))
+ return false;
+
+ if (op->data.dir != SPI_MEM_NO_DATA &&
+ zynq_qspi_check_buswidth(slave, op->data.buswidth))
+ return false;
+
+ return true;
+}
+
static const struct spi_controller_mem_ops zynq_qspi_mem_ops = {
.exec_op = zynq_qspi_exec_op,
+ .supports_op = zynq_qspi_mem_exec_op,
};
static const struct dm_spi_ops zynq_qspi_ops = {
@@ -746,4 +802,5 @@ U_BOOT_DRIVER(zynq_qspi) = {
.plat_auto = sizeof(struct zynq_qspi_plat),
.priv_auto = sizeof(struct zynq_qspi_priv),
.probe = zynq_qspi_probe,
+ .child_pre_probe = zynq_qspi_child_pre_probe,
};