[PATCH v2 0/5] clk: Add support to enable clocks

Hi,
Add support to enable clocks using clock subsystem ops for zynqmp & versal platforms. Enable rx clock in ethernet driver for versal platform. Add clock enable feature in i2c-cdns driver.
Thanks, Karthik, Michal
Changes in v2: - New patch is series - change patch possition - Use compatible data instead of CONFIG_
Michal Simek (1): clk: zynq: Add dummy clock enable function
T Karthik Reddy (4): clk: zynqmp: Add support to enable clocks clk: versal: Add support to enable clocks i2c: i2c_cdns: Enable i2c clock net: gem: Enable ethernet rx clock for versal
drivers/clk/clk_versal.c | 11 ++++++++ drivers/clk/clk_zynq.c | 11 ++++++++ drivers/clk/clk_zynqmp.c | 49 ++++++++++++++++++++++++++++++++++ drivers/i2c/i2c-cdns.c | 7 +++++ drivers/mmc/zynq_sdhci.c | 2 +- drivers/net/zynq_gem.c | 37 +++++++++++++++++++------ 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 +-- 11 files changed, 113 insertions(+), 15 deletions(-)

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 michal.simek@xilinx.com ---
Changes in v2: - New patch is series
drivers/clk/clk_zynq.c | 11 +++++++++++ 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, 19 insertions(+), 9 deletions(-)
diff --git a/drivers/clk/clk_zynq.c b/drivers/clk/clk_zynq.c index bf32d8317ab2..03a2f1991a08 100644 --- a/drivers/clk/clk_zynq.c +++ b/drivers/clk/clk_zynq.c @@ -422,6 +422,16 @@ static ulong zynq_clk_set_rate(struct clk *clk, ulong rate) return -ENXIO; } } + +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; +} + #else static ulong zynq_clk_get_rate(struct clk *clk) { @@ -448,6 +458,7 @@ static struct clk_ops zynq_clk_ops = { .get_rate = zynq_clk_get_rate, #ifndef CONFIG_SPL_BUILD .set_rate = zynq_clk_set_rate, + .enable = dummy_enable, #endif };
diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index d9ad0ff199d7..b79c4021b6a5 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 5cb02bb3a7d2..22237de66bc7 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 2883e2466f8b..799d5240473c 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 845f2d2f5f41..29dbbf555776 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 2971e55f41b1..650d4d71d925 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 c7db43a09a52..bd25511aae6a 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 9137d87697d4..11b30ae85df0 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: T Karthik Reddy t.karthik.reddy@xilinx.com
Add clock enable functionality in zynqmp clock driver to enable clocks from peripheral drivers using clk_ops.
Signed-off-by: T Karthik Reddy t.karthik.reddy@xilinx.com Signed-off-by: Michal Simek michal.simek@xilinx.com ---
(no changes since v1)
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 e8acca00660d..609d8e3b2fff 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: T Karthik Reddy t.karthik.reddy@xilinx.com
Add clock enable functionality in versal clock driver to enable clocks from peripheral drivers using clk_ops.
Signed-off-by: T Karthik Reddy t.karthik.reddy@xilinx.com Signed-off-by: Michal Simek michal.simek@xilinx.com ---
Changes in v2: - change patch possition
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 908bc7519c42..62523d290999 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: T Karthik Reddy t.karthik.reddy@xilinx.com
Enable i2c controller clock from driver probe function by calling clk_enable().
Signed-off-by: T Karthik Reddy t.karthik.reddy@xilinx.com Signed-off-by: Michal Simek michal.simek@xilinx.com ---
(no changes since v1)
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 db3c04fa6e75..a650dd69b89f 100644 --- a/drivers/i2c/i2c-cdns.c +++ b/drivers/i2c/i2c-cdns.c @@ -15,6 +15,7 @@ #include <linux/types.h> #include <linux/io.h> #include <linux/errno.h> +#include <dm/device_compat.h> #include <dm/root.h> #include <i2c.h> #include <fdtdec.h> @@ -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; }

Hello Michal,
On 10.02.21 13:42, Michal Simek wrote:
From: T Karthik Reddy t.karthik.reddy@xilinx.com
Enable i2c controller clock from driver probe function by calling clk_enable().
Signed-off-by: T Karthik Reddy t.karthik.reddy@xilinx.com Signed-off-by: Michal Simek michal.simek@xilinx.com
(no changes since v1)
drivers/i2c/i2c-cdns.c | 7 +++++++ 1 file changed, 7 insertions(+)
Reviewed-by: Heiko Schocher hs@denx.de
Thanks!
bye, Heiko

From: T Karthik Reddy t.karthik.reddy@xilinx.com
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 t.karthik.reddy@xilinx.com Signed-off-by: Michal Simek michal.simek@xilinx.com Reviewed-By: Ramon Fried rfried.dev@gmail.com ---
Changes in v2: - Use compatible data instead of CONFIG_
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 22237de66bc7..d6f58d87c873 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; @@ -792,11 +811,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" },
participants (2)
-
Heiko Schocher
-
Michal Simek