1 // SPDX-License-Identifier: GPL-2.0
3 * Xilinx 'Clocking Wizard' driver
5 * Copyright (c) 2021 Macronix Inc.
7 * Author: Zhengxun Li <zhengxunli@mxic.com.tw>
11 #include <clk-uclass.h>
14 #include <dm/device_compat.h>
15 #include <linux/iopoll.h>
17 #include <linux/bitfield.h>
22 #define SR_LOCKED BIT(0)
24 #define CCR(x) (0x200 + ((x) * 4))
26 #define FBOUT_CFG CCR(0)
27 #define FBOUT_DIV(x) (x)
28 #define FBOUT_DIV_MASK GENMASK(7, 0)
29 #define FBOUT_GET_DIV(x) FIELD_GET(FBOUT_DIV_MASK, x)
30 #define FBOUT_MUL(x) ((x) << 8)
31 #define FBOUT_MUL_MASK GENMASK(15, 8)
32 #define FBOUT_GET_MUL(x) FIELD_GET(FBOUT_MUL_MASK, x)
33 #define FBOUT_FRAC(x) ((x) << 16)
34 #define FBOUT_FRAC_MASK GENMASK(25, 16)
35 #define FBOUT_GET_FRAC(x) FIELD_GET(FBOUT_FRAC_MASK, x)
36 #define FBOUT_FRAC_EN BIT(26)
38 #define FBOUT_PHASE CCR(1)
40 #define OUT_CFG(x) CCR(2 + ((x) * 3))
41 #define OUT_DIV(x) (x)
42 #define OUT_DIV_MASK GENMASK(7, 0)
43 #define OUT_GET_DIV(x) FIELD_GET(OUT_DIV_MASK, x)
44 #define OUT_FRAC(x) ((x) << 8)
45 #define OUT_GET_MASK GENMASK(17, 8)
46 #define OUT_GET_FRAC(x) FIELD_GET(OUT_GET_MASK, x)
47 #define OUT_FRAC_EN BIT(18)
49 #define OUT_PHASE(x) CCR(3 + ((x) * 3))
50 #define OUT_DUTY(x) CCR(4 + ((x) * 3))
53 #define CTRL_SEN BIT(2)
54 #define CTRL_SADDR BIT(1)
55 #define CTRL_LOAD BIT(0)
58 * struct clkwzrd - Clock wizard private data structure
61 * @vco_clk: voltage-controlled oscillator frequency
73 static int clk_wzrd_enable(struct clk *clk)
75 struct clkwzd *priv = dev_get_priv(clk->dev);
79 ret = readl_poll_sleep_timeout(priv->base + SR, val, val & SR_LOCKED,
82 writel(CTRL_SEN | CTRL_SADDR | CTRL_LOAD, priv->base + CTRL);
83 writel(CTRL_SADDR, priv->base + CTRL);
84 ret = readl_poll_sleep_timeout(priv->base + SR, val,
85 val & SR_LOCKED, 1, 100);
91 static unsigned long clk_wzrd_set_rate(struct clk *clk, ulong rate)
93 struct clkwzd *priv = dev_get_priv(clk->dev);
97 /* Get output clock divide value */
98 div = DIV_ROUND_DOWN_ULL(priv->vco_clk * 1000, rate);
99 if (div < 1000 || div > 255999)
102 cfg = OUT_DIV((u32)div / 1000);
104 writel(cfg, priv->base + OUT_CFG(clk->id));
109 static struct clk_ops clk_wzrd_ops = {
110 .enable = clk_wzrd_enable,
111 .set_rate = clk_wzrd_set_rate,
114 static int clk_wzrd_probe(struct udevice *dev)
116 struct clkwzd_plat *plat = dev_get_plat(dev);
117 struct clkwzd *priv = dev_get_priv(dev);
123 priv->base = (void *)plat->addr;
125 ret = clk_get_by_name(dev, "clk_in1", &clk_in1);
127 dev_err(dev, "failed to get clock\n");
131 clock = clk_get_rate(&clk_in1);
132 if (IS_ERR_VALUE(clock)) {
133 dev_err(dev, "failed to get rate\n");
137 ret = clk_enable(&clk_in1);
139 dev_err(dev, "failed to enable clock\n");
144 /* Read clock configuration registers */
145 cfg = readl(priv->base + FBOUT_CFG);
147 /* Recalculate VCO rate */
148 if (cfg & FBOUT_FRAC_EN)
149 vco_clk = DIV_ROUND_DOWN_ULL(clock *
150 ((FBOUT_GET_MUL(cfg) * 1000) +
151 FBOUT_GET_FRAC(cfg)),
154 vco_clk = clock * FBOUT_GET_MUL(cfg);
156 priv->vco_clk = DIV_ROUND_DOWN_ULL(vco_clk, FBOUT_GET_DIV(cfg));
161 static int clk_wzrd_of_to_plat(struct udevice *dev)
163 struct clkwzd_plat *plat = dev_get_plat(dev);
165 plat->addr = dev_read_addr(dev);
166 if (plat->addr == FDT_ADDR_T_NONE)
172 static const struct udevice_id clk_wzrd_ids[] = {
173 { .compatible = "xlnx,clocking-wizard" },
177 U_BOOT_DRIVER(clk_wzrd) = {
178 .name = "zynq-clk-wizard",
180 .of_match = clk_wzrd_ids,
181 .ops = &clk_wzrd_ops,
182 .probe = clk_wzrd_probe,
183 .of_to_plat = clk_wzrd_of_to_plat,
184 .priv_auto = sizeof(struct clkwzd),
185 .plat_auto = sizeof(struct clkwzd_plat),