diff options
| author | Tom Rini <[email protected]> | 2022-09-13 09:34:12 -0400 |
|---|---|---|
| committer | Tom Rini <[email protected]> | 2022-09-13 09:34:12 -0400 |
| commit | b3d9c0b6d5895e91b3e6b3566423d09e5a4d5ee8 (patch) | |
| tree | bc8b9e23e3b38ab10bfecbbb4c55df5254f1fb46 /drivers | |
| parent | aa2ef9f525a4d31ec3ae451b927cc714ba926157 (diff) | |
| parent | 39d3c3cfaa4f5099a2d687de4530c9ca4bee256d (diff) | |
Merge tag 'xilinx-for-v2023.01-rc1' of https://source.denx.de/u-boot/custodians/u-boot-microblaze into next
Xilinx changes for v2023.01-rc1
cmd:
- bdinfo - guard LMB code to run only when LMB is enabled
timer:
- convert arm twd timer to DM
power-domain:
- Skip loading config object for Versal
xilinx:
- Fix logic when dfu_alt_info is generated
- Define only mmc devnum not partition
- Add xlnx prefix to GEM compatible string
- Add missing tca6416 to zynqmp SC - vck190
- Add env redund offset
- Enable CMD_GREPENV/SETEXPR by default
- Move board_get_usable_ram_top() to common location
- Add support for SOC detection
net/gem:
- Check rate before setting it up
microblaze:
- drop CONFIG_SYS_INIT_RAM_ADDR and CONFIG_SYS_INIT_RAM_SIZE
- Show cache size in bdinfo
spi:
- cadence_qspi: driver updates
- zynqmp_gqspi: driver updates
- zynqmp_gqspi: Add tap delays for Versal
zynq:
- Enable mkeficapsule compilation
- Use CONFIG_SPL_FS_LOAD_PAYLOAD_NAME for dfu_alt_info
- Align bss and end of u-boot image to 64bits
- Align qspi node name with Linux kernel
- DT: List OCM memory
zynqmp:
- Fix AES cache handling with a user provided key
- SOM: Add mtd partition for secure OS storage area
- Add ref_clk property for REFCLKPER calculation
- Fix mdio bus description for vck190-sc
xilinx-mini:
- Remove unneeded configs
- Disable LMB
versal:
- Enable i2c mux pca954x by default
- Define CONFIG_CQSPI_REF_CLK
- Enable power domain driver
- Enable zynqmp_gqspi driver
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/cpu/microblaze_cpu.c | 4 | ||||
| -rw-r--r-- | drivers/fpga/zynqpl.c | 3 | ||||
| -rw-r--r-- | drivers/net/zynq_gem.c | 11 | ||||
| -rw-r--r-- | drivers/power/domain/zynqmp-power-domain.c | 5 | ||||
| -rw-r--r-- | drivers/spi/cadence_ospi_versal.c | 56 | ||||
| -rw-r--r-- | drivers/spi/cadence_qspi.c | 104 | ||||
| -rw-r--r-- | drivers/spi/cadence_qspi.h | 56 | ||||
| -rw-r--r-- | drivers/spi/cadence_qspi_apb.c | 231 | ||||
| -rw-r--r-- | drivers/spi/zynqmp_gqspi.c | 221 | ||||
| -rw-r--r-- | drivers/timer/Kconfig | 6 | ||||
| -rw-r--r-- | drivers/timer/Makefile | 1 | ||||
| -rw-r--r-- | drivers/timer/arm_twd_timer.c | 108 |
12 files changed, 532 insertions, 274 deletions
diff --git a/drivers/cpu/microblaze_cpu.c b/drivers/cpu/microblaze_cpu.c index 969a1047e59..b9d07928223 100644 --- a/drivers/cpu/microblaze_cpu.c +++ b/drivers/cpu/microblaze_cpu.c @@ -97,8 +97,10 @@ static int microblaze_cpu_get_desc(const struct udevice *dev, char *buf, ret = snprintf(buf, size, "MicroBlaze @ %uMHz, Rev: %s, FPGA family: %s", cpu_freq_mhz, cpu_ver, fpga_family); + if (ret < 0) + return ret; - return 0; + return (ret >= size) ? -ENOSPC : 0; } static int microblaze_cpu_get_info(const struct udevice *dev, diff --git a/drivers/fpga/zynqpl.c b/drivers/fpga/zynqpl.c index d8ebd542abd..0c83df46da4 100644 --- a/drivers/fpga/zynqpl.c +++ b/drivers/fpga/zynqpl.c @@ -413,7 +413,8 @@ static int zynq_load(xilinx_desc *desc, const void *buf, size_t bsize, if (bstype != BIT_PARTIAL) zynq_slcr_devcfg_enable(); - puts("INFO:post config was not run, please run manually if needed\n"); + if (!IS_ENABLED(CONFIG_SPL_BUILD)) + puts("INFO:post config was not run, please run manually if needed\n"); return FPGA_SUCCESS; } diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 4e8dd4badd6..61a6c83e335 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -500,10 +500,13 @@ static int zynq_gem_init(struct udevice *dev) } #endif - ret = clk_set_rate(&priv->tx_clk, clk_rate); - if (IS_ERR_VALUE(ret)) { - dev_err(dev, "failed to set tx clock rate\n"); - return ret; + ret = clk_get_rate(&priv->tx_clk); + if (ret != clk_rate) { + ret = clk_set_rate(&priv->tx_clk, clk_rate); + if (IS_ERR_VALUE(ret)) { + dev_err(dev, "failed to set tx clock rate %ld\n", clk_rate); + return ret; + } } ret = clk_enable(&priv->tx_clk); diff --git a/drivers/power/domain/zynqmp-power-domain.c b/drivers/power/domain/zynqmp-power-domain.c index 6943658be42..adbbb5fdd93 100644 --- a/drivers/power/domain/zynqmp-power-domain.c +++ b/drivers/power/domain/zynqmp-power-domain.c @@ -25,7 +25,10 @@ static int zynqmp_power_domain_request(struct power_domain *power_domain) { dev_dbg(power_domain->dev, "Request for id: %ld\n", power_domain->id); - return zynqmp_pmufw_node(power_domain->id); + if (IS_ENABLED(CONFIG_ARCH_ZYNQMP)) + return zynqmp_pmufw_node(power_domain->id); + + return 0; } static int zynqmp_power_domain_free(struct power_domain *power_domain) diff --git a/drivers/spi/cadence_ospi_versal.c b/drivers/spi/cadence_ospi_versal.c index 52bcad053fe..a25c50bc508 100644 --- a/drivers/spi/cadence_ospi_versal.c +++ b/drivers/spi/cadence_ospi_versal.c @@ -21,7 +21,7 @@ #define CMD_4BYTE_READ 0x13 #define CMD_4BYTE_FAST_READ 0x0C -int cadence_qspi_apb_dma_read(struct cadence_spi_plat *plat, +int cadence_qspi_apb_dma_read(struct cadence_spi_priv *priv, const struct spi_mem_op *op) { u32 reg, ret, rx_rem, n_rx, bytes_to_dma, data; @@ -34,86 +34,86 @@ int cadence_qspi_apb_dma_read(struct cadence_spi_plat *plat, if (bytes_to_dma) { cadence_qspi_apb_enable_linear_mode(false); - reg = readl(plat->regbase + CQSPI_REG_CONFIG); + reg = readl(priv->regbase + CQSPI_REG_CONFIG); reg |= CQSPI_REG_CONFIG_ENBL_DMA; - writel(reg, plat->regbase + CQSPI_REG_CONFIG); + writel(reg, priv->regbase + CQSPI_REG_CONFIG); - writel(bytes_to_dma, plat->regbase + CQSPI_REG_INDIRECTRDBYTES); + writel(bytes_to_dma, priv->regbase + CQSPI_REG_INDIRECTRDBYTES); writel(CQSPI_DFLT_INDIR_TRIG_ADDR_RANGE, - plat->regbase + CQSPI_REG_INDIR_TRIG_ADDR_RANGE); + priv->regbase + CQSPI_REG_INDIR_TRIG_ADDR_RANGE); writel(CQSPI_DFLT_DMA_PERIPH_CFG, - plat->regbase + CQSPI_REG_DMA_PERIPH_CFG); - writel((unsigned long)rxbuf, plat->regbase + + priv->regbase + CQSPI_REG_DMA_PERIPH_CFG); + writel((unsigned long)rxbuf, priv->regbase + CQSPI_DMA_DST_ADDR_REG); - writel(plat->trigger_address, plat->regbase + + writel(priv->trigger_address, priv->regbase + CQSPI_DMA_SRC_RD_ADDR_REG); - writel(bytes_to_dma, plat->regbase + + writel(bytes_to_dma, priv->regbase + CQSPI_DMA_DST_SIZE_REG); flush_dcache_range((unsigned long)rxbuf, (unsigned long)rxbuf + bytes_to_dma); writel(CQSPI_DFLT_DST_CTRL_REG_VAL, - plat->regbase + CQSPI_DMA_DST_CTRL_REG); + priv->regbase + CQSPI_DMA_DST_CTRL_REG); /* Start the indirect read transfer */ - writel(CQSPI_REG_INDIRECTRD_START, plat->regbase + + writel(CQSPI_REG_INDIRECTRD_START, priv->regbase + CQSPI_REG_INDIRECTRD); /* Wait for dma to complete transfer */ - ret = cadence_qspi_apb_wait_for_dma_cmplt(plat); + ret = cadence_qspi_apb_wait_for_dma_cmplt(priv); if (ret) return ret; /* Clear indirect completion status */ - writel(CQSPI_REG_INDIRECTRD_DONE, plat->regbase + + writel(CQSPI_REG_INDIRECTRD_DONE, priv->regbase + CQSPI_REG_INDIRECTRD); rxbuf += bytes_to_dma; } if (rx_rem) { - reg = readl(plat->regbase + CQSPI_REG_CONFIG); + reg = readl(priv->regbase + CQSPI_REG_CONFIG); reg &= ~CQSPI_REG_CONFIG_ENBL_DMA; - writel(reg, plat->regbase + CQSPI_REG_CONFIG); + writel(reg, priv->regbase + CQSPI_REG_CONFIG); - reg = readl(plat->regbase + CQSPI_REG_INDIRECTRDSTARTADDR); + reg = readl(priv->regbase + CQSPI_REG_INDIRECTRDSTARTADDR); reg += bytes_to_dma; - writel(reg, plat->regbase + CQSPI_REG_CMDADDRESS); + writel(reg, priv->regbase + CQSPI_REG_CMDADDRESS); - addr_bytes = readl(plat->regbase + CQSPI_REG_SIZE) & + addr_bytes = readl(priv->regbase + CQSPI_REG_SIZE) & CQSPI_REG_SIZE_ADDRESS_MASK; opcode = CMD_4BYTE_FAST_READ; dummy_cycles = 8; writel((dummy_cycles << CQSPI_REG_RD_INSTR_DUMMY_LSB) | opcode, - plat->regbase + CQSPI_REG_RD_INSTR); + priv->regbase + CQSPI_REG_RD_INSTR); reg = opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB; reg |= (0x1 << CQSPI_REG_CMDCTRL_RD_EN_LSB); reg |= (addr_bytes & CQSPI_REG_CMDCTRL_ADD_BYTES_MASK) << CQSPI_REG_CMDCTRL_ADD_BYTES_LSB; reg |= (0x1 << CQSPI_REG_CMDCTRL_ADDR_EN_LSB); - dummy_cycles = (readl(plat->regbase + CQSPI_REG_RD_INSTR) >> + dummy_cycles = (readl(priv->regbase + CQSPI_REG_RD_INSTR) >> CQSPI_REG_RD_INSTR_DUMMY_LSB) & CQSPI_REG_RD_INSTR_DUMMY_MASK; reg |= (dummy_cycles & CQSPI_REG_CMDCTRL_DUMMY_MASK) << CQSPI_REG_CMDCTRL_DUMMY_LSB; reg |= (((rx_rem - 1) & CQSPI_REG_CMDCTRL_RD_BYTES_MASK) << CQSPI_REG_CMDCTRL_RD_BYTES_LSB); - ret = cadence_qspi_apb_exec_flash_cmd(plat->regbase, reg); + ret = cadence_qspi_apb_exec_flash_cmd(priv->regbase, reg); if (ret) return ret; - data = readl(plat->regbase + CQSPI_REG_CMDREADDATALOWER); + data = readl(priv->regbase + CQSPI_REG_CMDREADDATALOWER); memcpy(rxbuf, &data, rx_rem); } return 0; } -int cadence_qspi_apb_wait_for_dma_cmplt(struct cadence_spi_plat *plat) +int cadence_qspi_apb_wait_for_dma_cmplt(struct cadence_spi_priv *priv) { u32 timeout = CQSPI_DMA_TIMEOUT; - while (!(readl(plat->regbase + CQSPI_DMA_DST_I_STS_REG) & + while (!(readl(priv->regbase + CQSPI_DMA_DST_I_STS_REG) & CQSPI_DMA_DST_I_STS_DONE) && timeout--) udelay(1); @@ -122,13 +122,13 @@ int cadence_qspi_apb_wait_for_dma_cmplt(struct cadence_spi_plat *plat) return -ETIMEDOUT; } - writel(readl(plat->regbase + CQSPI_DMA_DST_I_STS_REG), - plat->regbase + CQSPI_DMA_DST_I_STS_REG); + writel(readl(priv->regbase + CQSPI_DMA_DST_I_STS_REG), + priv->regbase + CQSPI_DMA_DST_I_STS_REG); return 0; } #if defined(CONFIG_DM_GPIO) -int cadence_spi_versal_flash_reset(struct udevice *dev) +int cadence_qspi_versal_flash_reset(struct udevice *dev) { struct gpio_desc gpio; u32 reset_gpio; @@ -169,7 +169,7 @@ int cadence_spi_versal_flash_reset(struct udevice *dev) return 0; } #else -int cadence_spi_versal_flash_reset(struct udevice *dev) +int cadence_qspi_versal_flash_reset(struct udevice *dev) { /* CRP WPROT */ writel(0, WPROT_CRP); diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c index 907f5dadc4f..ab0a681c837 100644 --- a/drivers/spi/cadence_qspi.c +++ b/drivers/spi/cadence_qspi.c @@ -29,7 +29,7 @@ #define CQSPI_READ 2 #define CQSPI_WRITE 3 -__weak int cadence_qspi_apb_dma_read(struct cadence_spi_plat *plat, +__weak int cadence_qspi_apb_dma_read(struct cadence_spi_priv *priv, const struct spi_mem_op *op) { return 0; @@ -42,36 +42,40 @@ __weak int cadence_qspi_versal_flash_reset(struct udevice *dev) static int cadence_spi_write_speed(struct udevice *bus, uint hz) { - struct cadence_spi_plat *plat = dev_get_plat(bus); struct cadence_spi_priv *priv = dev_get_priv(bus); cadence_qspi_apb_config_baudrate_div(priv->regbase, - plat->ref_clk_hz, hz); + priv->ref_clk_hz, hz); /* Reconfigure delay timing if speed is changed. */ - cadence_qspi_apb_delay(priv->regbase, plat->ref_clk_hz, hz, - plat->tshsl_ns, plat->tsd2d_ns, - plat->tchsh_ns, plat->tslch_ns); + cadence_qspi_apb_delay(priv->regbase, priv->ref_clk_hz, hz, + priv->tshsl_ns, priv->tsd2d_ns, + priv->tchsh_ns, priv->tslch_ns); return 0; } -static int cadence_spi_read_id(struct cadence_spi_plat *plat, u8 len, +static int cadence_spi_read_id(struct cadence_spi_priv *priv, u8 len, u8 *idcode) { + int err; + struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(0x9F, 1), SPI_MEM_OP_NO_ADDR, SPI_MEM_OP_NO_DUMMY, SPI_MEM_OP_DATA_IN(len, idcode, 1)); - return cadence_qspi_apb_command_read(plat, &op); + err = cadence_qspi_apb_command_read_setup(priv, &op); + if (!err) + err = cadence_qspi_apb_command_read(priv, &op); + + return err; } /* Calibration sequence to determine the read data capture delay register */ static int spi_calibration(struct udevice *bus, uint hz) { struct cadence_spi_priv *priv = dev_get_priv(bus); - struct cadence_spi_plat *plat = dev_get_plat(bus); void *base = priv->regbase; unsigned int idcode = 0, temp = 0; int err = 0, i, range_lo = -1, range_hi = -1; @@ -86,7 +90,7 @@ static int spi_calibration(struct udevice *bus, uint hz) cadence_qspi_apb_controller_enable(base); /* read the ID which will be our golden value */ - err = cadence_spi_read_id(plat, 3, (u8 *)&idcode); + err = cadence_spi_read_id(priv, 3, (u8 *)&idcode); if (err) { puts("SF: Calibration failed (read)\n"); return err; @@ -105,7 +109,7 @@ static int spi_calibration(struct udevice *bus, uint hz) cadence_qspi_apb_controller_enable(base); /* issue a RDID to get the ID value */ - err = cadence_spi_read_id(plat, 3, (u8 *)&temp); + err = cadence_spi_read_id(priv, 3, (u8 *)&temp); if (err) { puts("SF: Calibration failed (read)\n"); return err; @@ -147,13 +151,11 @@ static int spi_calibration(struct udevice *bus, uint hz) static int cadence_spi_set_speed(struct udevice *bus, uint hz) { - struct cadence_spi_plat *plat = dev_get_plat(bus); struct cadence_spi_priv *priv = dev_get_priv(bus); int err; - if (!hz || hz > plat->max_hz) - hz = plat->max_hz; - + if (!hz || hz > priv->max_hz) + hz = priv->max_hz; /* Disable QSPI */ cadence_qspi_apb_controller_disable(priv->regbase); @@ -161,10 +163,10 @@ static int cadence_spi_set_speed(struct udevice *bus, uint hz) * If the device tree already provides a read delay value, use that * instead of calibrating. */ - if (plat->read_delay >= 0) { + if (priv->read_delay >= 0) { cadence_spi_write_speed(bus, hz); cadence_qspi_apb_readdata_capture(priv->regbase, 1, - plat->read_delay); + priv->read_delay); } else if (priv->previous_hz != hz || priv->qspi_calibrated_hz != hz || priv->qspi_calibrated_cs != spi_chip_select(bus)) { @@ -195,29 +197,44 @@ static int cadence_spi_probe(struct udevice *bus) struct clk clk; int ret; - priv->regbase = plat->regbase; - priv->ahbbase = plat->ahbbase; + priv->regbase = plat->regbase; + priv->ahbbase = plat->ahbbase; + priv->is_dma = plat->is_dma; + priv->is_decoded_cs = plat->is_decoded_cs; + priv->fifo_depth = plat->fifo_depth; + priv->fifo_width = plat->fifo_width; + priv->trigger_address = plat->trigger_address; + priv->read_delay = plat->read_delay; + priv->ahbsize = plat->ahbsize; + priv->max_hz = plat->max_hz; + + priv->page_size = plat->page_size; + priv->block_size = plat->block_size; + priv->tshsl_ns = plat->tshsl_ns; + priv->tsd2d_ns = plat->tsd2d_ns; + priv->tchsh_ns = plat->tchsh_ns; + priv->tslch_ns = plat->tslch_ns; if (CONFIG_IS_ENABLED(ZYNQMP_FIRMWARE)) xilinx_pm_request(PM_REQUEST_NODE, PM_DEV_OSPI, ZYNQMP_PM_CAPABILITY_ACCESS, ZYNQMP_PM_MAX_QOS, ZYNQMP_PM_REQUEST_ACK_NO, NULL); - if (plat->ref_clk_hz == 0) { + if (priv->ref_clk_hz == 0) { ret = clk_get_by_index(bus, 0, &clk); if (ret) { #ifdef CONFIG_HAS_CQSPI_REF_CLK - plat->ref_clk_hz = CONFIG_CQSPI_REF_CLK; + priv->ref_clk_hz = CONFIG_CQSPI_REF_CLK; #elif defined(CONFIG_ARCH_SOCFPGA) - plat->ref_clk_hz = cm_get_qspi_controller_clk_hz(); + priv->ref_clk_hz = cm_get_qspi_controller_clk_hz(); #else return ret; #endif } else { - plat->ref_clk_hz = clk_get_rate(&clk); + priv->ref_clk_hz = clk_get_rate(&clk); clk_free(&clk); - if (IS_ERR_VALUE(plat->ref_clk_hz)) - return plat->ref_clk_hz; + if (IS_ERR_VALUE(priv->ref_clk_hz)) + return priv->ref_clk_hz; } } @@ -226,16 +243,16 @@ static int cadence_spi_probe(struct udevice *bus) reset_deassert_bulk(priv->resets); if (!priv->qspi_is_init) { - cadence_qspi_apb_controller_init(plat); + cadence_qspi_apb_controller_init(priv); priv->qspi_is_init = 1; } - plat->wr_delay = 50 * DIV_ROUND_UP(NSEC_PER_SEC, plat->ref_clk_hz); + priv->wr_delay = 50 * DIV_ROUND_UP(NSEC_PER_SEC, priv->ref_clk_hz); if (CONFIG_IS_ENABLED(ARCH_VERSAL)) { /* Versal platform uses spi calibration to set read delay */ - if (plat->read_delay >= 0) - plat->read_delay = -1; + if (priv->read_delay >= 0) + priv->read_delay = -1; /* Reset ospi flash device */ ret = cadence_qspi_versal_flash_reset(bus); if (ret) @@ -258,7 +275,6 @@ static int cadence_spi_remove(struct udevice *dev) static int cadence_spi_set_mode(struct udevice *bus, uint mode) { - struct cadence_spi_plat *plat = dev_get_plat(bus); struct cadence_spi_priv *priv = dev_get_priv(bus); /* Disable QSPI */ @@ -268,7 +284,7 @@ static int cadence_spi_set_mode(struct udevice *bus, uint mode) cadence_qspi_apb_set_clk_mode(priv->regbase, mode); /* Enable Direct Access Controller */ - if (plat->use_dac_mode) + if (priv->use_dac_mode) cadence_qspi_apb_dac_mode_enable(priv->regbase); /* Enable QSPI */ @@ -281,7 +297,6 @@ static int cadence_spi_mem_exec_op(struct spi_slave *spi, const struct spi_mem_op *op) { struct udevice *bus = spi->dev->parent; - struct cadence_spi_plat *plat = dev_get_plat(bus); struct cadence_spi_priv *priv = dev_get_priv(bus); void *base = priv->regbase; int err = 0; @@ -289,7 +304,7 @@ static int cadence_spi_mem_exec_op(struct spi_slave *spi, /* Set Chip select */ cadence_qspi_apb_chipselect(base, spi_chip_select(spi->dev), - plat->is_decoded_cs); + priv->is_decoded_cs); if (op->data.dir == SPI_MEM_DATA_IN && op->data.buf.in) { if (!op->addr.nbytes) @@ -305,28 +320,28 @@ static int cadence_spi_mem_exec_op(struct spi_slave *spi, switch (mode) { case CQSPI_STIG_READ: - err = cadence_qspi_apb_command_read_setup(plat, op); + err = cadence_qspi_apb_command_read_setup(priv, op); if (!err) - err = cadence_qspi_apb_command_read(plat, op); + err = cadence_qspi_apb_command_read(priv, op); break; case CQSPI_STIG_WRITE: - err = cadence_qspi_apb_command_write_setup(plat, op); + err = cadence_qspi_apb_command_write_setup(priv, op); if (!err) - err = cadence_qspi_apb_command_write(plat, op); + err = cadence_qspi_apb_command_write(priv, op); break; case CQSPI_READ: - err = cadence_qspi_apb_read_setup(plat, op); + err = cadence_qspi_apb_read_setup(priv, op); if (!err) { - if (plat->is_dma) - err = cadence_qspi_apb_dma_read(plat, op); + if (priv->is_dma) + err = cadence_qspi_apb_dma_read(priv, op); else - err = cadence_qspi_apb_read_execute(plat, op); + err = cadence_qspi_apb_read_execute(priv, op); } break; case CQSPI_WRITE: - err = cadence_qspi_apb_write_setup(plat, op); + err = cadence_qspi_apb_write_setup(priv, op); if (!err) - err = cadence_qspi_apb_write_execute(plat, op); + err = cadence_qspi_apb_write_execute(priv, op); break; default: err = -1; @@ -359,6 +374,7 @@ static bool cadence_spi_mem_supports_op(struct spi_slave *slave, static int cadence_spi_of_to_plat(struct udevice *bus) { struct cadence_spi_plat *plat = dev_get_plat(bus); + struct cadence_spi_priv *priv = dev_get_priv(bus); ofnode subnode; plat->regbase = (void *)devfdt_get_addr_index(bus, 0); @@ -372,7 +388,7 @@ static int cadence_spi_of_to_plat(struct udevice *bus) 0); /* Use DAC mode only when MMIO window is at least 8M wide */ if (plat->ahbsize >= SZ_8M) - plat->use_dac_mode = true; + priv->use_dac_mode = true; plat->is_dma = dev_read_bool(bus, "cdns,is-dma"); diff --git a/drivers/spi/cadence_qspi.h b/drivers/spi/cadence_qspi.h index c8d16bb0e44..1c59d1a9d9a 100644 --- a/drivers/spi/cadence_qspi.h +++ b/drivers/spi/cadence_qspi.h @@ -198,7 +198,6 @@ CQSPI_REG_SDRAMLEVEL_WR_LSB) & CQSPI_REG_SDRAMLEVEL_WR_MASK) struct cadence_spi_plat { - unsigned int ref_clk_hz; unsigned int max_hz; void *regbase; void *ahbbase; @@ -209,7 +208,6 @@ struct cadence_spi_plat { fdt_addr_t ahbsize; bool use_dac_mode; int read_delay; - u32 wr_delay; /* Flash parameters */ u32 page_size; @@ -219,17 +217,18 @@ struct cadence_spi_plat { u32 tchsh_ns; u32 tslch_ns; - /* Transaction protocol parameters. */ - u8 inst_width; - u8 addr_width; - u8 data_width; - bool dtr; bool is_dma; }; struct cadence_spi_priv { + unsigned int ref_clk_hz; + unsigned int max_hz; void *regbase; void *ahbbase; + unsigned int fifo_depth; + unsigned int fifo_width; + unsigned int trigger_address; + fdt_addr_t ahbsize; size_t cmd_len; u8 cmd_buf[32]; size_t data_len; @@ -238,32 +237,53 @@ struct cadence_spi_priv { unsigned int qspi_calibrated_hz; unsigned int qspi_calibrated_cs; unsigned int previous_hz; + u32 wr_delay; + int read_delay; struct reset_ctl_bulk *resets; + u32 page_size; + u32 block_size; + u32 tshsl_ns; + u32 tsd2d_ns; + u32 tchsh_ns; + u32 tslch_ns; + u8 edge_mode; + u8 dll_mode; + bool extra_dummy; + bool ddr_init; + bool is_decoded_cs; + bool use_dac_mode; + bool is_dma; + + /* Transaction protocol parameters. */ + u8 inst_width; + u8 addr_width; + u8 data_width; + bool dtr; }; /* Functions call declaration */ -void cadence_qspi_apb_controller_init(struct cadence_spi_plat *plat); +void cadence_qspi_apb_controller_init(struct cadence_spi_priv *priv); void cadence_qspi_apb_controller_enable(void *reg_base_addr); void cadence_qspi_apb_controller_disable(void *reg_base_addr); void cadence_qspi_apb_dac_mode_enable(void *reg_base); -int cadence_qspi_apb_command_read_setup(struct cadence_spi_plat *plat, +int cadence_qspi_apb_command_read_setup(struct cadence_spi_priv *priv, const struct spi_mem_op *op); -int cadence_qspi_apb_command_read(struct cadence_spi_plat *plat, +int cadence_qspi_apb_command_read(struct cadence_spi_priv *priv, const struct spi_mem_op *op); -int cadence_qspi_apb_command_write_setup(struct cadence_spi_plat *plat, +int cadence_qspi_apb_command_write_setup(struct cadence_spi_priv *priv, const struct spi_mem_op *op); -int cadence_qspi_apb_command_write(struct cadence_spi_plat *plat, +int cadence_qspi_apb_command_write(struct cadence_spi_priv *priv, const struct spi_mem_op *op); -int cadence_qspi_apb_read_setup(struct cadence_spi_plat *plat, +int cadence_qspi_apb_read_setup(struct cadence_spi_priv *priv, const struct spi_mem_op *op); -int cadence_qspi_apb_read_execute(struct cadence_spi_plat *plat, +int cadence_qspi_apb_read_execute(struct cadence_spi_priv *priv, const struct spi_mem_op *op); -int cadence_qspi_apb_write_setup(struct cadence_spi_plat *plat, +int cadence_qspi_apb_write_setup(struct cadence_spi_priv *priv, const struct spi_mem_op *op); -int cadence_qspi_apb_write_execute(struct cadence_spi_plat *plat, +int cadence_qspi_apb_write_execute(struct cadence_spi_priv *priv, const struct spi_mem_op *op); void cadence_qspi_apb_chipselect(void *reg_base, @@ -279,9 +299,9 @@ void cadence_qspi_apb_enter_xip(void *reg_base, char xip_dummy); void cadence_qspi_apb_readdata_capture(void *reg_base, unsigned int bypass, unsigned int delay); unsigned int cm_get_qspi_controller_clk_hz(void); -int cadence_qspi_apb_dma_read(struct cadence_spi_plat *plat, +int cadence_qspi_apb_dma_read(struct cadence_spi_priv *priv, const struct spi_mem_op *op); -int cadence_qspi_apb_wait_for_dma_cmplt(struct cadence_spi_plat *plat); +int cadence_qspi_apb_wait_for_dma_cmplt(struct cadence_spi_priv *priv); int cadence_qspi_apb_exec_flash_cmd(void *reg_base, unsigned int reg); int cadence_qspi_versal_flash_reset(struct udevice *dev); void cadence_qspi_apb_enable_linear_mode(bool enable); diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c index c00755050e1..cfae5dcbda0 100644 --- a/drivers/spi/cadence_qspi_apb.c +++ b/drivers/spi/cadence_qspi_apb.c @@ -83,13 +83,13 @@ static unsigned int cadence_qspi_calc_dummy(const struct spi_mem_op *op, return dummy_clk; } -static u32 cadence_qspi_calc_rdreg(struct cadence_spi_plat *plat) +static u32 cadence_qspi_calc_rdreg(struct cadence_spi_priv *priv) { u32 rdreg = 0; - rdreg |= plat->inst_width << CQSPI_REG_RD_INSTR_TYPE_INSTR_LSB; - rdreg |= plat->addr_width << CQSPI_REG_RD_INSTR_TYPE_ADDR_LSB; - rdreg |= plat->data_width << CQSPI_REG_RD_INSTR_TYPE_DATA_LSB; + rdreg |= priv->inst_width << CQSPI_REG_RD_INSTR_TYPE_INSTR_LSB; + rdreg |= priv->addr_width << CQSPI_REG_RD_INSTR_TYPE_ADDR_LSB; + rdreg |= priv->data_width << CQSPI_REG_RD_INSTR_TYPE_DATA_LSB; return rdreg; } @@ -115,27 +115,27 @@ static int cadence_qspi_buswidth_to_inst_type(u8 buswidth) } } -static int cadence_qspi_set_protocol(struct cadence_spi_plat *plat, +static int cadence_qspi_set_protocol(struct cadence_spi_priv *priv, const struct spi_mem_op *op) { int ret; - plat->dtr = op->data.dtr && op->cmd.dtr && op->addr.dtr; + priv->dtr = op->data.dtr && op->cmd.dtr && op->addr.dtr; ret = cadence_qspi_buswidth_to_inst_type(op->cmd.buswidth); if (ret < 0) return ret; - plat->inst_width = ret; + priv->inst_width = ret; ret = cadence_qspi_buswidth_to_inst_type(op->addr.buswidth); if (ret < 0) return ret; - plat->addr_width = ret; + priv->addr_width = ret; ret = cadence_qspi_buswidth_to_inst_type(op->data.buswidth); if (ret < 0) return ret; - plat->data_width = ret; + priv->data_width = ret; return 0; } @@ -314,31 +314,31 @@ void cadence_qspi_apb_delay(void *reg_base, cadence_qspi_apb_controller_enable(reg_base); } -void cadence_qspi_apb_controller_init(struct cadence_spi_plat *plat) +void cadence_qspi_apb_controller_init(struct cadence_spi_priv *priv) { unsigned reg; - cadence_qspi_apb_controller_disable(plat->regbase); + cadence_qspi_apb_controller_disable(priv->regbase); /* Configure the device size and address bytes */ - reg = readl(plat->regbase + CQSPI_REG_SIZE); + reg = readl(priv->regbase + CQSPI_REG_SIZE); /* Clear the previous value */ reg &= ~(CQSPI_REG_SIZE_PAGE_MASK << CQSPI_REG_SIZE_PAGE_LSB); reg &= ~(CQSPI_REG_SIZE_BLOCK_MASK << CQSPI_REG_SIZE_BLOCK_LSB); - reg |= (plat->page_size << CQSPI_REG_SIZE_PAGE_LSB); - reg |= (plat->block_size << CQSPI_REG_SIZE_BLOCK_LSB); - writel(reg, plat->regbase + CQSPI_REG_SIZE); + reg |= (priv->page_size << CQSPI_REG_SIZE_PAGE_LSB); + reg |= (priv->block_size << CQSPI_REG_SIZE_BLOCK_LSB); + writel(reg, priv->regbase + CQSPI_REG_SIZE); /* Configure the remap address register, no remap */ - writel(0, plat->regbase + CQSPI_REG_REMAP); + writel(0, priv->regbase + CQSPI_REG_REMAP); /* Indirect mode configurations */ - writel(plat->fifo_depth / 2, plat->regbase + CQSPI_REG_SRAMPARTITION); + writel(priv->fifo_depth / 2, priv->regbase + CQSPI_REG_SRAMPARTITION); /* Disable all interrupts */ - writel(0, plat->regbase + CQSPI_REG_IRQMASK); + writel(0, priv->regbase + CQSPI_REG_IRQMASK); - cadence_qspi_apb_controller_enable(plat->regbase); + cadence_qspi_apb_controller_enable(priv->regbase); } int cadence_qspi_apb_exec_flash_cmd(void *reg_base, unsigned int reg) @@ -370,7 +370,7 @@ int cadence_qspi_apb_exec_flash_cmd(void *reg_base, unsigned int reg) return 0; } -static int cadence_qspi_setup_opcode_ext(struct cadence_spi_plat *plat, +static int cadence_qspi_setup_opcode_ext(struct cadence_spi_priv *priv, const struct spi_mem_op *op, unsigned int shift) { @@ -383,15 +383,15 @@ static int cadence_qspi_setup_opcode_ext(struct cadence_spi_plat *plat, /* Opcode extension is the LSB. */ ext = op->cmd.opcode & 0xff; - reg = readl(plat->regbase + CQSPI_REG_OP_EXT_LOWER); + reg = readl(priv->regbase + CQSPI_REG_OP_EXT_LOWER); reg &= ~(0xff << shift); reg |= ext << shift; - writel(reg, plat->regbase + CQSPI_REG_OP_EXT_LOWER); + writel(reg, priv->regbase + CQSPI_REG_OP_EXT_LOWER); return 0; } -static int cadence_qspi_enable_dtr(struct cadence_spi_plat *plat, +static int cadence_qspi_enable_dtr(struct cadence_spi_priv *priv, const struct spi_mem_op *op, unsigned int shift, bool enable) @@ -399,14 +399,14 @@ static int cadence_qspi_enable_dtr(struct cadence_spi_plat *plat, unsigned int reg; int ret; - reg = readl(plat->regbase + CQSPI_REG_CONFIG); + reg = readl(priv->regbase + CQSPI_REG_CONFIG); if (enable) { reg |= CQSPI_REG_CONFIG_DTR_PROTO; reg |= CQSPI_REG_CONFIG_DUAL_OPCODE; /* Set up command opcode extension. */ - ret = cadence_qspi_setup_opcode_ext(plat, op, shift); + ret = cadence_qspi_setup_opcode_ext(priv, op, shift); if (ret) return ret; } else { @@ -414,37 +414,37 @@ static int cadence_qspi_enable_dtr(struct cadence_spi_plat *plat, reg &= ~CQSPI_REG_CONFIG_DUAL_OPCODE; } - writel(reg, plat->regbase + CQSPI_REG_CONFIG); + writel(reg, priv->regbase + CQSPI_REG_CONFIG); return 0; } -int cadence_qspi_apb_command_read_setup(struct cadence_spi_plat *plat, +int cadence_qspi_apb_command_read_setup(struct cadence_spi_priv *priv, const struct spi_mem_op *op) { int ret; unsigned int reg; - ret = cadence_qspi_set_protocol(plat, op); + ret = cadence_qspi_set_protocol(priv, op); if (ret) return ret; - ret = cadence_qspi_enable_dtr(plat, op, CQSPI_REG_OP_EXT_STIG_LSB, - plat->dtr); + ret = cadence_qspi_enable_dtr(priv, op, CQSPI_REG_OP_EXT_STIG_LSB, + priv->dtr); if (ret) return ret; - reg = cadence_qspi_calc_rdreg(plat); - writel(reg, plat->regbase + CQSPI_REG_RD_INSTR); + reg = cadence_qspi_calc_rdreg(priv); + writel(reg, priv->regbase + CQSPI_REG_RD_INSTR); return 0; } /* For command RDID, RDSR. */ -int cadence_qspi_apb_command_read(struct cadence_spi_plat *plat, +int cadence_qspi_apb_command_read(struct cadence_spi_priv *priv, const struct spi_mem_op *op) { - void *reg_base = plat->regbase; + void *reg_base = priv->regbase; unsigned int reg; unsigned int read_len; int status; @@ -458,7 +458,7 @@ int cadence_qspi_apb_command_read(struct cadence_spi_plat *plat, return -EINVAL; } - if (plat->dtr) + if (priv->dtr) opcode = op->cmd.opcode >> 8; else opcode = op->cmd.opcode; @@ -466,7 +466,7 @@ int cadence_qspi_apb_command_read(struct cadence_spi_plat *plat, reg = opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB; /* Set up dummy cycles. */ - dummy_clk = cadence_qspi_calc_dummy(op, plat->dtr); + dummy_clk = cadence_qspi_calc_dummy(op, priv->dtr); if (dummy_clk > CQSPI_DUMMY_CLKS_MAX) return -ENOTSUPP; @@ -499,29 +499,29 @@ int cadence_qspi_apb_command_read(struct cadence_spi_plat *plat, return 0; } -int cadence_qspi_apb_command_write_setup(struct cadence_spi_plat *plat, +int cadence_qspi_apb_command_write_setup(struct cadence_spi_priv *priv, const struct spi_mem_op *op) { int ret; unsigned int reg; - ret = cadence_qspi_set_protocol(plat, op); + ret = cadence_qspi_set_protocol(priv, op); if (ret) return ret; - ret = cadence_qspi_enable_dtr(plat, op, CQSPI_REG_OP_EXT_STIG_LSB, - plat->dtr); + ret = cadence_qspi_enable_dtr(priv, op, CQSPI_REG_OP_EXT_STIG_LSB, + priv->dtr); if (ret) return ret; - reg = cadence_qspi_calc_rdreg(plat); - writel(reg, plat->regbase + CQSPI_REG_RD_INSTR); + reg = cadence_qspi_calc_rdreg(priv); + writel(reg, priv->regbase + CQSPI_REG_RD_INSTR); return 0; } /* For commands: WRSR, WREN, WRDI, CHIP_ERASE, BE, etc. */ -int cadence_qspi_apb_command_write(struct cadence_spi_plat *plat, +int cadence_qspi_apb_command_write(struct cadence_spi_priv *priv, const struct spi_mem_op *op) { unsigned int reg = 0; @@ -529,7 +529,7 @@ int cadence_qspi_apb_command_write(struct cadence_spi_plat *plat, unsigned int wr_len; unsigned int txlen = op->data.nbytes; const void *txbuf = op->data.buf.out; - void *reg_base = plat->regbase; + void *reg_base = priv->regbase; u32 addr; u8 opcode; @@ -547,7 +547,7 @@ int cadence_qspi_apb_command_write(struct cadence_spi_plat *plat, return -EINVAL; } - if (plat->dtr) + if (priv->dtr) opcode = op->cmd.opcode >> 8; else opcode = op->cmd.opcode; @@ -579,7 +579,7 @@ int cadence_qspi_apb_command_write(struct cadence_spi_plat *plat, } /* Opcode + Address (3/4 bytes) + dummy bytes (0-4 bytes) */ -int cadence_qspi_apb_read_setup(struct cadence_spi_plat *plat, +int cadence_qspi_apb_read_setup(struct cadence_spi_priv *priv, const struct spi_mem_op *op) { unsigned int reg; @@ -589,33 +589,33 @@ int cadence_qspi_apb_read_setup(struct cadence_spi_plat *plat, int ret; u8 opcode; - ret = cadence_qspi_set_protocol(plat, op); + ret = cadence_qspi_set_protocol(priv, op); if (ret) return ret; - ret = cadence_qspi_enable_dtr(plat, op, CQSPI_REG_OP_EXT_READ_LSB, - plat->dtr); + ret = cadence_qspi_enable_dtr(priv, op, CQSPI_REG_OP_EXT_READ_LSB, + priv->dtr); if (ret) return ret; /* Setup the indirect trigger address */ - writel(plat->trigger_address, - plat->regbase + CQSPI_REG_INDIRECTTRIGGER); + writel(priv->trigger_address, + priv->regbase + CQSPI_REG_INDIRECTTRIGGER); /* Configure the opcode */ - if (plat->dtr) + if (priv->dtr) opcode = op->cmd.opcode >> 8; else opcode = op->cmd.opcode; rd_reg = opcode << CQSPI_REG_RD_INSTR_OPCODE_LSB; - rd_reg |= cadence_qspi_calc_rdreg(plat); + rd_reg |= cadence_qspi_calc_rdreg(priv); - writel(op->addr.val, plat->regbase + CQSPI_REG_INDIRECTRDSTARTADDR); + writel(op->addr.val, priv->regbase + CQSPI_REG_INDIRECTRDSTARTADDR); if (dummy_bytes) { /* Convert to clock cycles. */ - dummy_clk = cadence_qspi_calc_dummy(op, plat->dtr); + dummy_clk = cadence_qspi_calc_dummy(op, priv->dtr); if (dummy_clk > CQSPI_DUMMY_CLKS_MAX) return -ENOTSUPP; @@ -625,30 +625,30 @@ int cadence_qspi_apb_read_setup(struct cadence_spi_plat *plat, << CQSPI_REG_RD_INSTR_DUMMY_LSB; } - writel(rd_reg, plat->regbase + CQSPI_REG_RD_INSTR); + writel(rd_reg, priv->regbase + CQSPI_REG_RD_INSTR); /* set device size */ - reg = readl(plat->regbase + CQSPI_REG_SIZE); + reg = readl(priv->regbase + CQSPI_REG_SIZE); reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK; reg |= (op->addr.nbytes - 1); - writel(reg, plat->regbase + CQSPI_REG_SIZE); + writel(reg, priv->regbase + CQSPI_REG_SIZE); return 0; } -static u32 cadence_qspi_get_rd_sram_level(struct cadence_spi_plat *plat) +static u32 cadence_qspi_get_rd_sram_level(struct cadence_spi_priv *priv) { - u32 reg = readl(plat->regbase + CQSPI_REG_SDRAMLEVEL); + u32 reg = readl(priv->regbase + CQSPI_REG_SDRAMLEVEL); reg >>= CQSPI_REG_SDRAMLEVEL_RD_LSB; return reg & CQSPI_REG_SDRAMLEVEL_RD_MASK; } -static int cadence_qspi_wait_for_data(struct cadence_spi_plat *plat) +static int cadence_qspi_wait_for_data(struct cadence_spi_priv *priv) { unsigned int timeout = 10000; u32 reg; while (timeout--) { - reg = cadence_qspi_get_rd_sram_level(plat); + reg = cadence_qspi_get_rd_sram_level(priv); if (reg) return reg; udelay(1); @@ -658,21 +658,21 @@ static int cadence_qspi_wait_for_data(struct cadence_spi_plat *plat) } static int -cadence_qspi_apb_indirect_read_execute(struct cadence_spi_plat *plat, +cadence_qspi_apb_indirect_read_execute(struct cadence_spi_priv *priv, unsigned int n_rx, u8 *rxbuf) { unsigned int remaining = n_rx; unsigned int bytes_to_read = 0; int ret; - writel(n_rx, plat->regbase + CQSPI_REG_INDIRECTRDBYTES); + writel(n_rx, priv->regbase + CQSPI_REG_INDIRECTRDBYTES); /* Start the indirect read transfer */ writel(CQSPI_REG_INDIRECTRD_START, - plat->regbase + CQSPI_REG_INDIRECTRD); + priv->regbase + CQSPI_REG_INDIRECTRD); while (remaining > 0) { - ret = cadence_qspi_wait_for_data(plat); + ret = cadence_qspi_wait_for_data(priv); if (ret < 0) { printf("Indirect write timed out (%i)\n", ret); goto failrd; @@ -681,7 +681,7 @@ cadence_qspi_apb_indirect_read_execute(struct cadence_spi_plat *plat, bytes_to_read = ret; while (bytes_to_read != 0) { - bytes_to_read *= plat->fifo_width; + bytes_to_read *= priv->fifo_width; bytes_to_read = bytes_to_read > remaining ? remaining : bytes_to_read; /* @@ -689,18 +689,18 @@ cadence_qspi_apb_indirect_read_execute(struct cadence_spi_plat *plat, * data abort. */ if (((uintptr_t)rxbuf % 4) || (bytes_to_read % 4)) - readsb(plat->ahbbase, rxbuf, bytes_to_read); + readsb(priv->ahbbase, rxbuf, bytes_to_read); else - readsl(plat->ahbbase, rxbuf, + readsl(priv->ahbbase, rxbuf, bytes_to_read >> 2); rxbuf += bytes_to_read; remaining -= bytes_to_read; - bytes_to_read = cadence_qspi_get_rd_sram_level(plat); + bytes_to_read = cadence_qspi_get_rd_sram_level(priv); } } /* Check indirect done status */ - ret = wait_for_bit_le32(plat->regbase + CQSPI_REG_INDIRECTRD, + ret = wait_for_bit_le32(priv->regbase + CQSPI_REG_INDIRECTRD, CQSPI_REG_INDIRECTRD_DONE, 1, 10, 0); if (ret) { printf("Indirect read completion error (%i)\n", ret); @@ -709,10 +709,10 @@ cadence_qspi_apb_indirect_read_execute(struct cadence_spi_plat *plat, /* Clear indirect completion status */ writel(CQSPI_REG_INDIRECTRD_DONE, - plat->regbase + CQSPI_REG_INDIRECTRD); + priv->regbase + CQSPI_REG_INDIRECTRD); /* Check indirect done status */ - ret = wait_for_bit_le32(plat->regbase + CQSPI_REG_INDIRECTRD, + ret = wait_for_bit_le32(priv->regbase + CQSPI_REG_INDIRECTRD, CQSPI_REG_INDIRECTRD_DONE, 0, 10, 0); if (ret) { printf("Indirect read clear completion error (%i)\n", ret); @@ -724,11 +724,11 @@ cadence_qspi_apb_indirect_read_execute(struct cadence_spi_plat *plat, failrd: /* Cancel the indirect read */ writel(CQSPI_REG_INDIRECTRD_CANCEL, - plat->regbase + CQSPI_REG_INDIRECTRD); + priv->regbase + CQSPI_REG_INDIRECTRD); return ret; } -int cadence_qspi_apb_read_execute(struct cadence_spi_plat *plat, +int cadence_qspi_apb_read_execute(struct cadence_spi_priv *priv, const struct spi_mem_op *op) { u64 from = op->addr.val; @@ -738,57 +738,57 @@ int cadence_qspi_apb_read_execute(struct cadence_spi_plat *plat, if (CONFIG_IS_ENABLED(ARCH_VERSAL)) cadence_qspi_apb_enable_linear_mode(true); - if (plat->use_dac_mode && (from + len < plat->ahbsize)) { + if (priv->use_dac_mode && (from + len < priv->ahbsize)) { if (len < 256 || - dma_memcpy(buf, plat->ahbbase + from, len) < 0) { - memcpy_fromio(buf, plat->ahbbase + from, len); + dma_memcpy(buf, priv->ahbbase + from, len) < 0) { + memcpy_fromio(buf, priv->ahbbase + from, len); } - if (!cadence_qspi_wait_idle(plat->regbase)) + if (!cadence_qspi_wait_idle(priv->regbase)) return -EIO; return 0; } - return cadence_qspi_apb_indirect_read_execute(plat, len, buf); + return cadence_qspi_apb_indirect_read_execute(priv, len, buf); } /* Opcode + Address (3/4 bytes) */ -int cadence_qspi_apb_write_setup(struct cadence_spi_plat *plat, +int cadence_qspi_apb_write_setup(struct cadence_spi_priv *priv, const struct spi_mem_op *op) { unsigned int reg; int ret; u8 opcode; - ret = cadence_qspi_set_protocol(plat, op); + ret = cadence_qspi_set_protocol(priv, op); if (ret) return ret; - ret = cadence_qspi_enable_dtr(plat, op, CQSPI_REG_OP_EXT_WRITE_LSB, - plat->dtr); + ret = cadence_qspi_enable_dtr(priv, op, CQSPI_REG_OP_EXT_WRITE_LSB, + priv->dtr); if (ret) return ret; /* Setup the indirect trigger address */ - writel(plat->trigger_address, - plat->regbase + CQSPI_REG_INDIRECTTRIGGER); + writel(priv->trigger_address, + priv->regbase + CQSPI_REG_INDIRECTTRIGGER); /* Configure the opcode */ - if (plat->dtr) + if (priv->dtr) opcode = op->cmd.opcode >> 8; else opcode = op->cmd.opcode; reg = opcode << CQSPI_REG_WR_INSTR_OPCODE_LSB; - reg |= plat->data_width << CQSPI_REG_WR_INSTR_TYPE_DATA_LSB; - reg |= plat->addr_width << CQSPI_REG_WR_INSTR_TYPE_ADDR_LSB; - writel(reg, plat->regbase + CQSPI_REG_WR_INSTR); + reg |= priv->data_width << CQSPI_REG_WR_INSTR_TYPE_DATA_LSB; + reg |= priv->addr_width << CQSPI_REG_WR_INSTR_TYPE_ADDR_LSB; + writel(reg, priv->regbase + CQSPI_REG_WR_INSTR); - reg = cadence_qspi_calc_rdreg(plat); - writel(reg, plat->regbase + CQSPI_REG_RD_INSTR); + reg = cadence_qspi_calc_rdreg(priv); + writel(reg, priv->regbase + CQSPI_REG_RD_INSTR); - writel(op->addr.val, plat->regbase + CQSPI_REG_INDIRECTWRSTARTADDR); + writel(op->addr.val, priv->regbase + CQSPI_REG_INDIRECTWRSTARTADDR); - if (plat->dtr) { + if (priv->dtr) { /* * Some flashes like the cypress Semper flash expect a 4-byte * dummy address with the Read SR command in DTR mode, but this @@ -797,23 +797,23 @@ int cadence_qspi_apb_write_setup(struct cadence_spi_plat *plat, * controller's side. spi-nor will take care of polling the * status register. */ - reg = readl(plat->regbase + CQSPI_REG_WR_COMPLETION_CTRL); + reg = readl(priv->regbase + CQSPI_REG_WR_COMPLETION_CTRL); reg |= CQSPI_REG_WR_DISABLE_AUTO_POLL; - writel(reg, plat->regbase + CQSPI_REG_WR_COMPLETION_CTRL); + writel(reg, priv->regbase + CQSPI_REG_WR_COMPLETION_CTRL); } - reg = readl(plat->regbase + CQSPI_REG_SIZE); + reg = readl(priv->regbase + CQSPI_REG_SIZE); reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK; reg |= (op->addr.nbytes - 1); - writel(reg, plat->regbase + CQSPI_REG_SIZE); + writel(reg, priv->regbase + CQSPI_REG_SIZE); return 0; } static int -cadence_qspi_apb_indirect_write_execute(struct cadence_spi_plat *plat, +cadence_qspi_apb_indirect_write_execute(struct cadence_spi_priv *priv, unsigned int n_tx, const u8 *txbuf) { - unsigned int page_size = plat->page_size; + unsigned int page_size = priv->page_size; unsigned int remaining = n_tx; const u8 *bb_txbuf = txbuf; void *bounce_buf = NULL; @@ -833,27 +833,27 @@ cadence_qspi_apb_indirect_write_execute(struct cadence_spi_plat *plat, } /* Configure the indirect read transfer bytes */ - writel(n_tx, plat->regbase + CQSPI_REG_INDIRECTWRBYTES); + writel(n_tx, priv->regbase + CQSPI_REG_INDIRECTWRBYTES); /* Start the indirect write transfer */ writel(CQSPI_REG_INDIRECTWR_START, - plat->regbase + CQSPI_REG_INDIRECTWR); + priv->regbase + CQSPI_REG_INDIRECTWR); /* * Some delay is required for the above bit to be internally * synchronized by the QSPI module. */ - ndelay(plat->wr_delay); + ndelay(priv->wr_delay); while (remaining > 0) { write_bytes = remaining > page_size ? page_size : remaining; - writesl(plat->ahbbase, bb_txbuf, write_bytes >> 2); + writesl(priv->ahbbase, bb_txbuf, write_bytes >> 2); if (write_bytes % 4) - writesb(plat->ahbbase, + writesb(priv->ahbbase, bb_txbuf + rounddown(write_bytes, 4), write_bytes % 4); - ret = wait_for_bit_le32(plat->regbase + CQSPI_REG_SDRAMLEVEL, + ret = wait_for_bit_le32(priv->regbase + CQSPI_REG_SDRAMLEVEL, CQSPI_REG_SDRAMLEVEL_WR_MASK << CQSPI_REG_SDRAMLEVEL_WR_LSB, 0, 10, 0); if (ret) { @@ -866,7 +866,7 @@ cadence_qspi_apb_indirect_write_execute(struct cadence_spi_plat *plat, } /* Check indirect done status */ - ret = wait_for_bit_le32(plat->regbase + CQSPI_REG_INDIRECTWR, + ret = wait_for_bit_le32(priv->regbase + CQSPI_REG_INDIRECTWR, CQSPI_REG_INDIRECTWR_DONE, 1, 10, 0); if (ret) { printf("Indirect write completion error (%i)\n", ret); @@ -875,10 +875,10 @@ cadence_qspi_apb_indirect_write_execute(struct cadence_spi_plat *plat, /* Clear indirect completion status */ writel(CQSPI_REG_INDIRECTWR_DONE, - plat->regbase + CQSPI_REG_INDIRECTWR); + priv->regbase + CQSPI_REG_INDIRECTWR); /* Check indirect done status */ - ret = wait_for_bit_le32(plat->regbase + CQSPI_REG_INDIRECTWR, + ret = wait_for_bit_le32(priv->regbase + CQSPI_REG_INDIRECTWR, CQSPI_REG_INDIRECTWR_DONE, 0, 10, 0); if (ret) { printf("Indirect write clear completion error (%i)\n", ret); @@ -892,13 +892,13 @@ cadence_qspi_apb_indirect_write_execute(struct cadence_spi_plat *plat, failwr: /* Cancel the indirect write */ writel(CQSPI_REG_INDIRECTWR_CANCEL, - plat->regbase + CQSPI_REG_INDIRECTWR); + priv->regbase + CQSPI_REG_INDIRECTWR); if (bounce_buf) free(bounce_buf); return ret; } -int cadence_qspi_apb_write_execute(struct cadence_spi_plat *plat, +int cadence_qspi_apb_write_execute(struct cadence_spi_priv *priv, const struct spi_mem_op *op) { u32 to = op->addr.val; @@ -916,14 +916,15 @@ int cadence_qspi_apb_write_execute(struct cadence_spi_plat *plat, * mode. So, we can not use direct mode when in DTR mode for writing * data. */ - if (!plat->dtr && plat->use_dac_mode && (to + len < plat->ahbsize)) { - memcpy_toio(plat->ahbbase + to, buf, len); - if (!cadence_qspi_wait_idle(plat->regbase)) + cadence_qspi_apb_enable_linear_mode(true); + if (!priv->dtr && priv->use_dac_mode && (to + len < priv->ahbsize)) { + memcpy_toio(priv->ahbbase + to, buf, len); + if (!cadence_qspi_wait_idle(priv->regbase)) return -EIO; return 0; } - return cadence_qspi_apb_indirect_write_execute(plat, len, buf); + return cadence_qspi_apb_indirect_write_execute(priv, len, buf); } void cadence_qspi_apb_enter_xip(void *reg_base, char xip_dummy) diff --git a/drivers/spi/zynqmp_gqspi.c b/drivers/spi/zynqmp_gqspi.c index c772bae3ccf..4e718c545c6 100644 --- a/drivers/spi/zynqmp_gqspi.c +++ b/drivers/spi/zynqmp_gqspi.c @@ -22,6 +22,8 @@ #include <dm/device_compat.h> #include <linux/bitops.h> #include <linux/err.h> +#include <linux/sizes.h> +#include <zynqmp_firmware.h> #define GQSPI_GFIFO_STRT_MODE_MASK BIT(29) #define GQSPI_CONFIG_MODE_EN_MASK (3 << 30) @@ -102,8 +104,10 @@ #define TAP_DLY_BYPASS_LQSPI_RX_VALUE 0x1 #define TAP_DLY_BYPASS_LQSPI_RX_SHIFT 2 #define GQSPI_DATA_DLY_ADJ_OFST 0x000001F8 -#define IOU_TAPDLY_BYPASS_OFST 0xFF180390 +#define IOU_TAPDLY_BYPASS_OFST !IS_ENABLED(CONFIG_ARCH_VERSAL) ? \ + 0xFF180390 : 0xF103003C #define GQSPI_LPBK_DLY_ADJ_LPBK_MASK 0x00000020 +#define GQSPI_FREQ_37_5MHZ 37500000 #define GQSPI_FREQ_40MHZ 40000000 #define GQSPI_FREQ_100MHZ 100000000 #define GQSPI_FREQ_150MHZ 150000000 @@ -163,6 +167,7 @@ struct zynqmp_qspi_plat { struct zynqmp_qspi_dma_regs *dma_regs; u32 frequency; u32 speed_hz; + unsigned int io_mode; }; struct zynqmp_qspi_priv { @@ -171,6 +176,7 @@ struct zynqmp_qspi_priv { const void *tx_buf; void *rx_buf; unsigned int len; + unsigned int io_mode; int bytes_to_transfer; int bytes_to_receive; const struct spi_mem_op *op; @@ -187,6 +193,8 @@ static int zynqmp_qspi_of_to_plat(struct udevice *bus) plat->dma_regs = (struct zynqmp_qspi_dma_regs *) (dev_read_addr(bus) + GQSPI_DMA_REG_OFFSET); + plat->io_mode = dev_read_bool(bus, "has-io-mode"); + return 0; } @@ -206,8 +214,11 @@ static void zynqmp_qspi_init_hw(struct zynqmp_qspi_priv *priv) config_reg = readl(®s->confr); config_reg &= ~(GQSPI_GFIFO_STRT_MODE_MASK | GQSPI_CONFIG_MODE_EN_MASK); - config_reg |= GQSPI_CONFIG_DMA_MODE | GQSPI_GFIFO_WP_HOLD | - GQSPI_DFLT_BAUD_RATE_DIV | GQSPI_GFIFO_STRT_MODE_MASK; + config_reg |= GQSPI_GFIFO_WP_HOLD | GQSPI_DFLT_BAUD_RATE_DIV; + config_reg |= GQSPI_GFIFO_STRT_MODE_MASK; + if (!priv->io_mode) + config_reg |= GQSPI_CONFIG_DMA_MODE; + writel(config_reg, ®s->confr); writel(GQSPI_ENABLE_ENABLE_MASK, ®s->enbr); @@ -297,28 +308,41 @@ void zynqmp_qspi_set_tapdelay(struct udevice *bus, u32 baudrateval) debug("%s, req_hz:%d, clk_rate:%d, baudrateval:%d\n", __func__, reqhz, clk_rate, baudrateval); - if (reqhz < GQSPI_FREQ_40MHZ) { - zynqmp_mmio_read(IOU_TAPDLY_BYPASS_OFST, &tapdlybypass); - tapdlybypass |= (TAP_DLY_BYPASS_LQSPI_RX_VALUE << - TAP_DLY_BYPASS_LQSPI_RX_SHIFT); - } else if (reqhz <= GQSPI_FREQ_100MHZ) { - zynqmp_mmio_read(IOU_TAPDLY_BYPASS_OFST, &tapdlybypass); - tapdlybypass |= (TAP_DLY_BYPASS_LQSPI_RX_VALUE << - TAP_DLY_BYPASS_LQSPI_RX_SHIFT); - lpbkdlyadj = readl(®s->lpbkdly); - lpbkdlyadj |= (GQSPI_LPBK_DLY_ADJ_LPBK_MASK); - datadlyadj = readl(®s->gqspidlyadj); - datadlyadj |= ((GQSPI_USE_DATA_DLY << GQSPI_USE_DATA_DLY_SHIFT) - | (GQSPI_DATA_DLY_ADJ_VALUE << - GQSPI_DATA_DLY_ADJ_SHIFT)); - } else if (reqhz <= GQSPI_FREQ_150MHZ) { - lpbkdlyadj = readl(®s->lpbkdly); - lpbkdlyadj |= ((GQSPI_LPBK_DLY_ADJ_LPBK_MASK) | - GQSPI_LPBK_DLY_ADJ_DLY_0); + if (!IS_ENABLED(CONFIG_ARCH_VERSAL)) { + if (reqhz <= GQSPI_FREQ_40MHZ) { + tapdlybypass = TAP_DLY_BYPASS_LQSPI_RX_VALUE << + TAP_DLY_BYPASS_LQSPI_RX_SHIFT; + } else if (reqhz <= GQSPI_FREQ_100MHZ) { + tapdlybypass = TAP_DLY_BYPASS_LQSPI_RX_VALUE << + TAP_DLY_BYPASS_LQSPI_RX_SHIFT; + lpbkdlyadj = GQSPI_LPBK_DLY_ADJ_LPBK_MASK; + datadlyadj = (GQSPI_USE_DATA_DLY << + GQSPI_USE_DATA_DLY_SHIFT) | + (GQSPI_DATA_DLY_ADJ_VALUE << + GQSPI_DATA_DLY_ADJ_SHIFT); + } else if (reqhz <= GQSPI_FREQ_150MHZ) { + lpbkdlyadj = GQSPI_LPBK_DLY_ADJ_LPBK_MASK | + GQSPI_LPBK_DLY_ADJ_DLY_0; + } + zynqmp_mmio_write(IOU_TAPDLY_BYPASS_OFST, + IOU_TAPDLY_BYPASS_MASK, tapdlybypass); + } else { + if (reqhz <= GQSPI_FREQ_37_5MHZ) { + tapdlybypass = TAP_DLY_BYPASS_LQSPI_RX_VALUE << + TAP_DLY_BYPASS_LQSPI_RX_SHIFT; + } else if (reqhz <= GQSPI_FREQ_100MHZ) { + tapdlybypass = TAP_DLY_BYPASS_LQSPI_RX_VALUE << + TAP_DLY_BYPASS_LQSPI_RX_SHIFT; + lpbkdlyadj = GQSPI_LPBK_DLY_ADJ_LPBK_MASK; + datadlyadj = GQSPI_USE_DATA_DLY << + GQSPI_USE_DATA_DLY_SHIFT; + } else if (reqhz <= GQSPI_FREQ_150MHZ) { + lpbkdlyadj = GQSPI_LPBK_DLY_ADJ_LPBK_MASK | + (GQSPI_LPBK_DLY_ADJ_DLY_1 << + GQSPI_LPBK_DLY_ADJ_DLY_1_SHIFT); + } + writel(tapdlybypass, IOU_TAPDLY_BYPASS_OFST); } - - zynqmp_mmio_write(IOU_TAPDLY_BYPASS_OFST, IOU_TAPDLY_BYPASS_MASK, - tapdlybypass); writel(lpbkdlyadj, ®s->lpbkdly); writel(datadlyadj, ®s->gqspidlyadj); } @@ -372,6 +396,7 @@ static int zynqmp_qspi_probe(struct udevice *bus) priv->regs = plat->regs; priv->dma_regs = plat->dma_regs; + priv->io_mode = plat->io_mode; ret = clk_get_by_index(bus, 0, &clk); if (ret < 0) { @@ -409,8 +434,7 @@ static int zynqmp_qspi_set_mode(struct udevice *bus, uint mode) debug("%s\n", __func__); /* Set the SPI Clock phase and polarities */ confr = readl(®s->confr); - confr &= ~(GQSPI_CONFIG_CPHA_MASK | - GQSPI_CONFIG_CPOL_MASK); + confr &= ~(GQSPI_CONFIG_CPHA_MASK | GQSPI_CONFIG_CPOL_MASK); if (mode & SPI_CPHA) confr |= GQSPI_CONFIG_CPHA_MASK; @@ -554,8 +578,7 @@ static int zynqmp_qspi_genfifo_fill_tx(struct zynqmp_qspi_priv *priv) gen_fifo_cmd = zynqmp_qspi_bus_select(priv); gen_fifo_cmd |= zynqmp_qspi_genfifo_mode(priv->op->data.buswidth); - gen_fifo_cmd |= GQSPI_GFIFO_TX | - GQSPI_GFIFO_DATA_XFR_MASK; + gen_fifo_cmd |= GQSPI_GFIFO_TX | GQSPI_GFIFO_DATA_XFR_MASK; while (priv->len) { len = zynqmp_qspi_calc_exp(priv, &gen_fifo_cmd); @@ -564,11 +587,9 @@ static int zynqmp_qspi_genfifo_fill_tx(struct zynqmp_qspi_priv *priv) 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); + ret = zynqmp_qspi_fill_tx_fifo(priv, 1 << len); else - ret = zynqmp_qspi_fill_tx_fifo(priv, - len); + ret = zynqmp_qspi_fill_tx_fifo(priv, len); if (ret) return ret; @@ -576,44 +597,119 @@ static int zynqmp_qspi_genfifo_fill_tx(struct zynqmp_qspi_priv *priv) 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, u32 gen_fifo_cmd, u32 *buf) { u32 addr; u32 size; u32 actuallen = priv->len; + u32 totallen = 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, GQSPI_DMA_ALIGN), &dma_regs->dmasize); - writel(GQSPI_DMA_DST_I_STS_MASK, &dma_regs->dmaier); - addr = (unsigned long)buf; - size = roundup(priv->len, GQSPI_DMA_ALIGN); - flush_dcache_range(addr, addr + size); + while (totallen) { + if (totallen >= SZ_512M) + priv->len = SZ_256M; + else + priv->len = totallen; - while (priv->len) { - zynqmp_qspi_calc_exp(priv, &gen_fifo_cmd); - zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd); + totallen -= priv->len; /* Save remaining bytes length to read */ + actuallen = priv->len; /* Actual number of bytes reading */ - debug("GFIFO_CMD_RX:0x%x\n", gen_fifo_cmd); - } + writel((unsigned long)buf, &dma_regs->dmadst); + writel(roundup(priv->len, GQSPI_DMA_ALIGN), &dma_regs->dmasize); + writel(GQSPI_DMA_DST_I_STS_MASK, &dma_regs->dmaier); + addr = (unsigned long)buf; + size = roundup(priv->len, GQSPI_DMA_ALIGN); + flush_dcache_range(addr, addr + size); - 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 -ETIMEDOUT; - } + while (priv->len) { + zynqmp_qspi_calc_exp(priv, &gen_fifo_cmd); + 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 -ETIMEDOUT; + } - writel(GQSPI_DMA_DST_I_STS_DONE, &dma_regs->dmaisr); + 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); + 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); + if (buf != priv->rx_buf) + memcpy(priv->rx_buf, buf, actuallen); + + buf = (u32 *)((u8 *)buf + actuallen); + priv->rx_buf = (u8 *)priv->rx_buf + actuallen; + } return 0; } @@ -626,21 +722,22 @@ static int zynqmp_qspi_genfifo_fill_rx(struct zynqmp_qspi_priv *priv) gen_fifo_cmd = zynqmp_qspi_bus_select(priv); gen_fifo_cmd |= zynqmp_qspi_genfifo_mode(priv->op->data.buswidth); - gen_fifo_cmd |= GQSPI_GFIFO_RX | - GQSPI_GFIFO_DATA_XFR_MASK; + gen_fifo_cmd |= GQSPI_GFIFO_RX | GQSPI_GFIFO_DATA_XFR_MASK; /* * 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)) { + if ((!((unsigned long)priv->rx_buf & (GQSPI_DMA_ALIGN - 1)) && + !(actuallen % GQSPI_DMA_ALIGN)) || priv->io_mode) { 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, - GQSPI_DMA_ALIGN)); + 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); } diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 40492901481..1b492360396 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -73,6 +73,12 @@ config ARC_TIMER usually at least one of them exists. Either of them is supported in U-Boot. +config ARM_TWD_TIMER + bool "ARM timer watchdog (TWD) timer support" + depends on TIMER && CLK + help + Select this to enable support for the ARM global timer watchdog timer. + config AST_TIMER bool "Aspeed ast2400/ast2500 timer support" depends on TIMER diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile index 560e2d27e14..7bfb7749e97 100644 --- a/drivers/timer/Makefile +++ b/drivers/timer/Makefile @@ -6,6 +6,7 @@ obj-y += timer-uclass.o obj-$(CONFIG_ALTERA_TIMER) += altera_timer.o obj-$(CONFIG_ANDES_PLMT_TIMER) += andes_plmt_timer.o obj-$(CONFIG_ARC_TIMER) += arc_timer.o +obj-$(CONFIG_ARM_TWD_TIMER) += arm_twd_timer.o obj-$(CONFIG_AST_TIMER) += ast_timer.o obj-$(CONFIG_ATCPIT100_TIMER) += atcpit100_timer.o obj-$(CONFIG_$(SPL_)ATMEL_PIT_TIMER) += atmel_pit_timer.o diff --git a/drivers/timer/arm_twd_timer.c b/drivers/timer/arm_twd_timer.c new file mode 100644 index 00000000000..40ccd165874 --- /dev/null +++ b/drivers/timer/arm_twd_timer.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2017-2022 Weidmüller Interface GmbH & Co. KG + * Stefan Herbrechtsmeier <[email protected]> + * + * Copyright (C) 2012 Michal Simek <[email protected]> + * Copyright (C) 2011-2017 Xilinx, Inc. All rights reserved. + * + * (C) Copyright 2008 + * Guennadi Liakhovetki, DENX Software Engineering, <[email protected]> + * + * (C) Copyright 2004 + * Philippe Robin, ARM Ltd. <[email protected]> + * + * (C) Copyright 2002-2004 + * Gary Jennejohn, DENX Software Engineering, <[email protected]> + * + * (C) Copyright 2003 + * Texas Instruments <www.ti.com> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <[email protected]> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Alex Zuepke <[email protected]> + */ + +#include <common.h> +#include <dm.h> +#include <fdtdec.h> +#include <timer.h> +#include <linux/bitops.h> + +#include <asm/io.h> + +#define SCUTIMER_CONTROL_PRESCALER_MASK 0x0000FF00 /* Prescaler */ +#define SCUTIMER_CONTROL_AUTO_RELOAD_MASK 0x00000002 /* Auto-reload */ +#define SCUTIMER_CONTROL_ENABLE_MASK 0x00000001 /* Timer enable */ + +#define TIMER_LOAD_VAL 0xFFFFFFFF + +struct arm_twd_timer_regs { + u32 load; /* Timer Load Register */ + u32 counter; /* Timer Counter Register */ + u32 control; /* Timer Control Register */ +}; + +struct arm_twd_timer_priv { + struct arm_twd_timer_regs *base; +}; + +static u64 arm_twd_timer_get_count(struct udevice *dev) +{ + struct arm_twd_timer_priv *priv = dev_get_priv(dev); + struct arm_twd_timer_regs *regs = priv->base; + u32 count = TIMER_LOAD_VAL - readl(®s->counter); + + return timer_conv_64(count); +} + +static int arm_twd_timer_probe(struct udevice *dev) +{ + struct arm_twd_timer_priv *priv = dev_get_priv(dev); + struct arm_twd_timer_regs *regs; + fdt_addr_t addr; + + addr = dev_read_addr(dev); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->base = (struct arm_twd_timer_regs *)addr; + + regs = priv->base; + + /* Load the timer counter register */ + writel(0xFFFFFFFF, ®s->load); + + /* + * Start the A9Timer device + * Enable Auto reload mode, Clear prescaler control bits + * Set prescaler value, Enable the decrementer + */ + clrsetbits_le32(®s->control, SCUTIMER_CONTROL_PRESCALER_MASK, + SCUTIMER_CONTROL_AUTO_RELOAD_MASK | + SCUTIMER_CONTROL_ENABLE_MASK); + + return 0; +} + +static const struct timer_ops arm_twd_timer_ops = { + .get_count = arm_twd_timer_get_count, +}; + +static const struct udevice_id arm_twd_timer_ids[] = { + { .compatible = "arm,cortex-a9-twd-timer" }, + {} +}; + +U_BOOT_DRIVER(arm_twd_timer) = { + .name = "arm_twd_timer", + .id = UCLASS_TIMER, + .of_match = arm_twd_timer_ids, + .priv_auto = sizeof(struct arm_twd_timer_priv), + .probe = arm_twd_timer_probe, + .ops = &arm_twd_timer_ops, +}; |
