aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini2017-01-11 08:04:26 -0500
committerTom Rini2017-01-11 08:04:26 -0500
commit5b30997fd26f0e13837e9ba3cd289a037b8353bd (patch)
treedf8233b2d73eff88fcdf5d0d5f62da02cf498fa1 /drivers
parentf401e907fcbc94adff1a8e8097c8f0a5b0aee580 (diff)
parent7364dfe7bfca8632bfe02de5c333a64472812ebe (diff)
Merge tag 'xilinx-for-v2017.03' of git://www.denx.de/git/u-boot-microblaze
Xilinx changes for v2017.03 - ATF handoff - DT syncups - gem: Use wait_for_bit(), add simple clk support - Simple clk driver for ZynqMP - Other small changes
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/Kconfig7
-rw-r--r--drivers/clk/Makefile1
-rw-r--r--drivers/clk/clk_zynqmp.c241
-rw-r--r--drivers/fpga/zynqpl.c12
-rw-r--r--drivers/i2c/i2c-cdns.c1
-rw-r--r--drivers/net/phy/xilinx_phy.c4
-rw-r--r--drivers/net/zynq_gem.c50
7 files changed, 279 insertions, 37 deletions
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index c05ce2a9efa..335ef9e1d7c 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 40a5e8cae86..f55348e8f15 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 00000000000..694274d9910
--- /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,
+};
diff --git a/drivers/fpga/zynqpl.c b/drivers/fpga/zynqpl.c
index ef889ea4e66..2ff716c2522 100644
--- a/drivers/fpga/zynqpl.c
+++ b/drivers/fpga/zynqpl.c
@@ -38,11 +38,6 @@
#define CONFIG_SYS_FPGA_PROG_TIME (CONFIG_SYS_HZ * 4) /* 4 s */
#endif
-static int zynq_info(xilinx_desc *desc)
-{
- return FPGA_SUCCESS;
-}
-
#define DUMMY_WORD 0xffffffff
/* Xilinx binary format header */
@@ -481,16 +476,9 @@ static int zynq_loadfs(xilinx_desc *desc, const void *buf, size_t bsize,
}
#endif
-static int zynq_dump(xilinx_desc *desc, const void *buf, size_t bsize)
-{
- return FPGA_FAIL;
-}
-
struct xilinx_fpga_op zynq_op = {
.load = zynq_load,
#if defined(CONFIG_CMD_FPGA_LOADFS)
.loadfs = zynq_loadfs,
#endif
- .dump = zynq_dump,
- .info = zynq_info,
};
diff --git a/drivers/i2c/i2c-cdns.c b/drivers/i2c/i2c-cdns.c
index f49f60bb373..ef85a70ed38 100644
--- a/drivers/i2c/i2c-cdns.c
+++ b/drivers/i2c/i2c-cdns.c
@@ -366,6 +366,7 @@ static const struct dm_i2c_ops cdns_i2c_ops = {
static const struct udevice_id cdns_i2c_of_match[] = {
{ .compatible = "cdns,i2c-r1p10" },
+ { .compatible = "cdns,i2c-r1p14" },
{ /* end of table */ }
};
diff --git a/drivers/net/phy/xilinx_phy.c b/drivers/net/phy/xilinx_phy.c
index f3eaf2e97ce..920bfcb380b 100644
--- a/drivers/net/phy/xilinx_phy.c
+++ b/drivers/net/phy/xilinx_phy.c
@@ -101,11 +101,11 @@ static int xilinxphy_startup(struct phy_device *phydev)
static int xilinxphy_of_init(struct phy_device *phydev)
{
- struct udevice *dev = (struct udevice *)&phydev->dev;
u32 phytype;
debug("%s\n", __func__);
- phytype = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "phy-type", -1);
+ phytype = fdtdec_get_int(gd->fdt_blob, phydev->dev->of_offset,
+ "phy-type", -1);
if (phytype == XAE_PHY_TYPE_1000BASE_X)
phydev->flags |= XAE_PHY_TYPE_1000BASE_X;
diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c
index d2e5e7c7cd1..6dd87cf28f9 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,35 +182,22 @@ 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 inline int mdio_wait(struct zynq_gem_regs *regs)
-{
- u32 timeout = 20000;
-
- /* Wait till MDIO interface is ready to accept a new transaction. */
- while (--timeout) {
- if (readl(&regs->nwsr) & ZYNQ_GEM_NWSR_MDIOIDLE_MASK)
- break;
- WATCHDOG_RESET();
- }
-
- if (!timeout) {
- printf("%s: Timeout\n", __func__);
- return 1;
- }
-
- return 0;
-}
-
static u32 phy_setup_op(struct zynq_gem_priv *priv, u32 phy_addr, u32 regnum,
u32 op, u16 *data)
{
u32 mgtcr;
struct zynq_gem_regs *regs = priv->iobase;
+ int err;
- if (mdio_wait(regs))
- return 1;
+ err = wait_for_bit(__func__, &regs->nwsr, ZYNQ_GEM_NWSR_MDIOIDLE_MASK,
+ true, 20000, true);
+ if (err)
+ return err;
/* Construct mgtcr mask for the operation */
mgtcr = ZYNQ_GEM_PHYMNTNC_OP_MASK | op |
@@ -219,8 +207,10 @@ static u32 phy_setup_op(struct zynq_gem_priv *priv, u32 phy_addr, u32 regnum,
/* Write mgtcr and wait for completion */
writel(mgtcr, &regs->phymntnc);
- if (mdio_wait(regs))
- return 1;
+ err = wait_for_bit(__func__, &regs->nwsr, ZYNQ_GEM_NWSR_MDIOIDLE_MASK,
+ true, 20000, true);
+ if (err)
+ return err;
if (op == ZYNQ_GEM_PHYMNTNC_OP_R_MASK)
*data = readl(&regs->phymntnc);
@@ -469,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);
@@ -643,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;