[U-Boot] [PATCH 0/8] zynq: clk: Move zynq platform to clock framework

From: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com
The old platform clock driver use a dynamic array which is filled at every boot with static clock tree information and unused clock rates. This needs much memory and complicates the strip down for the SPL. The new clock framework driver contains the tree information in functions and reads clock rates on demand.
Stefan Herbrechtsmeier (8): net: zynq: Don't overwrite gem_rclk_ctrl with default value net: zynq: Add clk framework support to zynq ethernet driver zynq: Add clk framework support to zynq timer zynq: Move static clock names into separate array zynq: Remove zynq_clk_get_name function clk: zynq: Add zynq clock framework driver zynq: Move zynq to clock framework clk: zynq: Add optional ethernet emio clock source support
arch/arm/Kconfig | 2 + arch/arm/dts/zynq-7000.dtsi | 2 + arch/arm/include/asm/arch-zynqmp/sys_proto.h | 5 - arch/arm/mach-zynq/clk.c | 687 +++------------------------ arch/arm/mach-zynq/cpu.c | 1 - arch/arm/mach-zynq/include/mach/clk.h | 6 - arch/arm/mach-zynq/include/mach/sys_proto.h | 1 - arch/arm/mach-zynq/slcr.c | 29 -- arch/arm/mach-zynq/timer.c | 23 + drivers/clk/Kconfig | 7 + drivers/clk/Makefile | 1 + drivers/clk/clk_zynq.c | 499 +++++++++++++++++++ drivers/net/zynq_gem.c | 27 +- drivers/serial/serial_zynq.c | 6 +- include/configs/topic_miami.h | 2 - include/configs/zynq_zybo.h | 3 - scripts/config_whitelist.txt | 1 - 17 files changed, 618 insertions(+), 684 deletions(-) create mode 100644 drivers/clk/clk_zynq.c

From: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.de
The gem[0-1]_rclk_ctrl registers control the source of the rx clock, control and data signals and configure via ps7_init function. Don't overwrite the register with the default value.
Signed-off-by: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com ---
arch/arm/mach-zynq/slcr.c | 7 ------- drivers/net/zynq_gem.c | 9 ++------- 2 files changed, 2 insertions(+), 14 deletions(-)
diff --git a/arch/arm/mach-zynq/slcr.c b/arch/arm/mach-zynq/slcr.c index 2d3bf2a..c1129cd 100644 --- a/arch/arm/mach-zynq/slcr.c +++ b/arch/arm/mach-zynq/slcr.c @@ -140,13 +140,6 @@ void zynq_slcr_gem_clk_setup(u32 gem_id, unsigned long clk_rate) if (ret) goto out;
- if (gem_id) { - /* Configure GEM_RCLK_CTRL */ - writel(1, &slcr_base->gem1_rclk_ctrl); - } else { - /* Configure GEM_RCLK_CTRL */ - writel(1, &slcr_base->gem0_rclk_ctrl); - } udelay(100000); out: zynq_slcr_lock(); diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index d2e5e7c..9bfb89f 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -174,7 +174,6 @@ struct zynq_gem_priv { u32 rxbd_current; u32 rx_first_buf; int phyaddr; - u32 emio; int init; struct zynq_gem_regs *iobase; phy_interface_t interface; @@ -467,10 +466,8 @@ static int zynq_gem_init(struct udevice *dev) break; }
- /* Change the rclk and clk only not using EMIO interface */ - if (!priv->emio) - zynq_slcr_gem_clk_setup((ulong)priv->iobase != - ZYNQ_GEM_BASEADDR0, clk_rate); + zynq_slcr_gem_clk_setup((ulong)priv->iobase != + ZYNQ_GEM_BASEADDR0, clk_rate);
setbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_RXEN_MASK | ZYNQ_GEM_NWCTRL_TXEN_MASK); @@ -685,7 +682,6 @@ static int zynq_gem_ofdata_to_platdata(struct udevice *dev) pdata->iobase = (phys_addr_t)dev_get_addr(dev); priv->iobase = (struct zynq_gem_regs *)pdata->iobase; /* Hardcode for now */ - priv->emio = 0; priv->phyaddr = -1;
priv->phy_of_handle = fdtdec_lookup_phandle(gd->fdt_blob, @@ -703,7 +699,6 @@ static int zynq_gem_ofdata_to_platdata(struct udevice *dev) } priv->interface = pdata->phy_interface;
- priv->emio = fdtdec_get_bool(gd->fdt_blob, dev->of_offset, "xlnx,emio");
printf("ZYNQ GEM: %lx, phyaddr %x, interface %s\n", (ulong)priv->iobase, priv->phyaddr, phy_string_for_interface(priv->interface));

On 4.1.2017 13:27, stefan.herbrechtsmeier@weidmueller.com wrote:
From: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.de
The gem[0-1]_rclk_ctrl registers control the source of the rx clock, control and data signals and configure via ps7_init function. Don't overwrite the register with the default value.
TBH I don't think this is a win for us to relate on ps7_init configuration. There are a lot of things there but I would like to control this in this sw instead of psu_init.
Thanks, Michal

Hi Michal,
-----Ursprüngliche Nachricht----- Von: Michal Simek [mailto:monstr@monstr.eu] Gesendet: Dienstag, 10. Januar 2017 14:53 An: Herbrechtsmeier, Stefan; u-boot@lists.denx.de Cc: Herbrechtsmeier, Stefan; Michal Simek; Jagan Teki; Albert Aribaud; Joe Hershberger; Mike Looijmans Betreff: Re: [PATCH 1/8] net: zynq: Don't overwrite gem_rclk_ctrl with default value
On 4.1.2017 13:27, stefan.herbrechtsmeier@weidmueller.com wrote:
From: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.de
The gem[0-1]_rclk_ctrl registers control the source of the rx clock, control and data signals and configure via ps7_init function. Don't overwrite the register with the default value.
TBH I don't think this is a win for us to relate on ps7_init configuration. There are a lot of things there but I would like to control this in this sw instead of psu_init.
At the moment the ps7_init only touch the register if the board doesn't use the default configuration. U-boot overwrite the register with the default value if 'xlnx,emio' isn't set in the device tree. It doesn't change the value to gem_rclk_ctrl if 'xlnx,emio' is set.
At the moment the clock configuration is managed by the ps7_init and only the gem_rclk_ctrl configuration is overwritten by u-boot. I don't think it is correct do overwrite some part of the clock tree configuration which is generated by Xilinx tools.
Regards, Stefan
Kommanditgesellschaft - Sitz: Detmold - Amtsgericht Lemgo HRA 2790 - Komplementärin: Weidmüller Interface Führungsgesellschaft mbH - Sitz: Detmold - Amtsgericht Lemgo HRB 3924; Geschäftsführer: José Carlos Álvarez Tobar, Elke Eckstein, Dr. Peter Köhler, Jörg Timmermann; USt-ID-Nr. DE124599660

+siva
On 10.1.2017 15:28, Stefan.Herbrechtsmeier@weidmueller.com wrote:
Hi Michal,
-----Ursprüngliche Nachricht----- Von: Michal Simek [mailto:monstr@monstr.eu] Gesendet: Dienstag, 10. Januar 2017 14:53 An: Herbrechtsmeier, Stefan; u-boot@lists.denx.de Cc: Herbrechtsmeier, Stefan; Michal Simek; Jagan Teki; Albert Aribaud; Joe Hershberger; Mike Looijmans Betreff: Re: [PATCH 1/8] net: zynq: Don't overwrite gem_rclk_ctrl with default value
On 4.1.2017 13:27, stefan.herbrechtsmeier@weidmueller.com wrote:
From: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.de
The gem[0-1]_rclk_ctrl registers control the source of the rx clock, control and data signals and configure via ps7_init function. Don't overwrite the register with the default value.
TBH I don't think this is a win for us to relate on ps7_init configuration. There are a lot of things there but I would like to control this in this sw instead of psu_init.
At the moment the ps7_init only touch the register if the board doesn't use the default configuration. U-boot overwrite the register with the default value if 'xlnx,emio' isn't set in the device tree. It doesn't change the value to gem_rclk_ctrl if 'xlnx,emio' is set.
At the moment the clock configuration is managed by the ps7_init and only the gem_rclk_ctrl configuration is overwritten by u-boot. I don't think it is correct do overwrite some part of the clock tree configuration which is generated by Xilinx tools.
ok.
Siva: I don't have testcase for emio or any hw design to test this. Do you have something which we can check?
Thanks, Michal

From: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.de
If available use the clock framework to set the tx clock rate of the zynq ethernet controller.
Signed-off-by: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com ---
arch/arm/include/asm/arch-zynqmp/sys_proto.h | 5 ----- drivers/net/zynq_gem.c | 31 ++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 5 deletions(-)
diff --git a/arch/arm/include/asm/arch-zynqmp/sys_proto.h b/arch/arm/include/asm/arch-zynqmp/sys_proto.h index 1db2bd6..bd633a6 100644 --- a/arch/arm/include/asm/arch-zynqmp/sys_proto.h +++ b/arch/arm/include/asm/arch-zynqmp/sys_proto.h @@ -8,11 +8,6 @@ #ifndef _ASM_ARCH_SYS_PROTO_H #define _ASM_ARCH_SYS_PROTO_H
-/* Setup clk for network */ -static inline void zynq_slcr_gem_clk_setup(u32 gem_id, unsigned long clk_rate) -{ -} - int zynq_slcr_get_mio_pin_status(const char *periph);
unsigned int zynqmp_get_silicon_version(void); diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 9bfb89f..9118e49 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -9,6 +9,7 @@ * SPDX-License-Identifier: GPL-2.0+ */
+#include <clk.h> #include <common.h> #include <dm.h> #include <net.h> @@ -180,6 +181,9 @@ struct zynq_gem_priv { struct phy_device *phydev; int phy_of_handle; struct mii_dev *bus; +#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK) + struct clk tx_clk; +#endif };
static inline int mdio_wait(struct zynq_gem_regs *regs) @@ -364,6 +368,9 @@ static int zynq_gem_init(struct udevice *dev) u32 i, nwconfig; int ret; unsigned long clk_rate = 0; +#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK) + unsigned long clk_rate_rounded; +#endif struct zynq_gem_priv *priv = dev_get_priv(dev); struct zynq_gem_regs *regs = priv->iobase; struct emac_bd *dummy_tx_bd = &priv->tx_bd[TX_FREE_DESC]; @@ -466,8 +473,22 @@ static int zynq_gem_init(struct udevice *dev) break; }
+#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK) + clk_rate_rounded = clk_set_rate(&priv->tx_clk, clk_rate); + if (IS_ERR_VALUE(clk_rate_rounded)) { + dev_err(dev, "failed to set tx clock rate\n"); + return clk_rate_rounded; + } + + ret = clk_enable(&priv->tx_clk); + if (ret && ret != -ENOSYS) { + dev_err(dev, "failed to enable tx clock\n"); + return ret; + } +#else zynq_slcr_gem_clk_setup((ulong)priv->iobase != ZYNQ_GEM_BASEADDR0, clk_rate); +#endif
setbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_RXEN_MASK | ZYNQ_GEM_NWCTRL_TXEN_MASK); @@ -678,6 +699,9 @@ static int zynq_gem_ofdata_to_platdata(struct udevice *dev) struct eth_pdata *pdata = dev_get_platdata(dev); struct zynq_gem_priv *priv = dev_get_priv(dev); const char *phy_mode; +#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK) + int ret; +#endif
pdata->iobase = (phys_addr_t)dev_get_addr(dev); priv->iobase = (struct zynq_gem_regs *)pdata->iobase; @@ -699,6 +723,13 @@ static int zynq_gem_ofdata_to_platdata(struct udevice *dev) } priv->interface = pdata->phy_interface;
+#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK) + ret = clk_get_by_index(dev, 2, &priv->tx_clk); + if (ret < 0) { + dev_err(dev, "failed to get clock\n"); + return ret; + } +#endif
printf("ZYNQ GEM: %lx, phyaddr %x, interface %s\n", (ulong)priv->iobase, priv->phyaddr, phy_string_for_interface(priv->interface));

On 4.1.2017 13:27, stefan.herbrechtsmeier@weidmueller.com wrote:
From: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.de
If available use the clock framework to set the tx clock rate of the zynq ethernet controller.
Signed-off-by: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com
arch/arm/include/asm/arch-zynqmp/sys_proto.h | 5 ----- drivers/net/zynq_gem.c | 31 ++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 5 deletions(-)
diff --git a/arch/arm/include/asm/arch-zynqmp/sys_proto.h b/arch/arm/include/asm/arch-zynqmp/sys_proto.h index 1db2bd6..bd633a6 100644 --- a/arch/arm/include/asm/arch-zynqmp/sys_proto.h +++ b/arch/arm/include/asm/arch-zynqmp/sys_proto.h @@ -8,11 +8,6 @@ #ifndef _ASM_ARCH_SYS_PROTO_H #define _ASM_ARCH_SYS_PROTO_H
-/* Setup clk for network */ -static inline void zynq_slcr_gem_clk_setup(u32 gem_id, unsigned long clk_rate) -{ -}
int zynq_slcr_get_mio_pin_status(const char *periph);
unsigned int zynqmp_get_silicon_version(void); diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 9bfb89f..9118e49 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -9,6 +9,7 @@
- SPDX-License-Identifier: GPL-2.0+
*/
+#include <clk.h> #include <common.h> #include <dm.h> #include <net.h> @@ -180,6 +181,9 @@ struct zynq_gem_priv { struct phy_device *phydev; int phy_of_handle; struct mii_dev *bus; +#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK)
- struct clk tx_clk;
+#endif };
static inline int mdio_wait(struct zynq_gem_regs *regs) @@ -364,6 +368,9 @@ static int zynq_gem_init(struct udevice *dev) u32 i, nwconfig; int ret; unsigned long clk_rate = 0; +#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK)
- unsigned long clk_rate_rounded;
+#endif struct zynq_gem_priv *priv = dev_get_priv(dev); struct zynq_gem_regs *regs = priv->iobase; struct emac_bd *dummy_tx_bd = &priv->tx_bd[TX_FREE_DESC]; @@ -466,8 +473,22 @@ static int zynq_gem_init(struct udevice *dev) break; }
+#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK)
- clk_rate_rounded = clk_set_rate(&priv->tx_clk, clk_rate);
- if (IS_ERR_VALUE(clk_rate_rounded)) {
dev_err(dev, "failed to set tx clock rate\n");
return clk_rate_rounded;
- }
- ret = clk_enable(&priv->tx_clk);
- if (ret && ret != -ENOSYS) {
dev_err(dev, "failed to enable tx clock\n");
return ret;
- }
+#else zynq_slcr_gem_clk_setup((ulong)priv->iobase != ZYNQ_GEM_BASEADDR0, clk_rate); +#endif
setbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_RXEN_MASK | ZYNQ_GEM_NWCTRL_TXEN_MASK); @@ -678,6 +699,9 @@ static int zynq_gem_ofdata_to_platdata(struct udevice *dev) struct eth_pdata *pdata = dev_get_platdata(dev); struct zynq_gem_priv *priv = dev_get_priv(dev); const char *phy_mode; +#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK)
- int ret;
+#endif
pdata->iobase = (phys_addr_t)dev_get_addr(dev); priv->iobase = (struct zynq_gem_regs *)pdata->iobase; @@ -699,6 +723,13 @@ static int zynq_gem_ofdata_to_platdata(struct udevice *dev) } priv->interface = pdata->phy_interface;
+#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK)
- ret = clk_get_by_index(dev, 2, &priv->tx_clk);
- if (ret < 0) {
dev_err(dev, "failed to get clock\n");
return ret;
- }
+#endif
printf("ZYNQ GEM: %lx, phyaddr %x, interface %s\n", (ulong)priv->iobase, priv->phyaddr, phy_string_for_interface(priv->interface));
Can you please rebase it on the top of this? https://patchwork.ozlabs.org/patch/706419/
The reason why this patch was written in this way is that we don't have full zynqmp clk driver yet but we are using fixed clock where you can't run set_rate which fails.
The patch above will be merged soon that's why please rebase it on the top of it. Here is branch with this patch. http://git.denx.de/?p=u-boot/u-boot-microblaze.git;a=summary
Thanks, Michal

-----Ursprüngliche Nachricht----- Von: Michal Simek [mailto:monstr@monstr.eu] Gesendet: Dienstag, 10. Januar 2017 14:59 An: Herbrechtsmeier, Stefan; u-boot@lists.denx.de Cc: Herbrechtsmeier, Stefan; Albert Aribaud; Michal Simek; Joe Hershberger Betreff: Re: [PATCH 2/8] net: zynq: Add clk framework support to zynq ethernet driver
On 4.1.2017 13:27, stefan.herbrechtsmeier@weidmueller.com wrote:
From: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.de
If available use the clock framework to set the tx clock rate of the zynq ethernet controller.
Signed-off-by: Stefan Herbrechtsmeier
stefan.herbrechtsmeier@weidmueller.com
arch/arm/include/asm/arch-zynqmp/sys_proto.h | 5 ----- drivers/net/zynq_gem.c | 31
++++++++++++++++++++++++++++
2 files changed, 31 insertions(+), 5 deletions(-)
diff --git a/arch/arm/include/asm/arch-zynqmp/sys_proto.h b/arch/arm/include/asm/arch-zynqmp/sys_proto.h index 1db2bd6..bd633a6 100644 --- a/arch/arm/include/asm/arch-zynqmp/sys_proto.h +++ b/arch/arm/include/asm/arch-zynqmp/sys_proto.h @@ -8,11 +8,6 @@ #ifndef _ASM_ARCH_SYS_PROTO_H #define _ASM_ARCH_SYS_PROTO_H
-/* Setup clk for network */ -static inline void zynq_slcr_gem_clk_setup(u32 gem_id, unsigned long clk_rate) -{ -}
int zynq_slcr_get_mio_pin_status(const char *periph);
unsigned int zynqmp_get_silicon_version(void); diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 9bfb89f..9118e49 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -9,6 +9,7 @@
- SPDX-License-Identifier: GPL-2.0+
*/
+#include <clk.h> #include <common.h> #include <dm.h> #include <net.h> @@ -180,6 +181,9 @@ struct zynq_gem_priv { struct phy_device *phydev; int phy_of_handle; struct mii_dev *bus; +#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK)
- struct clk tx_clk;
+#endif };
static inline int mdio_wait(struct zynq_gem_regs *regs) @@ -364,6 +368,9 @@ static int zynq_gem_init(struct udevice *dev) u32 i, nwconfig; int ret; unsigned long clk_rate = 0; +#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK)
- unsigned long clk_rate_rounded;
+#endif struct zynq_gem_priv *priv = dev_get_priv(dev); struct zynq_gem_regs *regs = priv->iobase; struct emac_bd *dummy_tx_bd = &priv->tx_bd[TX_FREE_DESC]; @@ -
466,8
+473,22 @@ static int zynq_gem_init(struct udevice *dev) break; }
+#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK)
- clk_rate_rounded = clk_set_rate(&priv->tx_clk, clk_rate);
- if (IS_ERR_VALUE(clk_rate_rounded)) {
dev_err(dev, "failed to set tx clock rate\n");
return clk_rate_rounded;
- }
- ret = clk_enable(&priv->tx_clk);
- if (ret && ret != -ENOSYS) {
dev_err(dev, "failed to enable tx clock\n");
return ret;
- }
+#else zynq_slcr_gem_clk_setup((ulong)priv->iobase != ZYNQ_GEM_BASEADDR0, clk_rate); +#endif
setbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_RXEN_MASK | ZYNQ_GEM_NWCTRL_TXEN_MASK); @@ -678,6 +699,9 @@ static int zynq_gem_ofdata_to_platdata(struct
udevice *dev)
struct eth_pdata *pdata = dev_get_platdata(dev); struct zynq_gem_priv *priv = dev_get_priv(dev); const char *phy_mode; +#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK)
- int ret;
+#endif
pdata->iobase = (phys_addr_t)dev_get_addr(dev); priv->iobase = (struct zynq_gem_regs *)pdata->iobase; @@ -699,6 +723,13 @@ static int zynq_gem_ofdata_to_platdata(struct udevice
*dev)
} priv->interface = pdata->phy_interface;
+#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK)
- ret = clk_get_by_index(dev, 2, &priv->tx_clk);
- if (ret < 0) {
dev_err(dev, "failed to get clock\n");
return ret;
- }
+#endif
printf("ZYNQ GEM: %lx, phyaddr %x, interface %s\n", (ulong)priv- iobase, priv->phyaddr, phy_string_for_interface(priv->interface));
Can you please rebase it on the top of this? https://patchwork.ozlabs.org/patch/706419/
The reason why this patch was written in this way is that we don't have full zynqmp clk driver yet but we are using fixed clock where you can't run set_rate which fails.
The patch assumes that the EMIO_ENET_TX_CLK is always fixed. Is this true?
Why don't you add a set_rate() function to the fixed clock?
Additionally the patch is missing an enable function call.
I don't think the emio configuration should be keep in the Ethernet driver as it is part of the clock configuration and doesn't influent the network interface.
Regards, Stefan
Kommanditgesellschaft - Sitz: Detmold - Amtsgericht Lemgo HRA 2790 - Komplementärin: Weidmüller Interface Führungsgesellschaft mbH - Sitz: Detmold - Amtsgericht Lemgo HRB 3924; Geschäftsführer: José Carlos Álvarez Tobar, Elke Eckstein, Dr. Peter Köhler, Jörg Timmermann; USt-ID-Nr. DE124599660

On 10.1.2017 15:46, Stefan.Herbrechtsmeier@weidmueller.com wrote:
-----Ursprüngliche Nachricht----- Von: Michal Simek [mailto:monstr@monstr.eu] Gesendet: Dienstag, 10. Januar 2017 14:59 An: Herbrechtsmeier, Stefan; u-boot@lists.denx.de Cc: Herbrechtsmeier, Stefan; Albert Aribaud; Michal Simek; Joe Hershberger Betreff: Re: [PATCH 2/8] net: zynq: Add clk framework support to zynq ethernet driver
On 4.1.2017 13:27, stefan.herbrechtsmeier@weidmueller.com wrote:
From: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.de
If available use the clock framework to set the tx clock rate of the zynq ethernet controller.
Signed-off-by: Stefan Herbrechtsmeier
stefan.herbrechtsmeier@weidmueller.com
arch/arm/include/asm/arch-zynqmp/sys_proto.h | 5 ----- drivers/net/zynq_gem.c | 31
++++++++++++++++++++++++++++
2 files changed, 31 insertions(+), 5 deletions(-)
diff --git a/arch/arm/include/asm/arch-zynqmp/sys_proto.h b/arch/arm/include/asm/arch-zynqmp/sys_proto.h index 1db2bd6..bd633a6 100644 --- a/arch/arm/include/asm/arch-zynqmp/sys_proto.h +++ b/arch/arm/include/asm/arch-zynqmp/sys_proto.h @@ -8,11 +8,6 @@ #ifndef _ASM_ARCH_SYS_PROTO_H #define _ASM_ARCH_SYS_PROTO_H
-/* Setup clk for network */ -static inline void zynq_slcr_gem_clk_setup(u32 gem_id, unsigned long clk_rate) -{ -}
int zynq_slcr_get_mio_pin_status(const char *periph);
unsigned int zynqmp_get_silicon_version(void); diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 9bfb89f..9118e49 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -9,6 +9,7 @@
- SPDX-License-Identifier: GPL-2.0+
*/
+#include <clk.h> #include <common.h> #include <dm.h> #include <net.h> @@ -180,6 +181,9 @@ struct zynq_gem_priv { struct phy_device *phydev; int phy_of_handle; struct mii_dev *bus; +#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK)
- struct clk tx_clk;
+#endif };
static inline int mdio_wait(struct zynq_gem_regs *regs) @@ -364,6 +368,9 @@ static int zynq_gem_init(struct udevice *dev) u32 i, nwconfig; int ret; unsigned long clk_rate = 0; +#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK)
- unsigned long clk_rate_rounded;
+#endif struct zynq_gem_priv *priv = dev_get_priv(dev); struct zynq_gem_regs *regs = priv->iobase; struct emac_bd *dummy_tx_bd = &priv->tx_bd[TX_FREE_DESC]; @@ -
466,8
+473,22 @@ static int zynq_gem_init(struct udevice *dev) break; }
+#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK)
- clk_rate_rounded = clk_set_rate(&priv->tx_clk, clk_rate);
- if (IS_ERR_VALUE(clk_rate_rounded)) {
dev_err(dev, "failed to set tx clock rate\n");
return clk_rate_rounded;
- }
- ret = clk_enable(&priv->tx_clk);
- if (ret && ret != -ENOSYS) {
dev_err(dev, "failed to enable tx clock\n");
return ret;
- }
+#else zynq_slcr_gem_clk_setup((ulong)priv->iobase != ZYNQ_GEM_BASEADDR0, clk_rate); +#endif
setbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_RXEN_MASK | ZYNQ_GEM_NWCTRL_TXEN_MASK); @@ -678,6 +699,9 @@ static int zynq_gem_ofdata_to_platdata(struct
udevice *dev)
struct eth_pdata *pdata = dev_get_platdata(dev); struct zynq_gem_priv *priv = dev_get_priv(dev); const char *phy_mode; +#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK)
- int ret;
+#endif
pdata->iobase = (phys_addr_t)dev_get_addr(dev); priv->iobase = (struct zynq_gem_regs *)pdata->iobase; @@ -699,6 +723,13 @@ static int zynq_gem_ofdata_to_platdata(struct udevice
*dev)
} priv->interface = pdata->phy_interface;
+#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK)
- ret = clk_get_by_index(dev, 2, &priv->tx_clk);
- if (ret < 0) {
dev_err(dev, "failed to get clock\n");
return ret;
- }
+#endif
printf("ZYNQ GEM: %lx, phyaddr %x, interface %s\n", (ulong)priv- iobase, priv->phyaddr, phy_string_for_interface(priv->interface));
Can you please rebase it on the top of this? https://patchwork.ozlabs.org/patch/706419/
The reason why this patch was written in this way is that we don't have full zynqmp clk driver yet but we are using fixed clock where you can't run set_rate which fails.
The patch assumes that the EMIO_ENET_TX_CLK is always fixed. Is this true?
Why don't you add a set_rate() function to the fixed clock?
It would be a solution but I am not sure if fixed clock was designed for this. I would expect that fixed clock only provided clock which you can't change. It means we need to have something as transition when u-boot has real clk driver for zynqmp.
Additionally the patch is missing an enable function call.
correct.
I don't think the emio configuration should be keep in the Ethernet driver as it is part of the clock configuration and doesn't influent the network interface.
Please correct me if I am wrong. Are you saying that with these patches especially 8/8 clock for emio will handled automatically?
Thanks, Michal

-----Ursprüngliche Nachricht----- Von: Michal Simek [mailto:monstr@monstr.eu] Gesendet: Dienstag, 10. Januar 2017 16:23
On 10.1.2017 15:46, Stefan.Herbrechtsmeier@weidmueller.com wrote:
-----Ursprüngliche Nachricht----- Von: Michal Simek [mailto:monstr@monstr.eu] Gesendet: Dienstag, 10. Januar 2017 14:59 An: Herbrechtsmeier, Stefan; u-boot@lists.denx.de Cc: Herbrechtsmeier, Stefan; Albert Aribaud; Michal Simek; Joe Hershberger Betreff: Re: [PATCH 2/8] net: zynq: Add clk framework support to
zynq
ethernet driver
On 4.1.2017 13:27, stefan.herbrechtsmeier@weidmueller.com wrote:
From: Stefan Herbrechtsmeier
stefan.herbrechtsmeier@weidmueller.de
If available use the clock framework to set the tx clock rate of
the
zynq ethernet controller.
Signed-off-by: Stefan Herbrechtsmeier
stefan.herbrechtsmeier@weidmueller.com
arch/arm/include/asm/arch-zynqmp/sys_proto.h | 5 ----- drivers/net/zynq_gem.c | 31
++++++++++++++++++++++++++++
2 files changed, 31 insertions(+), 5 deletions(-)
diff --git a/arch/arm/include/asm/arch-zynqmp/sys_proto.h b/arch/arm/include/asm/arch-zynqmp/sys_proto.h index 1db2bd6..bd633a6 100644 --- a/arch/arm/include/asm/arch-zynqmp/sys_proto.h +++ b/arch/arm/include/asm/arch-zynqmp/sys_proto.h @@ -8,11 +8,6 @@ #ifndef _ASM_ARCH_SYS_PROTO_H #define _ASM_ARCH_SYS_PROTO_H
-/* Setup clk for network */ -static inline void zynq_slcr_gem_clk_setup(u32 gem_id, unsigned long clk_rate) -{ -}
int zynq_slcr_get_mio_pin_status(const char *periph);
unsigned int zynqmp_get_silicon_version(void); diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 9bfb89f..9118e49 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -9,6 +9,7 @@
- SPDX-License-Identifier: GPL-2.0+
*/
+#include <clk.h> #include <common.h> #include <dm.h> #include <net.h> @@ -180,6 +181,9 @@ struct zynq_gem_priv { struct phy_device *phydev; int phy_of_handle; struct mii_dev *bus; +#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK)
- struct clk tx_clk;
+#endif };
static inline int mdio_wait(struct zynq_gem_regs *regs) @@ -364,6 +368,9 @@ static int zynq_gem_init(struct udevice *dev) u32 i, nwconfig; int ret; unsigned long clk_rate = 0; +#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK)
- unsigned long clk_rate_rounded;
+#endif struct zynq_gem_priv *priv = dev_get_priv(dev); struct zynq_gem_regs *regs = priv->iobase; struct emac_bd *dummy_tx_bd = &priv->tx_bd[TX_FREE_DESC]; @@ -
466,8
+473,22 @@ static int zynq_gem_init(struct udevice *dev) break; }
+#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK)
- clk_rate_rounded = clk_set_rate(&priv->tx_clk, clk_rate);
- if (IS_ERR_VALUE(clk_rate_rounded)) {
dev_err(dev, "failed to set tx clock rate\n");
return clk_rate_rounded;
- }
- ret = clk_enable(&priv->tx_clk);
- if (ret && ret != -ENOSYS) {
dev_err(dev, "failed to enable tx clock\n");
return ret;
- }
+#else zynq_slcr_gem_clk_setup((ulong)priv->iobase != ZYNQ_GEM_BASEADDR0, clk_rate); +#endif
setbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_RXEN_MASK | ZYNQ_GEM_NWCTRL_TXEN_MASK); @@ -678,6 +699,9 @@ static int zynq_gem_ofdata_to_platdata(struct
udevice *dev)
struct eth_pdata *pdata = dev_get_platdata(dev); struct zynq_gem_priv *priv = dev_get_priv(dev); const char *phy_mode; +#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK)
- int ret;
+#endif
pdata->iobase = (phys_addr_t)dev_get_addr(dev); priv->iobase = (struct zynq_gem_regs *)pdata->iobase; @@ -699,6 +723,13 @@ static int zynq_gem_ofdata_to_platdata(struct udevice
*dev)
} priv->interface = pdata->phy_interface;
+#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK)
- ret = clk_get_by_index(dev, 2, &priv->tx_clk);
- if (ret < 0) {
dev_err(dev, "failed to get clock\n");
return ret;
- }
+#endif
printf("ZYNQ GEM: %lx, phyaddr %x, interface %s\n", (ulong)priv- iobase, priv->phyaddr, phy_string_for_interface(priv->interface));
Can you please rebase it on the top of this? https://patchwork.ozlabs.org/patch/706419/
The reason why this patch was written in this way is that we don't have full zynqmp clk driver yet but we are using fixed clock where you can't run set_rate which fails.
The patch assumes that the EMIO_ENET_TX_CLK is always fixed. Is this
true?
Why don't you add a set_rate() function to the fixed clock?
It would be a solution but I am not sure if fixed clock was designed for this. I would expect that fixed clock only provided clock which you can't change.
I think the current clock framework is not optimal as it doesn't abstract the clock framework from the drivers. I don't know why a not clock driver want to know that an internal clock ops isn't implemented.
I would expect that the driver should not care what clock provides the rate. The clk_set_rate() function should always return the nearest possible clock rate and the clk_enable() shouldn't failed with a missing ops function. Otherwise this functions should be mandatory.
It means we need to have something as transition when u- boot has real clk driver for zynqmp.
We could use the same fall back for the clk_set_rate() as we use for the clk_enable() and ignore the -ENOSYS error.
Additionally the patch is missing an enable function call.
correct.
I don't think the emio configuration should be keep in the Ethernet
driver as it is part of the clock configuration and doesn't influent the network interface.
Please correct me if I am wrong. Are you saying that with these patches especially 8/8 clock for emio will handled automatically?
What do you mean by 8/8 clock?
The Ethernet driver should not care how the clock is connected and only set the required clock rate. The clock driver should route the function calls to the correct clock.
Regards, Stefan
Kommanditgesellschaft - Sitz: Detmold - Amtsgericht Lemgo HRA 2790 - Komplementärin: Weidmüller Interface Führungsgesellschaft mbH - Sitz: Detmold - Amtsgericht Lemgo HRB 3924; Geschäftsführer: José Carlos Álvarez Tobar, Elke Eckstein, Dr. Peter Köhler, Jörg Timmermann; USt-ID-Nr. DE124599660

On 11.1.2017 08:30, Stefan.Herbrechtsmeier@weidmueller.com wrote:
-----Ursprüngliche Nachricht----- Von: Michal Simek [mailto:monstr@monstr.eu] Gesendet: Dienstag, 10. Januar 2017 16:23
On 10.1.2017 15:46, Stefan.Herbrechtsmeier@weidmueller.com wrote:
-----Ursprüngliche Nachricht----- Von: Michal Simek [mailto:monstr@monstr.eu] Gesendet: Dienstag, 10. Januar 2017 14:59 An: Herbrechtsmeier, Stefan; u-boot@lists.denx.de Cc: Herbrechtsmeier, Stefan; Albert Aribaud; Michal Simek; Joe Hershberger Betreff: Re: [PATCH 2/8] net: zynq: Add clk framework support to
zynq
ethernet driver
On 4.1.2017 13:27, stefan.herbrechtsmeier@weidmueller.com wrote:
From: Stefan Herbrechtsmeier
stefan.herbrechtsmeier@weidmueller.de
If available use the clock framework to set the tx clock rate of
the
zynq ethernet controller.
Signed-off-by: Stefan Herbrechtsmeier
stefan.herbrechtsmeier@weidmueller.com
arch/arm/include/asm/arch-zynqmp/sys_proto.h | 5 ----- drivers/net/zynq_gem.c | 31
++++++++++++++++++++++++++++
2 files changed, 31 insertions(+), 5 deletions(-)
diff --git a/arch/arm/include/asm/arch-zynqmp/sys_proto.h b/arch/arm/include/asm/arch-zynqmp/sys_proto.h index 1db2bd6..bd633a6 100644 --- a/arch/arm/include/asm/arch-zynqmp/sys_proto.h +++ b/arch/arm/include/asm/arch-zynqmp/sys_proto.h @@ -8,11 +8,6 @@ #ifndef _ASM_ARCH_SYS_PROTO_H #define _ASM_ARCH_SYS_PROTO_H
-/* Setup clk for network */ -static inline void zynq_slcr_gem_clk_setup(u32 gem_id, unsigned long clk_rate) -{ -}
int zynq_slcr_get_mio_pin_status(const char *periph);
unsigned int zynqmp_get_silicon_version(void); diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 9bfb89f..9118e49 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -9,6 +9,7 @@
- SPDX-License-Identifier: GPL-2.0+
*/
+#include <clk.h> #include <common.h> #include <dm.h> #include <net.h> @@ -180,6 +181,9 @@ struct zynq_gem_priv { struct phy_device *phydev; int phy_of_handle; struct mii_dev *bus; +#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK)
- struct clk tx_clk;
+#endif };
static inline int mdio_wait(struct zynq_gem_regs *regs) @@ -364,6 +368,9 @@ static int zynq_gem_init(struct udevice *dev) u32 i, nwconfig; int ret; unsigned long clk_rate = 0; +#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK)
- unsigned long clk_rate_rounded;
+#endif struct zynq_gem_priv *priv = dev_get_priv(dev); struct zynq_gem_regs *regs = priv->iobase; struct emac_bd *dummy_tx_bd = &priv->tx_bd[TX_FREE_DESC]; @@ -
466,8
+473,22 @@ static int zynq_gem_init(struct udevice *dev) break; }
+#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK)
- clk_rate_rounded = clk_set_rate(&priv->tx_clk, clk_rate);
- if (IS_ERR_VALUE(clk_rate_rounded)) {
dev_err(dev, "failed to set tx clock rate\n");
return clk_rate_rounded;
- }
- ret = clk_enable(&priv->tx_clk);
- if (ret && ret != -ENOSYS) {
dev_err(dev, "failed to enable tx clock\n");
return ret;
- }
+#else zynq_slcr_gem_clk_setup((ulong)priv->iobase != ZYNQ_GEM_BASEADDR0, clk_rate); +#endif
setbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_RXEN_MASK | ZYNQ_GEM_NWCTRL_TXEN_MASK); @@ -678,6 +699,9 @@ static int zynq_gem_ofdata_to_platdata(struct
udevice *dev)
struct eth_pdata *pdata = dev_get_platdata(dev); struct zynq_gem_priv *priv = dev_get_priv(dev); const char *phy_mode; +#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK)
- int ret;
+#endif
pdata->iobase = (phys_addr_t)dev_get_addr(dev); priv->iobase = (struct zynq_gem_regs *)pdata->iobase; @@ -699,6 +723,13 @@ static int zynq_gem_ofdata_to_platdata(struct udevice
*dev)
} priv->interface = pdata->phy_interface;
+#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK)
- ret = clk_get_by_index(dev, 2, &priv->tx_clk);
- if (ret < 0) {
dev_err(dev, "failed to get clock\n");
return ret;
- }
+#endif
printf("ZYNQ GEM: %lx, phyaddr %x, interface %s\n", (ulong)priv- iobase, priv->phyaddr, phy_string_for_interface(priv->interface));
Can you please rebase it on the top of this? https://patchwork.ozlabs.org/patch/706419/
The reason why this patch was written in this way is that we don't have full zynqmp clk driver yet but we are using fixed clock where you can't run set_rate which fails.
The patch assumes that the EMIO_ENET_TX_CLK is always fixed. Is this
true?
Why don't you add a set_rate() function to the fixed clock?
It would be a solution but I am not sure if fixed clock was designed for this. I would expect that fixed clock only provided clock which you can't change.
I think the current clock framework is not optimal as it doesn't abstract the clock framework from the drivers. I don't know why a not clock driver want to know that an internal clock ops isn't implemented.
I would expect that the driver should not care what clock provides the rate. The clk_set_rate() function should always return the nearest possible clock rate and the clk_enable() shouldn't failed with a missing ops function.
Otherwise this functions should be mandatory.
I can't see an issue if clk_set_rate simply failed for clocks which can't change. It is up to driver to handle this if this is fine or not. In ZynqMP some clocks can be locked because they are used for something more important than non secure sw.
It means we need to have something as transition when u- boot has real clk driver for zynqmp.
We could use the same fall back for the clk_set_rate() as we use for the clk_enable() and ignore the -ENOSYS error.
Not a problem with using -ENOSYS which is just a signal that clk driver doesn't care about it.
Additionally the patch is missing an enable function call.
correct.
I don't think the emio configuration should be keep in the Ethernet
driver as it is part of the clock configuration and doesn't influent the network interface.
Please correct me if I am wrong. Are you saying that with these patches especially 8/8 clock for emio will handled automatically?
What do you mean by 8/8 clock?
I meant patch 8/8 in this series.
The Ethernet driver should not care how the clock is connected and only set the required clock rate. The clock driver should route the function calls to the correct clock.
ok. I will try to get testcases for emio to make sure that they are still working correctly.
Thanks, Michal

-----Ursprüngliche Nachricht----- Von: Michal Simek [mailto:michal.simek@xilinx.com] Gesendet: Mittwoch, 11. Januar 2017 09:22
On 11.1.2017 08:30, Stefan.Herbrechtsmeier@weidmueller.com wrote:
-----Ursprüngliche Nachricht----- Von: Michal Simek [mailto:monstr@monstr.eu] Gesendet: Dienstag, 10. Januar 2017 16:23
On 10.1.2017 15:46, Stefan.Herbrechtsmeier@weidmueller.com wrote:
-----Ursprüngliche Nachricht----- Von: Michal Simek [mailto:monstr@monstr.eu] Gesendet: Dienstag, 10. Januar 2017 14:59 An: Herbrechtsmeier, Stefan; u-boot@lists.denx.de Cc: Herbrechtsmeier, Stefan; Albert Aribaud; Michal Simek; Joe Hershberger Betreff: Re: [PATCH 2/8] net: zynq: Add clk framework support to
zynq
ethernet driver
On 4.1.2017 13:27, stefan.herbrechtsmeier@weidmueller.com wrote:
From: Stefan Herbrechtsmeier
stefan.herbrechtsmeier@weidmueller.de
If available use the clock framework to set the tx clock rate of
the
zynq ethernet controller.
Signed-off-by: Stefan Herbrechtsmeier
stefan.herbrechtsmeier@weidmueller.com
arch/arm/include/asm/arch-zynqmp/sys_proto.h | 5 ----- drivers/net/zynq_gem.c | 31
++++++++++++++++++++++++++++
2 files changed, 31 insertions(+), 5 deletions(-)
diff --git a/arch/arm/include/asm/arch-zynqmp/sys_proto.h b/arch/arm/include/asm/arch-zynqmp/sys_proto.h index 1db2bd6..bd633a6 100644 --- a/arch/arm/include/asm/arch-zynqmp/sys_proto.h +++ b/arch/arm/include/asm/arch-zynqmp/sys_proto.h @@ -8,11 +8,6 @@ #ifndef _ASM_ARCH_SYS_PROTO_H #define _ASM_ARCH_SYS_PROTO_H
-/* Setup clk for network */ -static inline void zynq_slcr_gem_clk_setup(u32 gem_id, unsigned long clk_rate) -{ -}
int zynq_slcr_get_mio_pin_status(const char *periph);
unsigned int zynqmp_get_silicon_version(void); diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 9bfb89f..9118e49 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -9,6 +9,7 @@
- SPDX-License-Identifier: GPL-2.0+
*/
+#include <clk.h> #include <common.h> #include <dm.h> #include <net.h> @@ -180,6 +181,9 @@ struct zynq_gem_priv { struct phy_device *phydev; int phy_of_handle; struct mii_dev *bus; +#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK)
- struct clk tx_clk;
+#endif };
static inline int mdio_wait(struct zynq_gem_regs *regs) @@ -
364,6
+368,9 @@ static int zynq_gem_init(struct udevice *dev) u32 i, nwconfig; int ret; unsigned long clk_rate = 0; +#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK)
- unsigned long clk_rate_rounded;
+#endif struct zynq_gem_priv *priv = dev_get_priv(dev); struct zynq_gem_regs *regs = priv->iobase; struct emac_bd *dummy_tx_bd = &priv->tx_bd[TX_FREE_DESC];
@@ -
466,8
+473,22 @@ static int zynq_gem_init(struct udevice *dev) break; }
+#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK)
- clk_rate_rounded = clk_set_rate(&priv->tx_clk, clk_rate);
- if (IS_ERR_VALUE(clk_rate_rounded)) {
dev_err(dev, "failed to set tx clock rate\n");
return clk_rate_rounded;
- }
- ret = clk_enable(&priv->tx_clk);
- if (ret && ret != -ENOSYS) {
dev_err(dev, "failed to enable tx clock\n");
return ret;
- }
+#else zynq_slcr_gem_clk_setup((ulong)priv->iobase != ZYNQ_GEM_BASEADDR0, clk_rate); +#endif
setbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_RXEN_MASK | ZYNQ_GEM_NWCTRL_TXEN_MASK); @@ -678,6 +699,9 @@ static int zynq_gem_ofdata_to_platdata(struct
udevice *dev)
struct eth_pdata *pdata = dev_get_platdata(dev); struct zynq_gem_priv *priv = dev_get_priv(dev); const char *phy_mode; +#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK)
- int ret;
+#endif
pdata->iobase = (phys_addr_t)dev_get_addr(dev); priv->iobase = (struct zynq_gem_regs *)pdata->iobase; @@ -
699,6
+723,13 @@ static int zynq_gem_ofdata_to_platdata(struct udevice
*dev)
} priv->interface = pdata->phy_interface;
+#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK)
- ret = clk_get_by_index(dev, 2, &priv->tx_clk);
- if (ret < 0) {
dev_err(dev, "failed to get clock\n");
return ret;
- }
+#endif
printf("ZYNQ GEM: %lx, phyaddr %x, interface %s\n",
(ulong)priv-
iobase, priv->phyaddr, phy_string_for_interface(priv->interface));
Can you please rebase it on the top of this? https://patchwork.ozlabs.org/patch/706419/
The reason why this patch was written in this way is that we don't have full zynqmp clk driver yet but we are using fixed clock where you can't run set_rate which fails.
The patch assumes that the EMIO_ENET_TX_CLK is always fixed. Is
this
true?
Why don't you add a set_rate() function to the fixed clock?
It would be a solution but I am not sure if fixed clock was designed for this. I would expect that fixed clock only provided clock which you can't change.
I think the current clock framework is not optimal as it doesn't
abstract the clock framework from the drivers. I don't know why a not clock driver want to know that an internal clock ops isn't implemented.
I would expect that the driver should not care what clock provides the rate. The clk_set_rate() function should always return the nearest possible clock rate and the clk_enable() shouldn't failed with a missing ops function. Otherwise this functions should be mandatory.
I can't see an issue if clk_set_rate simply failed for clocks which can't change. It is up to driver to handle this if this is fine or not. In ZynqMP some clocks can be locked because they are used for something more important than non secure sw.
In this case the clock should return the current rate and the not clock driver could decide if it could work with this clock rate or not.
It means we need to have something as transition when u- boot has real clk driver for zynqmp.
We could use the same fall back for the clk_set_rate() as we use for the clk_enable() and ignore the -ENOSYS error.
Not a problem with using -ENOSYS which is just a signal that clk driver doesn't care about it.
Okay. Will you update your patch?
Additionally the patch is missing an enable function call.
correct.
I don't think the emio configuration should be keep in the Ethernet
driver as it is part of the clock configuration and doesn't influent the network interface.
Please correct me if I am wrong. Are you saying that with these patches especially 8/8 clock for emio will handled automatically?
What do you mean by 8/8 clock?
I meant patch 8/8 in this series.
Okay. After patch 8/8 the emio clock should be handled automatically like in Linux kernel.
The Ethernet driver should not care how the clock is connected and
only set the required clock rate. The clock driver should route the function calls to the correct clock.
ok. I will try to get testcases for emio to make sure that they are still working correctly.
Thanks.
Regards, Stefan
Kommanditgesellschaft - Sitz: Detmold - Amtsgericht Lemgo HRA 2790 - Komplementärin: Weidmüller Interface Führungsgesellschaft mbH - Sitz: Detmold - Amtsgericht Lemgo HRB 3924; Geschäftsführer: José Carlos Álvarez Tobar, Elke Eckstein, Dr. Peter Köhler, Jörg Timmermann; USt-ID-Nr. DE124599660

On 11.1.2017 10:55, Stefan.Herbrechtsmeier@weidmueller.com wrote:
-----Ursprüngliche Nachricht----- Von: Michal Simek [mailto:michal.simek@xilinx.com] Gesendet: Mittwoch, 11. Januar 2017 09:22
On 11.1.2017 08:30, Stefan.Herbrechtsmeier@weidmueller.com wrote:
-----Ursprüngliche Nachricht----- Von: Michal Simek [mailto:monstr@monstr.eu] Gesendet: Dienstag, 10. Januar 2017 16:23
On 10.1.2017 15:46, Stefan.Herbrechtsmeier@weidmueller.com wrote:
-----Ursprüngliche Nachricht----- Von: Michal Simek [mailto:monstr@monstr.eu] Gesendet: Dienstag, 10. Januar 2017 14:59 An: Herbrechtsmeier, Stefan; u-boot@lists.denx.de Cc: Herbrechtsmeier, Stefan; Albert Aribaud; Michal Simek; Joe Hershberger Betreff: Re: [PATCH 2/8] net: zynq: Add clk framework support to
zynq
ethernet driver
On 4.1.2017 13:27, stefan.herbrechtsmeier@weidmueller.com wrote: > From: Stefan Herbrechtsmeier
stefan.herbrechtsmeier@weidmueller.de
> > If available use the clock framework to set the tx clock rate of
the
> zynq ethernet controller. > > Signed-off-by: Stefan Herbrechtsmeier > stefan.herbrechtsmeier@weidmueller.com > --- > > arch/arm/include/asm/arch-zynqmp/sys_proto.h | 5 ----- > drivers/net/zynq_gem.c | 31 ++++++++++++++++++++++++++++ > 2 files changed, 31 insertions(+), 5 deletions(-) > > diff --git a/arch/arm/include/asm/arch-zynqmp/sys_proto.h > b/arch/arm/include/asm/arch-zynqmp/sys_proto.h > index 1db2bd6..bd633a6 100644 > --- a/arch/arm/include/asm/arch-zynqmp/sys_proto.h > +++ b/arch/arm/include/asm/arch-zynqmp/sys_proto.h > @@ -8,11 +8,6 @@ > #ifndef _ASM_ARCH_SYS_PROTO_H > #define _ASM_ARCH_SYS_PROTO_H > > -/* Setup clk for network */ > -static inline void zynq_slcr_gem_clk_setup(u32 gem_id, unsigned > long > clk_rate) -{ -} > - > int zynq_slcr_get_mio_pin_status(const char *periph); > > unsigned int zynqmp_get_silicon_version(void); diff --git > a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index > 9bfb89f..9118e49 100644 > --- a/drivers/net/zynq_gem.c > +++ b/drivers/net/zynq_gem.c > @@ -9,6 +9,7 @@ > * SPDX-License-Identifier: GPL-2.0+ > */ > > +#include <clk.h> > #include <common.h> > #include <dm.h> > #include <net.h> > @@ -180,6 +181,9 @@ struct zynq_gem_priv { > struct phy_device *phydev; > int phy_of_handle; > struct mii_dev *bus; > +#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK) > + struct clk tx_clk; > +#endif > }; > > static inline int mdio_wait(struct zynq_gem_regs *regs) @@ -
364,6
> +368,9 @@ static int zynq_gem_init(struct udevice *dev) > u32 i, nwconfig; > int ret; > unsigned long clk_rate = 0; > +#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK) > + unsigned long clk_rate_rounded; > +#endif > struct zynq_gem_priv *priv = dev_get_priv(dev); > struct zynq_gem_regs *regs = priv->iobase; > struct emac_bd *dummy_tx_bd = &priv->tx_bd[TX_FREE_DESC];
@@ -
466,8 > +473,22 @@ static int zynq_gem_init(struct udevice *dev) > break; > } > > +#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK) > + clk_rate_rounded = clk_set_rate(&priv->tx_clk, clk_rate); > + if (IS_ERR_VALUE(clk_rate_rounded)) { > + dev_err(dev, "failed to set tx clock rate\n"); > + return clk_rate_rounded; > + } > + > + ret = clk_enable(&priv->tx_clk); > + if (ret && ret != -ENOSYS) { > + dev_err(dev, "failed to enable tx clock\n"); > + return ret; > + } > +#else > zynq_slcr_gem_clk_setup((ulong)priv->iobase != > ZYNQ_GEM_BASEADDR0, clk_rate); > +#endif > > setbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_RXEN_MASK | > ZYNQ_GEM_NWCTRL_TXEN_MASK); > @@ -678,6 +699,9 @@ static int zynq_gem_ofdata_to_platdata(struct udevice *dev) > struct eth_pdata *pdata = dev_get_platdata(dev); > struct zynq_gem_priv *priv = dev_get_priv(dev); > const char *phy_mode; > +#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK) > + int ret; > +#endif > > pdata->iobase = (phys_addr_t)dev_get_addr(dev); > priv->iobase = (struct zynq_gem_regs *)pdata->iobase; @@ -
699,6
> +723,13 @@ static int zynq_gem_ofdata_to_platdata(struct udevice *dev) > } > priv->interface = pdata->phy_interface; > > +#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK) > + ret = clk_get_by_index(dev, 2, &priv->tx_clk); > + if (ret < 0) { > + dev_err(dev, "failed to get clock\n"); > + return ret; > + } > +#endif > > printf("ZYNQ GEM: %lx, phyaddr %x, interface %s\n",
(ulong)priv-
> iobase, > priv->phyaddr, > phy_string_for_interface(priv->interface)); >
Can you please rebase it on the top of this? https://patchwork.ozlabs.org/patch/706419/
The reason why this patch was written in this way is that we don't have full zynqmp clk driver yet but we are using fixed clock where you can't run set_rate which fails.
The patch assumes that the EMIO_ENET_TX_CLK is always fixed. Is
this
true?
Why don't you add a set_rate() function to the fixed clock?
It would be a solution but I am not sure if fixed clock was designed for this. I would expect that fixed clock only provided clock which you can't change.
I think the current clock framework is not optimal as it doesn't
abstract the clock framework from the drivers. I don't know why a not clock driver want to know that an internal clock ops isn't implemented.
I would expect that the driver should not care what clock provides the rate. The clk_set_rate() function should always return the nearest possible clock rate and the clk_enable() shouldn't failed with a missing ops function. Otherwise this functions should be mandatory.
I can't see an issue if clk_set_rate simply failed for clocks which can't change. It is up to driver to handle this if this is fine or not. In ZynqMP some clocks can be locked because they are used for something more important than non secure sw.
In this case the clock should return the current rate and the not clock driver could decide if it could work with this clock rate or not.
I would discuss this with clk guys. I was checking existing code and a lot of drivers are only checking error value not rate which is return. But based on clk.h driver should check if clk rate is sufficient for that particular case.
It means we need to have something as transition when u- boot has real clk driver for zynqmp.
We could use the same fall back for the clk_set_rate() as we use for the clk_enable() and ignore the -ENOSYS error.
Not a problem with using -ENOSYS which is just a signal that clk driver doesn't care about it.
Okay. Will you update your patch?
I have sent PR to Tom some hours ago. It is not big deal to patch it. If you can do it as the part of your rebase that will be great. If you want me to do I can send another patch just for this one.
Additionally the patch is missing an enable function call.
correct.
I don't think the emio configuration should be keep in the Ethernet
driver as it is part of the clock configuration and doesn't influent the network interface.
Please correct me if I am wrong. Are you saying that with these patches especially 8/8 clock for emio will handled automatically?
What do you mean by 8/8 clock?
I meant patch 8/8 in this series.
Okay. After patch 8/8 the emio clock should be handled automatically like in Linux kernel.
good.
Thanks, Michal

From: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com
If available use the clock framework to calculate the clock rate of the zynq timer.
Signed-off-by: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com ---
arch/arm/mach-zynq/timer.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)
diff --git a/arch/arm/mach-zynq/timer.c b/arch/arm/mach-zynq/timer.c index 8ff82dc..0335cbe 100644 --- a/arch/arm/mach-zynq/timer.c +++ b/arch/arm/mach-zynq/timer.c @@ -1,4 +1,7 @@ /* + * Copyright (C) 2017 Weidmüller Interface GmbH & Co. KG + * Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com + * * Copyright (C) 2012 Michal Simek monstr@monstr.eu * Copyright (C) 2011-2012 Xilinx, Inc. All rights reserved. * @@ -25,8 +28,10 @@ * SPDX-License-Identifier: GPL-2.0+ */
+#include <clk.h> #include <common.h> #include <div64.h> +#include <dm.h> #include <asm/io.h> #include <asm/arch/hardware.h> #include <asm/arch/clk.h> @@ -56,6 +61,26 @@ int timer_init(void) (TIMER_PRESCALE << SCUTIMER_CONTROL_PRESCALER_SHIFT) | SCUTIMER_CONTROL_ENABLE_MASK;
+#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK) + struct udevice *dev; + struct clk clk; + int ret; + + ret = uclass_get_device_by_driver(UCLASS_CLK, + DM_GET_DRIVER(zynq_clk), &dev); + if (ret) + return ret; + + clk.id = cpu_6or4x_clk; + ret = clk_request(dev, &clk); + if (ret < 0) + return ret; + + gd->cpu_clk = clk_get_rate(&clk); + + clk_free(&clk); +#endif + gd->arch.timer_rate_hz = (gd->cpu_clk / 2) / (TIMER_PRESCALE + 1);
/* Load the timer counter register */

On 4.1.2017 13:27, stefan.herbrechtsmeier@weidmueller.com wrote:
From: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com
If available use the clock framework to calculate the clock rate of the zynq timer.
Signed-off-by: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com
arch/arm/mach-zynq/timer.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)
diff --git a/arch/arm/mach-zynq/timer.c b/arch/arm/mach-zynq/timer.c index 8ff82dc..0335cbe 100644 --- a/arch/arm/mach-zynq/timer.c +++ b/arch/arm/mach-zynq/timer.c @@ -1,4 +1,7 @@ /*
- Copyright (C) 2017 Weidmüller Interface GmbH & Co. KG
- Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com
- Copyright (C) 2012 Michal Simek monstr@monstr.eu
- Copyright (C) 2011-2012 Xilinx, Inc. All rights reserved.
@@ -25,8 +28,10 @@
- SPDX-License-Identifier: GPL-2.0+
*/
+#include <clk.h> #include <common.h> #include <div64.h> +#include <dm.h> #include <asm/io.h> #include <asm/arch/hardware.h> #include <asm/arch/clk.h> @@ -56,6 +61,26 @@ int timer_init(void) (TIMER_PRESCALE << SCUTIMER_CONTROL_PRESCALER_SHIFT) | SCUTIMER_CONTROL_ENABLE_MASK;
+#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK)
- struct udevice *dev;
- struct clk clk;
- int ret;
- ret = uclass_get_device_by_driver(UCLASS_CLK,
DM_GET_DRIVER(zynq_clk), &dev);
- if (ret)
return ret;
- clk.id = cpu_6or4x_clk;
This information is already present in DT file. What's the reason not to take it from it?
- ret = clk_request(dev, &clk);
- if (ret < 0)
return ret;
- gd->cpu_clk = clk_get_rate(&clk);
- clk_free(&clk);
Not clk expert but isn't there a way to handle it like it is handled for other drivers? clk_get(), clk_get_rate()?
+#endif
gd->arch.timer_rate_hz = (gd->cpu_clk / 2) / (TIMER_PRESCALE + 1);
/* Load the timer counter register */
Thanks, Michal

-----Ursprüngliche Nachricht----- Von: Michal Simek [mailto:monstr@monstr.eu] Gesendet: Dienstag, 10. Januar 2017 15:10 An: Herbrechtsmeier, Stefan; u-boot@lists.denx.de Cc: Albert Aribaud; Herbrechtsmeier, Stefan Betreff: Re: [PATCH 3/8] zynq: Add clk framework support to zynq timer
On 4.1.2017 13:27, stefan.herbrechtsmeier@weidmueller.com wrote:
From: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com
If available use the clock framework to calculate the clock rate of the zynq timer.
Signed-off-by: Stefan Herbrechtsmeier
stefan.herbrechtsmeier@weidmueller.com
arch/arm/mach-zynq/timer.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)
diff --git a/arch/arm/mach-zynq/timer.c b/arch/arm/mach-zynq/timer.c index 8ff82dc..0335cbe 100644 --- a/arch/arm/mach-zynq/timer.c +++ b/arch/arm/mach-zynq/timer.c @@ -1,4 +1,7 @@ /*
- Copyright (C) 2017 Weidmüller Interface GmbH & Co. KG
- Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com
- Copyright (C) 2012 Michal Simek monstr@monstr.eu
- Copyright (C) 2011-2012 Xilinx, Inc. All rights reserved.
@@ -25,8 +28,10 @@
- SPDX-License-Identifier: GPL-2.0+
*/
+#include <clk.h> #include <common.h> #include <div64.h> +#include <dm.h> #include <asm/io.h> #include <asm/arch/hardware.h> #include <asm/arch/clk.h> @@ -56,6 +61,26 @@ int timer_init(void) (TIMER_PRESCALE << SCUTIMER_CONTROL_PRESCALER_SHIFT)
|
SCUTIMER_CONTROL_ENABLE_MASK;
+#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK)
- struct udevice *dev;
- struct clk clk;
- int ret;
- ret = uclass_get_device_by_driver(UCLASS_CLK,
DM_GET_DRIVER(zynq_clk), &dev);
- if (ret)
return ret;
- clk.id = cpu_6or4x_clk;
This information is already present in DT file. What's the reason not to take it from it?
Because this is not a DM driver and I don't know the device node. This could be done if we move the driver to drivers/timer.
- ret = clk_request(dev, &clk);
- if (ret < 0)
return ret;
- gd->cpu_clk = clk_get_rate(&clk);
- clk_free(&clk);
Not clk expert but isn't there a way to handle it like it is handled for other drivers? clk_get(), clk_get_rate()?
This is the solution I found in other platform drivers. The clk_get function requires a DM device.
+#endif
- gd->arch.timer_rate_hz = (gd->cpu_clk / 2) / (TIMER_PRESCALE +
1);
/* Load the timer counter register */
Regards, Stefan
Kommanditgesellschaft - Sitz: Detmold - Amtsgericht Lemgo HRA 2790 - Komplementärin: Weidmüller Interface Führungsgesellschaft mbH - Sitz: Detmold - Amtsgericht Lemgo HRB 3924; Geschäftsführer: José Carlos Álvarez Tobar, Elke Eckstein, Dr. Peter Köhler, Jörg Timmermann; USt-ID-Nr. DE124599660

On 10.1.2017 15:54, Stefan.Herbrechtsmeier@weidmueller.com wrote:
-----Ursprüngliche Nachricht----- Von: Michal Simek [mailto:monstr@monstr.eu] Gesendet: Dienstag, 10. Januar 2017 15:10 An: Herbrechtsmeier, Stefan; u-boot@lists.denx.de Cc: Albert Aribaud; Herbrechtsmeier, Stefan Betreff: Re: [PATCH 3/8] zynq: Add clk framework support to zynq timer
On 4.1.2017 13:27, stefan.herbrechtsmeier@weidmueller.com wrote:
From: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com
If available use the clock framework to calculate the clock rate of the zynq timer.
Signed-off-by: Stefan Herbrechtsmeier
stefan.herbrechtsmeier@weidmueller.com
arch/arm/mach-zynq/timer.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)
diff --git a/arch/arm/mach-zynq/timer.c b/arch/arm/mach-zynq/timer.c index 8ff82dc..0335cbe 100644 --- a/arch/arm/mach-zynq/timer.c +++ b/arch/arm/mach-zynq/timer.c @@ -1,4 +1,7 @@ /*
- Copyright (C) 2017 Weidmüller Interface GmbH & Co. KG
- Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com
- Copyright (C) 2012 Michal Simek monstr@monstr.eu
- Copyright (C) 2011-2012 Xilinx, Inc. All rights reserved.
@@ -25,8 +28,10 @@
- SPDX-License-Identifier: GPL-2.0+
*/
+#include <clk.h> #include <common.h> #include <div64.h> +#include <dm.h> #include <asm/io.h> #include <asm/arch/hardware.h> #include <asm/arch/clk.h> @@ -56,6 +61,26 @@ int timer_init(void) (TIMER_PRESCALE << SCUTIMER_CONTROL_PRESCALER_SHIFT)
|
SCUTIMER_CONTROL_ENABLE_MASK;
+#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK)
- struct udevice *dev;
- struct clk clk;
- int ret;
- ret = uclass_get_device_by_driver(UCLASS_CLK,
DM_GET_DRIVER(zynq_clk), &dev);
- if (ret)
return ret;
- clk.id = cpu_6or4x_clk;
This information is already present in DT file. What's the reason not to take it from it?
Because this is not a DM driver and I don't know the device node. This could be done if we move the driver to drivers/timer.
- ret = clk_request(dev, &clk);
- if (ret < 0)
return ret;
- gd->cpu_clk = clk_get_rate(&clk);
- clk_free(&clk);
Not clk expert but isn't there a way to handle it like it is handled for other drivers? clk_get(), clk_get_rate()?
This is the solution I found in other platform drivers. The clk_get function requires a DM device.
Ok fair enough. We can use it when driver is moved.
Thanks, Michal

From: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.de
The clock names are static and correspond to the clock id. Separate them from the dynamic filled clock array.
Signed-off-by: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com ---
arch/arm/mach-zynq/clk.c | 121 +++++++++++++++++++++++------------------------ 1 file changed, 60 insertions(+), 61 deletions(-)
diff --git a/arch/arm/mach-zynq/clk.c b/arch/arm/mach-zynq/clk.c index 40383c1..7bff964 100644 --- a/arch/arm/mach-zynq/clk.c +++ b/arch/arm/mach-zynq/clk.c @@ -58,7 +58,6 @@ struct zynq_clk_ops {
/** * struct clk: - * @name: Clock name * @frequency: Currenct frequency * @parent: Parent clock * @flags: Clock flags @@ -66,7 +65,6 @@ struct zynq_clk_ops { * @ops: Clock operations */ struct clk { - char *name; unsigned long frequency; enum zynq_clk parent; unsigned int flags; @@ -77,6 +75,20 @@ struct clk {
static struct clk clks[clk_max];
+static const char * const clk_names[clk_max] = { + "armpll", "ddrpll", "iopll", + "cpu_6or4x", "cpu_3or2x", "cpu_2x", "cpu_1x", + "ddr2x", "ddr3x", "dci", + "lqspi", "smc", "pcap", "gem0", "gem1", + "fclk0", "fclk1", "fclk2", "fclk3", "can0", "can1", + "sdio0", "sdio1", "uart0", "uart1", "spi0", "spi1", "dma", + "usb0_aper", "usb1_aper", "gem0_aper", "gem1_aper", + "sdio0_aper", "sdio1_aper", "spi0_aper", "spi1_aper", + "can0_aper", "can1_aper", "i2c0_aper", "i2c1_aper", + "uart0_aper", "uart1_aper", "gpio_aper", "lqspi_aper", + "smc_aper", "swdt", "dbg_trc", "dbg_apb" +}; + /** * __zynq_clk_cpu_get_parent() - Decode clock multiplexer * @srcsel: Mux select value @@ -140,14 +152,12 @@ static void init_ddr_clocks(void) /* DDR2x */ clks[ddr2x_clk].reg = &slcr_base->ddr_clk_ctrl; clks[ddr2x_clk].parent = ddrpll_clk; - clks[ddr2x_clk].name = "ddr_2x"; clks[ddr2x_clk].frequency = ddr2x_get_rate(&clks[ddr2x_clk]); clks[ddr2x_clk].ops.get_rate = ddr2x_get_rate;
/* DDR3x */ clks[ddr3x_clk].reg = &slcr_base->ddr_clk_ctrl; clks[ddr3x_clk].parent = ddrpll_clk; - clks[ddr3x_clk].name = "ddr_3x"; clks[ddr3x_clk].frequency = ddr3x_get_rate(&clks[ddr3x_clk]); clks[ddr3x_clk].ops.get_rate = ddr3x_get_rate;
@@ -159,7 +169,6 @@ static void init_ddr_clocks(void) clks[dci_clk].parent = ddrpll_clk; clks[dci_clk].frequency = DIV_ROUND_CLOSEST( DIV_ROUND_CLOSEST(prate, div0), div1); - clks[dci_clk].name = "dci";
gd->bd->bi_ddr_freq = clks[ddr3x_clk].frequency / 1000000; } @@ -181,24 +190,20 @@ static void init_cpu_clocks(void) clks[cpu_6or4x_clk].parent = parent; clks[cpu_6or4x_clk].frequency = DIV_ROUND_CLOSEST( zynq_clk_get_rate(parent), div); - clks[cpu_6or4x_clk].name = "cpu_6or4x";
clks[cpu_3or2x_clk].reg = &slcr_base->arm_clk_ctrl; clks[cpu_3or2x_clk].parent = cpu_6or4x_clk; clks[cpu_3or2x_clk].frequency = zynq_clk_get_rate(cpu_6or4x_clk) / 2; - clks[cpu_3or2x_clk].name = "cpu_3or2x";
clks[cpu_2x_clk].reg = &slcr_base->arm_clk_ctrl; clks[cpu_2x_clk].parent = cpu_6or4x_clk; clks[cpu_2x_clk].frequency = zynq_clk_get_rate(cpu_6or4x_clk) / (2 + clk_621); - clks[cpu_2x_clk].name = "cpu_2x";
clks[cpu_1x_clk].reg = &slcr_base->arm_clk_ctrl; clks[cpu_1x_clk].parent = cpu_6or4x_clk; clks[cpu_1x_clk].frequency = zynq_clk_get_rate(cpu_6or4x_clk) / (4 + 2 * clk_621); - clks[cpu_1x_clk].name = "cpu_1x"; }
/** @@ -338,13 +343,11 @@ static enum zynq_clk zynq_clk_periph_get_parent(struct clk *clk) * zynq_clk_register_periph_clk() - Set up a peripheral clock with the framework * @clk: Pointer to struct clk for the clock * @ctrl: Clock control register - * @name: PLL name * @two_divs: Indicates whether the clock features one or two dividers */ -static int zynq_clk_register_periph_clk(struct clk *clk, u32 *ctrl, char *name, +static int zynq_clk_register_periph_clk(struct clk *clk, u32 *ctrl, bool two_divs) { - clk->name = name; clk->reg = ctrl; if (two_divs) clk->flags = ZYNQ_CLK_FLAGS_HAS_2_DIVS; @@ -358,59 +361,57 @@ static int zynq_clk_register_periph_clk(struct clk *clk, u32 *ctrl, char *name,
static void init_periph_clocks(void) { - zynq_clk_register_periph_clk(&clks[gem0_clk], &slcr_base->gem0_clk_ctrl, - "gem0", 1); - zynq_clk_register_periph_clk(&clks[gem1_clk], &slcr_base->gem1_clk_ctrl, - "gem1", 1); + zynq_clk_register_periph_clk(&clks[gem0_clk], + &slcr_base->gem0_clk_ctrl, 1); + zynq_clk_register_periph_clk(&clks[gem1_clk], + &slcr_base->gem1_clk_ctrl, 1);
- zynq_clk_register_periph_clk(&clks[smc_clk], &slcr_base->smc_clk_ctrl, - "smc", 0); + zynq_clk_register_periph_clk(&clks[smc_clk], + &slcr_base->smc_clk_ctrl, 0);
zynq_clk_register_periph_clk(&clks[lqspi_clk], - &slcr_base->lqspi_clk_ctrl, "lqspi", 0); + &slcr_base->lqspi_clk_ctrl, 0);
zynq_clk_register_periph_clk(&clks[sdio0_clk], - &slcr_base->sdio_clk_ctrl, "sdio0", 0); + &slcr_base->sdio_clk_ctrl, 0); zynq_clk_register_periph_clk(&clks[sdio1_clk], - &slcr_base->sdio_clk_ctrl, "sdio1", 0); + &slcr_base->sdio_clk_ctrl, 0);
- zynq_clk_register_periph_clk(&clks[spi0_clk], &slcr_base->spi_clk_ctrl, - "spi0", 0); - zynq_clk_register_periph_clk(&clks[spi1_clk], &slcr_base->spi_clk_ctrl, - "spi1", 0); + zynq_clk_register_periph_clk(&clks[spi0_clk], + &slcr_base->spi_clk_ctrl, 0); + zynq_clk_register_periph_clk(&clks[spi1_clk], + &slcr_base->spi_clk_ctrl, 0);
zynq_clk_register_periph_clk(&clks[uart0_clk], - &slcr_base->uart_clk_ctrl, "uart0", 0); + &slcr_base->uart_clk_ctrl, 0); zynq_clk_register_periph_clk(&clks[uart1_clk], - &slcr_base->uart_clk_ctrl, "uart1", 0); + &slcr_base->uart_clk_ctrl, 0);
zynq_clk_register_periph_clk(&clks[dbg_trc_clk], - &slcr_base->dbg_clk_ctrl, "dbg_trc", 0); + &slcr_base->dbg_clk_ctrl, 0); zynq_clk_register_periph_clk(&clks[dbg_apb_clk], - &slcr_base->dbg_clk_ctrl, "dbg_apb", 0); + &slcr_base->dbg_clk_ctrl, 0);
zynq_clk_register_periph_clk(&clks[pcap_clk], - &slcr_base->pcap_clk_ctrl, "pcap", 0); + &slcr_base->pcap_clk_ctrl, 0);
zynq_clk_register_periph_clk(&clks[fclk0_clk], - &slcr_base->fpga0_clk_ctrl, "fclk0", 1); + &slcr_base->fpga0_clk_ctrl, 1); zynq_clk_register_periph_clk(&clks[fclk1_clk], - &slcr_base->fpga1_clk_ctrl, "fclk1", 1); + &slcr_base->fpga1_clk_ctrl, 1); zynq_clk_register_periph_clk(&clks[fclk2_clk], - &slcr_base->fpga2_clk_ctrl, "fclk2", 1); + &slcr_base->fpga2_clk_ctrl, 1); zynq_clk_register_periph_clk(&clks[fclk3_clk], - &slcr_base->fpga3_clk_ctrl, "fclk3", 1); + &slcr_base->fpga3_clk_ctrl, 1); }
/** * zynq_clk_register_aper_clk() - Set up a APER clock with the framework * @clk: Pointer to struct clk for the clock * @ctrl: Clock control register - * @name: PLL name */ -static void zynq_clk_register_aper_clk(struct clk *clk, u32 *ctrl, char *name) +static void zynq_clk_register_aper_clk(struct clk *clk, u32 *ctrl) { - clk->name = name; clk->reg = ctrl; clk->parent = cpu_1x_clk; clk->frequency = zynq_clk_get_rate(clk->parent); @@ -419,48 +420,48 @@ static void zynq_clk_register_aper_clk(struct clk *clk, u32 *ctrl, char *name) static void init_aper_clocks(void) { zynq_clk_register_aper_clk(&clks[usb0_aper_clk], - &slcr_base->aper_clk_ctrl, "usb0_aper"); + &slcr_base->aper_clk_ctrl); zynq_clk_register_aper_clk(&clks[usb1_aper_clk], - &slcr_base->aper_clk_ctrl, "usb1_aper"); + &slcr_base->aper_clk_ctrl);
zynq_clk_register_aper_clk(&clks[gem0_aper_clk], - &slcr_base->aper_clk_ctrl, "gem0_aper"); + &slcr_base->aper_clk_ctrl); zynq_clk_register_aper_clk(&clks[gem1_aper_clk], - &slcr_base->aper_clk_ctrl, "gem1_aper"); + &slcr_base->aper_clk_ctrl);
zynq_clk_register_aper_clk(&clks[sdio0_aper_clk], - &slcr_base->aper_clk_ctrl, "sdio0_aper"); + &slcr_base->aper_clk_ctrl); zynq_clk_register_aper_clk(&clks[sdio1_aper_clk], - &slcr_base->aper_clk_ctrl, "sdio1_aper"); + &slcr_base->aper_clk_ctrl);
zynq_clk_register_aper_clk(&clks[spi0_aper_clk], - &slcr_base->aper_clk_ctrl, "spi0_aper"); + &slcr_base->aper_clk_ctrl); zynq_clk_register_aper_clk(&clks[spi1_aper_clk], - &slcr_base->aper_clk_ctrl, "spi1_aper"); + &slcr_base->aper_clk_ctrl);
zynq_clk_register_aper_clk(&clks[can0_aper_clk], - &slcr_base->aper_clk_ctrl, "can0_aper"); + &slcr_base->aper_clk_ctrl); zynq_clk_register_aper_clk(&clks[can1_aper_clk], - &slcr_base->aper_clk_ctrl, "can1_aper"); + &slcr_base->aper_clk_ctrl);
zynq_clk_register_aper_clk(&clks[i2c0_aper_clk], - &slcr_base->aper_clk_ctrl, "i2c0_aper"); + &slcr_base->aper_clk_ctrl); zynq_clk_register_aper_clk(&clks[i2c1_aper_clk], - &slcr_base->aper_clk_ctrl, "i2c1_aper"); + &slcr_base->aper_clk_ctrl);
zynq_clk_register_aper_clk(&clks[uart0_aper_clk], - &slcr_base->aper_clk_ctrl, "uart0_aper"); + &slcr_base->aper_clk_ctrl); zynq_clk_register_aper_clk(&clks[uart1_aper_clk], - &slcr_base->aper_clk_ctrl, "uart1_aper"); + &slcr_base->aper_clk_ctrl);
zynq_clk_register_aper_clk(&clks[gpio_aper_clk], - &slcr_base->aper_clk_ctrl, "gpio_aper"); + &slcr_base->aper_clk_ctrl);
zynq_clk_register_aper_clk(&clks[lqspi_aper_clk], - &slcr_base->aper_clk_ctrl, "lqspi_aper"); + &slcr_base->aper_clk_ctrl);
zynq_clk_register_aper_clk(&clks[smc_aper_clk], - &slcr_base->aper_clk_ctrl, "smc_aper"); + &slcr_base->aper_clk_ctrl); }
/** @@ -496,13 +497,11 @@ static unsigned long zynq_clk_pll_get_rate(struct clk *pll) * zynq_clk_register_pll() - Set up a PLL with the framework * @clk: Pointer to struct clk for the PLL * @ctrl: PLL control register - * @name: PLL name * @prate: PLL input clock rate */ -static void zynq_clk_register_pll(struct clk *clk, u32 *ctrl, char *name, +static void zynq_clk_register_pll(struct clk *clk, u32 *ctrl, unsigned long prate) { - clk->name = name; clk->reg = ctrl; clk->frequency = zynq_clk_pll_get_rate(clk); clk->ops.get_rate = zynq_clk_pll_get_rate; @@ -583,11 +582,11 @@ unsigned long get_uart_clk(int dev_index) int set_cpu_clk_info(void) { zynq_clk_register_pll(&clks[armpll_clk], &slcr_base->arm_pll_ctrl, - "armpll", CONFIG_ZYNQ_PS_CLK_FREQ); + CONFIG_ZYNQ_PS_CLK_FREQ); zynq_clk_register_pll(&clks[ddrpll_clk], &slcr_base->ddr_pll_ctrl, - "ddrpll", CONFIG_ZYNQ_PS_CLK_FREQ); + CONFIG_ZYNQ_PS_CLK_FREQ); zynq_clk_register_pll(&clks[iopll_clk], &slcr_base->io_pll_ctrl, - "iopll", CONFIG_ZYNQ_PS_CLK_FREQ); + CONFIG_ZYNQ_PS_CLK_FREQ);
init_ddr_clocks(); init_cpu_clocks(); @@ -639,7 +638,7 @@ int zynq_clk_set_rate(enum zynq_clk clk, unsigned long rate) */ const char *zynq_clk_get_name(enum zynq_clk clk) { - return clks[clk].name; + return clk_names[clk]; }
/**

On 4.1.2017 13:27, stefan.herbrechtsmeier@weidmueller.com wrote:
From: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.de
The clock names are static and correspond to the clock id. Separate them from the dynamic filled clock array.
Signed-off-by: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com
arch/arm/mach-zynq/clk.c | 121 +++++++++++++++++++++++------------------------ 1 file changed, 60 insertions(+), 61 deletions(-)
diff --git a/arch/arm/mach-zynq/clk.c b/arch/arm/mach-zynq/clk.c index 40383c1..7bff964 100644 --- a/arch/arm/mach-zynq/clk.c +++ b/arch/arm/mach-zynq/clk.c @@ -58,7 +58,6 @@ struct zynq_clk_ops {
/**
- struct clk:
- @name: Clock name
- @frequency: Currenct frequency
- @parent: Parent clock
- @flags: Clock flags
@@ -66,7 +65,6 @@ struct zynq_clk_ops {
- @ops: Clock operations
*/ struct clk {
- char *name; unsigned long frequency; enum zynq_clk parent; unsigned int flags;
@@ -77,6 +75,20 @@ struct clk {
static struct clk clks[clk_max];
+static const char * const clk_names[clk_max] = {
- "armpll", "ddrpll", "iopll",
- "cpu_6or4x", "cpu_3or2x", "cpu_2x", "cpu_1x",
- "ddr2x", "ddr3x", "dci",
- "lqspi", "smc", "pcap", "gem0", "gem1",
- "fclk0", "fclk1", "fclk2", "fclk3", "can0", "can1",
- "sdio0", "sdio1", "uart0", "uart1", "spi0", "spi1", "dma",
- "usb0_aper", "usb1_aper", "gem0_aper", "gem1_aper",
- "sdio0_aper", "sdio1_aper", "spi0_aper", "spi1_aper",
- "can0_aper", "can1_aper", "i2c0_aper", "i2c1_aper",
- "uart0_aper", "uart1_aper", "gpio_aper", "lqspi_aper",
- "smc_aper", "swdt", "dbg_trc", "dbg_apb"
+};
/**
- __zynq_clk_cpu_get_parent() - Decode clock multiplexer
- @srcsel: Mux select value
@@ -140,14 +152,12 @@ static void init_ddr_clocks(void) /* DDR2x */ clks[ddr2x_clk].reg = &slcr_base->ddr_clk_ctrl; clks[ddr2x_clk].parent = ddrpll_clk;
clks[ddr2x_clk].name = "ddr_2x"; clks[ddr2x_clk].frequency = ddr2x_get_rate(&clks[ddr2x_clk]); clks[ddr2x_clk].ops.get_rate = ddr2x_get_rate;
/* DDR3x */ clks[ddr3x_clk].reg = &slcr_base->ddr_clk_ctrl; clks[ddr3x_clk].parent = ddrpll_clk;
clks[ddr3x_clk].name = "ddr_3x"; clks[ddr3x_clk].frequency = ddr3x_get_rate(&clks[ddr3x_clk]); clks[ddr3x_clk].ops.get_rate = ddr3x_get_rate;
@@ -159,7 +169,6 @@ static void init_ddr_clocks(void) clks[dci_clk].parent = ddrpll_clk; clks[dci_clk].frequency = DIV_ROUND_CLOSEST( DIV_ROUND_CLOSEST(prate, div0), div1);
clks[dci_clk].name = "dci";
gd->bd->bi_ddr_freq = clks[ddr3x_clk].frequency / 1000000;
} @@ -181,24 +190,20 @@ static void init_cpu_clocks(void) clks[cpu_6or4x_clk].parent = parent; clks[cpu_6or4x_clk].frequency = DIV_ROUND_CLOSEST( zynq_clk_get_rate(parent), div);
clks[cpu_6or4x_clk].name = "cpu_6or4x";
clks[cpu_3or2x_clk].reg = &slcr_base->arm_clk_ctrl; clks[cpu_3or2x_clk].parent = cpu_6or4x_clk; clks[cpu_3or2x_clk].frequency = zynq_clk_get_rate(cpu_6or4x_clk) / 2;
clks[cpu_3or2x_clk].name = "cpu_3or2x";
clks[cpu_2x_clk].reg = &slcr_base->arm_clk_ctrl; clks[cpu_2x_clk].parent = cpu_6or4x_clk; clks[cpu_2x_clk].frequency = zynq_clk_get_rate(cpu_6or4x_clk) / (2 + clk_621);
clks[cpu_2x_clk].name = "cpu_2x";
clks[cpu_1x_clk].reg = &slcr_base->arm_clk_ctrl; clks[cpu_1x_clk].parent = cpu_6or4x_clk; clks[cpu_1x_clk].frequency = zynq_clk_get_rate(cpu_6or4x_clk) / (4 + 2 * clk_621);
clks[cpu_1x_clk].name = "cpu_1x";
}
/** @@ -338,13 +343,11 @@ static enum zynq_clk zynq_clk_periph_get_parent(struct clk *clk)
- zynq_clk_register_periph_clk() - Set up a peripheral clock with the framework
- @clk: Pointer to struct clk for the clock
- @ctrl: Clock control register
*/
- @name: PLL name
- @two_divs: Indicates whether the clock features one or two dividers
-static int zynq_clk_register_periph_clk(struct clk *clk, u32 *ctrl, char *name, +static int zynq_clk_register_periph_clk(struct clk *clk, u32 *ctrl, bool two_divs) {
- clk->name = name; clk->reg = ctrl; if (two_divs) clk->flags = ZYNQ_CLK_FLAGS_HAS_2_DIVS;
@@ -358,59 +361,57 @@ static int zynq_clk_register_periph_clk(struct clk *clk, u32 *ctrl, char *name,
static void init_periph_clocks(void) {
- zynq_clk_register_periph_clk(&clks[gem0_clk], &slcr_base->gem0_clk_ctrl,
"gem0", 1);
- zynq_clk_register_periph_clk(&clks[gem1_clk], &slcr_base->gem1_clk_ctrl,
"gem1", 1);
- zynq_clk_register_periph_clk(&clks[gem0_clk],
&slcr_base->gem0_clk_ctrl, 1);
- zynq_clk_register_periph_clk(&clks[gem1_clk],
&slcr_base->gem1_clk_ctrl, 1);
These position changes are a little bit confusing but I get it.
- zynq_clk_register_periph_clk(&clks[smc_clk], &slcr_base->smc_clk_ctrl,
"smc", 0);
zynq_clk_register_periph_clk(&clks[smc_clk],
&slcr_base->smc_clk_ctrl, 0);
zynq_clk_register_periph_clk(&clks[lqspi_clk],
&slcr_base->lqspi_clk_ctrl, "lqspi", 0);
&slcr_base->lqspi_clk_ctrl, 0);
zynq_clk_register_periph_clk(&clks[sdio0_clk],
&slcr_base->sdio_clk_ctrl, "sdio0", 0);
zynq_clk_register_periph_clk(&clks[sdio1_clk],&slcr_base->sdio_clk_ctrl, 0);
&slcr_base->sdio_clk_ctrl, "sdio1", 0);
&slcr_base->sdio_clk_ctrl, 0);
- zynq_clk_register_periph_clk(&clks[spi0_clk], &slcr_base->spi_clk_ctrl,
"spi0", 0);
- zynq_clk_register_periph_clk(&clks[spi1_clk], &slcr_base->spi_clk_ctrl,
"spi1", 0);
zynq_clk_register_periph_clk(&clks[spi0_clk],
&slcr_base->spi_clk_ctrl, 0);
zynq_clk_register_periph_clk(&clks[spi1_clk],
&slcr_base->spi_clk_ctrl, 0);
zynq_clk_register_periph_clk(&clks[uart0_clk],
&slcr_base->uart_clk_ctrl, "uart0", 0);
zynq_clk_register_periph_clk(&clks[uart1_clk],&slcr_base->uart_clk_ctrl, 0);
&slcr_base->uart_clk_ctrl, "uart1", 0);
&slcr_base->uart_clk_ctrl, 0);
zynq_clk_register_periph_clk(&clks[dbg_trc_clk],
&slcr_base->dbg_clk_ctrl, "dbg_trc", 0);
zynq_clk_register_periph_clk(&clks[dbg_apb_clk],&slcr_base->dbg_clk_ctrl, 0);
&slcr_base->dbg_clk_ctrl, "dbg_apb", 0);
&slcr_base->dbg_clk_ctrl, 0);
zynq_clk_register_periph_clk(&clks[pcap_clk],
&slcr_base->pcap_clk_ctrl, "pcap", 0);
&slcr_base->pcap_clk_ctrl, 0);
zynq_clk_register_periph_clk(&clks[fclk0_clk],
&slcr_base->fpga0_clk_ctrl, "fclk0", 1);
zynq_clk_register_periph_clk(&clks[fclk1_clk],&slcr_base->fpga0_clk_ctrl, 1);
&slcr_base->fpga1_clk_ctrl, "fclk1", 1);
zynq_clk_register_periph_clk(&clks[fclk2_clk],&slcr_base->fpga1_clk_ctrl, 1);
&slcr_base->fpga2_clk_ctrl, "fclk2", 1);
zynq_clk_register_periph_clk(&clks[fclk3_clk],&slcr_base->fpga2_clk_ctrl, 1);
&slcr_base->fpga3_clk_ctrl, "fclk3", 1);
&slcr_base->fpga3_clk_ctrl, 1);
}
/**
- zynq_clk_register_aper_clk() - Set up a APER clock with the framework
- @clk: Pointer to struct clk for the clock
- @ctrl: Clock control register
*/
- @name: PLL name
-static void zynq_clk_register_aper_clk(struct clk *clk, u32 *ctrl, char *name) +static void zynq_clk_register_aper_clk(struct clk *clk, u32 *ctrl) {
- clk->name = name; clk->reg = ctrl; clk->parent = cpu_1x_clk; clk->frequency = zynq_clk_get_rate(clk->parent);
@@ -419,48 +420,48 @@ static void zynq_clk_register_aper_clk(struct clk *clk, u32 *ctrl, char *name) static void init_aper_clocks(void) { zynq_clk_register_aper_clk(&clks[usb0_aper_clk],
&slcr_base->aper_clk_ctrl, "usb0_aper");
zynq_clk_register_aper_clk(&clks[usb1_aper_clk],&slcr_base->aper_clk_ctrl);
&slcr_base->aper_clk_ctrl, "usb1_aper");
&slcr_base->aper_clk_ctrl);
zynq_clk_register_aper_clk(&clks[gem0_aper_clk],
&slcr_base->aper_clk_ctrl, "gem0_aper");
zynq_clk_register_aper_clk(&clks[gem1_aper_clk],&slcr_base->aper_clk_ctrl);
&slcr_base->aper_clk_ctrl, "gem1_aper");
&slcr_base->aper_clk_ctrl);
zynq_clk_register_aper_clk(&clks[sdio0_aper_clk],
&slcr_base->aper_clk_ctrl, "sdio0_aper");
zynq_clk_register_aper_clk(&clks[sdio1_aper_clk],&slcr_base->aper_clk_ctrl);
&slcr_base->aper_clk_ctrl, "sdio1_aper");
&slcr_base->aper_clk_ctrl);
zynq_clk_register_aper_clk(&clks[spi0_aper_clk],
&slcr_base->aper_clk_ctrl, "spi0_aper");
zynq_clk_register_aper_clk(&clks[spi1_aper_clk],&slcr_base->aper_clk_ctrl);
&slcr_base->aper_clk_ctrl, "spi1_aper");
&slcr_base->aper_clk_ctrl);
zynq_clk_register_aper_clk(&clks[can0_aper_clk],
&slcr_base->aper_clk_ctrl, "can0_aper");
zynq_clk_register_aper_clk(&clks[can1_aper_clk],&slcr_base->aper_clk_ctrl);
&slcr_base->aper_clk_ctrl, "can1_aper");
&slcr_base->aper_clk_ctrl);
zynq_clk_register_aper_clk(&clks[i2c0_aper_clk],
&slcr_base->aper_clk_ctrl, "i2c0_aper");
zynq_clk_register_aper_clk(&clks[i2c1_aper_clk],&slcr_base->aper_clk_ctrl);
&slcr_base->aper_clk_ctrl, "i2c1_aper");
&slcr_base->aper_clk_ctrl);
zynq_clk_register_aper_clk(&clks[uart0_aper_clk],
&slcr_base->aper_clk_ctrl, "uart0_aper");
zynq_clk_register_aper_clk(&clks[uart1_aper_clk],&slcr_base->aper_clk_ctrl);
&slcr_base->aper_clk_ctrl, "uart1_aper");
&slcr_base->aper_clk_ctrl);
zynq_clk_register_aper_clk(&clks[gpio_aper_clk],
&slcr_base->aper_clk_ctrl, "gpio_aper");
&slcr_base->aper_clk_ctrl);
zynq_clk_register_aper_clk(&clks[lqspi_aper_clk],
&slcr_base->aper_clk_ctrl, "lqspi_aper");
&slcr_base->aper_clk_ctrl);
zynq_clk_register_aper_clk(&clks[smc_aper_clk],
&slcr_base->aper_clk_ctrl, "smc_aper");
&slcr_base->aper_clk_ctrl);
}
/** @@ -496,13 +497,11 @@ static unsigned long zynq_clk_pll_get_rate(struct clk *pll)
- zynq_clk_register_pll() - Set up a PLL with the framework
- @clk: Pointer to struct clk for the PLL
- @ctrl: PLL control register
*/
- @name: PLL name
- @prate: PLL input clock rate
-static void zynq_clk_register_pll(struct clk *clk, u32 *ctrl, char *name, +static void zynq_clk_register_pll(struct clk *clk, u32 *ctrl, unsigned long prate) {
- clk->name = name; clk->reg = ctrl; clk->frequency = zynq_clk_pll_get_rate(clk); clk->ops.get_rate = zynq_clk_pll_get_rate;
@@ -583,11 +582,11 @@ unsigned long get_uart_clk(int dev_index) int set_cpu_clk_info(void) { zynq_clk_register_pll(&clks[armpll_clk], &slcr_base->arm_pll_ctrl,
"armpll", CONFIG_ZYNQ_PS_CLK_FREQ);
zynq_clk_register_pll(&clks[ddrpll_clk], &slcr_base->ddr_pll_ctrl,CONFIG_ZYNQ_PS_CLK_FREQ);
"ddrpll", CONFIG_ZYNQ_PS_CLK_FREQ);
zynq_clk_register_pll(&clks[iopll_clk], &slcr_base->io_pll_ctrl,CONFIG_ZYNQ_PS_CLK_FREQ);
"iopll", CONFIG_ZYNQ_PS_CLK_FREQ);
CONFIG_ZYNQ_PS_CLK_FREQ);
init_ddr_clocks(); init_cpu_clocks();
@@ -639,7 +638,7 @@ int zynq_clk_set_rate(enum zynq_clk clk, unsigned long rate) */ const char *zynq_clk_get_name(enum zynq_clk clk) {
- return clks[clk].name;
- return clk_names[clk];
}
/**
Patch is good. Reviewed-by: Michal Simek michal.simek@xilinx.com
Thanks, Michal

From: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com
The zynq_clk_get_name function is only used once inside the clock driver. Replace the function call with the one-line code.
Signed-off-by: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com ---
arch/arm/mach-zynq/clk.c | 12 +----------- arch/arm/mach-zynq/include/mach/clk.h | 1 - 2 files changed, 1 insertion(+), 12 deletions(-)
diff --git a/arch/arm/mach-zynq/clk.c b/arch/arm/mach-zynq/clk.c index 7bff964..570ebd7 100644 --- a/arch/arm/mach-zynq/clk.c +++ b/arch/arm/mach-zynq/clk.c @@ -632,16 +632,6 @@ int zynq_clk_set_rate(enum zynq_clk clk, unsigned long rate) }
/** - * zynq_clk_get_name() - Get clock name - * @clk: Clock identifier - * Returns the name of @clk. - */ -const char *zynq_clk_get_name(enum zynq_clk clk) -{ - return clk_names[clk]; -} - -/** * soc_clk_dump() - Print clock frequencies * Returns zero on success * @@ -653,7 +643,7 @@ int soc_clk_dump(void)
printf("clk\t\tfrequency\n"); for (i = 0; i < clk_max; i++) { - const char *name = zynq_clk_get_name(i); + const char *name = clk_names[i]; if (name) printf("%10s%20lu\n", name, zynq_clk_get_rate(i)); } diff --git a/arch/arm/mach-zynq/include/mach/clk.h b/arch/arm/mach-zynq/include/mach/clk.h index 250c5bc..5c2758a 100644 --- a/arch/arm/mach-zynq/include/mach/clk.h +++ b/arch/arm/mach-zynq/include/mach/clk.h @@ -23,7 +23,6 @@ enum zynq_clk { void zynq_clk_early_init(void); int zynq_clk_set_rate(enum zynq_clk clk, unsigned long rate); unsigned long zynq_clk_get_rate(enum zynq_clk clk); -const char *zynq_clk_get_name(enum zynq_clk clk); unsigned long get_uart_clk(int dev_id);
#endif

On 4.1.2017 13:27, stefan.herbrechtsmeier@weidmueller.com wrote:
From: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com
The zynq_clk_get_name function is only used once inside the clock driver. Replace the function call with the one-line code.
Signed-off-by: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com
arch/arm/mach-zynq/clk.c | 12 +----------- arch/arm/mach-zynq/include/mach/clk.h | 1 - 2 files changed, 1 insertion(+), 12 deletions(-)
diff --git a/arch/arm/mach-zynq/clk.c b/arch/arm/mach-zynq/clk.c index 7bff964..570ebd7 100644 --- a/arch/arm/mach-zynq/clk.c +++ b/arch/arm/mach-zynq/clk.c @@ -632,16 +632,6 @@ int zynq_clk_set_rate(enum zynq_clk clk, unsigned long rate) }
/**
- zynq_clk_get_name() - Get clock name
- @clk: Clock identifier
- Returns the name of @clk.
- */
-const char *zynq_clk_get_name(enum zynq_clk clk) -{
- return clk_names[clk];
-}
-/**
- soc_clk_dump() - Print clock frequencies
- Returns zero on success
@@ -653,7 +643,7 @@ int soc_clk_dump(void)
printf("clk\t\tfrequency\n"); for (i = 0; i < clk_max; i++) {
const char *name = zynq_clk_get_name(i);
if (name) printf("%10s%20lu\n", name, zynq_clk_get_rate(i)); }const char *name = clk_names[i];
diff --git a/arch/arm/mach-zynq/include/mach/clk.h b/arch/arm/mach-zynq/include/mach/clk.h index 250c5bc..5c2758a 100644 --- a/arch/arm/mach-zynq/include/mach/clk.h +++ b/arch/arm/mach-zynq/include/mach/clk.h @@ -23,7 +23,6 @@ enum zynq_clk { void zynq_clk_early_init(void); int zynq_clk_set_rate(enum zynq_clk clk, unsigned long rate); unsigned long zynq_clk_get_rate(enum zynq_clk clk); -const char *zynq_clk_get_name(enum zynq_clk clk); unsigned long get_uart_clk(int dev_id);
#endif
Reviewed-by: Michal Simek michal.simek@xilinx.com
Thanks, Michal

From: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com
Add a clock framework driver for the zynq platform. The driver is based on the platform zynq clock driver but reworked to use static functions instead of run-time generated objects even for unused clocks. Additionally the CONFIG_ZYNQ_PS_CLK_FREQ is replaced by the ps-clk-frequency from the device tree.
Signed-off-by: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com ---
drivers/clk/Kconfig | 7 + drivers/clk/Makefile | 1 + drivers/clk/clk_zynq.c | 470 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 478 insertions(+) create mode 100644 drivers/clk/clk_zynq.c
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index c05ce2a..714ccca 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -28,6 +28,13 @@ config CLK_BOSTON help Enable this to support the clocks
+config CLK_ZYNQ + bool "Zynq clock driver" + depends on CLK && ARCH_ZYNQ + default y + help + Enable this to support the clocks + source "drivers/clk/tegra/Kconfig" source "drivers/clk/uniphier/Kconfig" source "drivers/clk/exynos/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 40a5e8c..5e5b6b1 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_CLK_UNIPHIER) += uniphier/ obj-$(CONFIG_CLK_EXYNOS) += exynos/ obj-$(CONFIG_CLK_AT91) += at91/ obj-$(CONFIG_CLK_BOSTON) += clk_boston.o +obj-$(CONFIG_CLK_ZYNQ) += clk_zynq.o diff --git a/drivers/clk/clk_zynq.c b/drivers/clk/clk_zynq.c new file mode 100644 index 0000000..d276155 --- /dev/null +++ b/drivers/clk/clk_zynq.c @@ -0,0 +1,470 @@ +/* + * Copyright (C) 2017 Weidmüller Interface GmbH & Co. KG + * Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com + * + * Copyright (C) 2013 Soren Brinkmann soren.brinkmann@xilinx.com + * Copyright (C) 2013 Xilinx, Inc. All rights reserved. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <clk-uclass.h> +#include <dm.h> +#include <dm/lists.h> +#include <errno.h> +#include <asm/io.h> +#include <asm/arch/clk.h> +#include <asm/arch/hardware.h> +#include <asm/arch/sys_proto.h> + +/* Register bitfield defines */ +#define PLLCTRL_FBDIV_MASK 0x7f000 +#define PLLCTRL_FBDIV_SHIFT 12 +#define PLLCTRL_BPFORCE_MASK (1 << 4) +#define PLLCTRL_PWRDWN_MASK 2 +#define PLLCTRL_PWRDWN_SHIFT 1 +#define PLLCTRL_RESET_MASK 1 +#define PLLCTRL_RESET_SHIFT 0 + +#define ZYNQ_CLK_MAXDIV 0x3f +#define CLK_CTRL_DIV1_SHIFT 20 +#define CLK_CTRL_DIV1_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV1_SHIFT) +#define CLK_CTRL_DIV0_SHIFT 8 +#define CLK_CTRL_DIV0_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV0_SHIFT) +#define CLK_CTRL_SRCSEL_SHIFT 4 +#define CLK_CTRL_SRCSEL_MASK (0x3 << CLK_CTRL_SRCSEL_SHIFT) + +#define CLK_CTRL_DIV2X_SHIFT 26 +#define CLK_CTRL_DIV2X_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV2X_SHIFT) +#define CLK_CTRL_DIV3X_SHIFT 20 +#define CLK_CTRL_DIV3X_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV3X_SHIFT) + +#define ZYNQ_CLKMUX_SEL_0 0 +#define ZYNQ_CLKMUX_SEL_1 1 +#define ZYNQ_CLKMUX_SEL_2 2 +#define ZYNQ_CLKMUX_SEL_3 3 + +DECLARE_GLOBAL_DATA_PTR; + +#ifndef CONFIG_SPL_BUILD +enum zynq_clk_rclk {mio_clk, emio_clk}; +#endif + +struct zynq_clk_priv { + ulong ps_clk_freq; +}; + +static void *zynq_clk_get_register(enum zynq_clk id) +{ + switch (id) { + case armpll_clk: + return &slcr_base->arm_pll_ctrl; + case ddrpll_clk: + return &slcr_base->ddr_pll_ctrl; + case iopll_clk: + return &slcr_base->io_pll_ctrl; +#ifndef CONFIG_SPL_BUILD + case dci_clk: + return &slcr_base->dci_clk_ctrl; +#endif + case lqspi_clk: + return &slcr_base->lqspi_clk_ctrl; + case smc_clk: + return &slcr_base->smc_clk_ctrl; + case pcap_clk: + return &slcr_base->pcap_clk_ctrl; +#ifndef CONFIG_SPL_BUILD + case gem0_clk: + return &slcr_base->gem0_clk_ctrl; + case gem1_clk: + return &slcr_base->gem1_clk_ctrl; + case fclk0_clk: + return &slcr_base->fpga0_clk_ctrl; + case fclk1_clk: + return &slcr_base->fpga1_clk_ctrl; + case fclk2_clk: + return &slcr_base->fpga2_clk_ctrl; + case fclk3_clk: + return &slcr_base->fpga3_clk_ctrl; + case can0_clk ... can1_clk: + return &slcr_base->can_clk_ctrl; +#endif + case sdio0_clk: + case sdio1_clk: + return &slcr_base->sdio_clk_ctrl; + case uart0_clk: + case uart1_clk: + return &slcr_base->uart_clk_ctrl; + case spi0_clk: + case spi1_clk: + return &slcr_base->spi_clk_ctrl; +#ifndef CONFIG_SPL_BUILD + case dbg_trc_clk: + case dbg_apb_clk: + return &slcr_base->dbg_clk_ctrl; +#endif + default: + return &slcr_base->dbg_clk_ctrl; + } +} + +static enum zynq_clk zynq_clk_get_cpu_pll(u32 clk_ctrl) +{ + u32 srcsel = (clk_ctrl & CLK_CTRL_SRCSEL_MASK) >> CLK_CTRL_SRCSEL_SHIFT; + + switch (srcsel) { + case ZYNQ_CLKMUX_SEL_0: + case ZYNQ_CLKMUX_SEL_1: + return armpll_clk; + case ZYNQ_CLKMUX_SEL_2: + return ddrpll_clk; + case ZYNQ_CLKMUX_SEL_3: + return iopll_clk; + default: + return armpll_clk; + } +} + +static enum zynq_clk zynq_clk_get_peripheral_pll(u32 clk_ctrl) +{ + u32 srcsel = (clk_ctrl & CLK_CTRL_SRCSEL_MASK) >> CLK_CTRL_SRCSEL_SHIFT; + + switch (srcsel) { + case ZYNQ_CLKMUX_SEL_0: + case ZYNQ_CLKMUX_SEL_1: + return iopll_clk; + case ZYNQ_CLKMUX_SEL_2: + return armpll_clk; + case ZYNQ_CLKMUX_SEL_3: + return ddrpll_clk; + default: + return iopll_clk; + } +} + +static ulong zynq_clk_get_pll_rate(struct zynq_clk_priv *priv, enum zynq_clk id) +{ + u32 clk_ctrl, reset, pwrdwn, mul, bypass; + + clk_ctrl = readl(zynq_clk_get_register(id)); + + reset = (clk_ctrl & PLLCTRL_RESET_MASK) >> PLLCTRL_RESET_SHIFT; + pwrdwn = (clk_ctrl & PLLCTRL_PWRDWN_MASK) >> PLLCTRL_PWRDWN_SHIFT; + if (reset || pwrdwn) + return 0; + + bypass = clk_ctrl & PLLCTRL_BPFORCE_MASK; + if (bypass) + mul = 1; + else + mul = (clk_ctrl & PLLCTRL_FBDIV_MASK) >> PLLCTRL_FBDIV_SHIFT; + + return priv->ps_clk_freq * mul; +} + +#ifndef CONFIG_SPL_BUILD +static enum zynq_clk_rclk zynq_clk_get_gem_rclk(enum zynq_clk id) +{ + u32 clk_ctrl, srcsel; + + if (id == gem0_clk) + clk_ctrl = readl(&slcr_base->gem0_rclk_ctrl); + else + clk_ctrl = readl(&slcr_base->gem1_rclk_ctrl); + + srcsel = (clk_ctrl & CLK_CTRL_SRCSEL_MASK) >> CLK_CTRL_SRCSEL_SHIFT; + if (srcsel) + return emio_clk; + else + return mio_clk; +} +#endif + +static ulong zynq_clk_get_cpu_rate(struct zynq_clk_priv *priv, enum zynq_clk id) +{ + u32 clk_621, clk_ctrl, div; + enum zynq_clk pll; + + clk_ctrl = readl(&slcr_base->arm_clk_ctrl); + + div = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT; + + switch (id) { + case cpu_1x_clk: + div *= 2; + /* fall through */ + case cpu_2x_clk: + clk_621 = readl(&slcr_base->clk_621_true) & 1; + div *= 2 + clk_621; + break; + case cpu_3or2x_clk: + div *= 2; + /* fall through */ + case cpu_6or4x_clk: + break; + default: + return 0; + } + + pll = zynq_clk_get_cpu_pll(clk_ctrl); + + return DIV_ROUND_CLOSEST(zynq_clk_get_pll_rate(priv, pll), div); +} + +#ifndef CONFIG_SPL_BUILD +static ulong zynq_clk_get_ddr2x_rate(struct zynq_clk_priv *priv) +{ + u32 clk_ctrl, div; + + clk_ctrl = readl(&slcr_base->ddr_clk_ctrl); + + div = (clk_ctrl & CLK_CTRL_DIV2X_MASK) >> CLK_CTRL_DIV2X_SHIFT; + + return DIV_ROUND_CLOSEST(zynq_clk_get_pll_rate(priv, ddrpll_clk), div); +} +#endif + +static ulong zynq_clk_get_ddr3x_rate(struct zynq_clk_priv *priv) +{ + u32 clk_ctrl, div; + + clk_ctrl = readl(&slcr_base->ddr_clk_ctrl); + + div = (clk_ctrl & CLK_CTRL_DIV3X_MASK) >> CLK_CTRL_DIV3X_SHIFT; + + return DIV_ROUND_CLOSEST(zynq_clk_get_pll_rate(priv, ddrpll_clk), div); +} + +#ifndef CONFIG_SPL_BUILD +static ulong zynq_clk_get_dci_rate(struct zynq_clk_priv *priv) +{ + u32 clk_ctrl, div0, div1; + + clk_ctrl = readl(&slcr_base->dci_clk_ctrl); + + div0 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT; + div1 = (clk_ctrl & CLK_CTRL_DIV1_MASK) >> CLK_CTRL_DIV1_SHIFT; + + return DIV_ROUND_CLOSEST(DIV_ROUND_CLOSEST( + zynq_clk_get_pll_rate(priv, ddrpll_clk), div0), div1); +} +#endif + +static ulong zynq_clk_get_peripheral_rate(struct zynq_clk_priv *priv, + enum zynq_clk id, bool two_divs) +{ + enum zynq_clk pll; + u32 clk_ctrl, div0; + u32 div1 = 1; + + clk_ctrl = readl(zynq_clk_get_register(id)); + + div0 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT; + if (!div0) + div0 = 1; + +#ifndef CONFIG_SPL_BUILD + if (two_divs) { + div1 = (clk_ctrl & CLK_CTRL_DIV1_MASK) >> CLK_CTRL_DIV1_SHIFT; + if (!div1) + div1 = 1; + } +#endif + + pll = zynq_clk_get_peripheral_pll(clk_ctrl); + + return + DIV_ROUND_CLOSEST( + DIV_ROUND_CLOSEST( + zynq_clk_get_pll_rate(priv, pll), div0), + div1); +} + +#ifndef CONFIG_SPL_BUILD +static ulong zynq_clk_get_gem_rate(struct zynq_clk_priv *priv, enum zynq_clk id) +{ + if (zynq_clk_get_gem_rclk(id) == mio_clk) + return zynq_clk_get_peripheral_rate(priv, id, true); + + return 0; +} + +static unsigned long zynq_clk_calc_peripheral_two_divs( + ulong rate, ulong pll_rate, u32 *div0, + u32 *div1) +{ + long new_err, best_err = (long)(~0UL >> 1); + ulong new_rate, best_rate = 0; + u32 d0, d1; + + for (d0 = 1; d0 <= ZYNQ_CLK_MAXDIV; d0++) { + for (d1 = 1; d1 <= ZYNQ_CLK_MAXDIV >> 1; d1++) { + new_rate = DIV_ROUND_CLOSEST( + DIV_ROUND_CLOSEST(pll_rate, d0), d1); + new_err = abs(new_rate - rate); + + if (new_err < best_err) { + *div0 = d0; + *div1 = d1; + best_err = new_err; + best_rate = new_rate; + } + } + } + + return best_rate; +} + +static ulong zynq_clk_set_peripheral_rate(struct zynq_clk_priv *priv, + enum zynq_clk id, ulong rate, + bool two_divs) +{ + enum zynq_clk pll; + u32 clk_ctrl, div0 = 0, div1 = 0; + ulong pll_rate, new_rate; + u32 *reg; + + reg = zynq_clk_get_register(id); + clk_ctrl = readl(reg); + + pll = zynq_clk_get_peripheral_pll(clk_ctrl); + pll_rate = zynq_clk_get_pll_rate(priv, pll); + clk_ctrl &= ~CLK_CTRL_DIV0_MASK; + if (two_divs) { + clk_ctrl &= ~CLK_CTRL_DIV1_MASK; + new_rate = zynq_clk_calc_peripheral_two_divs(rate, pll_rate, + &div0, &div1); + clk_ctrl |= div1 << CLK_CTRL_DIV1_SHIFT; + } else { + div0 = DIV_ROUND_CLOSEST(pll_rate, rate); + if (div0 > ZYNQ_CLK_MAXDIV) + div0 = ZYNQ_CLK_MAXDIV; + new_rate = DIV_ROUND_CLOSEST(rate, div0); + } + clk_ctrl |= div0 << CLK_CTRL_DIV0_SHIFT; + + zynq_slcr_unlock(); + writel(clk_ctrl, reg); + zynq_slcr_lock(); + + return new_rate; +} + +static ulong zynq_clk_set_gem_rate(struct zynq_clk_priv *priv, enum zynq_clk id, + ulong rate) +{ + if (zynq_clk_get_gem_rclk(id) == mio_clk) + return zynq_clk_set_peripheral_rate(priv, id, rate, true); + + return 0; +} +#endif + +#ifndef CONFIG_SPL_BUILD +static ulong zynq_clk_get_rate(struct clk *clk) +{ + struct zynq_clk_priv *priv = dev_get_priv(clk->dev); + enum zynq_clk id = clk->id; + bool two_divs = false; + + switch (id) { + case armpll_clk ... iopll_clk: + return zynq_clk_get_pll_rate(priv, id); + case cpu_6or4x_clk ... cpu_1x_clk: + return zynq_clk_get_cpu_rate(priv, id); + case ddr2x_clk: + return zynq_clk_get_ddr2x_rate(priv); + case ddr3x_clk: + return zynq_clk_get_ddr3x_rate(priv); + case dci_clk: + return zynq_clk_get_dci_rate(priv); + case gem0_clk ... gem1_clk: + return zynq_clk_get_gem_rate(priv, id); + case fclk0_clk ... can1_clk: + two_divs = true; + /* fall through */ + case dbg_trc_clk ... dbg_apb_clk: + case lqspi_clk ... pcap_clk: + case sdio0_clk ... spi1_clk: + return zynq_clk_get_peripheral_rate(priv, id, two_divs); + case dma_clk: + return zynq_clk_get_cpu_rate(priv, cpu_2x_clk); + case usb0_aper_clk ... smc_aper_clk: + return zynq_clk_get_cpu_rate(priv, cpu_1x_clk); + default: + return -ENXIO; + } +} + +static ulong zynq_clk_set_rate(struct clk *clk, ulong rate) +{ + struct zynq_clk_priv *priv = dev_get_priv(clk->dev); + enum zynq_clk id = clk->id; + bool two_divs = false; + + switch (id) { + case gem0_clk ... gem1_clk: + return zynq_clk_set_gem_rate(priv, id, rate); + case fclk0_clk ... can1_clk: + two_divs = true; + /* fall through */ + case lqspi_clk ... pcap_clk: + case sdio0_clk ... spi1_clk: + case dbg_trc_clk ... dbg_apb_clk: + return zynq_clk_set_peripheral_rate(priv, id, rate, two_divs); + default: + return -ENXIO; + } +} +#else +static ulong zynq_clk_get_rate(struct clk *clk) +{ + struct zynq_clk_priv *priv = dev_get_priv(clk->dev); + enum zynq_clk id = clk->id; + + switch (id) { + case cpu_6or4x_clk ... cpu_1x_clk: + return zynq_clk_get_cpu_rate(priv, id); + case ddr3x_clk: + return zynq_clk_get_ddr3x_rate(priv); + case lqspi_clk ... pcap_clk: + case sdio0_clk ... spi1_clk: + return zynq_clk_get_peripheral_rate(priv, id, 0); + default: + return -ENXIO; + } +} +#endif + +static struct clk_ops zynq_clk_ops = { + .get_rate = zynq_clk_get_rate, +#ifndef CONFIG_SPL_BUILD + .set_rate = zynq_clk_set_rate, +#endif +}; + +static int zynq_clk_probe(struct udevice *dev) +{ + struct zynq_clk_priv *priv = dev_get_priv(dev); + + priv->ps_clk_freq = fdtdec_get_uint(gd->fdt_blob, dev->of_offset, + "ps-clk-frequency", 33333333UL); + + return 0; +} + +static const struct udevice_id zynq_clk_ids[] = { + { .compatible = "xlnx,ps7-clkc"}, + {} +}; + +U_BOOT_DRIVER(zynq_clk) = { + .name = "zynq_clk", + .id = UCLASS_CLK, + .of_match = zynq_clk_ids, + .flags = DM_FLAG_PRE_RELOC, + .ops = &zynq_clk_ops, + .priv_auto_alloc_size = sizeof(struct zynq_clk_priv), + .probe = zynq_clk_probe, +};

+Soren
On 4.1.2017 13:27, stefan.herbrechtsmeier@weidmueller.com wrote:
From: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com
Add a clock framework driver for the zynq platform. The driver is based on the platform zynq clock driver but reworked to use static functions instead of run-time generated objects even for unused clocks. Additionally the CONFIG_ZYNQ_PS_CLK_FREQ is replaced by the ps-clk-frequency from the device tree.
Signed-off-by: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com
drivers/clk/Kconfig | 7 + drivers/clk/Makefile | 1 + drivers/clk/clk_zynq.c | 470 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 478 insertions(+) create mode 100644 drivers/clk/clk_zynq.c
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index c05ce2a..714ccca 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -28,6 +28,13 @@ config CLK_BOSTON help Enable this to support the clocks
+config CLK_ZYNQ
- bool "Zynq clock driver"
- depends on CLK && ARCH_ZYNQ
- default y
- help
Enable this to support the clocks
source "drivers/clk/tegra/Kconfig" source "drivers/clk/uniphier/Kconfig" source "drivers/clk/exynos/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 40a5e8c..5e5b6b1 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_CLK_UNIPHIER) += uniphier/ obj-$(CONFIG_CLK_EXYNOS) += exynos/ obj-$(CONFIG_CLK_AT91) += at91/ obj-$(CONFIG_CLK_BOSTON) += clk_boston.o +obj-$(CONFIG_CLK_ZYNQ) += clk_zynq.o diff --git a/drivers/clk/clk_zynq.c b/drivers/clk/clk_zynq.c new file mode 100644 index 0000000..d276155 --- /dev/null +++ b/drivers/clk/clk_zynq.c @@ -0,0 +1,470 @@ +/*
- Copyright (C) 2017 Weidmüller Interface GmbH & Co. KG
- Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com
- Copyright (C) 2013 Soren Brinkmann soren.brinkmann@xilinx.com
- Copyright (C) 2013 Xilinx, Inc. All rights reserved.
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <clk-uclass.h> +#include <dm.h> +#include <dm/lists.h> +#include <errno.h> +#include <asm/io.h> +#include <asm/arch/clk.h> +#include <asm/arch/hardware.h> +#include <asm/arch/sys_proto.h>
+/* Register bitfield defines */ +#define PLLCTRL_FBDIV_MASK 0x7f000 +#define PLLCTRL_FBDIV_SHIFT 12 +#define PLLCTRL_BPFORCE_MASK (1 << 4) +#define PLLCTRL_PWRDWN_MASK 2 +#define PLLCTRL_PWRDWN_SHIFT 1 +#define PLLCTRL_RESET_MASK 1 +#define PLLCTRL_RESET_SHIFT 0
+#define ZYNQ_CLK_MAXDIV 0x3f +#define CLK_CTRL_DIV1_SHIFT 20 +#define CLK_CTRL_DIV1_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV1_SHIFT) +#define CLK_CTRL_DIV0_SHIFT 8 +#define CLK_CTRL_DIV0_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV0_SHIFT) +#define CLK_CTRL_SRCSEL_SHIFT 4 +#define CLK_CTRL_SRCSEL_MASK (0x3 << CLK_CTRL_SRCSEL_SHIFT)
+#define CLK_CTRL_DIV2X_SHIFT 26 +#define CLK_CTRL_DIV2X_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV2X_SHIFT) +#define CLK_CTRL_DIV3X_SHIFT 20 +#define CLK_CTRL_DIV3X_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV3X_SHIFT)
+#define ZYNQ_CLKMUX_SEL_0 0 +#define ZYNQ_CLKMUX_SEL_1 1 +#define ZYNQ_CLKMUX_SEL_2 2 +#define ZYNQ_CLKMUX_SEL_3 3
+DECLARE_GLOBAL_DATA_PTR;
+#ifndef CONFIG_SPL_BUILD +enum zynq_clk_rclk {mio_clk, emio_clk}; +#endif
+struct zynq_clk_priv {
- ulong ps_clk_freq;
+};
+static void *zynq_clk_get_register(enum zynq_clk id) +{
- switch (id) {
- case armpll_clk:
return &slcr_base->arm_pll_ctrl;
- case ddrpll_clk:
return &slcr_base->ddr_pll_ctrl;
- case iopll_clk:
return &slcr_base->io_pll_ctrl;
+#ifndef CONFIG_SPL_BUILD
- case dci_clk:
return &slcr_base->dci_clk_ctrl;
+#endif
- case lqspi_clk:
return &slcr_base->lqspi_clk_ctrl;
- case smc_clk:
return &slcr_base->smc_clk_ctrl;
- case pcap_clk:
return &slcr_base->pcap_clk_ctrl;
+#ifndef CONFIG_SPL_BUILD
- case gem0_clk:
return &slcr_base->gem0_clk_ctrl;
- case gem1_clk:
return &slcr_base->gem1_clk_ctrl;
- case fclk0_clk:
return &slcr_base->fpga0_clk_ctrl;
- case fclk1_clk:
return &slcr_base->fpga1_clk_ctrl;
- case fclk2_clk:
return &slcr_base->fpga2_clk_ctrl;
- case fclk3_clk:
return &slcr_base->fpga3_clk_ctrl;
- case can0_clk ... can1_clk:
return &slcr_base->can_clk_ctrl;
+#endif
- case sdio0_clk:
- case sdio1_clk:
return &slcr_base->sdio_clk_ctrl;
- case uart0_clk:
- case uart1_clk:
return &slcr_base->uart_clk_ctrl;
- case spi0_clk:
- case spi1_clk:
return &slcr_base->spi_clk_ctrl;
+#ifndef CONFIG_SPL_BUILD
- case dbg_trc_clk:
- case dbg_apb_clk:
return &slcr_base->dbg_clk_ctrl;
+#endif
Please put them together.
- default:
return &slcr_base->dbg_clk_ctrl;
- }
+}
+static enum zynq_clk zynq_clk_get_cpu_pll(u32 clk_ctrl) +{
- u32 srcsel = (clk_ctrl & CLK_CTRL_SRCSEL_MASK) >> CLK_CTRL_SRCSEL_SHIFT;
- switch (srcsel) {
- case ZYNQ_CLKMUX_SEL_0:
- case ZYNQ_CLKMUX_SEL_1:
return armpll_clk;
- case ZYNQ_CLKMUX_SEL_2:
return ddrpll_clk;
- case ZYNQ_CLKMUX_SEL_3:
return iopll_clk;
- default:
return armpll_clk;
Default case shouldn't happen because of mask above. But if you want to keep it maybe this is a little bit better.
case ZYNQ_CLKMUX_SEL_2: return ddrpll_clk; case ZYNQ_CLKMUX_SEL_3: return iopll_clk; case ZYNQ_CLKMUX_SEL_0: case ZYNQ_CLKMUX_SEL_1: default: return armpll_clk;
- }
+}
+static enum zynq_clk zynq_clk_get_peripheral_pll(u32 clk_ctrl) +{
- u32 srcsel = (clk_ctrl & CLK_CTRL_SRCSEL_MASK) >> CLK_CTRL_SRCSEL_SHIFT;
- switch (srcsel) {
- case ZYNQ_CLKMUX_SEL_0:
- case ZYNQ_CLKMUX_SEL_1:
return iopll_clk;
- case ZYNQ_CLKMUX_SEL_2:
return armpll_clk;
- case ZYNQ_CLKMUX_SEL_3:
return ddrpll_clk;
- default:
return iopll_clk;
ditto.
- }
+}
+static ulong zynq_clk_get_pll_rate(struct zynq_clk_priv *priv, enum zynq_clk id) +{
- u32 clk_ctrl, reset, pwrdwn, mul, bypass;
- clk_ctrl = readl(zynq_clk_get_register(id));
- reset = (clk_ctrl & PLLCTRL_RESET_MASK) >> PLLCTRL_RESET_SHIFT;
- pwrdwn = (clk_ctrl & PLLCTRL_PWRDWN_MASK) >> PLLCTRL_PWRDWN_SHIFT;
- if (reset || pwrdwn)
return 0;
- bypass = clk_ctrl & PLLCTRL_BPFORCE_MASK;
- if (bypass)
mul = 1;
- else
mul = (clk_ctrl & PLLCTRL_FBDIV_MASK) >> PLLCTRL_FBDIV_SHIFT;
- return priv->ps_clk_freq * mul;
+}
+#ifndef CONFIG_SPL_BUILD +static enum zynq_clk_rclk zynq_clk_get_gem_rclk(enum zynq_clk id) +{
- u32 clk_ctrl, srcsel;
- if (id == gem0_clk)
clk_ctrl = readl(&slcr_base->gem0_rclk_ctrl);
- else
clk_ctrl = readl(&slcr_base->gem1_rclk_ctrl);
- srcsel = (clk_ctrl & CLK_CTRL_SRCSEL_MASK) >> CLK_CTRL_SRCSEL_SHIFT;
- if (srcsel)
return emio_clk;
- else
return mio_clk;
+} +#endif
+static ulong zynq_clk_get_cpu_rate(struct zynq_clk_priv *priv, enum zynq_clk id) +{
- u32 clk_621, clk_ctrl, div;
- enum zynq_clk pll;
- clk_ctrl = readl(&slcr_base->arm_clk_ctrl);
- div = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
- switch (id) {
- case cpu_1x_clk:
div *= 2;
/* fall through */
- case cpu_2x_clk:
clk_621 = readl(&slcr_base->clk_621_true) & 1;
div *= 2 + clk_621;
break;
- case cpu_3or2x_clk:
div *= 2;
/* fall through */
- case cpu_6or4x_clk:
break;
- default:
return 0;
- }
- pll = zynq_clk_get_cpu_pll(clk_ctrl);
- return DIV_ROUND_CLOSEST(zynq_clk_get_pll_rate(priv, pll), div);
+}
+#ifndef CONFIG_SPL_BUILD +static ulong zynq_clk_get_ddr2x_rate(struct zynq_clk_priv *priv) +{
- u32 clk_ctrl, div;
- clk_ctrl = readl(&slcr_base->ddr_clk_ctrl);
- div = (clk_ctrl & CLK_CTRL_DIV2X_MASK) >> CLK_CTRL_DIV2X_SHIFT;
- return DIV_ROUND_CLOSEST(zynq_clk_get_pll_rate(priv, ddrpll_clk), div);
+} +#endif
+static ulong zynq_clk_get_ddr3x_rate(struct zynq_clk_priv *priv) +{
- u32 clk_ctrl, div;
- clk_ctrl = readl(&slcr_base->ddr_clk_ctrl);
- div = (clk_ctrl & CLK_CTRL_DIV3X_MASK) >> CLK_CTRL_DIV3X_SHIFT;
- return DIV_ROUND_CLOSEST(zynq_clk_get_pll_rate(priv, ddrpll_clk), div);
+}
+#ifndef CONFIG_SPL_BUILD +static ulong zynq_clk_get_dci_rate(struct zynq_clk_priv *priv) +{
- u32 clk_ctrl, div0, div1;
- clk_ctrl = readl(&slcr_base->dci_clk_ctrl);
- div0 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
- div1 = (clk_ctrl & CLK_CTRL_DIV1_MASK) >> CLK_CTRL_DIV1_SHIFT;
- return DIV_ROUND_CLOSEST(DIV_ROUND_CLOSEST(
zynq_clk_get_pll_rate(priv, ddrpll_clk), div0), div1);
+} +#endif
+static ulong zynq_clk_get_peripheral_rate(struct zynq_clk_priv *priv,
enum zynq_clk id, bool two_divs)
+{
- enum zynq_clk pll;
- u32 clk_ctrl, div0;
- u32 div1 = 1;
- clk_ctrl = readl(zynq_clk_get_register(id));
- div0 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
- if (!div0)
div0 = 1;
+#ifndef CONFIG_SPL_BUILD
- if (two_divs) {
div1 = (clk_ctrl & CLK_CTRL_DIV1_MASK) >> CLK_CTRL_DIV1_SHIFT;
if (!div1)
div1 = 1;
- }
+#endif
- pll = zynq_clk_get_peripheral_pll(clk_ctrl);
- return
DIV_ROUND_CLOSEST(
DIV_ROUND_CLOSEST(
zynq_clk_get_pll_rate(priv, pll), div0),
div1);
+}
+#ifndef CONFIG_SPL_BUILD +static ulong zynq_clk_get_gem_rate(struct zynq_clk_priv *priv, enum zynq_clk id) +{
- if (zynq_clk_get_gem_rclk(id) == mio_clk)
return zynq_clk_get_peripheral_rate(priv, id, true);
Not sure if my understanding is correct here but I would expect if input is via emio that you will ask someone else to provide this value. Returning 0 without message seems to me not enough.
- return 0;
+}
+static unsigned long zynq_clk_calc_peripheral_two_divs(
incorrect parameter indetation
ulong rate, ulong pll_rate, u32 *div0,
u32 *div1)
+{
- long new_err, best_err = (long)(~0UL >> 1);
- ulong new_rate, best_rate = 0;
- u32 d0, d1;
- for (d0 = 1; d0 <= ZYNQ_CLK_MAXDIV; d0++) {
for (d1 = 1; d1 <= ZYNQ_CLK_MAXDIV >> 1; d1++) {
new_rate = DIV_ROUND_CLOSEST(
DIV_ROUND_CLOSEST(pll_rate, d0), d1);
new_err = abs(new_rate - rate);
if (new_err < best_err) {
*div0 = d0;
*div1 = d1;
best_err = new_err;
best_rate = new_rate;
}
}
- }
- return best_rate;
+}
+static ulong zynq_clk_set_peripheral_rate(struct zynq_clk_priv *priv,
enum zynq_clk id, ulong rate,
bool two_divs)
+{
- enum zynq_clk pll;
- u32 clk_ctrl, div0 = 0, div1 = 0;
- ulong pll_rate, new_rate;
- u32 *reg;
- reg = zynq_clk_get_register(id);
- clk_ctrl = readl(reg);
- pll = zynq_clk_get_peripheral_pll(clk_ctrl);
- pll_rate = zynq_clk_get_pll_rate(priv, pll);
- clk_ctrl &= ~CLK_CTRL_DIV0_MASK;
- if (two_divs) {
clk_ctrl &= ~CLK_CTRL_DIV1_MASK;
new_rate = zynq_clk_calc_peripheral_two_divs(rate, pll_rate,
&div0, &div1);
clk_ctrl |= div1 << CLK_CTRL_DIV1_SHIFT;
- } else {
div0 = DIV_ROUND_CLOSEST(pll_rate, rate);
if (div0 > ZYNQ_CLK_MAXDIV)
div0 = ZYNQ_CLK_MAXDIV;
new_rate = DIV_ROUND_CLOSEST(rate, div0);
- }
- clk_ctrl |= div0 << CLK_CTRL_DIV0_SHIFT;
- zynq_slcr_unlock();
- writel(clk_ctrl, reg);
- zynq_slcr_lock();
- return new_rate;
+}
+static ulong zynq_clk_set_gem_rate(struct zynq_clk_priv *priv, enum zynq_clk id,
ulong rate)
+{
- if (zynq_clk_get_gem_rclk(id) == mio_clk)
return zynq_clk_set_peripheral_rate(priv, id, rate, true);
- return 0;
+} +#endif
+#ifndef CONFIG_SPL_BUILD +static ulong zynq_clk_get_rate(struct clk *clk) +{
- struct zynq_clk_priv *priv = dev_get_priv(clk->dev);
- enum zynq_clk id = clk->id;
- bool two_divs = false;
- switch (id) {
- case armpll_clk ... iopll_clk:
return zynq_clk_get_pll_rate(priv, id);
- case cpu_6or4x_clk ... cpu_1x_clk:
return zynq_clk_get_cpu_rate(priv, id);
- case ddr2x_clk:
return zynq_clk_get_ddr2x_rate(priv);
- case ddr3x_clk:
return zynq_clk_get_ddr3x_rate(priv);
- case dci_clk:
return zynq_clk_get_dci_rate(priv);
- case gem0_clk ... gem1_clk:
return zynq_clk_get_gem_rate(priv, id);
- case fclk0_clk ... can1_clk:
two_divs = true;
/* fall through */
- case dbg_trc_clk ... dbg_apb_clk:
- case lqspi_clk ... pcap_clk:
- case sdio0_clk ... spi1_clk:
return zynq_clk_get_peripheral_rate(priv, id, two_divs);
- case dma_clk:
return zynq_clk_get_cpu_rate(priv, cpu_2x_clk);
- case usb0_aper_clk ... smc_aper_clk:
return zynq_clk_get_cpu_rate(priv, cpu_1x_clk);
- default:
return -ENXIO;
- }
+}
+static ulong zynq_clk_set_rate(struct clk *clk, ulong rate) +{
- struct zynq_clk_priv *priv = dev_get_priv(clk->dev);
- enum zynq_clk id = clk->id;
- bool two_divs = false;
- switch (id) {
- case gem0_clk ... gem1_clk:
return zynq_clk_set_gem_rate(priv, id, rate);
- case fclk0_clk ... can1_clk:
two_divs = true;
/* fall through */
- case lqspi_clk ... pcap_clk:
- case sdio0_clk ... spi1_clk:
- case dbg_trc_clk ... dbg_apb_clk:
return zynq_clk_set_peripheral_rate(priv, id, rate, two_divs);
- default:
return -ENXIO;
- }
+} +#else +static ulong zynq_clk_get_rate(struct clk *clk) +{
- struct zynq_clk_priv *priv = dev_get_priv(clk->dev);
- enum zynq_clk id = clk->id;
- switch (id) {
- case cpu_6or4x_clk ... cpu_1x_clk:
return zynq_clk_get_cpu_rate(priv, id);
- case ddr3x_clk:
return zynq_clk_get_ddr3x_rate(priv);
- case lqspi_clk ... pcap_clk:
- case sdio0_clk ... spi1_clk:
return zynq_clk_get_peripheral_rate(priv, id, 0);
- default:
return -ENXIO;
- }
+} +#endif
+static struct clk_ops zynq_clk_ops = {
- .get_rate = zynq_clk_get_rate,
+#ifndef CONFIG_SPL_BUILD
- .set_rate = zynq_clk_set_rate,
+#endif +};
+static int zynq_clk_probe(struct udevice *dev) +{
- struct zynq_clk_priv *priv = dev_get_priv(dev);
- priv->ps_clk_freq = fdtdec_get_uint(gd->fdt_blob, dev->of_offset,
"ps-clk-frequency", 33333333UL);
- return 0;
+}
+static const struct udevice_id zynq_clk_ids[] = {
- { .compatible = "xlnx,ps7-clkc"},
- {}
+};
+U_BOOT_DRIVER(zynq_clk) = {
- .name = "zynq_clk",
- .id = UCLASS_CLK,
- .of_match = zynq_clk_ids,
- .flags = DM_FLAG_PRE_RELOC,
- .ops = &zynq_clk_ops,
- .priv_auto_alloc_size = sizeof(struct zynq_clk_priv),
- .probe = zynq_clk_probe,
+};
The rest looks good. Soren: Can you please look at it? IIRC you have written that origin driver.
Thanks, Michal

On Tue, 2017-01-10 at 15:57:09 +0100, Michal Simek wrote:
+Soren
On 4.1.2017 13:27, stefan.herbrechtsmeier@weidmueller.com wrote:
From: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com
Add a clock framework driver for the zynq platform. The driver is based on the platform zynq clock driver but reworked to use static functions instead of run-time generated objects even for unused clocks. Additionally the CONFIG_ZYNQ_PS_CLK_FREQ is replaced by the ps-clk-frequency from the device tree.
Signed-off-by: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com
drivers/clk/Kconfig | 7 + drivers/clk/Makefile | 1 + drivers/clk/clk_zynq.c | 470 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 478 insertions(+) create mode 100644 drivers/clk/clk_zynq.c
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index c05ce2a..714ccca 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -28,6 +28,13 @@ config CLK_BOSTON help Enable this to support the clocks
+config CLK_ZYNQ
- bool "Zynq clock driver"
- depends on CLK && ARCH_ZYNQ
- default y
- help
Enable this to support the clocks
source "drivers/clk/tegra/Kconfig" source "drivers/clk/uniphier/Kconfig" source "drivers/clk/exynos/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 40a5e8c..5e5b6b1 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_CLK_UNIPHIER) += uniphier/ obj-$(CONFIG_CLK_EXYNOS) += exynos/ obj-$(CONFIG_CLK_AT91) += at91/ obj-$(CONFIG_CLK_BOSTON) += clk_boston.o +obj-$(CONFIG_CLK_ZYNQ) += clk_zynq.o diff --git a/drivers/clk/clk_zynq.c b/drivers/clk/clk_zynq.c new file mode 100644 index 0000000..d276155 --- /dev/null +++ b/drivers/clk/clk_zynq.c @@ -0,0 +1,470 @@ +/*
- Copyright (C) 2017 Weidmüller Interface GmbH & Co. KG
- Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com
- Copyright (C) 2013 Soren Brinkmann soren.brinkmann@xilinx.com
- Copyright (C) 2013 Xilinx, Inc. All rights reserved.
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <clk-uclass.h> +#include <dm.h> +#include <dm/lists.h> +#include <errno.h> +#include <asm/io.h> +#include <asm/arch/clk.h> +#include <asm/arch/hardware.h> +#include <asm/arch/sys_proto.h>
+/* Register bitfield defines */ +#define PLLCTRL_FBDIV_MASK 0x7f000 +#define PLLCTRL_FBDIV_SHIFT 12 +#define PLLCTRL_BPFORCE_MASK (1 << 4) +#define PLLCTRL_PWRDWN_MASK 2 +#define PLLCTRL_PWRDWN_SHIFT 1 +#define PLLCTRL_RESET_MASK 1 +#define PLLCTRL_RESET_SHIFT 0
+#define ZYNQ_CLK_MAXDIV 0x3f +#define CLK_CTRL_DIV1_SHIFT 20 +#define CLK_CTRL_DIV1_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV1_SHIFT) +#define CLK_CTRL_DIV0_SHIFT 8 +#define CLK_CTRL_DIV0_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV0_SHIFT) +#define CLK_CTRL_SRCSEL_SHIFT 4 +#define CLK_CTRL_SRCSEL_MASK (0x3 << CLK_CTRL_SRCSEL_SHIFT)
+#define CLK_CTRL_DIV2X_SHIFT 26 +#define CLK_CTRL_DIV2X_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV2X_SHIFT) +#define CLK_CTRL_DIV3X_SHIFT 20 +#define CLK_CTRL_DIV3X_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV3X_SHIFT)
+#define ZYNQ_CLKMUX_SEL_0 0 +#define ZYNQ_CLKMUX_SEL_1 1 +#define ZYNQ_CLKMUX_SEL_2 2 +#define ZYNQ_CLKMUX_SEL_3 3
+DECLARE_GLOBAL_DATA_PTR;
+#ifndef CONFIG_SPL_BUILD +enum zynq_clk_rclk {mio_clk, emio_clk}; +#endif
+struct zynq_clk_priv {
- ulong ps_clk_freq;
+};
+static void *zynq_clk_get_register(enum zynq_clk id) +{
- switch (id) {
- case armpll_clk:
return &slcr_base->arm_pll_ctrl;
- case ddrpll_clk:
return &slcr_base->ddr_pll_ctrl;
- case iopll_clk:
return &slcr_base->io_pll_ctrl;
+#ifndef CONFIG_SPL_BUILD
- case dci_clk:
return &slcr_base->dci_clk_ctrl;
+#endif
- case lqspi_clk:
return &slcr_base->lqspi_clk_ctrl;
- case smc_clk:
return &slcr_base->smc_clk_ctrl;
- case pcap_clk:
return &slcr_base->pcap_clk_ctrl;
+#ifndef CONFIG_SPL_BUILD
- case gem0_clk:
return &slcr_base->gem0_clk_ctrl;
- case gem1_clk:
return &slcr_base->gem1_clk_ctrl;
- case fclk0_clk:
return &slcr_base->fpga0_clk_ctrl;
- case fclk1_clk:
return &slcr_base->fpga1_clk_ctrl;
- case fclk2_clk:
return &slcr_base->fpga2_clk_ctrl;
- case fclk3_clk:
return &slcr_base->fpga3_clk_ctrl;
- case can0_clk ... can1_clk:
return &slcr_base->can_clk_ctrl;
+#endif
- case sdio0_clk:
- case sdio1_clk:
return &slcr_base->sdio_clk_ctrl;
- case uart0_clk:
- case uart1_clk:
return &slcr_base->uart_clk_ctrl;
- case spi0_clk:
- case spi1_clk:
return &slcr_base->spi_clk_ctrl;
+#ifndef CONFIG_SPL_BUILD
- case dbg_trc_clk:
- case dbg_apb_clk:
return &slcr_base->dbg_clk_ctrl;
+#endif
Please put them together.
- default:
return &slcr_base->dbg_clk_ctrl;
- }
+}
+static enum zynq_clk zynq_clk_get_cpu_pll(u32 clk_ctrl) +{
- u32 srcsel = (clk_ctrl & CLK_CTRL_SRCSEL_MASK) >> CLK_CTRL_SRCSEL_SHIFT;
- switch (srcsel) {
- case ZYNQ_CLKMUX_SEL_0:
- case ZYNQ_CLKMUX_SEL_1:
return armpll_clk;
- case ZYNQ_CLKMUX_SEL_2:
return ddrpll_clk;
- case ZYNQ_CLKMUX_SEL_3:
return iopll_clk;
- default:
return armpll_clk;
Default case shouldn't happen because of mask above. But if you want to keep it maybe this is a little bit better.
case ZYNQ_CLKMUX_SEL_2: return ddrpll_clk; case ZYNQ_CLKMUX_SEL_3: return iopll_clk; case ZYNQ_CLKMUX_SEL_0: case ZYNQ_CLKMUX_SEL_1: default: return armpll_clk;
- }
+}
+static enum zynq_clk zynq_clk_get_peripheral_pll(u32 clk_ctrl) +{
- u32 srcsel = (clk_ctrl & CLK_CTRL_SRCSEL_MASK) >> CLK_CTRL_SRCSEL_SHIFT;
- switch (srcsel) {
- case ZYNQ_CLKMUX_SEL_0:
- case ZYNQ_CLKMUX_SEL_1:
return iopll_clk;
- case ZYNQ_CLKMUX_SEL_2:
return armpll_clk;
- case ZYNQ_CLKMUX_SEL_3:
return ddrpll_clk;
- default:
return iopll_clk;
ditto.
- }
+}
+static ulong zynq_clk_get_pll_rate(struct zynq_clk_priv *priv, enum zynq_clk id) +{
- u32 clk_ctrl, reset, pwrdwn, mul, bypass;
- clk_ctrl = readl(zynq_clk_get_register(id));
- reset = (clk_ctrl & PLLCTRL_RESET_MASK) >> PLLCTRL_RESET_SHIFT;
- pwrdwn = (clk_ctrl & PLLCTRL_PWRDWN_MASK) >> PLLCTRL_PWRDWN_SHIFT;
- if (reset || pwrdwn)
return 0;
- bypass = clk_ctrl & PLLCTRL_BPFORCE_MASK;
- if (bypass)
mul = 1;
- else
mul = (clk_ctrl & PLLCTRL_FBDIV_MASK) >> PLLCTRL_FBDIV_SHIFT;
- return priv->ps_clk_freq * mul;
+}
+#ifndef CONFIG_SPL_BUILD +static enum zynq_clk_rclk zynq_clk_get_gem_rclk(enum zynq_clk id) +{
- u32 clk_ctrl, srcsel;
- if (id == gem0_clk)
clk_ctrl = readl(&slcr_base->gem0_rclk_ctrl);
- else
clk_ctrl = readl(&slcr_base->gem1_rclk_ctrl);
- srcsel = (clk_ctrl & CLK_CTRL_SRCSEL_MASK) >> CLK_CTRL_SRCSEL_SHIFT;
- if (srcsel)
return emio_clk;
- else
return mio_clk;
+} +#endif
+static ulong zynq_clk_get_cpu_rate(struct zynq_clk_priv *priv, enum zynq_clk id) +{
- u32 clk_621, clk_ctrl, div;
- enum zynq_clk pll;
- clk_ctrl = readl(&slcr_base->arm_clk_ctrl);
- div = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
- switch (id) {
- case cpu_1x_clk:
div *= 2;
/* fall through */
- case cpu_2x_clk:
clk_621 = readl(&slcr_base->clk_621_true) & 1;
div *= 2 + clk_621;
break;
- case cpu_3or2x_clk:
div *= 2;
/* fall through */
- case cpu_6or4x_clk:
break;
- default:
return 0;
- }
- pll = zynq_clk_get_cpu_pll(clk_ctrl);
- return DIV_ROUND_CLOSEST(zynq_clk_get_pll_rate(priv, pll), div);
+}
+#ifndef CONFIG_SPL_BUILD +static ulong zynq_clk_get_ddr2x_rate(struct zynq_clk_priv *priv) +{
- u32 clk_ctrl, div;
- clk_ctrl = readl(&slcr_base->ddr_clk_ctrl);
- div = (clk_ctrl & CLK_CTRL_DIV2X_MASK) >> CLK_CTRL_DIV2X_SHIFT;
- return DIV_ROUND_CLOSEST(zynq_clk_get_pll_rate(priv, ddrpll_clk), div);
+} +#endif
+static ulong zynq_clk_get_ddr3x_rate(struct zynq_clk_priv *priv) +{
- u32 clk_ctrl, div;
- clk_ctrl = readl(&slcr_base->ddr_clk_ctrl);
- div = (clk_ctrl & CLK_CTRL_DIV3X_MASK) >> CLK_CTRL_DIV3X_SHIFT;
- return DIV_ROUND_CLOSEST(zynq_clk_get_pll_rate(priv, ddrpll_clk), div);
+}
+#ifndef CONFIG_SPL_BUILD +static ulong zynq_clk_get_dci_rate(struct zynq_clk_priv *priv) +{
- u32 clk_ctrl, div0, div1;
- clk_ctrl = readl(&slcr_base->dci_clk_ctrl);
- div0 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
- div1 = (clk_ctrl & CLK_CTRL_DIV1_MASK) >> CLK_CTRL_DIV1_SHIFT;
- return DIV_ROUND_CLOSEST(DIV_ROUND_CLOSEST(
zynq_clk_get_pll_rate(priv, ddrpll_clk), div0), div1);
+} +#endif
+static ulong zynq_clk_get_peripheral_rate(struct zynq_clk_priv *priv,
enum zynq_clk id, bool two_divs)
+{
- enum zynq_clk pll;
- u32 clk_ctrl, div0;
- u32 div1 = 1;
- clk_ctrl = readl(zynq_clk_get_register(id));
- div0 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
- if (!div0)
div0 = 1;
+#ifndef CONFIG_SPL_BUILD
- if (two_divs) {
div1 = (clk_ctrl & CLK_CTRL_DIV1_MASK) >> CLK_CTRL_DIV1_SHIFT;
if (!div1)
div1 = 1;
- }
+#endif
- pll = zynq_clk_get_peripheral_pll(clk_ctrl);
- return
DIV_ROUND_CLOSEST(
DIV_ROUND_CLOSEST(
zynq_clk_get_pll_rate(priv, pll), div0),
div1);
+}
+#ifndef CONFIG_SPL_BUILD +static ulong zynq_clk_get_gem_rate(struct zynq_clk_priv *priv, enum zynq_clk id) +{
- if (zynq_clk_get_gem_rclk(id) == mio_clk)
return zynq_clk_get_peripheral_rate(priv, id, true);
Not sure if my understanding is correct here but I would expect if input is via emio that you will ask someone else to provide this value. Returning 0 without message seems to me not enough.
- return 0;
+}
+static unsigned long zynq_clk_calc_peripheral_two_divs(
incorrect parameter indetation
ulong rate, ulong pll_rate, u32 *div0,
u32 *div1)
+{
- long new_err, best_err = (long)(~0UL >> 1);
- ulong new_rate, best_rate = 0;
- u32 d0, d1;
- for (d0 = 1; d0 <= ZYNQ_CLK_MAXDIV; d0++) {
for (d1 = 1; d1 <= ZYNQ_CLK_MAXDIV >> 1; d1++) {
new_rate = DIV_ROUND_CLOSEST(
DIV_ROUND_CLOSEST(pll_rate, d0), d1);
new_err = abs(new_rate - rate);
if (new_err < best_err) {
*div0 = d0;
*div1 = d1;
best_err = new_err;
best_rate = new_rate;
}
}
- }
- return best_rate;
+}
+static ulong zynq_clk_set_peripheral_rate(struct zynq_clk_priv *priv,
enum zynq_clk id, ulong rate,
bool two_divs)
+{
- enum zynq_clk pll;
- u32 clk_ctrl, div0 = 0, div1 = 0;
- ulong pll_rate, new_rate;
- u32 *reg;
- reg = zynq_clk_get_register(id);
- clk_ctrl = readl(reg);
- pll = zynq_clk_get_peripheral_pll(clk_ctrl);
- pll_rate = zynq_clk_get_pll_rate(priv, pll);
- clk_ctrl &= ~CLK_CTRL_DIV0_MASK;
- if (two_divs) {
clk_ctrl &= ~CLK_CTRL_DIV1_MASK;
new_rate = zynq_clk_calc_peripheral_two_divs(rate, pll_rate,
&div0, &div1);
clk_ctrl |= div1 << CLK_CTRL_DIV1_SHIFT;
- } else {
div0 = DIV_ROUND_CLOSEST(pll_rate, rate);
if (div0 > ZYNQ_CLK_MAXDIV)
div0 = ZYNQ_CLK_MAXDIV;
new_rate = DIV_ROUND_CLOSEST(rate, div0);
- }
- clk_ctrl |= div0 << CLK_CTRL_DIV0_SHIFT;
- zynq_slcr_unlock();
- writel(clk_ctrl, reg);
- zynq_slcr_lock();
- return new_rate;
+}
+static ulong zynq_clk_set_gem_rate(struct zynq_clk_priv *priv, enum zynq_clk id,
ulong rate)
+{
- if (zynq_clk_get_gem_rclk(id) == mio_clk)
return zynq_clk_set_peripheral_rate(priv, id, rate, true);
- return 0;
+} +#endif
+#ifndef CONFIG_SPL_BUILD +static ulong zynq_clk_get_rate(struct clk *clk) +{
- struct zynq_clk_priv *priv = dev_get_priv(clk->dev);
- enum zynq_clk id = clk->id;
- bool two_divs = false;
- switch (id) {
- case armpll_clk ... iopll_clk:
return zynq_clk_get_pll_rate(priv, id);
- case cpu_6or4x_clk ... cpu_1x_clk:
return zynq_clk_get_cpu_rate(priv, id);
- case ddr2x_clk:
return zynq_clk_get_ddr2x_rate(priv);
- case ddr3x_clk:
return zynq_clk_get_ddr3x_rate(priv);
- case dci_clk:
return zynq_clk_get_dci_rate(priv);
- case gem0_clk ... gem1_clk:
return zynq_clk_get_gem_rate(priv, id);
- case fclk0_clk ... can1_clk:
two_divs = true;
/* fall through */
- case dbg_trc_clk ... dbg_apb_clk:
- case lqspi_clk ... pcap_clk:
- case sdio0_clk ... spi1_clk:
return zynq_clk_get_peripheral_rate(priv, id, two_divs);
- case dma_clk:
return zynq_clk_get_cpu_rate(priv, cpu_2x_clk);
- case usb0_aper_clk ... smc_aper_clk:
return zynq_clk_get_cpu_rate(priv, cpu_1x_clk);
- default:
return -ENXIO;
- }
+}
+static ulong zynq_clk_set_rate(struct clk *clk, ulong rate) +{
- struct zynq_clk_priv *priv = dev_get_priv(clk->dev);
- enum zynq_clk id = clk->id;
- bool two_divs = false;
- switch (id) {
- case gem0_clk ... gem1_clk:
return zynq_clk_set_gem_rate(priv, id, rate);
- case fclk0_clk ... can1_clk:
two_divs = true;
/* fall through */
- case lqspi_clk ... pcap_clk:
- case sdio0_clk ... spi1_clk:
- case dbg_trc_clk ... dbg_apb_clk:
return zynq_clk_set_peripheral_rate(priv, id, rate, two_divs);
- default:
return -ENXIO;
- }
+} +#else +static ulong zynq_clk_get_rate(struct clk *clk) +{
- struct zynq_clk_priv *priv = dev_get_priv(clk->dev);
- enum zynq_clk id = clk->id;
- switch (id) {
- case cpu_6or4x_clk ... cpu_1x_clk:
return zynq_clk_get_cpu_rate(priv, id);
- case ddr3x_clk:
return zynq_clk_get_ddr3x_rate(priv);
- case lqspi_clk ... pcap_clk:
- case sdio0_clk ... spi1_clk:
return zynq_clk_get_peripheral_rate(priv, id, 0);
- default:
return -ENXIO;
- }
+} +#endif
+static struct clk_ops zynq_clk_ops = {
- .get_rate = zynq_clk_get_rate,
+#ifndef CONFIG_SPL_BUILD
- .set_rate = zynq_clk_set_rate,
+#endif +};
+static int zynq_clk_probe(struct udevice *dev) +{
- struct zynq_clk_priv *priv = dev_get_priv(dev);
- priv->ps_clk_freq = fdtdec_get_uint(gd->fdt_blob, dev->of_offset,
"ps-clk-frequency", 33333333UL);
- return 0;
+}
+static const struct udevice_id zynq_clk_ids[] = {
- { .compatible = "xlnx,ps7-clkc"},
- {}
+};
+U_BOOT_DRIVER(zynq_clk) = {
- .name = "zynq_clk",
- .id = UCLASS_CLK,
- .of_match = zynq_clk_ids,
- .flags = DM_FLAG_PRE_RELOC,
- .ops = &zynq_clk_ops,
- .priv_auto_alloc_size = sizeof(struct zynq_clk_priv),
- .probe = zynq_clk_probe,
+};
The rest looks good. Soren: Can you please look at it? IIRC you have written that origin driver.
Yeah, a long time ago. I'd say if everything works with this it should be good (and given that my name is still mentioned in the sources means this must be good, right? :) ). Only questions I have: Is the clock support really optional? Usually there are many dependencies on the clocks making this critical infrastructure. Hence, the kconfig option making this selectable could probably go away and the feature could just be enabled as part of the Zynq platform.
Sören

-----Ursprüngliche Nachricht----- Von: Michal Simek [mailto:monstr@monstr.eu] Gesendet: Dienstag, 10. Januar 2017 15:57
+Soren
On 4.1.2017 13:27, stefan.herbrechtsmeier@weidmueller.com wrote:
From: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com
Add a clock framework driver for the zynq platform. The driver is based on the platform zynq clock driver but reworked to use static functions instead of run-time generated objects even for unused
clocks.
Additionally the CONFIG_ZYNQ_PS_CLK_FREQ is replaced by the ps-clk-frequency from the device tree.
Signed-off-by: Stefan Herbrechtsmeier
stefan.herbrechtsmeier@weidmueller.com
drivers/clk/Kconfig | 7 + drivers/clk/Makefile | 1 + drivers/clk/clk_zynq.c | 470 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 478 insertions(+) create mode 100644 drivers/clk/clk_zynq.c
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index c05ce2a..714ccca 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -28,6 +28,13 @@ config CLK_BOSTON help Enable this to support the clocks
+config CLK_ZYNQ
- bool "Zynq clock driver"
- depends on CLK && ARCH_ZYNQ
- default y
- help
Enable this to support the clocks
source "drivers/clk/tegra/Kconfig" source "drivers/clk/uniphier/Kconfig" source "drivers/clk/exynos/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 40a5e8c..5e5b6b1 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_CLK_UNIPHIER) += uniphier/ obj-$(CONFIG_CLK_EXYNOS) += exynos/ obj-$(CONFIG_CLK_AT91) += at91/ obj-$(CONFIG_CLK_BOSTON) += clk_boston.o +obj-$(CONFIG_CLK_ZYNQ) += clk_zynq.o diff --git a/drivers/clk/clk_zynq.c b/drivers/clk/clk_zynq.c new file mode 100644 index 0000000..d276155 --- /dev/null +++ b/drivers/clk/clk_zynq.c @@ -0,0 +1,470 @@ +/*
- Copyright (C) 2017 Weidmüller Interface GmbH & Co. KG
- Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com
- Copyright (C) 2013 Soren Brinkmann soren.brinkmann@xilinx.com
- Copyright (C) 2013 Xilinx, Inc. All rights reserved.
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <clk-uclass.h> +#include <dm.h> +#include <dm/lists.h> +#include <errno.h> +#include <asm/io.h> +#include <asm/arch/clk.h> +#include <asm/arch/hardware.h> +#include <asm/arch/sys_proto.h>
+/* Register bitfield defines */ +#define PLLCTRL_FBDIV_MASK 0x7f000 +#define PLLCTRL_FBDIV_SHIFT 12 +#define PLLCTRL_BPFORCE_MASK (1 << 4) +#define PLLCTRL_PWRDWN_MASK 2 +#define PLLCTRL_PWRDWN_SHIFT 1 +#define PLLCTRL_RESET_MASK 1 +#define PLLCTRL_RESET_SHIFT 0
+#define ZYNQ_CLK_MAXDIV 0x3f +#define CLK_CTRL_DIV1_SHIFT 20 +#define CLK_CTRL_DIV1_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV1_SHIFT) +#define CLK_CTRL_DIV0_SHIFT 8 +#define CLK_CTRL_DIV0_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV0_SHIFT) +#define CLK_CTRL_SRCSEL_SHIFT 4 +#define CLK_CTRL_SRCSEL_MASK (0x3 << CLK_CTRL_SRCSEL_SHIFT)
+#define CLK_CTRL_DIV2X_SHIFT 26 +#define CLK_CTRL_DIV2X_MASK (ZYNQ_CLK_MAXDIV <<
CLK_CTRL_DIV2X_SHIFT)
+#define CLK_CTRL_DIV3X_SHIFT 20 +#define CLK_CTRL_DIV3X_MASK (ZYNQ_CLK_MAXDIV <<
CLK_CTRL_DIV3X_SHIFT)
+#define ZYNQ_CLKMUX_SEL_0 0 +#define ZYNQ_CLKMUX_SEL_1 1 +#define ZYNQ_CLKMUX_SEL_2 2 +#define ZYNQ_CLKMUX_SEL_3 3
+DECLARE_GLOBAL_DATA_PTR;
+#ifndef CONFIG_SPL_BUILD +enum zynq_clk_rclk {mio_clk, emio_clk}; #endif
+struct zynq_clk_priv {
- ulong ps_clk_freq;
+};
+static void *zynq_clk_get_register(enum zynq_clk id) {
- switch (id) {
- case armpll_clk:
return &slcr_base->arm_pll_ctrl;
- case ddrpll_clk:
return &slcr_base->ddr_pll_ctrl;
- case iopll_clk:
return &slcr_base->io_pll_ctrl;
+#ifndef CONFIG_SPL_BUILD
- case dci_clk:
return &slcr_base->dci_clk_ctrl;
+#endif
- case lqspi_clk:
return &slcr_base->lqspi_clk_ctrl;
- case smc_clk:
return &slcr_base->smc_clk_ctrl;
- case pcap_clk:
return &slcr_base->pcap_clk_ctrl;
+#ifndef CONFIG_SPL_BUILD
- case gem0_clk:
return &slcr_base->gem0_clk_ctrl;
- case gem1_clk:
return &slcr_base->gem1_clk_ctrl;
- case fclk0_clk:
return &slcr_base->fpga0_clk_ctrl;
- case fclk1_clk:
return &slcr_base->fpga1_clk_ctrl;
- case fclk2_clk:
return &slcr_base->fpga2_clk_ctrl;
- case fclk3_clk:
return &slcr_base->fpga3_clk_ctrl;
- case can0_clk ... can1_clk:
return &slcr_base->can_clk_ctrl;
+#endif
- case sdio0_clk:
- case sdio1_clk:
return &slcr_base->sdio_clk_ctrl;
- case uart0_clk:
- case uart1_clk:
return &slcr_base->uart_clk_ctrl;
- case spi0_clk:
- case spi1_clk:
return &slcr_base->spi_clk_ctrl;
+#ifndef CONFIG_SPL_BUILD
- case dbg_trc_clk:
- case dbg_apb_clk:
return &slcr_base->dbg_clk_ctrl;
+#endif
Please put them together.
Do you mean the ifndef or the default?
- default:
return &slcr_base->dbg_clk_ctrl;
- }
+}
+static enum zynq_clk zynq_clk_get_cpu_pll(u32 clk_ctrl) {
- u32 srcsel = (clk_ctrl & CLK_CTRL_SRCSEL_MASK) >>
+CLK_CTRL_SRCSEL_SHIFT;
- switch (srcsel) {
- case ZYNQ_CLKMUX_SEL_0:
- case ZYNQ_CLKMUX_SEL_1:
return armpll_clk;
- case ZYNQ_CLKMUX_SEL_2:
return ddrpll_clk;
- case ZYNQ_CLKMUX_SEL_3:
return iopll_clk;
- default:
return armpll_clk;
Default case shouldn't happen because of mask above. But if you want to keep it maybe this is a little bit better.
case ZYNQ_CLKMUX_SEL_2: return ddrpll_clk; case ZYNQ_CLKMUX_SEL_3: return iopll_clk; case ZYNQ_CLKMUX_SEL_0: case ZYNQ_CLKMUX_SEL_1: default: return armpll_clk;
Okay. Is it okay if I replace the defines with the plain numbers?
- }
+}
+static enum zynq_clk zynq_clk_get_peripheral_pll(u32 clk_ctrl) {
- u32 srcsel = (clk_ctrl & CLK_CTRL_SRCSEL_MASK) >>
+CLK_CTRL_SRCSEL_SHIFT;
- switch (srcsel) {
- case ZYNQ_CLKMUX_SEL_0:
- case ZYNQ_CLKMUX_SEL_1:
return iopll_clk;
- case ZYNQ_CLKMUX_SEL_2:
return armpll_clk;
- case ZYNQ_CLKMUX_SEL_3:
return ddrpll_clk;
- default:
return iopll_clk;
ditto.
Okay
- }
+}
+static ulong zynq_clk_get_pll_rate(struct zynq_clk_priv *priv, enum +zynq_clk id) {
- u32 clk_ctrl, reset, pwrdwn, mul, bypass;
- clk_ctrl = readl(zynq_clk_get_register(id));
- reset = (clk_ctrl & PLLCTRL_RESET_MASK) >> PLLCTRL_RESET_SHIFT;
- pwrdwn = (clk_ctrl & PLLCTRL_PWRDWN_MASK) >>
PLLCTRL_PWRDWN_SHIFT;
- if (reset || pwrdwn)
return 0;
- bypass = clk_ctrl & PLLCTRL_BPFORCE_MASK;
- if (bypass)
mul = 1;
- else
mul = (clk_ctrl & PLLCTRL_FBDIV_MASK) >>
PLLCTRL_FBDIV_SHIFT;
- return priv->ps_clk_freq * mul;
+}
+#ifndef CONFIG_SPL_BUILD +static enum zynq_clk_rclk zynq_clk_get_gem_rclk(enum zynq_clk id) {
- u32 clk_ctrl, srcsel;
- if (id == gem0_clk)
clk_ctrl = readl(&slcr_base->gem0_rclk_ctrl);
- else
clk_ctrl = readl(&slcr_base->gem1_rclk_ctrl);
- srcsel = (clk_ctrl & CLK_CTRL_SRCSEL_MASK) >>
CLK_CTRL_SRCSEL_SHIFT;
- if (srcsel)
return emio_clk;
- else
return mio_clk;
+} +#endif
+static ulong zynq_clk_get_cpu_rate(struct zynq_clk_priv *priv, enum +zynq_clk id) {
- u32 clk_621, clk_ctrl, div;
- enum zynq_clk pll;
- clk_ctrl = readl(&slcr_base->arm_clk_ctrl);
- div = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
- switch (id) {
- case cpu_1x_clk:
div *= 2;
/* fall through */
- case cpu_2x_clk:
clk_621 = readl(&slcr_base->clk_621_true) & 1;
div *= 2 + clk_621;
break;
- case cpu_3or2x_clk:
div *= 2;
/* fall through */
- case cpu_6or4x_clk:
break;
- default:
return 0;
- }
- pll = zynq_clk_get_cpu_pll(clk_ctrl);
- return DIV_ROUND_CLOSEST(zynq_clk_get_pll_rate(priv, pll), div);
}
+#ifndef CONFIG_SPL_BUILD +static ulong zynq_clk_get_ddr2x_rate(struct zynq_clk_priv *priv) {
- u32 clk_ctrl, div;
- clk_ctrl = readl(&slcr_base->ddr_clk_ctrl);
- div = (clk_ctrl & CLK_CTRL_DIV2X_MASK) >> CLK_CTRL_DIV2X_SHIFT;
- return DIV_ROUND_CLOSEST(zynq_clk_get_pll_rate(priv, ddrpll_clk),
+div); } #endif
+static ulong zynq_clk_get_ddr3x_rate(struct zynq_clk_priv *priv) {
- u32 clk_ctrl, div;
- clk_ctrl = readl(&slcr_base->ddr_clk_ctrl);
- div = (clk_ctrl & CLK_CTRL_DIV3X_MASK) >> CLK_CTRL_DIV3X_SHIFT;
- return DIV_ROUND_CLOSEST(zynq_clk_get_pll_rate(priv, ddrpll_clk),
+div); }
+#ifndef CONFIG_SPL_BUILD +static ulong zynq_clk_get_dci_rate(struct zynq_clk_priv *priv) {
- u32 clk_ctrl, div0, div1;
- clk_ctrl = readl(&slcr_base->dci_clk_ctrl);
- div0 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
- div1 = (clk_ctrl & CLK_CTRL_DIV1_MASK) >> CLK_CTRL_DIV1_SHIFT;
- return DIV_ROUND_CLOSEST(DIV_ROUND_CLOSEST(
zynq_clk_get_pll_rate(priv, ddrpll_clk), div0), div1); }
#endif
+static ulong zynq_clk_get_peripheral_rate(struct zynq_clk_priv
*priv,
enum zynq_clk id, bool two_divs) {
- enum zynq_clk pll;
- u32 clk_ctrl, div0;
- u32 div1 = 1;
- clk_ctrl = readl(zynq_clk_get_register(id));
- div0 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
- if (!div0)
div0 = 1;
+#ifndef CONFIG_SPL_BUILD
- if (two_divs) {
div1 = (clk_ctrl & CLK_CTRL_DIV1_MASK) >>
CLK_CTRL_DIV1_SHIFT;
if (!div1)
div1 = 1;
- }
+#endif
- pll = zynq_clk_get_peripheral_pll(clk_ctrl);
- return
DIV_ROUND_CLOSEST(
DIV_ROUND_CLOSEST(
zynq_clk_get_pll_rate(priv, pll), div0),
div1);
+}
+#ifndef CONFIG_SPL_BUILD +static ulong zynq_clk_get_gem_rate(struct zynq_clk_priv *priv, enum +zynq_clk id) {
- if (zynq_clk_get_gem_rclk(id) == mio_clk)
return zynq_clk_get_peripheral_rate(priv, id, true);
Not sure if my understanding is correct here but I would expect if input is via emio that you will ask someone else to provide this value.
As you realised I add this function in a later patch. Should I merge the patches?
Returning 0 without message seems to me not enough.
I will add a message. Should I also return a error code like ENODEV?
- return 0;
+}
+static unsigned long zynq_clk_calc_peripheral_two_divs(
incorrect parameter indetation
ulong rate, ulong pll_rate, u32 *div0,
u32 *div1)
+{
- long new_err, best_err = (long)(~0UL >> 1);
- ulong new_rate, best_rate = 0;
- u32 d0, d1;
- for (d0 = 1; d0 <= ZYNQ_CLK_MAXDIV; d0++) {
for (d1 = 1; d1 <= ZYNQ_CLK_MAXDIV >> 1; d1++) {
new_rate = DIV_ROUND_CLOSEST(
DIV_ROUND_CLOSEST(pll_rate, d0), d1);
new_err = abs(new_rate - rate);
if (new_err < best_err) {
*div0 = d0;
*div1 = d1;
best_err = new_err;
best_rate = new_rate;
}
}
- }
- return best_rate;
+}
+static ulong zynq_clk_set_peripheral_rate(struct zynq_clk_priv
*priv,
enum zynq_clk id, ulong rate,
bool two_divs)
+{
- enum zynq_clk pll;
- u32 clk_ctrl, div0 = 0, div1 = 0;
- ulong pll_rate, new_rate;
- u32 *reg;
- reg = zynq_clk_get_register(id);
- clk_ctrl = readl(reg);
- pll = zynq_clk_get_peripheral_pll(clk_ctrl);
- pll_rate = zynq_clk_get_pll_rate(priv, pll);
- clk_ctrl &= ~CLK_CTRL_DIV0_MASK;
- if (two_divs) {
clk_ctrl &= ~CLK_CTRL_DIV1_MASK;
new_rate = zynq_clk_calc_peripheral_two_divs(rate,
pll_rate,
&div0, &div1);
clk_ctrl |= div1 << CLK_CTRL_DIV1_SHIFT;
- } else {
div0 = DIV_ROUND_CLOSEST(pll_rate, rate);
if (div0 > ZYNQ_CLK_MAXDIV)
div0 = ZYNQ_CLK_MAXDIV;
new_rate = DIV_ROUND_CLOSEST(rate, div0);
- }
- clk_ctrl |= div0 << CLK_CTRL_DIV0_SHIFT;
- zynq_slcr_unlock();
- writel(clk_ctrl, reg);
- zynq_slcr_lock();
- return new_rate;
+}
+static ulong zynq_clk_set_gem_rate(struct zynq_clk_priv *priv, enum
zynq_clk id,
ulong rate)
+{
- if (zynq_clk_get_gem_rclk(id) == mio_clk)
return zynq_clk_set_peripheral_rate(priv, id, rate, true);
- return 0;
+} +#endif
+#ifndef CONFIG_SPL_BUILD +static ulong zynq_clk_get_rate(struct clk *clk) {
- struct zynq_clk_priv *priv = dev_get_priv(clk->dev);
- enum zynq_clk id = clk->id;
- bool two_divs = false;
- switch (id) {
- case armpll_clk ... iopll_clk:
return zynq_clk_get_pll_rate(priv, id);
- case cpu_6or4x_clk ... cpu_1x_clk:
return zynq_clk_get_cpu_rate(priv, id);
- case ddr2x_clk:
return zynq_clk_get_ddr2x_rate(priv);
- case ddr3x_clk:
return zynq_clk_get_ddr3x_rate(priv);
- case dci_clk:
return zynq_clk_get_dci_rate(priv);
- case gem0_clk ... gem1_clk:
return zynq_clk_get_gem_rate(priv, id);
- case fclk0_clk ... can1_clk:
two_divs = true;
/* fall through */
- case dbg_trc_clk ... dbg_apb_clk:
- case lqspi_clk ... pcap_clk:
- case sdio0_clk ... spi1_clk:
return zynq_clk_get_peripheral_rate(priv, id, two_divs);
- case dma_clk:
return zynq_clk_get_cpu_rate(priv, cpu_2x_clk);
- case usb0_aper_clk ... smc_aper_clk:
return zynq_clk_get_cpu_rate(priv, cpu_1x_clk);
- default:
return -ENXIO;
- }
+}
+static ulong zynq_clk_set_rate(struct clk *clk, ulong rate) {
- struct zynq_clk_priv *priv = dev_get_priv(clk->dev);
- enum zynq_clk id = clk->id;
- bool two_divs = false;
- switch (id) {
- case gem0_clk ... gem1_clk:
return zynq_clk_set_gem_rate(priv, id, rate);
- case fclk0_clk ... can1_clk:
two_divs = true;
/* fall through */
- case lqspi_clk ... pcap_clk:
- case sdio0_clk ... spi1_clk:
- case dbg_trc_clk ... dbg_apb_clk:
return zynq_clk_set_peripheral_rate(priv, id, rate,
two_divs);
- default:
return -ENXIO;
- }
+} +#else +static ulong zynq_clk_get_rate(struct clk *clk) {
- struct zynq_clk_priv *priv = dev_get_priv(clk->dev);
- enum zynq_clk id = clk->id;
- switch (id) {
- case cpu_6or4x_clk ... cpu_1x_clk:
return zynq_clk_get_cpu_rate(priv, id);
- case ddr3x_clk:
return zynq_clk_get_ddr3x_rate(priv);
- case lqspi_clk ... pcap_clk:
- case sdio0_clk ... spi1_clk:
return zynq_clk_get_peripheral_rate(priv, id, 0);
- default:
return -ENXIO;
- }
+} +#endif
+static struct clk_ops zynq_clk_ops = {
- .get_rate = zynq_clk_get_rate,
+#ifndef CONFIG_SPL_BUILD
- .set_rate = zynq_clk_set_rate,
+#endif +};
+static int zynq_clk_probe(struct udevice *dev) {
- struct zynq_clk_priv *priv = dev_get_priv(dev);
- priv->ps_clk_freq = fdtdec_get_uint(gd->fdt_blob, dev->of_offset,
"ps-clk-frequency", 33333333UL);
- return 0;
+}
+static const struct udevice_id zynq_clk_ids[] = {
- { .compatible = "xlnx,ps7-clkc"},
- {}
+};
+U_BOOT_DRIVER(zynq_clk) = {
- .name = "zynq_clk",
- .id = UCLASS_CLK,
- .of_match = zynq_clk_ids,
- .flags = DM_FLAG_PRE_RELOC,
- .ops = &zynq_clk_ops,
- .priv_auto_alloc_size = sizeof(struct zynq_clk_priv),
- .probe = zynq_clk_probe,
+};
The rest looks good. Soren: Can you please look at it? IIRC you have written that origin driver.
Regards, Stefan
Kommanditgesellschaft - Sitz: Detmold - Amtsgericht Lemgo HRA 2790 - Komplementärin: Weidmüller Interface Führungsgesellschaft mbH - Sitz: Detmold - Amtsgericht Lemgo HRB 3924; Geschäftsführer: José Carlos Álvarez Tobar, Elke Eckstein, Dr. Peter Köhler, Jörg Timmermann; USt-ID-Nr. DE124599660

From: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.de
Move the zynq to clock framework and remove unused functions as well as the CONFIG_ZYNQ_PS_CLK_FREQ configuration.
Signed-off-by: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com ---
arch/arm/Kconfig | 2 + arch/arm/dts/zynq-7000.dtsi | 2 + arch/arm/mach-zynq/clk.c | 650 +++------------------------- arch/arm/mach-zynq/cpu.c | 1 - arch/arm/mach-zynq/include/mach/clk.h | 5 - arch/arm/mach-zynq/include/mach/sys_proto.h | 1 - arch/arm/mach-zynq/slcr.c | 22 - arch/arm/mach-zynq/timer.c | 2 - drivers/net/zynq_gem.c | 13 - drivers/serial/serial_zynq.c | 6 +- include/configs/topic_miami.h | 2 - include/configs/zynq_zybo.h | 3 - scripts/config_whitelist.txt | 1 - 13 files changed, 55 insertions(+), 655 deletions(-)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 38080c0..f9daa99 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -631,6 +631,8 @@ config ARCH_ZYNQ select SPL_SEPARATE_BSS if SPL select DM_USB if USB select BLK + select CLK + select SPL_CLK
config ARCH_ZYNQMP bool "Support Xilinx ZynqMP Platform" diff --git a/arch/arm/dts/zynq-7000.dtsi b/arch/arm/dts/zynq-7000.dtsi index 668f54e..2464830 100644 --- a/arch/arm/dts/zynq-7000.dtsi +++ b/arch/arm/dts/zynq-7000.dtsi @@ -250,12 +250,14 @@ };
slcr: slcr@f8000000 { + u-boot,dm-pre-reloc; #address-cells = <1>; #size-cells = <1>; compatible = "xlnx,zynq-slcr", "syscon", "simple-mfd"; reg = <0xF8000000 0x1000>; ranges; clkc: clkc@100 { + u-boot,dm-pre-reloc; #clock-cells = <1>; compatible = "xlnx,ps7-clkc"; fclk-enable = <0>; diff --git a/arch/arm/mach-zynq/clk.c b/arch/arm/mach-zynq/clk.c index 570ebd7..7283a94 100644 --- a/arch/arm/mach-zynq/clk.c +++ b/arch/arm/mach-zynq/clk.c @@ -4,77 +4,13 @@ * * SPDX-License-Identifier: GPL-2.0+ */ +#include <clk.h> #include <common.h> -#include <errno.h> -#include <asm/io.h> -#include <asm/arch/hardware.h> +#include <dm.h> #include <asm/arch/clk.h>
-/* Board oscillator frequency */ -#ifndef CONFIG_ZYNQ_PS_CLK_FREQ -# define CONFIG_ZYNQ_PS_CLK_FREQ 33333333UL -#endif - -/* Register bitfield defines */ -#define PLLCTRL_FBDIV_MASK 0x7f000 -#define PLLCTRL_FBDIV_SHIFT 12 -#define PLLCTRL_BPFORCE_MASK (1 << 4) -#define PLLCTRL_PWRDWN_MASK 2 -#define PLLCTRL_PWRDWN_SHIFT 1 -#define PLLCTRL_RESET_MASK 1 -#define PLLCTRL_RESET_SHIFT 0 - -#define ZYNQ_CLK_MAXDIV 0x3f -#define CLK_CTRL_DIV1_SHIFT 20 -#define CLK_CTRL_DIV1_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV1_SHIFT) -#define CLK_CTRL_DIV0_SHIFT 8 -#define CLK_CTRL_DIV0_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV0_SHIFT) -#define CLK_CTRL_SRCSEL_SHIFT 4 -#define CLK_CTRL_SRCSEL_MASK (0x3 << CLK_CTRL_SRCSEL_SHIFT) - -#define CLK_CTRL_DIV2X_SHIFT 26 -#define CLK_CTRL_DIV2X_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV2X_SHIFT) -#define CLK_CTRL_DIV3X_SHIFT 20 -#define CLK_CTRL_DIV3X_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV3X_SHIFT) - -#define ZYNQ_CLKMUX_SEL_0 0 -#define ZYNQ_CLKMUX_SEL_1 1 -#define ZYNQ_CLKMUX_SEL_2 2 -#define ZYNQ_CLKMUX_SEL_3 3 - DECLARE_GLOBAL_DATA_PTR;
-struct clk; - -/** - * struct zynq_clk_ops: - * @set_rate: Function pointer to set_rate() implementation - * @get_rate: Function pointer to get_rate() implementation - */ -struct zynq_clk_ops { - int (*set_rate)(struct clk *clk, unsigned long rate); - unsigned long (*get_rate)(struct clk *clk); -}; - -/** - * struct clk: - * @frequency: Currenct frequency - * @parent: Parent clock - * @flags: Clock flags - * @reg: Clock control register - * @ops: Clock operations - */ -struct clk { - unsigned long frequency; - enum zynq_clk parent; - unsigned int flags; - u32 *reg; - struct zynq_clk_ops ops; -}; -#define ZYNQ_CLK_FLAGS_HAS_2_DIVS 1 - -static struct clk clks[clk_max]; - static const char * const clk_names[clk_max] = { "armpll", "ddrpll", "iopll", "cpu_6or4x", "cpu_3or2x", "cpu_2x", "cpu_1x", @@ -90,548 +26,43 @@ static const char * const clk_names[clk_max] = { };
/** - * __zynq_clk_cpu_get_parent() - Decode clock multiplexer - * @srcsel: Mux select value - * Returns the clock identifier associated with the selected mux input. - */ -static int __zynq_clk_cpu_get_parent(unsigned int srcsel) -{ - unsigned int ret; - - switch (srcsel) { - case ZYNQ_CLKMUX_SEL_0: - case ZYNQ_CLKMUX_SEL_1: - ret = armpll_clk; - break; - case ZYNQ_CLKMUX_SEL_2: - ret = ddrpll_clk; - break; - case ZYNQ_CLKMUX_SEL_3: - ret = iopll_clk; - break; - default: - ret = armpll_clk; - break; - } - - return ret; -} - -/** - * ddr2x_get_rate() - Get clock rate of DDR2x clock - * @clk: Clock handle - * Returns the current clock rate of @clk. - */ -static unsigned long ddr2x_get_rate(struct clk *clk) -{ - u32 clk_ctrl = readl(clk->reg); - u32 div = (clk_ctrl & CLK_CTRL_DIV2X_MASK) >> CLK_CTRL_DIV2X_SHIFT; - - return DIV_ROUND_CLOSEST(zynq_clk_get_rate(clk->parent), div); -} - -/** - * ddr3x_get_rate() - Get clock rate of DDR3x clock - * @clk: Clock handle - * Returns the current clock rate of @clk. - */ -static unsigned long ddr3x_get_rate(struct clk *clk) -{ - u32 clk_ctrl = readl(clk->reg); - u32 div = (clk_ctrl & CLK_CTRL_DIV3X_MASK) >> CLK_CTRL_DIV3X_SHIFT; - - return DIV_ROUND_CLOSEST(zynq_clk_get_rate(clk->parent), div); -} - -static void init_ddr_clocks(void) -{ - u32 div0, div1; - unsigned long prate = zynq_clk_get_rate(ddrpll_clk); - u32 clk_ctrl = readl(&slcr_base->ddr_clk_ctrl); - - /* DDR2x */ - clks[ddr2x_clk].reg = &slcr_base->ddr_clk_ctrl; - clks[ddr2x_clk].parent = ddrpll_clk; - clks[ddr2x_clk].frequency = ddr2x_get_rate(&clks[ddr2x_clk]); - clks[ddr2x_clk].ops.get_rate = ddr2x_get_rate; - - /* DDR3x */ - clks[ddr3x_clk].reg = &slcr_base->ddr_clk_ctrl; - clks[ddr3x_clk].parent = ddrpll_clk; - clks[ddr3x_clk].frequency = ddr3x_get_rate(&clks[ddr3x_clk]); - clks[ddr3x_clk].ops.get_rate = ddr3x_get_rate; - - /* DCI */ - clk_ctrl = readl(&slcr_base->dci_clk_ctrl); - div0 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT; - div1 = (clk_ctrl & CLK_CTRL_DIV1_MASK) >> CLK_CTRL_DIV1_SHIFT; - clks[dci_clk].reg = &slcr_base->dci_clk_ctrl; - clks[dci_clk].parent = ddrpll_clk; - clks[dci_clk].frequency = DIV_ROUND_CLOSEST( - DIV_ROUND_CLOSEST(prate, div0), div1); - - gd->bd->bi_ddr_freq = clks[ddr3x_clk].frequency / 1000000; -} - -static void init_cpu_clocks(void) -{ - int clk_621; - u32 reg, div, srcsel; - enum zynq_clk parent; - - reg = readl(&slcr_base->arm_clk_ctrl); - clk_621 = readl(&slcr_base->clk_621_true) & 1; - div = (reg & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT; - srcsel = (reg & CLK_CTRL_SRCSEL_MASK) >> CLK_CTRL_SRCSEL_SHIFT; - parent = __zynq_clk_cpu_get_parent(srcsel); - - /* cpu clocks */ - clks[cpu_6or4x_clk].reg = &slcr_base->arm_clk_ctrl; - clks[cpu_6or4x_clk].parent = parent; - clks[cpu_6or4x_clk].frequency = DIV_ROUND_CLOSEST( - zynq_clk_get_rate(parent), div); - - clks[cpu_3or2x_clk].reg = &slcr_base->arm_clk_ctrl; - clks[cpu_3or2x_clk].parent = cpu_6or4x_clk; - clks[cpu_3or2x_clk].frequency = zynq_clk_get_rate(cpu_6or4x_clk) / 2; - - clks[cpu_2x_clk].reg = &slcr_base->arm_clk_ctrl; - clks[cpu_2x_clk].parent = cpu_6or4x_clk; - clks[cpu_2x_clk].frequency = zynq_clk_get_rate(cpu_6or4x_clk) / - (2 + clk_621); - - clks[cpu_1x_clk].reg = &slcr_base->arm_clk_ctrl; - clks[cpu_1x_clk].parent = cpu_6or4x_clk; - clks[cpu_1x_clk].frequency = zynq_clk_get_rate(cpu_6or4x_clk) / - (4 + 2 * clk_621); -} - -/** - * periph_calc_two_divs() - Calculate clock dividers - * @cur_rate: Current clock rate - * @tgt_rate: Target clock rate - * @prate: Parent clock rate - * @div0: First divider (output) - * @div1: Second divider (output) - * Returns the actual clock rate possible. - * - * Calculates clock dividers for clocks with two 6-bit dividers. - */ -static unsigned long periph_calc_two_divs(unsigned long cur_rate, - unsigned long tgt_rate, unsigned long prate, u32 *div0, - u32 *div1) -{ - long err, best_err = (long)(~0UL >> 1); - unsigned long rate, best_rate = 0; - u32 d0, d1; - - for (d0 = 1; d0 <= ZYNQ_CLK_MAXDIV; d0++) { - for (d1 = 1; d1 <= ZYNQ_CLK_MAXDIV >> 1; d1++) { - rate = DIV_ROUND_CLOSEST(DIV_ROUND_CLOSEST(prate, d0), - d1); - err = abs(rate - tgt_rate); - - if (err < best_err) { - *div0 = d0; - *div1 = d1; - best_err = err; - best_rate = rate; - } - } - } - - return best_rate; -} - -/** - * zynq_clk_periph_set_rate() - Set clock rate - * @clk: Handle of the peripheral clock - * @rate: New clock rate - * Sets the clock frequency of @clk to @rate. Returns zero on success. - */ -static int zynq_clk_periph_set_rate(struct clk *clk, - unsigned long rate) -{ - u32 ctrl, div0 = 0, div1 = 0; - unsigned long prate, new_rate, cur_rate = clk->frequency; - - ctrl = readl(clk->reg); - prate = zynq_clk_get_rate(clk->parent); - ctrl &= ~CLK_CTRL_DIV0_MASK; - - if (clk->flags & ZYNQ_CLK_FLAGS_HAS_2_DIVS) { - ctrl &= ~CLK_CTRL_DIV1_MASK; - new_rate = periph_calc_two_divs(cur_rate, rate, prate, &div0, - &div1); - ctrl |= div1 << CLK_CTRL_DIV1_SHIFT; - } else { - div0 = DIV_ROUND_CLOSEST(prate, rate); - div0 &= ZYNQ_CLK_MAXDIV; - new_rate = DIV_ROUND_CLOSEST(rate, div0); - } - - /* write new divs to hardware */ - ctrl |= div0 << CLK_CTRL_DIV0_SHIFT; - writel(ctrl, clk->reg); - - /* update frequency in clk framework */ - clk->frequency = new_rate; - - return 0; -} - -/** - * zynq_clk_periph_get_rate() - Get clock rate - * @clk: Handle of the peripheral clock - * Returns the current clock rate of @clk. - */ -static unsigned long zynq_clk_periph_get_rate(struct clk *clk) -{ - u32 clk_ctrl = readl(clk->reg); - u32 div0 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT; - u32 div1 = 1; - - if (clk->flags & ZYNQ_CLK_FLAGS_HAS_2_DIVS) - div1 = (clk_ctrl & CLK_CTRL_DIV1_MASK) >> CLK_CTRL_DIV1_SHIFT; - - /* a register value of zero == division by 1 */ - if (!div0) - div0 = 1; - if (!div1) - div1 = 1; - - return - DIV_ROUND_CLOSEST( - DIV_ROUND_CLOSEST(zynq_clk_get_rate(clk->parent), div0), - div1); -} - -/** - * __zynq_clk_periph_get_parent() - Decode clock multiplexer - * @srcsel: Mux select value - * Returns the clock identifier associated with the selected mux input. - */ -static enum zynq_clk __zynq_clk_periph_get_parent(u32 srcsel) -{ - switch (srcsel) { - case ZYNQ_CLKMUX_SEL_0: - case ZYNQ_CLKMUX_SEL_1: - return iopll_clk; - case ZYNQ_CLKMUX_SEL_2: - return armpll_clk; - case ZYNQ_CLKMUX_SEL_3: - return ddrpll_clk; - default: - return 0; - } -} - -/** - * zynq_clk_periph_get_parent() - Decode clock multiplexer - * @clk: Clock handle - * Returns the clock identifier associated with the selected mux input. - */ -static enum zynq_clk zynq_clk_periph_get_parent(struct clk *clk) -{ - u32 clk_ctrl = readl(clk->reg); - u32 srcsel = (clk_ctrl & CLK_CTRL_SRCSEL_MASK) >> CLK_CTRL_SRCSEL_SHIFT; - - return __zynq_clk_periph_get_parent(srcsel); -} - -/** - * zynq_clk_register_periph_clk() - Set up a peripheral clock with the framework - * @clk: Pointer to struct clk for the clock - * @ctrl: Clock control register - * @two_divs: Indicates whether the clock features one or two dividers - */ -static int zynq_clk_register_periph_clk(struct clk *clk, u32 *ctrl, - bool two_divs) -{ - clk->reg = ctrl; - if (two_divs) - clk->flags = ZYNQ_CLK_FLAGS_HAS_2_DIVS; - clk->parent = zynq_clk_periph_get_parent(clk); - clk->frequency = zynq_clk_periph_get_rate(clk); - clk->ops.get_rate = zynq_clk_periph_get_rate; - clk->ops.set_rate = zynq_clk_periph_set_rate; - - return 0; -} - -static void init_periph_clocks(void) -{ - zynq_clk_register_periph_clk(&clks[gem0_clk], - &slcr_base->gem0_clk_ctrl, 1); - zynq_clk_register_periph_clk(&clks[gem1_clk], - &slcr_base->gem1_clk_ctrl, 1); - - zynq_clk_register_periph_clk(&clks[smc_clk], - &slcr_base->smc_clk_ctrl, 0); - - zynq_clk_register_periph_clk(&clks[lqspi_clk], - &slcr_base->lqspi_clk_ctrl, 0); - - zynq_clk_register_periph_clk(&clks[sdio0_clk], - &slcr_base->sdio_clk_ctrl, 0); - zynq_clk_register_periph_clk(&clks[sdio1_clk], - &slcr_base->sdio_clk_ctrl, 0); - - zynq_clk_register_periph_clk(&clks[spi0_clk], - &slcr_base->spi_clk_ctrl, 0); - zynq_clk_register_periph_clk(&clks[spi1_clk], - &slcr_base->spi_clk_ctrl, 0); - - zynq_clk_register_periph_clk(&clks[uart0_clk], - &slcr_base->uart_clk_ctrl, 0); - zynq_clk_register_periph_clk(&clks[uart1_clk], - &slcr_base->uart_clk_ctrl, 0); - - zynq_clk_register_periph_clk(&clks[dbg_trc_clk], - &slcr_base->dbg_clk_ctrl, 0); - zynq_clk_register_periph_clk(&clks[dbg_apb_clk], - &slcr_base->dbg_clk_ctrl, 0); - - zynq_clk_register_periph_clk(&clks[pcap_clk], - &slcr_base->pcap_clk_ctrl, 0); - - zynq_clk_register_periph_clk(&clks[fclk0_clk], - &slcr_base->fpga0_clk_ctrl, 1); - zynq_clk_register_periph_clk(&clks[fclk1_clk], - &slcr_base->fpga1_clk_ctrl, 1); - zynq_clk_register_periph_clk(&clks[fclk2_clk], - &slcr_base->fpga2_clk_ctrl, 1); - zynq_clk_register_periph_clk(&clks[fclk3_clk], - &slcr_base->fpga3_clk_ctrl, 1); -} - -/** - * zynq_clk_register_aper_clk() - Set up a APER clock with the framework - * @clk: Pointer to struct clk for the clock - * @ctrl: Clock control register - */ -static void zynq_clk_register_aper_clk(struct clk *clk, u32 *ctrl) -{ - clk->reg = ctrl; - clk->parent = cpu_1x_clk; - clk->frequency = zynq_clk_get_rate(clk->parent); -} - -static void init_aper_clocks(void) -{ - zynq_clk_register_aper_clk(&clks[usb0_aper_clk], - &slcr_base->aper_clk_ctrl); - zynq_clk_register_aper_clk(&clks[usb1_aper_clk], - &slcr_base->aper_clk_ctrl); - - zynq_clk_register_aper_clk(&clks[gem0_aper_clk], - &slcr_base->aper_clk_ctrl); - zynq_clk_register_aper_clk(&clks[gem1_aper_clk], - &slcr_base->aper_clk_ctrl); - - zynq_clk_register_aper_clk(&clks[sdio0_aper_clk], - &slcr_base->aper_clk_ctrl); - zynq_clk_register_aper_clk(&clks[sdio1_aper_clk], - &slcr_base->aper_clk_ctrl); - - zynq_clk_register_aper_clk(&clks[spi0_aper_clk], - &slcr_base->aper_clk_ctrl); - zynq_clk_register_aper_clk(&clks[spi1_aper_clk], - &slcr_base->aper_clk_ctrl); - - zynq_clk_register_aper_clk(&clks[can0_aper_clk], - &slcr_base->aper_clk_ctrl); - zynq_clk_register_aper_clk(&clks[can1_aper_clk], - &slcr_base->aper_clk_ctrl); - - zynq_clk_register_aper_clk(&clks[i2c0_aper_clk], - &slcr_base->aper_clk_ctrl); - zynq_clk_register_aper_clk(&clks[i2c1_aper_clk], - &slcr_base->aper_clk_ctrl); - - zynq_clk_register_aper_clk(&clks[uart0_aper_clk], - &slcr_base->aper_clk_ctrl); - zynq_clk_register_aper_clk(&clks[uart1_aper_clk], - &slcr_base->aper_clk_ctrl); - - zynq_clk_register_aper_clk(&clks[gpio_aper_clk], - &slcr_base->aper_clk_ctrl); - - zynq_clk_register_aper_clk(&clks[lqspi_aper_clk], - &slcr_base->aper_clk_ctrl); - - zynq_clk_register_aper_clk(&clks[smc_aper_clk], - &slcr_base->aper_clk_ctrl); -} - -/** - * __zynq_clk_pll_get_rate() - Get PLL rate - * @addr: Address of the PLL's control register - * Returns the current PLL output rate. - */ -static unsigned long __zynq_clk_pll_get_rate(u32 *addr) -{ - u32 reg, mul, bypass; - - reg = readl(addr); - bypass = reg & PLLCTRL_BPFORCE_MASK; - if (bypass) - mul = 1; - else - mul = (reg & PLLCTRL_FBDIV_MASK) >> PLLCTRL_FBDIV_SHIFT; - - return CONFIG_ZYNQ_PS_CLK_FREQ * mul; -} - -/** - * zynq_clk_pll_get_rate() - Get PLL rate - * @pll: Handle of the PLL - * Returns the current clock rate of @pll. - */ -static unsigned long zynq_clk_pll_get_rate(struct clk *pll) -{ - return __zynq_clk_pll_get_rate(pll->reg); -} - -/** - * zynq_clk_register_pll() - Set up a PLL with the framework - * @clk: Pointer to struct clk for the PLL - * @ctrl: PLL control register - * @prate: PLL input clock rate - */ -static void zynq_clk_register_pll(struct clk *clk, u32 *ctrl, - unsigned long prate) -{ - clk->reg = ctrl; - clk->frequency = zynq_clk_pll_get_rate(clk); - clk->ops.get_rate = zynq_clk_pll_get_rate; -} - -/** - * clkid_2_register() - Get clock control register - * @id: Clock identifier of one of the PLLs - * Returns the address of the requested PLL's control register. - */ -static u32 *clkid_2_register(enum zynq_clk id) -{ - switch (id) { - case armpll_clk: - return &slcr_base->arm_pll_ctrl; - case ddrpll_clk: - return &slcr_base->ddr_pll_ctrl; - case iopll_clk: - return &slcr_base->io_pll_ctrl; - default: - return &slcr_base->io_pll_ctrl; - } -} - -/* API */ -/** - * zynq_clk_early_init() - Early init for the clock framework - * - * This function is called from before relocation and sets up the CPU clock - * frequency in the global data struct. - */ -void zynq_clk_early_init(void) -{ - u32 reg = readl(&slcr_base->arm_clk_ctrl); - u32 div = (reg & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT; - u32 srcsel = (reg & CLK_CTRL_SRCSEL_MASK) >> CLK_CTRL_SRCSEL_SHIFT; - enum zynq_clk parent = __zynq_clk_cpu_get_parent(srcsel); - u32 *pllreg = clkid_2_register(parent); - unsigned long prate = __zynq_clk_pll_get_rate(pllreg); - - if (!div) - div = 1; - - gd->cpu_clk = DIV_ROUND_CLOSEST(prate, div); -} - -/** - * get_uart_clk() - Get UART input frequency - * @dev_index: UART ID - * Returns UART input clock frequency in Hz. - * - * Compared to zynq_clk_get_rate() this function is designed to work before - * relocation and can be called when the serial UART is set up. - */ -unsigned long get_uart_clk(int dev_index) -{ - u32 reg = readl(&slcr_base->uart_clk_ctrl); - u32 div = (reg & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT; - u32 srcsel = (reg & CLK_CTRL_SRCSEL_MASK) >> CLK_CTRL_SRCSEL_SHIFT; - enum zynq_clk parent = __zynq_clk_periph_get_parent(srcsel); - u32 *pllreg = clkid_2_register(parent); - unsigned long prate = __zynq_clk_pll_get_rate(pllreg); - - if (!div) - div = 1; - - return DIV_ROUND_CLOSEST(prate, div); -} - -/** - * set_cpu_clk_info() - Initialize clock framework - * Always returns zero. + * set_cpu_clk_info() - Setup clock information * * This function is called from common code after relocation and sets up the - * clock framework. The framework must not be used before this function had been - * called. + * clock information. */ int set_cpu_clk_info(void) { - zynq_clk_register_pll(&clks[armpll_clk], &slcr_base->arm_pll_ctrl, - CONFIG_ZYNQ_PS_CLK_FREQ); - zynq_clk_register_pll(&clks[ddrpll_clk], &slcr_base->ddr_pll_ctrl, - CONFIG_ZYNQ_PS_CLK_FREQ); - zynq_clk_register_pll(&clks[iopll_clk], &slcr_base->io_pll_ctrl, - CONFIG_ZYNQ_PS_CLK_FREQ); - - init_ddr_clocks(); - init_cpu_clocks(); - init_periph_clocks(); - init_aper_clocks(); - - gd->bd->bi_arm_freq = gd->cpu_clk / 1000000; + struct clk clk; + struct udevice *dev; + ulong rate; + int i, ret; + + ret = uclass_get_device_by_driver(UCLASS_CLK, + DM_GET_DRIVER(zynq_clk), &dev); + if (ret) + return ret; + + for (i = 0; i < 2; i++) { + clk.id = i ? ddr3x_clk : cpu_6or4x_clk; + ret = clk_request(dev, &clk); + if (ret < 0) + return ret; + + rate = clk_get_rate(&clk) / 1000000; + if (i) + gd->bd->bi_ddr_freq = rate; + else + gd->bd->bi_arm_freq = rate; + + clk_free(&clk); + } gd->bd->bi_dsp_freq = 0;
return 0; }
/** - * zynq_clk_get_rate() - Get clock rate - * @clk: Clock identifier - * Returns the current clock rate of @clk on success or zero for an invalid - * clock id. - */ -unsigned long zynq_clk_get_rate(enum zynq_clk clk) -{ - if (clk < 0 || clk >= clk_max) - return 0; - - return clks[clk].frequency; -} - -/** - * zynq_clk_set_rate() - Set clock rate - * @clk: Clock identifier - * @rate: Requested clock rate - * Passes on the return value from the clock's set_rate() function or negative - * errno. - */ -int zynq_clk_set_rate(enum zynq_clk clk, unsigned long rate) -{ - if (clk < 0 || clk >= clk_max) - return -ENODEV; - - if (clks[clk].ops.set_rate) - return clks[clk].ops.set_rate(&clks[clk], rate); - - return -ENXIO; -} - -/** * soc_clk_dump() - Print clock frequencies * Returns zero on success * @@ -639,13 +70,32 @@ int zynq_clk_set_rate(enum zynq_clk clk, unsigned long rate) */ int soc_clk_dump(void) { - int i; + struct udevice *dev; + int i, ret; + + ret = uclass_get_device_by_driver(UCLASS_CLK, + DM_GET_DRIVER(zynq_clk), &dev); + if (ret) + return ret;
printf("clk\t\tfrequency\n"); for (i = 0; i < clk_max; i++) { const char *name = clk_names[i]; - if (name) - printf("%10s%20lu\n", name, zynq_clk_get_rate(i)); + if (name) { + struct clk clk; + unsigned long rate; + + clk.id = i; + ret = clk_request(dev, &clk); + if (ret < 0) + return ret; + + rate = clk_get_rate(&clk); + + clk_free(&clk); + + printf("%10s%20lu\n", name, rate); + } }
return 0; diff --git a/arch/arm/mach-zynq/cpu.c b/arch/arm/mach-zynq/cpu.c index ba9171e..ee1c1a9 100644 --- a/arch/arm/mach-zynq/cpu.c +++ b/arch/arm/mach-zynq/cpu.c @@ -35,7 +35,6 @@ int arch_cpu_init(void) writel(0xC, &slcr_base->ddr_urgent); #endif #endif - zynq_clk_early_init(); zynq_slcr_lock();
return 0; diff --git a/arch/arm/mach-zynq/include/mach/clk.h b/arch/arm/mach-zynq/include/mach/clk.h index 5c2758a..8a039ae 100644 --- a/arch/arm/mach-zynq/include/mach/clk.h +++ b/arch/arm/mach-zynq/include/mach/clk.h @@ -20,9 +20,4 @@ enum zynq_clk { uart0_aper_clk, uart1_aper_clk, gpio_aper_clk, lqspi_aper_clk, smc_aper_clk, swdt_clk, dbg_trc_clk, dbg_apb_clk, clk_max};
-void zynq_clk_early_init(void); -int zynq_clk_set_rate(enum zynq_clk clk, unsigned long rate); -unsigned long zynq_clk_get_rate(enum zynq_clk clk); -unsigned long get_uart_clk(int dev_id); - #endif diff --git a/arch/arm/mach-zynq/include/mach/sys_proto.h b/arch/arm/mach-zynq/include/mach/sys_proto.h index 44c9b50..67238e7 100644 --- a/arch/arm/mach-zynq/include/mach/sys_proto.h +++ b/arch/arm/mach-zynq/include/mach/sys_proto.h @@ -10,7 +10,6 @@ extern void zynq_slcr_lock(void); extern void zynq_slcr_unlock(void); extern void zynq_slcr_cpu_reset(void); -extern void zynq_slcr_gem_clk_setup(u32 gem_id, unsigned long clk_rate); extern void zynq_slcr_devcfg_disable(void); extern void zynq_slcr_devcfg_enable(void); extern u32 zynq_slcr_get_boot_mode(void); diff --git a/arch/arm/mach-zynq/slcr.c b/arch/arm/mach-zynq/slcr.c index c1129cd..2a207ae 100644 --- a/arch/arm/mach-zynq/slcr.c +++ b/arch/arm/mach-zynq/slcr.c @@ -9,7 +9,6 @@ #include <malloc.h> #include <asm/arch/hardware.h> #include <asm/arch/sys_proto.h> -#include <asm/arch/clk.h>
#define SLCR_LOCK_MAGIC 0x767B #define SLCR_UNLOCK_MAGIC 0xDF0D @@ -124,27 +123,6 @@ void zynq_slcr_cpu_reset(void) writel(1, &slcr_base->pss_rst_ctrl); }
-/* Setup clk for network */ -void zynq_slcr_gem_clk_setup(u32 gem_id, unsigned long clk_rate) -{ - int ret; - - zynq_slcr_unlock(); - - if (gem_id > 1) { - printf("Non existing GEM id %d\n", gem_id); - goto out; - } - - ret = zynq_clk_set_rate(gem0_clk + gem_id, clk_rate); - if (ret) - goto out; - - udelay(100000); -out: - zynq_slcr_lock(); -} - void zynq_slcr_devcfg_disable(void) { u32 reg_val; diff --git a/arch/arm/mach-zynq/timer.c b/arch/arm/mach-zynq/timer.c index 0335cbe..b1bb3b8 100644 --- a/arch/arm/mach-zynq/timer.c +++ b/arch/arm/mach-zynq/timer.c @@ -61,7 +61,6 @@ int timer_init(void) (TIMER_PRESCALE << SCUTIMER_CONTROL_PRESCALER_SHIFT) | SCUTIMER_CONTROL_ENABLE_MASK;
-#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK) struct udevice *dev; struct clk clk; int ret; @@ -79,7 +78,6 @@ int timer_init(void) gd->cpu_clk = clk_get_rate(&clk);
clk_free(&clk); -#endif
gd->arch.timer_rate_hz = (gd->cpu_clk / 2) / (TIMER_PRESCALE + 1);
diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 9118e49..2c95188 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -181,9 +181,7 @@ struct zynq_gem_priv { struct phy_device *phydev; int phy_of_handle; struct mii_dev *bus; -#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK) struct clk tx_clk; -#endif };
static inline int mdio_wait(struct zynq_gem_regs *regs) @@ -368,9 +366,7 @@ static int zynq_gem_init(struct udevice *dev) u32 i, nwconfig; int ret; unsigned long clk_rate = 0; -#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK) unsigned long clk_rate_rounded; -#endif struct zynq_gem_priv *priv = dev_get_priv(dev); struct zynq_gem_regs *regs = priv->iobase; struct emac_bd *dummy_tx_bd = &priv->tx_bd[TX_FREE_DESC]; @@ -473,7 +469,6 @@ static int zynq_gem_init(struct udevice *dev) break; }
-#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK) clk_rate_rounded = clk_set_rate(&priv->tx_clk, clk_rate); if (IS_ERR_VALUE(clk_rate_rounded)) { dev_err(dev, "failed to set tx clock rate\n"); @@ -485,10 +480,6 @@ static int zynq_gem_init(struct udevice *dev) dev_err(dev, "failed to enable tx clock\n"); return ret; } -#else - zynq_slcr_gem_clk_setup((ulong)priv->iobase != - ZYNQ_GEM_BASEADDR0, clk_rate); -#endif
setbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_RXEN_MASK | ZYNQ_GEM_NWCTRL_TXEN_MASK); @@ -699,9 +690,7 @@ static int zynq_gem_ofdata_to_platdata(struct udevice *dev) struct eth_pdata *pdata = dev_get_platdata(dev); struct zynq_gem_priv *priv = dev_get_priv(dev); const char *phy_mode; -#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK) int ret; -#endif
pdata->iobase = (phys_addr_t)dev_get_addr(dev); priv->iobase = (struct zynq_gem_regs *)pdata->iobase; @@ -723,13 +712,11 @@ static int zynq_gem_ofdata_to_platdata(struct udevice *dev) } priv->interface = pdata->phy_interface;
-#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK) ret = clk_get_by_index(dev, 2, &priv->tx_clk); if (ret < 0) { dev_err(dev, "failed to get clock\n"); return ret; } -#endif
printf("ZYNQ GEM: %lx, phyaddr %x, interface %s\n", (ulong)priv->iobase, priv->phyaddr, phy_string_for_interface(priv->interface)); diff --git a/drivers/serial/serial_zynq.c b/drivers/serial/serial_zynq.c index 4f6e7e4..a2967c0 100644 --- a/drivers/serial/serial_zynq.c +++ b/drivers/serial/serial_zynq.c @@ -15,7 +15,6 @@ #include <asm/io.h> #include <linux/compiler.h> #include <serial.h> -#include <asm/arch/clk.h> #include <asm/arch/hardware.h>
DECLARE_GLOBAL_DATA_PTR; @@ -111,7 +110,6 @@ int zynq_serial_setbrg(struct udevice *dev, int baudrate) struct zynq_uart_priv *priv = dev_get_priv(dev); unsigned long clock;
-#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK) int ret; struct clk clk;
@@ -133,9 +131,7 @@ int zynq_serial_setbrg(struct udevice *dev, int baudrate) dev_err(dev, "failed to enable clock\n"); return ret; } -#else - clock = get_uart_clk(0); -#endif + _uart_zynq_serial_setbrg(priv->regs, clock, baudrate);
return 0; diff --git a/include/configs/topic_miami.h b/include/configs/topic_miami.h index 3b0fa29..a1ccc42 100644 --- a/include/configs/topic_miami.h +++ b/include/configs/topic_miami.h @@ -10,8 +10,6 @@ #ifndef __CONFIG_TOPIC_MIAMI_H #define __CONFIG_TOPIC_MIAMI_H
-#define CONFIG_ZYNQ_PS_CLK_FREQ 33333333UL - #define CONFIG_ZYNQ_I2C0 #define CONFIG_ZYNQ_I2C1
diff --git a/include/configs/zynq_zybo.h b/include/configs/zynq_zybo.h index b9ff391..1488fd8 100644 --- a/include/configs/zynq_zybo.h +++ b/include/configs/zynq_zybo.h @@ -20,9 +20,6 @@ #define CONFIG_DISPLAY #define CONFIG_I2C_EDID
-/* Define ZYBO PS Clock Frequency to 50MHz */ -#define CONFIG_ZYNQ_PS_CLK_FREQ 50000000UL - #include <configs/zynq-common.h>
#endif /* __CONFIG_ZYNQ_ZYBO_H */ diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt index 6d614c6..375b9b8 100644 --- a/scripts/config_whitelist.txt +++ b/scripts/config_whitelist.txt @@ -8248,7 +8248,6 @@ CONFIG_ZYNQ_GEM_I2C_MAC_OFFSET CONFIG_ZYNQ_HISPD_BROKEN CONFIG_ZYNQ_I2C0 CONFIG_ZYNQ_I2C1 -CONFIG_ZYNQ_PS_CLK_FREQ CONFIG_ZYNQ_SDHCI0 CONFIG_ZYNQ_SDHCI1 CONFIG_ZYNQ_SDHCI_MAX_FREQ

On 4.1.2017 13:27, stefan.herbrechtsmeier@weidmueller.com wrote:
From: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.de
Move the zynq to clock framework and remove unused functions as well as the CONFIG_ZYNQ_PS_CLK_FREQ configuration.
Signed-off-by: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com
arch/arm/Kconfig | 2 + arch/arm/dts/zynq-7000.dtsi | 2 + arch/arm/mach-zynq/clk.c | 650 +++------------------------- arch/arm/mach-zynq/cpu.c | 1 - arch/arm/mach-zynq/include/mach/clk.h | 5 - arch/arm/mach-zynq/include/mach/sys_proto.h | 1 - arch/arm/mach-zynq/slcr.c | 22 - arch/arm/mach-zynq/timer.c | 2 - drivers/net/zynq_gem.c | 13 - drivers/serial/serial_zynq.c | 6 +- include/configs/topic_miami.h | 2 - include/configs/zynq_zybo.h | 3 - scripts/config_whitelist.txt | 1 - 13 files changed, 55 insertions(+), 655 deletions(-)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 38080c0..f9daa99 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -631,6 +631,8 @@ config ARCH_ZYNQ select SPL_SEPARATE_BSS if SPL select DM_USB if USB select BLK
- select CLK
- select SPL_CLK
config ARCH_ZYNQMP bool "Support Xilinx ZynqMP Platform" diff --git a/arch/arm/dts/zynq-7000.dtsi b/arch/arm/dts/zynq-7000.dtsi index 668f54e..2464830 100644 --- a/arch/arm/dts/zynq-7000.dtsi +++ b/arch/arm/dts/zynq-7000.dtsi @@ -250,12 +250,14 @@ };
slcr: slcr@f8000000 {
u-boot,dm-pre-reloc; #address-cells = <1>; #size-cells = <1>; compatible = "xlnx,zynq-slcr", "syscon", "simple-mfd"; reg = <0xF8000000 0x1000>; ranges; clkc: clkc@100 {
u-boot,dm-pre-reloc; #clock-cells = <1>; compatible = "xlnx,ps7-clkc"; fclk-enable = <0>;
diff --git a/arch/arm/mach-zynq/clk.c b/arch/arm/mach-zynq/clk.c index 570ebd7..7283a94 100644 --- a/arch/arm/mach-zynq/clk.c +++ b/arch/arm/mach-zynq/clk.c @@ -4,77 +4,13 @@
- SPDX-License-Identifier: GPL-2.0+
*/ +#include <clk.h> #include <common.h> -#include <errno.h> -#include <asm/io.h> -#include <asm/arch/hardware.h> +#include <dm.h> #include <asm/arch/clk.h>
-/* Board oscillator frequency */ -#ifndef CONFIG_ZYNQ_PS_CLK_FREQ -# define CONFIG_ZYNQ_PS_CLK_FREQ 33333333UL -#endif
-/* Register bitfield defines */ -#define PLLCTRL_FBDIV_MASK 0x7f000 -#define PLLCTRL_FBDIV_SHIFT 12 -#define PLLCTRL_BPFORCE_MASK (1 << 4) -#define PLLCTRL_PWRDWN_MASK 2 -#define PLLCTRL_PWRDWN_SHIFT 1 -#define PLLCTRL_RESET_MASK 1 -#define PLLCTRL_RESET_SHIFT 0
-#define ZYNQ_CLK_MAXDIV 0x3f -#define CLK_CTRL_DIV1_SHIFT 20 -#define CLK_CTRL_DIV1_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV1_SHIFT) -#define CLK_CTRL_DIV0_SHIFT 8 -#define CLK_CTRL_DIV0_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV0_SHIFT) -#define CLK_CTRL_SRCSEL_SHIFT 4 -#define CLK_CTRL_SRCSEL_MASK (0x3 << CLK_CTRL_SRCSEL_SHIFT)
-#define CLK_CTRL_DIV2X_SHIFT 26 -#define CLK_CTRL_DIV2X_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV2X_SHIFT) -#define CLK_CTRL_DIV3X_SHIFT 20 -#define CLK_CTRL_DIV3X_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV3X_SHIFT)
-#define ZYNQ_CLKMUX_SEL_0 0 -#define ZYNQ_CLKMUX_SEL_1 1 -#define ZYNQ_CLKMUX_SEL_2 2 -#define ZYNQ_CLKMUX_SEL_3 3
DECLARE_GLOBAL_DATA_PTR;
-struct clk;
-/**
- struct zynq_clk_ops:
- @set_rate: Function pointer to set_rate() implementation
- @get_rate: Function pointer to get_rate() implementation
- */
-struct zynq_clk_ops {
- int (*set_rate)(struct clk *clk, unsigned long rate);
- unsigned long (*get_rate)(struct clk *clk);
-};
-/**
- struct clk:
- @frequency: Currenct frequency
- @parent: Parent clock
- @flags: Clock flags
- @reg: Clock control register
- @ops: Clock operations
- */
-struct clk {
- unsigned long frequency;
- enum zynq_clk parent;
- unsigned int flags;
- u32 *reg;
- struct zynq_clk_ops ops;
-}; -#define ZYNQ_CLK_FLAGS_HAS_2_DIVS 1
-static struct clk clks[clk_max];
static const char * const clk_names[clk_max] = { "armpll", "ddrpll", "iopll", "cpu_6or4x", "cpu_3or2x", "cpu_2x", "cpu_1x", @@ -90,548 +26,43 @@ static const char * const clk_names[clk_max] = { };
/**
- __zynq_clk_cpu_get_parent() - Decode clock multiplexer
- @srcsel: Mux select value
- Returns the clock identifier associated with the selected mux input.
- */
-static int __zynq_clk_cpu_get_parent(unsigned int srcsel) -{
- unsigned int ret;
- switch (srcsel) {
- case ZYNQ_CLKMUX_SEL_0:
- case ZYNQ_CLKMUX_SEL_1:
ret = armpll_clk;
break;
- case ZYNQ_CLKMUX_SEL_2:
ret = ddrpll_clk;
break;
- case ZYNQ_CLKMUX_SEL_3:
ret = iopll_clk;
break;
- default:
ret = armpll_clk;
break;
- }
- return ret;
-}
-/**
- ddr2x_get_rate() - Get clock rate of DDR2x clock
- @clk: Clock handle
- Returns the current clock rate of @clk.
- */
-static unsigned long ddr2x_get_rate(struct clk *clk) -{
- u32 clk_ctrl = readl(clk->reg);
- u32 div = (clk_ctrl & CLK_CTRL_DIV2X_MASK) >> CLK_CTRL_DIV2X_SHIFT;
- return DIV_ROUND_CLOSEST(zynq_clk_get_rate(clk->parent), div);
-}
-/**
- ddr3x_get_rate() - Get clock rate of DDR3x clock
- @clk: Clock handle
- Returns the current clock rate of @clk.
- */
-static unsigned long ddr3x_get_rate(struct clk *clk) -{
- u32 clk_ctrl = readl(clk->reg);
- u32 div = (clk_ctrl & CLK_CTRL_DIV3X_MASK) >> CLK_CTRL_DIV3X_SHIFT;
- return DIV_ROUND_CLOSEST(zynq_clk_get_rate(clk->parent), div);
-}
-static void init_ddr_clocks(void) -{
- u32 div0, div1;
- unsigned long prate = zynq_clk_get_rate(ddrpll_clk);
- u32 clk_ctrl = readl(&slcr_base->ddr_clk_ctrl);
- /* DDR2x */
- clks[ddr2x_clk].reg = &slcr_base->ddr_clk_ctrl;
- clks[ddr2x_clk].parent = ddrpll_clk;
- clks[ddr2x_clk].frequency = ddr2x_get_rate(&clks[ddr2x_clk]);
- clks[ddr2x_clk].ops.get_rate = ddr2x_get_rate;
- /* DDR3x */
- clks[ddr3x_clk].reg = &slcr_base->ddr_clk_ctrl;
- clks[ddr3x_clk].parent = ddrpll_clk;
- clks[ddr3x_clk].frequency = ddr3x_get_rate(&clks[ddr3x_clk]);
- clks[ddr3x_clk].ops.get_rate = ddr3x_get_rate;
- /* DCI */
- clk_ctrl = readl(&slcr_base->dci_clk_ctrl);
- div0 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
- div1 = (clk_ctrl & CLK_CTRL_DIV1_MASK) >> CLK_CTRL_DIV1_SHIFT;
- clks[dci_clk].reg = &slcr_base->dci_clk_ctrl;
- clks[dci_clk].parent = ddrpll_clk;
- clks[dci_clk].frequency = DIV_ROUND_CLOSEST(
DIV_ROUND_CLOSEST(prate, div0), div1);
- gd->bd->bi_ddr_freq = clks[ddr3x_clk].frequency / 1000000;
-}
-static void init_cpu_clocks(void) -{
- int clk_621;
- u32 reg, div, srcsel;
- enum zynq_clk parent;
- reg = readl(&slcr_base->arm_clk_ctrl);
- clk_621 = readl(&slcr_base->clk_621_true) & 1;
- div = (reg & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
- srcsel = (reg & CLK_CTRL_SRCSEL_MASK) >> CLK_CTRL_SRCSEL_SHIFT;
- parent = __zynq_clk_cpu_get_parent(srcsel);
- /* cpu clocks */
- clks[cpu_6or4x_clk].reg = &slcr_base->arm_clk_ctrl;
- clks[cpu_6or4x_clk].parent = parent;
- clks[cpu_6or4x_clk].frequency = DIV_ROUND_CLOSEST(
zynq_clk_get_rate(parent), div);
- clks[cpu_3or2x_clk].reg = &slcr_base->arm_clk_ctrl;
- clks[cpu_3or2x_clk].parent = cpu_6or4x_clk;
- clks[cpu_3or2x_clk].frequency = zynq_clk_get_rate(cpu_6or4x_clk) / 2;
- clks[cpu_2x_clk].reg = &slcr_base->arm_clk_ctrl;
- clks[cpu_2x_clk].parent = cpu_6or4x_clk;
- clks[cpu_2x_clk].frequency = zynq_clk_get_rate(cpu_6or4x_clk) /
(2 + clk_621);
- clks[cpu_1x_clk].reg = &slcr_base->arm_clk_ctrl;
- clks[cpu_1x_clk].parent = cpu_6or4x_clk;
- clks[cpu_1x_clk].frequency = zynq_clk_get_rate(cpu_6or4x_clk) /
(4 + 2 * clk_621);
-}
-/**
- periph_calc_two_divs() - Calculate clock dividers
- @cur_rate: Current clock rate
- @tgt_rate: Target clock rate
- @prate: Parent clock rate
- @div0: First divider (output)
- @div1: Second divider (output)
- Returns the actual clock rate possible.
- Calculates clock dividers for clocks with two 6-bit dividers.
- */
-static unsigned long periph_calc_two_divs(unsigned long cur_rate,
unsigned long tgt_rate, unsigned long prate, u32 *div0,
u32 *div1)
-{
- long err, best_err = (long)(~0UL >> 1);
- unsigned long rate, best_rate = 0;
- u32 d0, d1;
- for (d0 = 1; d0 <= ZYNQ_CLK_MAXDIV; d0++) {
for (d1 = 1; d1 <= ZYNQ_CLK_MAXDIV >> 1; d1++) {
rate = DIV_ROUND_CLOSEST(DIV_ROUND_CLOSEST(prate, d0),
d1);
err = abs(rate - tgt_rate);
if (err < best_err) {
*div0 = d0;
*div1 = d1;
best_err = err;
best_rate = rate;
}
}
- }
- return best_rate;
-}
-/**
- zynq_clk_periph_set_rate() - Set clock rate
- @clk: Handle of the peripheral clock
- @rate: New clock rate
- Sets the clock frequency of @clk to @rate. Returns zero on success.
- */
-static int zynq_clk_periph_set_rate(struct clk *clk,
unsigned long rate)
-{
- u32 ctrl, div0 = 0, div1 = 0;
- unsigned long prate, new_rate, cur_rate = clk->frequency;
- ctrl = readl(clk->reg);
- prate = zynq_clk_get_rate(clk->parent);
- ctrl &= ~CLK_CTRL_DIV0_MASK;
- if (clk->flags & ZYNQ_CLK_FLAGS_HAS_2_DIVS) {
ctrl &= ~CLK_CTRL_DIV1_MASK;
new_rate = periph_calc_two_divs(cur_rate, rate, prate, &div0,
&div1);
ctrl |= div1 << CLK_CTRL_DIV1_SHIFT;
- } else {
div0 = DIV_ROUND_CLOSEST(prate, rate);
div0 &= ZYNQ_CLK_MAXDIV;
new_rate = DIV_ROUND_CLOSEST(rate, div0);
- }
- /* write new divs to hardware */
- ctrl |= div0 << CLK_CTRL_DIV0_SHIFT;
- writel(ctrl, clk->reg);
- /* update frequency in clk framework */
- clk->frequency = new_rate;
- return 0;
-}
-/**
- zynq_clk_periph_get_rate() - Get clock rate
- @clk: Handle of the peripheral clock
- Returns the current clock rate of @clk.
- */
-static unsigned long zynq_clk_periph_get_rate(struct clk *clk) -{
- u32 clk_ctrl = readl(clk->reg);
- u32 div0 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
- u32 div1 = 1;
- if (clk->flags & ZYNQ_CLK_FLAGS_HAS_2_DIVS)
div1 = (clk_ctrl & CLK_CTRL_DIV1_MASK) >> CLK_CTRL_DIV1_SHIFT;
- /* a register value of zero == division by 1 */
- if (!div0)
div0 = 1;
- if (!div1)
div1 = 1;
- return
DIV_ROUND_CLOSEST(
DIV_ROUND_CLOSEST(zynq_clk_get_rate(clk->parent), div0),
div1);
-}
-/**
- __zynq_clk_periph_get_parent() - Decode clock multiplexer
- @srcsel: Mux select value
- Returns the clock identifier associated with the selected mux input.
- */
-static enum zynq_clk __zynq_clk_periph_get_parent(u32 srcsel) -{
- switch (srcsel) {
- case ZYNQ_CLKMUX_SEL_0:
- case ZYNQ_CLKMUX_SEL_1:
return iopll_clk;
- case ZYNQ_CLKMUX_SEL_2:
return armpll_clk;
- case ZYNQ_CLKMUX_SEL_3:
return ddrpll_clk;
- default:
return 0;
- }
-}
-/**
- zynq_clk_periph_get_parent() - Decode clock multiplexer
- @clk: Clock handle
- Returns the clock identifier associated with the selected mux input.
- */
-static enum zynq_clk zynq_clk_periph_get_parent(struct clk *clk) -{
- u32 clk_ctrl = readl(clk->reg);
- u32 srcsel = (clk_ctrl & CLK_CTRL_SRCSEL_MASK) >> CLK_CTRL_SRCSEL_SHIFT;
- return __zynq_clk_periph_get_parent(srcsel);
-}
-/**
- zynq_clk_register_periph_clk() - Set up a peripheral clock with the framework
- @clk: Pointer to struct clk for the clock
- @ctrl: Clock control register
- @two_divs: Indicates whether the clock features one or two dividers
- */
-static int zynq_clk_register_periph_clk(struct clk *clk, u32 *ctrl,
bool two_divs)
-{
- clk->reg = ctrl;
- if (two_divs)
clk->flags = ZYNQ_CLK_FLAGS_HAS_2_DIVS;
- clk->parent = zynq_clk_periph_get_parent(clk);
- clk->frequency = zynq_clk_periph_get_rate(clk);
- clk->ops.get_rate = zynq_clk_periph_get_rate;
- clk->ops.set_rate = zynq_clk_periph_set_rate;
- return 0;
-}
-static void init_periph_clocks(void) -{
- zynq_clk_register_periph_clk(&clks[gem0_clk],
&slcr_base->gem0_clk_ctrl, 1);
- zynq_clk_register_periph_clk(&clks[gem1_clk],
&slcr_base->gem1_clk_ctrl, 1);
- zynq_clk_register_periph_clk(&clks[smc_clk],
&slcr_base->smc_clk_ctrl, 0);
- zynq_clk_register_periph_clk(&clks[lqspi_clk],
&slcr_base->lqspi_clk_ctrl, 0);
- zynq_clk_register_periph_clk(&clks[sdio0_clk],
&slcr_base->sdio_clk_ctrl, 0);
- zynq_clk_register_periph_clk(&clks[sdio1_clk],
&slcr_base->sdio_clk_ctrl, 0);
- zynq_clk_register_periph_clk(&clks[spi0_clk],
&slcr_base->spi_clk_ctrl, 0);
- zynq_clk_register_periph_clk(&clks[spi1_clk],
&slcr_base->spi_clk_ctrl, 0);
- zynq_clk_register_periph_clk(&clks[uart0_clk],
&slcr_base->uart_clk_ctrl, 0);
- zynq_clk_register_periph_clk(&clks[uart1_clk],
&slcr_base->uart_clk_ctrl, 0);
- zynq_clk_register_periph_clk(&clks[dbg_trc_clk],
&slcr_base->dbg_clk_ctrl, 0);
- zynq_clk_register_periph_clk(&clks[dbg_apb_clk],
&slcr_base->dbg_clk_ctrl, 0);
- zynq_clk_register_periph_clk(&clks[pcap_clk],
&slcr_base->pcap_clk_ctrl, 0);
- zynq_clk_register_periph_clk(&clks[fclk0_clk],
&slcr_base->fpga0_clk_ctrl, 1);
- zynq_clk_register_periph_clk(&clks[fclk1_clk],
&slcr_base->fpga1_clk_ctrl, 1);
- zynq_clk_register_periph_clk(&clks[fclk2_clk],
&slcr_base->fpga2_clk_ctrl, 1);
- zynq_clk_register_periph_clk(&clks[fclk3_clk],
&slcr_base->fpga3_clk_ctrl, 1);
-}
-/**
- zynq_clk_register_aper_clk() - Set up a APER clock with the framework
- @clk: Pointer to struct clk for the clock
- @ctrl: Clock control register
- */
-static void zynq_clk_register_aper_clk(struct clk *clk, u32 *ctrl) -{
- clk->reg = ctrl;
- clk->parent = cpu_1x_clk;
- clk->frequency = zynq_clk_get_rate(clk->parent);
-}
-static void init_aper_clocks(void) -{
- zynq_clk_register_aper_clk(&clks[usb0_aper_clk],
&slcr_base->aper_clk_ctrl);
- zynq_clk_register_aper_clk(&clks[usb1_aper_clk],
&slcr_base->aper_clk_ctrl);
- zynq_clk_register_aper_clk(&clks[gem0_aper_clk],
&slcr_base->aper_clk_ctrl);
- zynq_clk_register_aper_clk(&clks[gem1_aper_clk],
&slcr_base->aper_clk_ctrl);
- zynq_clk_register_aper_clk(&clks[sdio0_aper_clk],
&slcr_base->aper_clk_ctrl);
- zynq_clk_register_aper_clk(&clks[sdio1_aper_clk],
&slcr_base->aper_clk_ctrl);
- zynq_clk_register_aper_clk(&clks[spi0_aper_clk],
&slcr_base->aper_clk_ctrl);
- zynq_clk_register_aper_clk(&clks[spi1_aper_clk],
&slcr_base->aper_clk_ctrl);
- zynq_clk_register_aper_clk(&clks[can0_aper_clk],
&slcr_base->aper_clk_ctrl);
- zynq_clk_register_aper_clk(&clks[can1_aper_clk],
&slcr_base->aper_clk_ctrl);
- zynq_clk_register_aper_clk(&clks[i2c0_aper_clk],
&slcr_base->aper_clk_ctrl);
- zynq_clk_register_aper_clk(&clks[i2c1_aper_clk],
&slcr_base->aper_clk_ctrl);
- zynq_clk_register_aper_clk(&clks[uart0_aper_clk],
&slcr_base->aper_clk_ctrl);
- zynq_clk_register_aper_clk(&clks[uart1_aper_clk],
&slcr_base->aper_clk_ctrl);
- zynq_clk_register_aper_clk(&clks[gpio_aper_clk],
&slcr_base->aper_clk_ctrl);
- zynq_clk_register_aper_clk(&clks[lqspi_aper_clk],
&slcr_base->aper_clk_ctrl);
- zynq_clk_register_aper_clk(&clks[smc_aper_clk],
&slcr_base->aper_clk_ctrl);
-}
-/**
- __zynq_clk_pll_get_rate() - Get PLL rate
- @addr: Address of the PLL's control register
- Returns the current PLL output rate.
- */
-static unsigned long __zynq_clk_pll_get_rate(u32 *addr) -{
- u32 reg, mul, bypass;
- reg = readl(addr);
- bypass = reg & PLLCTRL_BPFORCE_MASK;
- if (bypass)
mul = 1;
- else
mul = (reg & PLLCTRL_FBDIV_MASK) >> PLLCTRL_FBDIV_SHIFT;
- return CONFIG_ZYNQ_PS_CLK_FREQ * mul;
-}
-/**
- zynq_clk_pll_get_rate() - Get PLL rate
- @pll: Handle of the PLL
- Returns the current clock rate of @pll.
- */
-static unsigned long zynq_clk_pll_get_rate(struct clk *pll) -{
- return __zynq_clk_pll_get_rate(pll->reg);
-}
-/**
- zynq_clk_register_pll() - Set up a PLL with the framework
- @clk: Pointer to struct clk for the PLL
- @ctrl: PLL control register
- @prate: PLL input clock rate
- */
-static void zynq_clk_register_pll(struct clk *clk, u32 *ctrl,
unsigned long prate)
-{
- clk->reg = ctrl;
- clk->frequency = zynq_clk_pll_get_rate(clk);
- clk->ops.get_rate = zynq_clk_pll_get_rate;
-}
-/**
- clkid_2_register() - Get clock control register
- @id: Clock identifier of one of the PLLs
- Returns the address of the requested PLL's control register.
- */
-static u32 *clkid_2_register(enum zynq_clk id) -{
- switch (id) {
- case armpll_clk:
return &slcr_base->arm_pll_ctrl;
- case ddrpll_clk:
return &slcr_base->ddr_pll_ctrl;
- case iopll_clk:
return &slcr_base->io_pll_ctrl;
- default:
return &slcr_base->io_pll_ctrl;
- }
-}
-/* API */ -/**
- zynq_clk_early_init() - Early init for the clock framework
- This function is called from before relocation and sets up the CPU clock
- frequency in the global data struct.
- */
-void zynq_clk_early_init(void) -{
- u32 reg = readl(&slcr_base->arm_clk_ctrl);
- u32 div = (reg & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
- u32 srcsel = (reg & CLK_CTRL_SRCSEL_MASK) >> CLK_CTRL_SRCSEL_SHIFT;
- enum zynq_clk parent = __zynq_clk_cpu_get_parent(srcsel);
- u32 *pllreg = clkid_2_register(parent);
- unsigned long prate = __zynq_clk_pll_get_rate(pllreg);
- if (!div)
div = 1;
- gd->cpu_clk = DIV_ROUND_CLOSEST(prate, div);
-}
-/**
- get_uart_clk() - Get UART input frequency
- @dev_index: UART ID
- Returns UART input clock frequency in Hz.
- Compared to zynq_clk_get_rate() this function is designed to work before
- relocation and can be called when the serial UART is set up.
- */
-unsigned long get_uart_clk(int dev_index) -{
- u32 reg = readl(&slcr_base->uart_clk_ctrl);
- u32 div = (reg & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
- u32 srcsel = (reg & CLK_CTRL_SRCSEL_MASK) >> CLK_CTRL_SRCSEL_SHIFT;
- enum zynq_clk parent = __zynq_clk_periph_get_parent(srcsel);
- u32 *pllreg = clkid_2_register(parent);
- unsigned long prate = __zynq_clk_pll_get_rate(pllreg);
- if (!div)
div = 1;
- return DIV_ROUND_CLOSEST(prate, div);
-}
-/**
- set_cpu_clk_info() - Initialize clock framework
- Always returns zero.
- set_cpu_clk_info() - Setup clock information
- This function is called from common code after relocation and sets up the
- clock framework. The framework must not be used before this function had been
- called.
*/
- clock information.
int set_cpu_clk_info(void) {
- zynq_clk_register_pll(&clks[armpll_clk], &slcr_base->arm_pll_ctrl,
CONFIG_ZYNQ_PS_CLK_FREQ);
- zynq_clk_register_pll(&clks[ddrpll_clk], &slcr_base->ddr_pll_ctrl,
CONFIG_ZYNQ_PS_CLK_FREQ);
- zynq_clk_register_pll(&clks[iopll_clk], &slcr_base->io_pll_ctrl,
CONFIG_ZYNQ_PS_CLK_FREQ);
- init_ddr_clocks();
- init_cpu_clocks();
- init_periph_clocks();
- init_aper_clocks();
- gd->bd->bi_arm_freq = gd->cpu_clk / 1000000;
struct clk clk;
struct udevice *dev;
ulong rate;
int i, ret;
ret = uclass_get_device_by_driver(UCLASS_CLK,
DM_GET_DRIVER(zynq_clk), &dev);
if (ret)
return ret;
for (i = 0; i < 2; i++) {
clk.id = i ? ddr3x_clk : cpu_6or4x_clk;
ret = clk_request(dev, &clk);
if (ret < 0)
return ret;
rate = clk_get_rate(&clk) / 1000000;
if (i)
gd->bd->bi_ddr_freq = rate;
else
gd->bd->bi_arm_freq = rate;
clk_free(&clk);
} gd->bd->bi_dsp_freq = 0;
return 0;
}
/**
- zynq_clk_get_rate() - Get clock rate
- @clk: Clock identifier
- Returns the current clock rate of @clk on success or zero for an invalid
- clock id.
- */
-unsigned long zynq_clk_get_rate(enum zynq_clk clk) -{
- if (clk < 0 || clk >= clk_max)
return 0;
- return clks[clk].frequency;
-}
-/**
- zynq_clk_set_rate() - Set clock rate
- @clk: Clock identifier
- @rate: Requested clock rate
- Passes on the return value from the clock's set_rate() function or negative
- errno.
- */
-int zynq_clk_set_rate(enum zynq_clk clk, unsigned long rate) -{
- if (clk < 0 || clk >= clk_max)
return -ENODEV;
- if (clks[clk].ops.set_rate)
return clks[clk].ops.set_rate(&clks[clk], rate);
- return -ENXIO;
-}
-/**
- soc_clk_dump() - Print clock frequencies
- Returns zero on success
@@ -639,13 +70,32 @@ int zynq_clk_set_rate(enum zynq_clk clk, unsigned long rate) */ int soc_clk_dump(void) {
- int i;
struct udevice *dev;
int i, ret;
ret = uclass_get_device_by_driver(UCLASS_CLK,
DM_GET_DRIVER(zynq_clk), &dev);
if (ret)
return ret;
printf("clk\t\tfrequency\n"); for (i = 0; i < clk_max; i++) { const char *name = clk_names[i];
if (name)
printf("%10s%20lu\n", name, zynq_clk_get_rate(i));
if (name) {
struct clk clk;
unsigned long rate;
clk.id = i;
ret = clk_request(dev, &clk);
if (ret < 0)
return ret;
rate = clk_get_rate(&clk);
clk_free(&clk);
printf("%10s%20lu\n", name, rate);
}
}
return 0;
diff --git a/arch/arm/mach-zynq/cpu.c b/arch/arm/mach-zynq/cpu.c index ba9171e..ee1c1a9 100644 --- a/arch/arm/mach-zynq/cpu.c +++ b/arch/arm/mach-zynq/cpu.c @@ -35,7 +35,6 @@ int arch_cpu_init(void) writel(0xC, &slcr_base->ddr_urgent); #endif #endif
zynq_clk_early_init(); zynq_slcr_lock();
return 0;
diff --git a/arch/arm/mach-zynq/include/mach/clk.h b/arch/arm/mach-zynq/include/mach/clk.h index 5c2758a..8a039ae 100644 --- a/arch/arm/mach-zynq/include/mach/clk.h +++ b/arch/arm/mach-zynq/include/mach/clk.h @@ -20,9 +20,4 @@ enum zynq_clk { uart0_aper_clk, uart1_aper_clk, gpio_aper_clk, lqspi_aper_clk, smc_aper_clk, swdt_clk, dbg_trc_clk, dbg_apb_clk, clk_max};
-void zynq_clk_early_init(void); -int zynq_clk_set_rate(enum zynq_clk clk, unsigned long rate); -unsigned long zynq_clk_get_rate(enum zynq_clk clk); -unsigned long get_uart_clk(int dev_id);
#endif diff --git a/arch/arm/mach-zynq/include/mach/sys_proto.h b/arch/arm/mach-zynq/include/mach/sys_proto.h index 44c9b50..67238e7 100644 --- a/arch/arm/mach-zynq/include/mach/sys_proto.h +++ b/arch/arm/mach-zynq/include/mach/sys_proto.h @@ -10,7 +10,6 @@ extern void zynq_slcr_lock(void); extern void zynq_slcr_unlock(void); extern void zynq_slcr_cpu_reset(void); -extern void zynq_slcr_gem_clk_setup(u32 gem_id, unsigned long clk_rate); extern void zynq_slcr_devcfg_disable(void); extern void zynq_slcr_devcfg_enable(void); extern u32 zynq_slcr_get_boot_mode(void); diff --git a/arch/arm/mach-zynq/slcr.c b/arch/arm/mach-zynq/slcr.c index c1129cd..2a207ae 100644 --- a/arch/arm/mach-zynq/slcr.c +++ b/arch/arm/mach-zynq/slcr.c @@ -9,7 +9,6 @@ #include <malloc.h> #include <asm/arch/hardware.h> #include <asm/arch/sys_proto.h> -#include <asm/arch/clk.h>
#define SLCR_LOCK_MAGIC 0x767B #define SLCR_UNLOCK_MAGIC 0xDF0D @@ -124,27 +123,6 @@ void zynq_slcr_cpu_reset(void) writel(1, &slcr_base->pss_rst_ctrl); }
-/* Setup clk for network */ -void zynq_slcr_gem_clk_setup(u32 gem_id, unsigned long clk_rate) -{
- int ret;
- zynq_slcr_unlock();
- if (gem_id > 1) {
printf("Non existing GEM id %d\n", gem_id);
goto out;
- }
- ret = zynq_clk_set_rate(gem0_clk + gem_id, clk_rate);
- if (ret)
goto out;
- udelay(100000);
-out:
- zynq_slcr_lock();
-}
void zynq_slcr_devcfg_disable(void) { u32 reg_val; diff --git a/arch/arm/mach-zynq/timer.c b/arch/arm/mach-zynq/timer.c index 0335cbe..b1bb3b8 100644 --- a/arch/arm/mach-zynq/timer.c +++ b/arch/arm/mach-zynq/timer.c @@ -61,7 +61,6 @@ int timer_init(void) (TIMER_PRESCALE << SCUTIMER_CONTROL_PRESCALER_SHIFT) | SCUTIMER_CONTROL_ENABLE_MASK;
-#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK) struct udevice *dev; struct clk clk; int ret; @@ -79,7 +78,6 @@ int timer_init(void) gd->cpu_clk = clk_get_rate(&clk);
clk_free(&clk); -#endif
gd->arch.timer_rate_hz = (gd->cpu_clk / 2) / (TIMER_PRESCALE + 1);
diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 9118e49..2c95188 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -181,9 +181,7 @@ struct zynq_gem_priv { struct phy_device *phydev; int phy_of_handle; struct mii_dev *bus; -#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK) struct clk tx_clk; -#endif };
static inline int mdio_wait(struct zynq_gem_regs *regs) @@ -368,9 +366,7 @@ static int zynq_gem_init(struct udevice *dev) u32 i, nwconfig; int ret; unsigned long clk_rate = 0; -#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK) unsigned long clk_rate_rounded; -#endif struct zynq_gem_priv *priv = dev_get_priv(dev); struct zynq_gem_regs *regs = priv->iobase; struct emac_bd *dummy_tx_bd = &priv->tx_bd[TX_FREE_DESC]; @@ -473,7 +469,6 @@ static int zynq_gem_init(struct udevice *dev) break; }
-#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK) clk_rate_rounded = clk_set_rate(&priv->tx_clk, clk_rate); if (IS_ERR_VALUE(clk_rate_rounded)) { dev_err(dev, "failed to set tx clock rate\n"); @@ -485,10 +480,6 @@ static int zynq_gem_init(struct udevice *dev) dev_err(dev, "failed to enable tx clock\n"); return ret; } -#else
- zynq_slcr_gem_clk_setup((ulong)priv->iobase !=
ZYNQ_GEM_BASEADDR0, clk_rate);
-#endif
setbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_RXEN_MASK | ZYNQ_GEM_NWCTRL_TXEN_MASK); @@ -699,9 +690,7 @@ static int zynq_gem_ofdata_to_platdata(struct udevice *dev) struct eth_pdata *pdata = dev_get_platdata(dev); struct zynq_gem_priv *priv = dev_get_priv(dev); const char *phy_mode; -#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK) int ret; -#endif
pdata->iobase = (phys_addr_t)dev_get_addr(dev); priv->iobase = (struct zynq_gem_regs *)pdata->iobase; @@ -723,13 +712,11 @@ static int zynq_gem_ofdata_to_platdata(struct udevice *dev) } priv->interface = pdata->phy_interface;
-#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK) ret = clk_get_by_index(dev, 2, &priv->tx_clk); if (ret < 0) { dev_err(dev, "failed to get clock\n"); return ret; } -#endif
printf("ZYNQ GEM: %lx, phyaddr %x, interface %s\n", (ulong)priv->iobase, priv->phyaddr, phy_string_for_interface(priv->interface)); diff --git a/drivers/serial/serial_zynq.c b/drivers/serial/serial_zynq.c index 4f6e7e4..a2967c0 100644 --- a/drivers/serial/serial_zynq.c +++ b/drivers/serial/serial_zynq.c @@ -15,7 +15,6 @@ #include <asm/io.h> #include <linux/compiler.h> #include <serial.h> -#include <asm/arch/clk.h> #include <asm/arch/hardware.h>
DECLARE_GLOBAL_DATA_PTR; @@ -111,7 +110,6 @@ int zynq_serial_setbrg(struct udevice *dev, int baudrate) struct zynq_uart_priv *priv = dev_get_priv(dev); unsigned long clock;
-#if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK) int ret; struct clk clk;
@@ -133,9 +131,7 @@ int zynq_serial_setbrg(struct udevice *dev, int baudrate) dev_err(dev, "failed to enable clock\n"); return ret; } -#else
- clock = get_uart_clk(0);
-#endif
_uart_zynq_serial_setbrg(priv->regs, clock, baudrate);
return 0;
diff --git a/include/configs/topic_miami.h b/include/configs/topic_miami.h index 3b0fa29..a1ccc42 100644 --- a/include/configs/topic_miami.h +++ b/include/configs/topic_miami.h @@ -10,8 +10,6 @@ #ifndef __CONFIG_TOPIC_MIAMI_H #define __CONFIG_TOPIC_MIAMI_H
-#define CONFIG_ZYNQ_PS_CLK_FREQ 33333333UL
#define CONFIG_ZYNQ_I2C0 #define CONFIG_ZYNQ_I2C1
diff --git a/include/configs/zynq_zybo.h b/include/configs/zynq_zybo.h index b9ff391..1488fd8 100644 --- a/include/configs/zynq_zybo.h +++ b/include/configs/zynq_zybo.h @@ -20,9 +20,6 @@ #define CONFIG_DISPLAY #define CONFIG_I2C_EDID
-/* Define ZYBO PS Clock Frequency to 50MHz */ -#define CONFIG_ZYNQ_PS_CLK_FREQ 50000000UL
#include <configs/zynq-common.h>
#endif /* __CONFIG_ZYNQ_ZYBO_H */ diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt index 6d614c6..375b9b8 100644 --- a/scripts/config_whitelist.txt +++ b/scripts/config_whitelist.txt @@ -8248,7 +8248,6 @@ CONFIG_ZYNQ_GEM_I2C_MAC_OFFSET CONFIG_ZYNQ_HISPD_BROKEN CONFIG_ZYNQ_I2C0 CONFIG_ZYNQ_I2C1 -CONFIG_ZYNQ_PS_CLK_FREQ CONFIG_ZYNQ_SDHCI0 CONFIG_ZYNQ_SDHCI1 CONFIG_ZYNQ_SDHCI_MAX_FREQ
Looks good.
Acked-by: Michal Simek michal.simek@xilinx.com
Thanks, Michal

From: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com
Add support for the optional ethernet emio clock source to the zynq clock framework driver.
Signed-off-by: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com
---
drivers/clk/clk_zynq.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-)
diff --git a/drivers/clk/clk_zynq.c b/drivers/clk/clk_zynq.c index d276155..6f1448d 100644 --- a/drivers/clk/clk_zynq.c +++ b/drivers/clk/clk_zynq.c @@ -53,6 +53,9 @@ enum zynq_clk_rclk {mio_clk, emio_clk};
struct zynq_clk_priv { ulong ps_clk_freq; +#ifndef CONFIG_SPL_BUILD + struct clk gem_emio_clk[2]; +#endif };
static void *zynq_clk_get_register(enum zynq_clk id) @@ -284,10 +287,16 @@ static ulong zynq_clk_get_peripheral_rate(struct zynq_clk_priv *priv, #ifndef CONFIG_SPL_BUILD static ulong zynq_clk_get_gem_rate(struct zynq_clk_priv *priv, enum zynq_clk id) { + struct clk *parent; + if (zynq_clk_get_gem_rclk(id) == mio_clk) return zynq_clk_get_peripheral_rate(priv, id, true);
- return 0; + parent = &priv->gem_emio_clk[id - gem0_clk]; + if (parent) + return clk_get_rate(parent); + + return -ENXIO; }
static unsigned long zynq_clk_calc_peripheral_two_divs( @@ -354,10 +363,16 @@ static ulong zynq_clk_set_peripheral_rate(struct zynq_clk_priv *priv, static ulong zynq_clk_set_gem_rate(struct zynq_clk_priv *priv, enum zynq_clk id, ulong rate) { + struct clk *parent; + if (zynq_clk_get_gem_rclk(id) == mio_clk) return zynq_clk_set_peripheral_rate(priv, id, rate, true);
- return 0; + parent = &priv->gem_emio_clk[id - gem0_clk]; + if (parent) + return clk_set_rate(parent, rate); + + return -ENXIO; } #endif
@@ -447,6 +462,20 @@ static struct clk_ops zynq_clk_ops = { static int zynq_clk_probe(struct udevice *dev) { struct zynq_clk_priv *priv = dev_get_priv(dev); +#ifndef CONFIG_SPL_BUILD + unsigned int i; + char name[16]; + int ret; + + for (i = 0; i < 2; i++) { + sprintf(name, "gem%d_emio_clk", i); + ret = clk_get_by_name(dev, name, &priv->gem_emio_clk[i]); + if (ret < 0 && ret != -FDT_ERR_NOTFOUND) { + dev_err(dev, "failed to get %s clock\n", name); + return ret; + } + } +#endif
priv->ps_clk_freq = fdtdec_get_uint(gd->fdt_blob, dev->of_offset, "ps-clk-frequency", 33333333UL);

On 4.1.2017 13:27, stefan.herbrechtsmeier@weidmueller.com wrote:
From: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com
Add support for the optional ethernet emio clock source to the zynq clock framework driver.
Signed-off-by: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com
drivers/clk/clk_zynq.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-)
diff --git a/drivers/clk/clk_zynq.c b/drivers/clk/clk_zynq.c index d276155..6f1448d 100644 --- a/drivers/clk/clk_zynq.c +++ b/drivers/clk/clk_zynq.c @@ -53,6 +53,9 @@ enum zynq_clk_rclk {mio_clk, emio_clk};
struct zynq_clk_priv { ulong ps_clk_freq; +#ifndef CONFIG_SPL_BUILD
- struct clk gem_emio_clk[2];
+#endif };
static void *zynq_clk_get_register(enum zynq_clk id) @@ -284,10 +287,16 @@ static ulong zynq_clk_get_peripheral_rate(struct zynq_clk_priv *priv, #ifndef CONFIG_SPL_BUILD static ulong zynq_clk_get_gem_rate(struct zynq_clk_priv *priv, enum zynq_clk id) {
- struct clk *parent;
- if (zynq_clk_get_gem_rclk(id) == mio_clk) return zynq_clk_get_peripheral_rate(priv, id, true);
- return 0;
- parent = &priv->gem_emio_clk[id - gem0_clk];
- if (parent)
return clk_get_rate(parent);
- return -ENXIO;
}
static unsigned long zynq_clk_calc_peripheral_two_divs( @@ -354,10 +363,16 @@ static ulong zynq_clk_set_peripheral_rate(struct zynq_clk_priv *priv, static ulong zynq_clk_set_gem_rate(struct zynq_clk_priv *priv, enum zynq_clk id, ulong rate) {
- struct clk *parent;
- if (zynq_clk_get_gem_rclk(id) == mio_clk) return zynq_clk_set_peripheral_rate(priv, id, rate, true);
- return 0;
- parent = &priv->gem_emio_clk[id - gem0_clk];
- if (parent)
return clk_set_rate(parent, rate);
- return -ENXIO;
} #endif
@@ -447,6 +462,20 @@ static struct clk_ops zynq_clk_ops = { static int zynq_clk_probe(struct udevice *dev) { struct zynq_clk_priv *priv = dev_get_priv(dev); +#ifndef CONFIG_SPL_BUILD
- unsigned int i;
- char name[16];
- int ret;
- for (i = 0; i < 2; i++) {
sprintf(name, "gem%d_emio_clk", i);
ret = clk_get_by_name(dev, name, &priv->gem_emio_clk[i]);
if (ret < 0 && ret != -FDT_ERR_NOTFOUND) {
dev_err(dev, "failed to get %s clock\n", name);
return ret;
}
- }
+#endif
priv->ps_clk_freq = fdtdec_get_uint(gd->fdt_blob, dev->of_offset, "ps-clk-frequency", 33333333UL);
Ah ok. Here it is emio stuff for ethernet.
Thanks, Michal
participants (5)
-
Michal Simek
-
Michal Simek
-
Stefan.Herbrechtsmeier@weidmueller.com
-
stefan.herbrechtsmeier@weidmueller.com
-
Sören Brinkmann