All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH 1/2] clk: zynqmp: Add clock driver support for zynqmp
@ 2016-12-16 12:31 Michal Simek
  2016-12-16 12:31 ` [U-Boot] [PATCH 2/2] net: zynq_gem: Use clock driver for ZynqMP Michal Simek
  2016-12-17 22:48 ` [U-Boot] [PATCH 1/2] clk: zynqmp: Add clock driver support for zynqmp Simon Glass
  0 siblings, 2 replies; 3+ messages in thread
From: Michal Simek @ 2016-12-16 12:31 UTC (permalink / raw)
  To: u-boot

From: Siva Durga Prasad Paladugu <siva.durga.paladugu@xilinx.com>

Add basic clock driver support for zynqmp which
sets the required clock for GEM controller

Signed-off-by: Siva Durga Prasad Paladugu <sivadur@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
---

 drivers/clk/Kconfig      |   7 ++
 drivers/clk/Makefile     |   1 +
 drivers/clk/clk_zynqmp.c | 241 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 249 insertions(+)
 create mode 100644 drivers/clk/clk_zynqmp.c

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index c05ce2a9efa3..335ef9e1d7cf 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_ZYNQMP
+	bool "Enable clock driver support for ZynqMP"
+	depends on ARCH_ZYNQMP
+	help
+	  This clock driver adds support for clock realted settings for
+	  ZynqMP platform.
+
 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 40a5e8cae868..f55348e8f15f 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
 obj-$(CONFIG_SANDBOX) += clk_sandbox.o
 obj-$(CONFIG_SANDBOX) += clk_sandbox_test.o
 obj-$(CONFIG_MACH_PIC32) += clk_pic32.o
+obj-$(CONFIG_CLK_ZYNQMP) += clk_zynqmp.o
 
 obj-y += tegra/
 obj-$(CONFIG_CLK_UNIPHIER) += uniphier/
diff --git a/drivers/clk/clk_zynqmp.c b/drivers/clk/clk_zynqmp.c
new file mode 100644
index 000000000000..694274d99103
--- /dev/null
+++ b/drivers/clk/clk_zynqmp.c
@@ -0,0 +1,241 @@
+/*
+ * ZynqMP clock driver
+ *
+ * Copyright (C) 2016 Xilinx, Inc.
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/bitops.h>
+#include <clk-uclass.h>
+#include <dm/device.h>
+#include <clk.h>
+
+#define ZYNQMP_GEM0_REF_CTRL		0xFF5E0050
+#define ZYNQMP_IOPLL_CTRL		0xFF5E0020
+#define ZYNQMP_RPLL_CTRL		0xFF5E0030
+#define ZYNQMP_DPLL_CTRL		0xFD1A002C
+#define ZYNQMP_SIP_SVC_MMIO_WRITE	0xC2000013
+#define ZYNQMP_SIP_SVC_MMIO_WRITE	0xC2000013
+#define ZYNQMP_SIP_SVC_MMIO_WRITE	0xC2000013
+#define ZYNQMP_SIP_SVC_MMIO_READ	0xC2000014
+#define ZYNQMP_DIV_MAX_VAL		0x3F
+#define ZYNQMP_DIV1_SHFT		8
+#define ZYNQMP_DIV1_SHFT		8
+#define ZYNQMP_DIV2_SHFT		16
+#define ZYNQMP_DIV_MASK			0x3F
+#define ZYNQMP_PLL_CTRL_FBDIV_MASK	0x7F
+#define ZYNQMP_PLL_CTRL_FBDIV_SHFT	8
+#define ZYNQMP_GEM_REF_CTRL_SRC_MASK	0x7
+#define ZYNQMP_GEM0_CLK_ID		45
+#define ZYNQMP_GEM1_CLK_ID		46
+#define ZYNQMP_GEM2_CLK_ID		47
+#define ZYNQMP_GEM3_CLK_ID		48
+
+static unsigned long pss_ref_clk;
+
+static int zynqmp_calculate_divisors(unsigned long req_rate,
+				     unsigned long parent_rate,
+				     u32 *div1, u32 *div2)
+{
+	u32 req_div = 1;
+	u32 i;
+
+	/*
+	 * calculate two divisors to get
+	 * required rate and each divisor
+	 * should be less than 63
+	 */
+	req_div = DIV_ROUND_UP(parent_rate, req_rate);
+
+	for (i = 1; i <= req_div; i++) {
+		if ((req_div % i) == 0) {
+			*div1 = req_div / i;
+			*div2 = i;
+			if ((*div1 < ZYNQMP_DIV_MAX_VAL) &&
+			    (*div2 < ZYNQMP_DIV_MAX_VAL))
+				return 0;
+		}
+	}
+
+	return -1;
+}
+
+static int zynqmp_get_periph_id(unsigned long id)
+{
+	int periph_id;
+
+	switch (id) {
+	case ZYNQMP_GEM0_CLK_ID:
+		periph_id = 0;
+		break;
+	case ZYNQMP_GEM1_CLK_ID:
+		periph_id = 1;
+		break;
+	case ZYNQMP_GEM2_CLK_ID:
+		periph_id = 2;
+		break;
+	case ZYNQMP_GEM3_CLK_ID:
+		periph_id = 3;
+		break;
+	default:
+		printf("%s, Invalid clock id:%ld\n", __func__, id);
+		return -EINVAL;
+	}
+
+	return periph_id;
+}
+
+static int zynqmp_set_clk(unsigned long id, u32 div1, u32 div2)
+{
+	struct pt_regs regs;
+	ulong reg;
+	u32 mask, value;
+
+	id = zynqmp_get_periph_id(id);
+	if (id < 0)
+		return -EINVAL;
+
+	reg = (ulong)((u32 *)ZYNQMP_GEM0_REF_CTRL + id);
+	mask = (ZYNQMP_DIV_MASK << ZYNQMP_DIV1_SHFT) |
+	       (ZYNQMP_DIV_MASK << ZYNQMP_DIV2_SHFT);
+	value = (div1 << ZYNQMP_DIV1_SHFT) | (div2 << ZYNQMP_DIV2_SHFT);
+
+	debug("%s: reg:0x%lx, mask:0x%x, value:0x%x\n", __func__, reg, mask,
+	      value);
+
+	regs.regs[0] = ZYNQMP_SIP_SVC_MMIO_WRITE;
+	regs.regs[1] = ((u64)mask << 32) | reg;
+	regs.regs[2] = value;
+	regs.regs[3] = 0;
+
+	smc_call(&regs);
+
+	return regs.regs[0];
+}
+
+static unsigned long zynqmp_clk_get_rate(struct clk *clk)
+{
+	struct pt_regs regs;
+	ulong reg;
+	unsigned long value;
+	int id;
+
+	id = zynqmp_get_periph_id(clk->id);
+	if (id < 0)
+		return -EINVAL;
+
+	reg = (ulong)((u32 *)ZYNQMP_GEM0_REF_CTRL + id);
+
+	regs.regs[0] = ZYNQMP_SIP_SVC_MMIO_READ;
+	regs.regs[1] = reg;
+	regs.regs[2] = 0;
+	regs.regs[3] = 0;
+
+	smc_call(&regs);
+
+	value = upper_32_bits(regs.regs[0]);
+
+	value &= ZYNQMP_GEM_REF_CTRL_SRC_MASK;
+
+	switch (value) {
+	case 0:
+		regs.regs[1] = ZYNQMP_IOPLL_CTRL;
+		break;
+	case 2:
+		regs.regs[1] = ZYNQMP_RPLL_CTRL;
+		break;
+	case 3:
+		regs.regs[1] = ZYNQMP_DPLL_CTRL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regs.regs[0] = ZYNQMP_SIP_SVC_MMIO_READ;
+	regs.regs[2] = 0;
+	regs.regs[3] = 0;
+
+	smc_call(&regs);
+
+	value = upper_32_bits(regs.regs[0]) &
+		 (ZYNQMP_PLL_CTRL_FBDIV_MASK <<
+		 ZYNQMP_PLL_CTRL_FBDIV_SHFT);
+	value >>= ZYNQMP_PLL_CTRL_FBDIV_SHFT;
+	value *= pss_ref_clk;
+
+	return value;
+}
+
+static ulong zynqmp_clk_set_rate(struct clk *clk, unsigned long clk_rate)
+{
+	int ret;
+	u32 div1 = 0;
+	u32 div2 = 0;
+	unsigned long input_clk;
+
+	input_clk = zynqmp_clk_get_rate(clk);
+	if (IS_ERR_VALUE(input_clk)) {
+		dev_err(dev, "failed to get input_clk\n");
+		return -EINVAL;
+	}
+
+	debug("%s: i/p CLK %ld, clk_rate:0x%ld\n", __func__, input_clk,
+	      clk_rate);
+
+	ret = zynqmp_calculate_divisors(clk_rate, input_clk, &div1, &div2);
+	if (ret) {
+		dev_err(dev, "failed to proper divisors\n");
+		return -EINVAL;
+	}
+
+	debug("%s: Div1:%d, Div2:%d\n", __func__, div1, div2);
+
+	ret = zynqmp_set_clk(clk->id, div1, div2);
+	if (ret) {
+		dev_err(dev, "failed to set gem clk\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int zynqmp_clk_probe(struct udevice *dev)
+{
+	struct clk clk;
+	int ret;
+
+	debug("%s\n", __func__);
+	ret = clk_get_by_name(dev, "pss_ref_clk", &clk);
+	if (ret < 0) {
+		dev_err(dev, "failed to get pss_ref_clk\n");
+		return ret;
+	}
+
+	pss_ref_clk = clk_get_rate(&clk);
+	if (IS_ERR_VALUE(pss_ref_clk)) {
+		dev_err(dev, "failed to get rate pss_ref_clk\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static struct clk_ops zynqmp_clk_ops = {
+	.set_rate = zynqmp_clk_set_rate,
+	.get_rate = zynqmp_clk_get_rate,
+};
+
+static const struct udevice_id zynqmp_clk_ids[] = {
+	{ .compatible = "xlnx,zynqmp-clkc" },
+	{ }
+};
+
+U_BOOT_DRIVER(zynqmp_clk) = {
+	.name = "zynqmp-clk",
+	.id = UCLASS_CLK,
+	.of_match = zynqmp_clk_ids,
+	.probe = zynqmp_clk_probe,
+	.ops = &zynqmp_clk_ops,
+};
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [U-Boot] [PATCH 2/2] net: zynq_gem: Use clock driver for ZynqMP
  2016-12-16 12:31 [U-Boot] [PATCH 1/2] clk: zynqmp: Add clock driver support for zynqmp Michal Simek
@ 2016-12-16 12:31 ` Michal Simek
  2016-12-17 22:48 ` [U-Boot] [PATCH 1/2] clk: zynqmp: Add clock driver support for zynqmp Simon Glass
  1 sibling, 0 replies; 3+ messages in thread
From: Michal Simek @ 2016-12-16 12:31 UTC (permalink / raw)
  To: u-boot

From: Siva Durga Prasad Paladugu <siva.durga.paladugu@xilinx.com>

Enable and use the clock driver routine
defined in clock driver toset required
clock appropriately.

Signed-off-by: Siva Durga Prasad Paladugu <sivadur@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
---

 arch/arm/include/asm/arch-zynqmp/sys_proto.h |  2 ++
 drivers/net/zynq_gem.c                       | 18 ++++++++++++++++++
 2 files changed, 20 insertions(+)

diff --git a/arch/arm/include/asm/arch-zynqmp/sys_proto.h b/arch/arm/include/asm/arch-zynqmp/sys_proto.h
index 1db2bd6a4f7a..95fd91da2915 100644
--- a/arch/arm/include/asm/arch-zynqmp/sys_proto.h
+++ b/arch/arm/include/asm/arch-zynqmp/sys_proto.h
@@ -8,10 +8,12 @@
 #ifndef _ASM_ARCH_SYS_PROTO_H
 #define _ASM_ARCH_SYS_PROTO_H
 
+#ifndef CONFIG_CLK_ZYNQMP
 /* Setup clk for network */
 static inline void zynq_slcr_gem_clk_setup(u32 gem_id, unsigned long clk_rate)
 {
 }
+#endif
 
 int zynq_slcr_get_mio_pin_status(const char *periph);
 
diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c
index 95b4d6e4f0aa..6dd87cf28f95 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>
@@ -181,6 +182,9 @@ struct zynq_gem_priv {
 	struct phy_device *phydev;
 	int phy_of_handle;
 	struct mii_dev *bus;
+#ifdef CONFIG_CLK_ZYNQMP
+	struct clk clk;
+#endif
 };
 
 static u32 phy_setup_op(struct zynq_gem_priv *priv, u32 phy_addr, u32 regnum,
@@ -455,8 +459,14 @@ static int zynq_gem_init(struct udevice *dev)
 
 	/* Change the rclk and clk only not using EMIO interface */
 	if (!priv->emio)
+#ifndef CONFIG_CLK_ZYNQMP
 		zynq_slcr_gem_clk_setup((ulong)priv->iobase !=
 					ZYNQ_GEM_BASEADDR0, clk_rate);
+#else
+		ret = clk_set_rate(&priv->clk, clk_rate);
+		if (IS_ERR_VALUE(ret))
+			return -1;
+#endif
 
 	setbits_le32(&regs->nwctrl, ZYNQ_GEM_NWCTRL_RXEN_MASK |
 					ZYNQ_GEM_NWCTRL_TXEN_MASK);
@@ -629,6 +639,14 @@ static int zynq_gem_probe(struct udevice *dev)
 	priv->tx_bd = (struct emac_bd *)bd_space;
 	priv->rx_bd = (struct emac_bd *)((ulong)bd_space + BD_SEPRN_SPACE);
 
+#ifdef CONFIG_CLK_ZYNQMP
+	ret = clk_get_by_name(dev, "tx_clk", &priv->clk);
+	if (ret < 0) {
+		dev_err(dev, "failed to get clock\n");
+		return -EINVAL;
+	}
+#endif
+
 	priv->bus = mdio_alloc();
 	priv->bus->read = zynq_gem_miiphy_read;
 	priv->bus->write = zynq_gem_miiphy_write;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [U-Boot] [PATCH 1/2] clk: zynqmp: Add clock driver support for zynqmp
  2016-12-16 12:31 [U-Boot] [PATCH 1/2] clk: zynqmp: Add clock driver support for zynqmp Michal Simek
  2016-12-16 12:31 ` [U-Boot] [PATCH 2/2] net: zynq_gem: Use clock driver for ZynqMP Michal Simek
@ 2016-12-17 22:48 ` Simon Glass
  1 sibling, 0 replies; 3+ messages in thread
From: Simon Glass @ 2016-12-17 22:48 UTC (permalink / raw)
  To: u-boot

On 16 December 2016 at 05:31, Michal Simek <michal.simek@xilinx.com> wrote:
> From: Siva Durga Prasad Paladugu <siva.durga.paladugu@xilinx.com>
>
> Add basic clock driver support for zynqmp which
> sets the required clock for GEM controller
>
> Signed-off-by: Siva Durga Prasad Paladugu <sivadur@xilinx.com>
> Signed-off-by: Michal Simek <michal.simek@xilinx.com>
> ---
>
>  drivers/clk/Kconfig      |   7 ++
>  drivers/clk/Makefile     |   1 +
>  drivers/clk/clk_zynqmp.c | 241 +++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 249 insertions(+)
>  create mode 100644 drivers/clk/clk_zynqmp.c

Reviewed-by: Simon Glass <sjg@chromium.org>

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2016-12-17 22:48 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-12-16 12:31 [U-Boot] [PATCH 1/2] clk: zynqmp: Add clock driver support for zynqmp Michal Simek
2016-12-16 12:31 ` [U-Boot] [PATCH 2/2] net: zynq_gem: Use clock driver for ZynqMP Michal Simek
2016-12-17 22:48 ` [U-Boot] [PATCH 1/2] clk: zynqmp: Add clock driver support for zynqmp Simon Glass

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.