From f1fd79afad97df76f0d84847d98d80d5a8c7e4ec Mon Sep 17 00:00:00 2001 From: Brandon Maier Date: Wed, 20 Jan 2021 10:39:46 -0600 Subject: [PATCH 01/14] spi: zynqmp_gqspi: support dual and quad mode The dm_spi_ops.xfer() API does not support dual and quad SPI modes. It also doesn't allow the zynqmp_gqspi driver to calculate the correct number of dummy cycles for some NOR ops (as doing so also requires the buswidth). Port the zynqmp_gqspi driver to spi_controller_mem_ops, which gives us the buswidth values to correctly support all SNOR_PROTO_X_X_X commands and to properly calculate dummy cycles. Signed-off-by: Brandon Maier CC: jagan@amarulasolutions.com CC: michal.simek@xilinx.com CC: Ashok Reddy Soma Reviewed-by: Bin Meng Reviewed-by: Ashok Reddy Soma Signed-off-by: Michal Simek --- drivers/spi/zynqmp_gqspi.c | 164 ++++++++++++++++--------------------- 1 file changed, 70 insertions(+), 94 deletions(-) diff --git a/drivers/spi/zynqmp_gqspi.c b/drivers/spi/zynqmp_gqspi.c index efcbd0557f..c7db43a09a 100644 --- a/drivers/spi/zynqmp_gqspi.c +++ b/drivers/spi/zynqmp_gqspi.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -171,8 +172,7 @@ struct zynqmp_qspi_priv { unsigned int len; int bytes_to_transfer; int bytes_to_receive; - unsigned int is_inst; - unsigned int cs_change:1; + const struct spi_mem_op *op; }; static int zynqmp_qspi_of_to_plat(struct udevice *bus) @@ -221,6 +221,21 @@ static u32 zynqmp_qspi_bus_select(struct zynqmp_qspi_priv *priv) return gqspi_fifo_reg; } +static u32 zynqmp_qspi_genfifo_mode(u8 buswidth) +{ + switch (buswidth) { + case 1: + return GQSPI_SPI_MODE_SPI; + case 2: + return GQSPI_SPI_MODE_DUAL_SPI; + case 4: + return GQSPI_SPI_MODE_QSPI; + default: + debug("Unsupported bus width %u\n", buswidth); + return GQSPI_SPI_MODE_SPI; + } +} + static void zynqmp_qspi_fill_gen_fifo(struct zynqmp_qspi_priv *priv, u32 gqspi_fifo_reg) { @@ -445,21 +460,42 @@ static int zynqmp_qspi_fill_tx_fifo(struct zynqmp_qspi_priv *priv, u32 size) static void zynqmp_qspi_genfifo_cmd(struct zynqmp_qspi_priv *priv) { + const struct spi_mem_op *op = priv->op; u32 gen_fifo_cmd; - u32 bytecount = 0; + u8 i, dummy_cycles, addr; + + /* Send opcode */ + gen_fifo_cmd = zynqmp_qspi_bus_select(priv); + gen_fifo_cmd |= zynqmp_qspi_genfifo_mode(op->cmd.buswidth); + gen_fifo_cmd |= GQSPI_GFIFO_TX; + gen_fifo_cmd |= op->cmd.opcode; + zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd); + + /* Send address */ + for (i = 0; i < op->addr.nbytes; i++) { + addr = op->addr.val >> (8 * (op->addr.nbytes - i - 1)); - while (priv->len) { gen_fifo_cmd = zynqmp_qspi_bus_select(priv); - gen_fifo_cmd |= GQSPI_GFIFO_TX | GQSPI_SPI_MODE_SPI; - gen_fifo_cmd |= *(u8 *)priv->tx_buf; - bytecount++; - priv->len--; - priv->tx_buf = (u8 *)priv->tx_buf + 1; + gen_fifo_cmd |= zynqmp_qspi_genfifo_mode(op->addr.buswidth); + gen_fifo_cmd |= GQSPI_GFIFO_TX; + gen_fifo_cmd |= addr; debug("GFIFO_CMD_Cmd = 0x%x\n", gen_fifo_cmd); zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd); } + + /* Send dummy */ + if (op->dummy.nbytes) { + dummy_cycles = op->dummy.nbytes * 8 / op->dummy.buswidth; + + gen_fifo_cmd = zynqmp_qspi_bus_select(priv); + gen_fifo_cmd |= zynqmp_qspi_genfifo_mode(op->dummy.buswidth); + gen_fifo_cmd &= ~(GQSPI_GFIFO_TX | GQSPI_GFIFO_RX); + gen_fifo_cmd |= GQSPI_GFIFO_DATA_XFR_MASK; + gen_fifo_cmd |= dummy_cycles; + zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd); + } } static u32 zynqmp_qspi_calc_exp(struct zynqmp_qspi_priv *priv, @@ -496,11 +532,10 @@ static int zynqmp_qspi_genfifo_fill_tx(struct zynqmp_qspi_priv *priv) int ret = 0; 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_SPI_MODE_SPI; - while (priv->len) { len = zynqmp_qspi_calc_exp(priv, &gen_fifo_cmd); zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd); @@ -574,11 +609,10 @@ static int zynqmp_qspi_genfifo_fill_rx(struct zynqmp_qspi_priv *priv) u32 actuallen = priv->len; 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_SPI_MODE_SPI; - /* * Check if receive buffer is aligned to 4 byte and length * is multiples of four byte as we are using dma to receive. @@ -595,62 +629,6 @@ static int zynqmp_qspi_genfifo_fill_rx(struct zynqmp_qspi_priv *priv) return zynqmp_qspi_start_dma(priv, gen_fifo_cmd, buf); } -static int zynqmp_qspi_start_transfer(struct zynqmp_qspi_priv *priv) -{ - int ret = 0; - - if (priv->is_inst) { - if (priv->tx_buf) - zynqmp_qspi_genfifo_cmd(priv); - else - return -EINVAL; - } else { - if (priv->tx_buf) - ret = zynqmp_qspi_genfifo_fill_tx(priv); - else if (priv->rx_buf) - ret = zynqmp_qspi_genfifo_fill_rx(priv); - else - return -EINVAL; - } - return ret; -} - -static int zynqmp_qspi_transfer(struct zynqmp_qspi_priv *priv) -{ - static unsigned int cs_change = 1; - int status = 0; - - debug("%s\n", __func__); - - while (1) { - /* Select the chip if required */ - if (cs_change) - zynqmp_qspi_chipselect(priv, 1); - - cs_change = priv->cs_change; - - if (!priv->tx_buf && !priv->rx_buf && priv->len) { - status = -EINVAL; - break; - } - - /* Request the transfer */ - if (priv->len) { - status = zynqmp_qspi_start_transfer(priv); - priv->is_inst = 0; - if (status < 0) - break; - } - - if (cs_change) - /* Deselect the chip */ - zynqmp_qspi_chipselect(priv, 0); - break; - } - - return status; -} - static int zynqmp_qspi_claim_bus(struct udevice *dev) { struct udevice *bus = dev->parent; @@ -673,45 +651,43 @@ static int zynqmp_qspi_release_bus(struct udevice *dev) return 0; } -int zynqmp_qspi_xfer(struct udevice *dev, unsigned int bitlen, const void *dout, - void *din, unsigned long flags) +static int zynqmp_qspi_exec_op(struct spi_slave *slave, + const struct spi_mem_op *op) { - struct udevice *bus = dev->parent; - struct zynqmp_qspi_priv *priv = dev_get_priv(bus); + struct zynqmp_qspi_priv *priv = dev_get_priv(slave->dev->parent); + int ret = 0; - 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); + priv->op = op; + priv->tx_buf = op->data.buf.out; + priv->rx_buf = op->data.buf.in; + priv->len = op->data.nbytes; - priv->tx_buf = dout; - priv->rx_buf = din; - priv->len = bitlen / 8; + zynqmp_qspi_chipselect(priv, 1); - /* - * Assume that the beginning of a transfer with bits to - * transmit must contain a device command. - */ - if (dout && flags & SPI_XFER_BEGIN) - priv->is_inst = 1; - else - priv->is_inst = 0; + /* Send opcode, addr, dummy */ + zynqmp_qspi_genfifo_cmd(priv); - if (flags & SPI_XFER_END) - priv->cs_change = 1; - else - priv->cs_change = 0; + /* Request the transfer */ + if (op->data.dir == SPI_MEM_DATA_IN) + ret = zynqmp_qspi_genfifo_fill_rx(priv); + else if (op->data.dir == SPI_MEM_DATA_OUT) + ret = zynqmp_qspi_genfifo_fill_tx(priv); - zynqmp_qspi_transfer(priv); + zynqmp_qspi_chipselect(priv, 0); - return 0; + return ret; } +static const struct spi_controller_mem_ops zynqmp_qspi_mem_ops = { + .exec_op = zynqmp_qspi_exec_op, +}; + 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, + .mem_ops = &zynqmp_qspi_mem_ops, }; static const struct udevice_id zynqmp_qspi_ids[] = { From fc3c6fd75298b69175cc4a0732759f5e1054dc21 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 2 Feb 2021 13:33:22 +0100 Subject: [PATCH 02/14] xilinx: common: Fix CONFIG_XILINX_OF_BOARD_DTB_ADDR handling for ZynqMP Fix bug introduced by commit listed below. It is for cases where Versal or ZynqMP don't have DDR mapped. Later SPL was also excluded by commit a672b9871b57 ("xilinx: common: Do not touch CONFIG_XILINX_OF_BOARD_DTB_ADDR in SPL"). Fixes: 506009fc1022 ("xilinx: common: Change macro handling in board_fdt_blob_setup()") Signed-off-by: Michal Simek --- board/xilinx/common/board.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/board/xilinx/common/board.c b/board/xilinx/common/board.c index df19aeadd0..1a259c5785 100644 --- a/board/xilinx/common/board.c +++ b/board/xilinx/common/board.c @@ -326,7 +326,7 @@ void *board_fdt_blob_setup(void) if (!IS_ENABLED(CONFIG_SPL_BUILD) && !IS_ENABLED(CONFIG_VERSAL_NO_DDR) && - !IS_ENABLED(CONFIG_VERSAL_NO_DDR)) { + !IS_ENABLED(CONFIG_ZYNQMP_NO_DDR)) { fdt_blob = (void *)CONFIG_XILINX_OF_BOARD_DTB_ADDR; if (fdt_magic(fdt_blob) == FDT_MAGIC) From 98757d87ee04cd8f57e9f2d6a8017a1d1a4ea646 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 2 Feb 2021 16:34:48 +0100 Subject: [PATCH 03/14] xilinx: Show silicon version in SPL Both Zynq and ZynqMP can show silicon versions in SPL boot flow. It is useful to be aware. The patch is also fixing possition of these bits on ZynqMP. Signed-off-by: Michal Simek --- arch/arm/mach-zynqmp/include/mach/hardware.h | 4 ++-- board/xilinx/zynq/board.c | 3 +++ board/xilinx/zynqmp/zynqmp.c | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-zynqmp/include/mach/hardware.h b/arch/arm/mach-zynqmp/include/mach/hardware.h index b328837c69..3d3c48e247 100644 --- a/arch/arm/mach-zynqmp/include/mach/hardware.h +++ b/arch/arm/mach-zynqmp/include/mach/hardware.h @@ -128,8 +128,8 @@ struct apu_regs { #define ZYNQMP_CSU_VERSION_EMPTY_SHIFT 20 -#define ZYNQMP_SILICON_VER_MASK 0xF000 -#define ZYNQMP_SILICON_VER_SHIFT 12 +#define ZYNQMP_SILICON_VER_MASK 0xF +#define ZYNQMP_SILICON_VER_SHIFT 0 struct csu_regs { u32 reserved0[4]; diff --git a/board/xilinx/zynq/board.c b/board/xilinx/zynq/board.c index 7ac069aaaf..0fc11a48f1 100644 --- a/board/xilinx/zynq/board.c +++ b/board/xilinx/zynq/board.c @@ -24,6 +24,9 @@ DECLARE_GLOBAL_DATA_PTR; int board_init(void) { + if (IS_ENABLED(CONFIG_SPL_BUILD)) + printf("Silicon version:\t%d\n", zynq_get_silicon_version()); + return 0; } diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index 459d9b1e47..a216eeb35f 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -328,6 +328,7 @@ int board_init(void) if (sizeof(CONFIG_ZYNQMP_SPL_PM_CFG_OBJ_FILE) > 1) zynqmp_pmufw_load_config_object(zynqmp_pm_cfg_obj, zynqmp_pm_cfg_obj_size); + printf("Silicon version:\t%d\n", zynqmp_get_silicon_version()); #else if (CONFIG_IS_ENABLED(DM_I2C) && CONFIG_IS_ENABLED(I2C_EEPROM)) xilinx_read_eeprom(); From 038e02455bbc18d34946fdfe77faf2062adc3e2a Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Wed, 10 Feb 2021 22:41:57 +0100 Subject: [PATCH 04/14] net: gem: unregister mdio bus if probe fails If probe fails, the mdio bus isn't unregistered. Fix it. Signed-off-by: Michael Walle Reviewed-by: Ramon Fried Signed-off-by: Michal Simek --- drivers/net/zynq_gem.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 5cb02bb3a7..585c06d6bd 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -711,10 +711,12 @@ static int zynq_gem_probe(struct udevice *dev) ret = zynq_phy_init(dev); if (ret) - goto err2; + goto err3; return ret; +err3: + mdio_unregister(priv->bus); err2: free(priv->rxbuffers); err1: From 8c02d842b61ebd579e42ff3f0326457e7d10ec95 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Wed, 10 Feb 2021 22:42:29 +0100 Subject: [PATCH 05/14] fpga: zynqpl: fix buffer alignment Due to pointer arithmetic, "sizeof(u32) * ARCH_DMA_MINALIGN" is subtracted. It seems that the original intention was to just subtract ARCH_DMA_MINALIGN. Fix it. Signed-off-by: Michael Walle Signed-off-by: Michal Simek --- drivers/fpga/zynqpl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/fpga/zynqpl.c b/drivers/fpga/zynqpl.c index a11e485525..2de40109a8 100644 --- a/drivers/fpga/zynqpl.c +++ b/drivers/fpga/zynqpl.c @@ -315,7 +315,7 @@ static u32 *zynq_align_dma_buffer(u32 *buf, u32 len, u32 swap) if (new_buf > buf) { debug("%s: Aligned buffer is after buffer start\n", __func__); - new_buf -= ARCH_DMA_MINALIGN; + new_buf = (u32 *)((u32)new_buf - ARCH_DMA_MINALIGN); } printf("%s: Align buffer at %x to %x(swap %d)\n", __func__, (u32)buf, (u32)new_buf, swap); From 3aba25bc382beeb8a92b46d23fd1db47dfcb1121 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 9 Feb 2021 08:50:22 +0100 Subject: [PATCH 06/14] arm64: zynqmp: Do not clear reset reason There is no need to clear reset reason register because it is protected by PMUFW already which is reported when verbose log is enabled as: pm_core.c@733 APU> No write permission to 0xFF5E0220 Signed-off-by: Michal Simek --- board/xilinx/zynqmp/zynqmp.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index a216eeb35f..6babc0ebce 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -496,11 +496,7 @@ static int reset_reason(void) env_set("reset_reason", reason); - ret = zynqmp_mmio_write((ulong)&crlapb_base->reset_reason, ~0, ~0); - if (ret) - return -EINVAL; - - return ret; + return 0; } static int set_fdtfile(void) From 9b7aac75365b68bae2e8f7cf074ba95638d31882 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 9 Feb 2021 15:28:15 +0100 Subject: [PATCH 07/14] clk: zynq: Add dummy clock enable function A lot of Xilinx drivers are checking -ENOSYS which means that clock driver doesn't have enable function. Remove this checking from drivers and create dummy enable function as was done for clk_fixed_rate driver by commit 6bf6d81c1112 ("clk: fixed_rate: add dummy enable() function"). Signed-off-by: Michal Simek --- drivers/clk/clk_zynq.c | 10 ++++++++++ drivers/mmc/zynq_sdhci.c | 2 +- drivers/net/zynq_gem.c | 4 ++-- drivers/serial/serial_zynq.c | 2 +- drivers/spi/zynq_qspi.c | 2 +- drivers/spi/zynq_spi.c | 2 +- drivers/spi/zynqmp_gqspi.c | 2 +- drivers/watchdog/xilinx_wwdt.c | 3 +-- 8 files changed, 18 insertions(+), 9 deletions(-) diff --git a/drivers/clk/clk_zynq.c b/drivers/clk/clk_zynq.c index bf32d8317a..1f71b7d1e4 100644 --- a/drivers/clk/clk_zynq.c +++ b/drivers/clk/clk_zynq.c @@ -444,11 +444,21 @@ static ulong zynq_clk_get_rate(struct clk *clk) } #endif +static int dummy_enable(struct clk *clk) +{ + /* + * Add implementation but by default all clocks are enabled + * after power up which is only one supported case now. + */ + return 0; +} + static struct clk_ops zynq_clk_ops = { .get_rate = zynq_clk_get_rate, #ifndef CONFIG_SPL_BUILD .set_rate = zynq_clk_set_rate, #endif + .enable = dummy_enable, }; static int zynq_clk_probe(struct udevice *dev) diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index d9ad0ff199..b79c4021b6 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -577,7 +577,7 @@ static int arasan_sdhci_probe(struct udevice *dev) debug("%s: CLK %ld\n", __func__, clock); ret = clk_enable(&clk); - if (ret && ret != -ENOSYS) { + if (ret) { dev_err(dev, "failed to enable clock\n"); return ret; } diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 585c06d6bd..a2a0111201 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -477,13 +477,13 @@ static int zynq_gem_init(struct udevice *dev) } ret = clk_set_rate(&priv->clk, clk_rate); - if (IS_ERR_VALUE(ret) && ret != (unsigned long)-ENOSYS) { + if (IS_ERR_VALUE(ret)) { dev_err(dev, "failed to set tx clock rate\n"); return ret; } ret = clk_enable(&priv->clk); - if (ret && ret != -ENOSYS) { + if (ret) { dev_err(dev, "failed to enable tx clock\n"); return ret; } diff --git a/drivers/serial/serial_zynq.c b/drivers/serial/serial_zynq.c index 2883e2466f..799d524047 100644 --- a/drivers/serial/serial_zynq.c +++ b/drivers/serial/serial_zynq.c @@ -127,7 +127,7 @@ static int zynq_serial_setbrg(struct udevice *dev, int baudrate) debug("%s: CLK %ld\n", __func__, clock); ret = clk_enable(&clk); - if (ret && ret != -ENOSYS) { + if (ret) { dev_err(dev, "failed to enable clock\n"); return ret; } diff --git a/drivers/spi/zynq_qspi.c b/drivers/spi/zynq_qspi.c index 845f2d2f5f..29dbbf5557 100644 --- a/drivers/spi/zynq_qspi.c +++ b/drivers/spi/zynq_qspi.c @@ -193,7 +193,7 @@ static int zynq_qspi_probe(struct udevice *bus) } ret = clk_enable(&clk); - if (ret && ret != -ENOSYS) { + if (ret) { dev_err(bus, "failed to enable clock\n"); return ret; } diff --git a/drivers/spi/zynq_spi.c b/drivers/spi/zynq_spi.c index 2971e55f41..650d4d71d9 100644 --- a/drivers/spi/zynq_spi.c +++ b/drivers/spi/zynq_spi.c @@ -143,7 +143,7 @@ static int zynq_spi_probe(struct udevice *bus) } ret = clk_enable(&clk); - if (ret && ret != -ENOSYS) { + if (ret) { dev_err(bus, "failed to enable clock\n"); return ret; } diff --git a/drivers/spi/zynqmp_gqspi.c b/drivers/spi/zynqmp_gqspi.c index c7db43a09a..bd25511aae 100644 --- a/drivers/spi/zynqmp_gqspi.c +++ b/drivers/spi/zynqmp_gqspi.c @@ -373,7 +373,7 @@ static int zynqmp_qspi_probe(struct udevice *bus) debug("%s: CLK %ld\n", __func__, clock); ret = clk_enable(&clk); - if (ret && ret != -ENOSYS) { + if (ret) { dev_err(bus, "failed to enable clock\n"); return ret; } diff --git a/drivers/watchdog/xilinx_wwdt.c b/drivers/watchdog/xilinx_wwdt.c index 9137d87697..11b30ae85d 100644 --- a/drivers/watchdog/xilinx_wwdt.c +++ b/drivers/watchdog/xilinx_wwdt.c @@ -90,9 +90,8 @@ static int xlnx_wwdt_start(struct udevice *dev, u64 timeout, ulong flags) /* Calculate timeout count */ count = timeout * clock_f; - /* clk_enable will return -ENOSYS when it is not implemented */ ret = clk_enable(&wdt->clk); - if (ret && ret != -ENOSYS) { + if (ret) { dev_err(dev, "failed to enable clock\n"); return ret; } From a72a6ae3626add8b193fdcd037efea873f3224ef Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Wed, 3 Feb 2021 03:10:45 -0700 Subject: [PATCH 08/14] clk: zynqmp: Add support to enable clocks Add clock enable functionality in zynqmp clock driver to enable clocks from peripheral drivers using clk_ops. Signed-off-by: T Karthik Reddy Signed-off-by: Michal Simek --- drivers/clk/clk_zynqmp.c | 49 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/drivers/clk/clk_zynqmp.c b/drivers/clk/clk_zynqmp.c index e8acca0066..609d8e3b2f 100644 --- a/drivers/clk/clk_zynqmp.c +++ b/drivers/clk/clk_zynqmp.c @@ -199,6 +199,8 @@ static u32 zynqmp_clk_get_register(enum zynqmp_clk id) return CRF_APB_DDR_CTRL; case qspi_ref: return CRL_APB_QSPI_REF_CTRL; + case usb3_dual_ref: + return CRL_APB_USB3_DUAL_REF_CTRL; case gem0_ref: return CRL_APB_GEM0_REF_CTRL; case gem1_ref: @@ -207,6 +209,10 @@ static u32 zynqmp_clk_get_register(enum zynqmp_clk id) return CRL_APB_GEM2_REF_CTRL; case gem3_ref: return CRL_APB_GEM3_REF_CTRL; + case usb0_bus_ref: + return CRL_APB_USB0_BUS_REF_CTRL; + case usb1_bus_ref: + return CRL_APB_USB1_BUS_REF_CTRL; case uart0_ref: return CRL_APB_UART0_REF_CTRL; case uart1_ref: @@ -699,9 +705,52 @@ static int zynqmp_clk_probe(struct udevice *dev) return 0; } +static int zynqmp_clk_enable(struct clk *clk) +{ + enum zynqmp_clk id = clk->id; + u32 reg, clk_ctrl, clkact_shift, mask; + int ret; + + reg = zynqmp_clk_get_register(id); + debug("%s, clk_id:%x, clk_base:0x%x\n", __func__, id, reg); + + switch (id) { + case usb0_bus_ref ... usb1: + clkact_shift = 25; + mask = 0x1; + break; + case gem0_ref ... gem3_ref: + clkact_shift = 25; + mask = 0x3; + break; + case qspi_ref ... can1_ref: + clkact_shift = 24; + mask = 0x1; + break; + default: + return -ENXIO; + } + + ret = zynqmp_mmio_read(reg, &clk_ctrl); + if (ret) { + printf("%s mio read fail\n", __func__); + return -EIO; + } + + clk_ctrl |= (mask << clkact_shift); + ret = zynqmp_mmio_write(reg, mask << clkact_shift, clk_ctrl); + if (ret) { + printf("%s mio write fail\n", __func__); + return -EIO; + } + + return ret; +} + static struct clk_ops zynqmp_clk_ops = { .set_rate = zynqmp_clk_set_rate, .get_rate = zynqmp_clk_get_rate, + .enable = zynqmp_clk_enable, }; static const struct udevice_id zynqmp_clk_ids[] = { From 60b03f1cc408ffd2360303da4c5d09bec47b8cc2 Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Wed, 3 Feb 2021 03:10:47 -0700 Subject: [PATCH 09/14] clk: versal: Add support to enable clocks Add clock enable functionality in versal clock driver to enable clocks from peripheral drivers using clk_ops. Signed-off-by: T Karthik Reddy Signed-off-by: Michal Simek --- drivers/clk/clk_versal.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/clk/clk_versal.c b/drivers/clk/clk_versal.c index 908bc7519c..62523d2909 100644 --- a/drivers/clk/clk_versal.c +++ b/drivers/clk/clk_versal.c @@ -718,9 +718,20 @@ static ulong versal_clk_set_rate(struct clk *clk, ulong rate) return clk_rate; } +static int versal_clk_enable(struct clk *clk) +{ + struct versal_clk_priv *priv = dev_get_priv(clk->dev); + u32 clk_id; + + clk_id = priv->clk[clk->id].clk_id; + + return xilinx_pm_request(PM_CLOCK_ENABLE, clk_id, 0, 0, 0, NULL); +} + static struct clk_ops versal_clk_ops = { .set_rate = versal_clk_set_rate, .get_rate = versal_clk_get_rate, + .enable = versal_clk_enable, }; static const struct udevice_id versal_clk_ids[] = { From 8faa7913a425e9737df8e4183030dd72c1d668b7 Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Wed, 3 Feb 2021 03:10:46 -0700 Subject: [PATCH 10/14] i2c: i2c_cdns: Enable i2c clock Enable i2c controller clock from driver probe function by calling clk_enable(). Signed-off-by: T Karthik Reddy Signed-off-by: Michal Simek Reviewed-by: Heiko Schocher --- drivers/i2c/i2c-cdns.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/i2c/i2c-cdns.c b/drivers/i2c/i2c-cdns.c index db3c04fa6e..a650dd69b8 100644 --- a/drivers/i2c/i2c-cdns.c +++ b/drivers/i2c/i2c-cdns.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -481,6 +482,12 @@ static int cdns_i2c_of_to_plat(struct udevice *dev) i2c_bus->input_freq = clk_get_rate(&clk); + ret = clk_enable(&clk); + if (ret) { + dev_err(dev, "failed to enable clock\n"); + return ret; + } + return 0; } From ea4d4cb39a1bbe3bb94bff6b70367b3cb722b007 Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Wed, 3 Feb 2021 03:10:48 -0700 Subject: [PATCH 11/14] net: gem: Enable ethernet rx clock for versal Enable rx clock along with tx clock for versal platform. Use compatible data to enable/disable clocks in the driver. Signed-off-by: T Karthik Reddy Signed-off-by: Michal Simek Reviewed-by: Ramon Fried --- drivers/net/zynq_gem.c | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index a2a0111201..9ed013ee51 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -129,6 +129,8 @@ #define ZYNQ_GEM_FREQUENCY_100 25000000UL #define ZYNQ_GEM_FREQUENCY_1000 125000000UL +#define RXCLK_EN BIT(0) + /* Device registers */ struct zynq_gem_regs { u32 nwctrl; /* 0x0 - Network Control reg */ @@ -205,10 +207,12 @@ struct zynq_gem_priv { struct phy_device *phydev; ofnode phy_of_node; struct mii_dev *bus; - struct clk clk; + struct clk rx_clk; + struct clk tx_clk; u32 max_speed; bool int_pcs; bool dma_64bit; + u32 clk_en_info; }; static int phy_setup_op(struct zynq_gem_priv *priv, u32 phy_addr, u32 regnum, @@ -476,18 +480,25 @@ static int zynq_gem_init(struct udevice *dev) break; } - ret = clk_set_rate(&priv->clk, 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\n"); return ret; } - ret = clk_enable(&priv->clk); + ret = clk_enable(&priv->tx_clk); if (ret) { dev_err(dev, "failed to enable tx clock\n"); return ret; } + if (priv->clk_en_info & RXCLK_EN) { + ret = clk_enable(&priv->rx_clk); + if (ret) { + dev_err(dev, "failed to enable rx clock\n"); + return ret; + } + } setbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_RXEN_MASK | ZYNQ_GEM_NWCTRL_TXEN_MASK); @@ -694,12 +705,20 @@ static int zynq_gem_probe(struct udevice *dev) priv->tx_bd = (struct emac_bd *)bd_space; priv->rx_bd = (struct emac_bd *)((ulong)bd_space + BD_SEPRN_SPACE); - ret = clk_get_by_name(dev, "tx_clk", &priv->clk); + ret = clk_get_by_name(dev, "tx_clk", &priv->tx_clk); if (ret < 0) { - dev_err(dev, "failed to get clock\n"); + dev_err(dev, "failed to get tx_clock\n"); goto err1; } + if (priv->clk_en_info & RXCLK_EN) { + ret = clk_get_by_name(dev, "rx_clk", &priv->rx_clk); + if (ret < 0) { + dev_err(dev, "failed to get rx_clock\n"); + goto err1; + } + } + priv->bus = mdio_alloc(); priv->bus->read = zynq_gem_miiphy_read; priv->bus->write = zynq_gem_miiphy_write; @@ -794,11 +813,13 @@ static int zynq_gem_of_to_plat(struct udevice *dev) (ulong)priv->iobase, (ulong)priv->mdiobase, priv->phyaddr, phy_string_for_interface(priv->interface)); + priv->clk_en_info = dev_get_driver_data(dev); + return 0; } static const struct udevice_id zynq_gem_ids[] = { - { .compatible = "cdns,versal-gem" }, + { .compatible = "cdns,versal-gem", .data = RXCLK_EN }, { .compatible = "cdns,zynqmp-gem" }, { .compatible = "cdns,zynq-gem" }, { .compatible = "cdns,gem" }, From a13a82186e93c2e6e8533b8f06679091dc430062 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 11 Feb 2021 19:03:30 +0100 Subject: [PATCH 12/14] net: gem: Fix error path in zynq_gem_probe Clean up error path in connection where priv->rxbuffers and priv->tx_bd are allocated. Signed-off-by: Michal Simek --- drivers/net/zynq_gem.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 9ed013ee51..baf06a2ad8 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -708,14 +708,14 @@ static int zynq_gem_probe(struct udevice *dev) ret = clk_get_by_name(dev, "tx_clk", &priv->tx_clk); if (ret < 0) { dev_err(dev, "failed to get tx_clock\n"); - goto err1; + goto err2; } if (priv->clk_en_info & RXCLK_EN) { ret = clk_get_by_name(dev, "rx_clk", &priv->rx_clk); if (ret < 0) { dev_err(dev, "failed to get rx_clock\n"); - goto err1; + goto err2; } } @@ -737,9 +737,9 @@ static int zynq_gem_probe(struct udevice *dev) err3: mdio_unregister(priv->bus); err2: - free(priv->rxbuffers); -err1: free(priv->tx_bd); +err1: + free(priv->rxbuffers); return ret; } From 3600d47b734129c9cb9772c587d0bf1fbc458cc6 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 17 Feb 2021 08:55:34 +0100 Subject: [PATCH 13/14] arm64: zynqmp: Rename zc1275/zcu1275 to be aligned with DT name Folder names corresponds to DT name. These boards have been renamed from zc1275 to zcu1275 by commit shown below and this should be the part of that commit. Fixes: 420d44678119 ("arm64: zynqmp: Rename zc1275 to zcu1275") Signed-off-by: Michal Simek --- board/xilinx/zynqmp/{zynqmp-zc1275-revA => zynqmp-zcu1275-revA} | 0 .../{zynqmp-zc1275-revB => zynqmp-zcu1275-revB}/psu_init_gpl.c | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename board/xilinx/zynqmp/{zynqmp-zc1275-revA => zynqmp-zcu1275-revA} (100%) rename board/xilinx/zynqmp/{zynqmp-zc1275-revB => zynqmp-zcu1275-revB}/psu_init_gpl.c (100%) diff --git a/board/xilinx/zynqmp/zynqmp-zc1275-revA b/board/xilinx/zynqmp/zynqmp-zcu1275-revA similarity index 100% rename from board/xilinx/zynqmp/zynqmp-zc1275-revA rename to board/xilinx/zynqmp/zynqmp-zcu1275-revA diff --git a/board/xilinx/zynqmp/zynqmp-zc1275-revB/psu_init_gpl.c b/board/xilinx/zynqmp/zynqmp-zcu1275-revB/psu_init_gpl.c similarity index 100% rename from board/xilinx/zynqmp/zynqmp-zc1275-revB/psu_init_gpl.c rename to board/xilinx/zynqmp/zynqmp-zcu1275-revB/psu_init_gpl.c From d9aa19efa8a6c20d51b7884de0a7f8dae3f835d2 Mon Sep 17 00:00:00 2001 From: Brandon Maier Date: Wed, 20 Jan 2021 14:28:30 -0600 Subject: [PATCH 14/14] spi: zynqmp_gqspi: fix set_speed bug on multiple runs If zynqmp_qspi_set_speed() is called multiple times with the same speed, then on the second call it will skip recalculating the baud_rate_val as it assumes the speed is already configured correctly. But it will still write the baud_rate_val to the configuration register and call zynqmp_gqspi_set_tapdelay(). Because it skipped recalculating the baud_rate_val, it will use the initial value of 0 . This causes the driver to run at maximum speed which for many spi flashes is too fast and causes data corruption. Instead only write out a new baud_rate_val if we have calculated the correct baud_rate_val. This opens up another issue with the "if (speed == 0)", we don't save off the new plat->speed_hz value when setting the baud rate on the speed=0 path. Instead mimic what the Linux zynqmp gqspi driver does, and have speed==0 just use the same calculation as a normal speed. That will cause the baud_rate_val to use the slowest speed possible, which is the safest option. Signed-off-by: Brandon Maier CC: jagan@amarulasolutions.com CC: michal.simek@xilinx.com CC: Ashok Reddy Soma Signed-off-by: Michal Simek --- drivers/spi/zynqmp_gqspi.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/drivers/spi/zynqmp_gqspi.c b/drivers/spi/zynqmp_gqspi.c index bd25511aae..116319526f 100644 --- a/drivers/spi/zynqmp_gqspi.c +++ b/drivers/spi/zynqmp_gqspi.c @@ -320,12 +320,9 @@ static int zynqmp_qspi_set_speed(struct udevice *bus, uint speed) 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 = GQSPI_DFLT_BAUD_RATE_VAL; - } else if (plat->speed_hz != speed) { + if (plat->speed_hz != speed) { + /* Set the clock frequency */ + /* If speed == 0, default to lowest speed */ while ((baud_rate_val < 8) && ((plat->frequency / (2 << baud_rate_val)) > speed)) @@ -335,13 +332,15 @@ static int zynqmp_qspi_set_speed(struct udevice *bus, uint speed) baud_rate_val = GQSPI_DFLT_BAUD_RATE_VAL; plat->speed_hz = plat->frequency / (2 << baud_rate_val); - } - confr &= ~GQSPI_BAUD_DIV_MASK; - confr |= (baud_rate_val << 3); - writel(confr, ®s->confr); - zynqmp_qspi_set_tapdelay(bus, baud_rate_val); - debug("regs=%p, speed=%d\n", priv->regs, plat->speed_hz); + confr = readl(®s->confr); + confr &= ~GQSPI_BAUD_DIV_MASK; + confr |= (baud_rate_val << 3); + writel(confr, ®s->confr); + zynqmp_qspi_set_tapdelay(bus, baud_rate_val); + + debug("regs=%p, speed=%d\n", priv->regs, plat->speed_hz); + } return 0; }