dt-bindings: clock: sifive: sync FU740 PRCI clock binding header
[platform/kernel/u-boot.git] / drivers / clk / clk-xlnx-clock-wizard.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Xilinx 'Clocking Wizard' driver
4  *
5  * Copyright (c) 2021 Macronix Inc.
6  *
7  * Author: Zhengxun Li <zhengxunli@mxic.com.tw>
8  */
9
10 #include <common.h>
11 #include <clk-uclass.h>
12 #include <dm.h>
13 #include <div64.h>
14 #include <dm/device_compat.h>
15 #include <linux/iopoll.h>
16
17 #include <linux/bitfield.h>
18
19 #define SRR                     0x0
20
21 #define SR                      0x4
22 #define SR_LOCKED               BIT(0)
23
24 #define CCR(x)                  (0x200 + ((x) * 4))
25
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)
37
38 #define FBOUT_PHASE             CCR(1)
39
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)
48
49 #define OUT_PHASE(x)            CCR(3 + ((x) * 3))
50 #define OUT_DUTY(x)             CCR(4 + ((x) * 3))
51
52 #define CTRL                    CCR(23)
53 #define CTRL_SEN                BIT(2)
54 #define CTRL_SADDR              BIT(1)
55 #define CTRL_LOAD               BIT(0)
56
57 /**
58  * struct clkwzrd - Clock wizard private data structure
59  *
60  * @base:               memory base
61  * @vco_clk:            voltage-controlled oscillator frequency
62  *
63  */
64 struct clkwzd {
65         void *base;
66         u64 vco_clk;
67 };
68
69 struct clkwzd_plat {
70         fdt_addr_t addr;
71 };
72
73 static int clk_wzrd_enable(struct clk *clk)
74 {
75         struct clkwzd *priv = dev_get_priv(clk->dev);
76         int ret;
77         u32 val;
78
79         ret = readl_poll_sleep_timeout(priv->base + SR, val, val & SR_LOCKED,
80                                        1, 100);
81         if (!ret) {
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);
86         }
87
88         return ret;
89 }
90
91 static unsigned long clk_wzrd_set_rate(struct clk *clk, ulong rate)
92 {
93         struct clkwzd *priv = dev_get_priv(clk->dev);
94         u64 div;
95         u32 cfg;
96
97         /* Get output clock divide value */
98         div = DIV_ROUND_DOWN_ULL(priv->vco_clk * 1000, rate);
99         if (div < 1000 || div > 255999)
100                 return -EINVAL;
101
102         cfg = OUT_DIV((u32)div / 1000);
103
104         writel(cfg, priv->base + OUT_CFG(clk->id));
105
106         return 0;
107 }
108
109 static struct clk_ops clk_wzrd_ops = {
110         .enable = clk_wzrd_enable,
111         .set_rate = clk_wzrd_set_rate,
112 };
113
114 static int clk_wzrd_probe(struct udevice *dev)
115 {
116         struct clkwzd_plat *plat = dev_get_plat(dev);
117         struct clkwzd *priv = dev_get_priv(dev);
118         struct clk clk_in1;
119         u64 clock, vco_clk;
120         u32 cfg;
121         int ret;
122
123         priv->base = (void *)plat->addr;
124
125         ret = clk_get_by_name(dev, "clk_in1", &clk_in1);
126         if (ret < 0) {
127                 dev_err(dev, "failed to get clock\n");
128                 return ret;
129         }
130
131         clock = clk_get_rate(&clk_in1);
132         if (IS_ERR_VALUE(clock)) {
133                 dev_err(dev, "failed to get rate\n");
134                 return clock;
135         }
136
137         ret = clk_enable(&clk_in1);
138         if (ret) {
139                 dev_err(dev, "failed to enable clock\n");
140                 clk_free(&clk_in1);
141                 return ret;
142         }
143
144         /* Read clock configuration registers */
145         cfg = readl(priv->base + FBOUT_CFG);
146
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)),
152                                              1000);
153         else
154                 vco_clk = clock * FBOUT_GET_MUL(cfg);
155
156         priv->vco_clk = DIV_ROUND_DOWN_ULL(vco_clk, FBOUT_GET_DIV(cfg));
157
158         return 0;
159 }
160
161 static int clk_wzrd_of_to_plat(struct udevice *dev)
162 {
163         struct clkwzd_plat *plat = dev_get_plat(dev);
164
165         plat->addr = dev_read_addr(dev);
166         if (plat->addr == FDT_ADDR_T_NONE)
167                 return -EINVAL;
168
169         return 0;
170 }
171
172 static const struct udevice_id clk_wzrd_ids[] = {
173         { .compatible = "xlnx,clocking-wizard" },
174         { /* sentinel */ }
175 };
176
177 U_BOOT_DRIVER(clk_wzrd) = {
178         .name = "zynq-clk-wizard",
179         .id = UCLASS_CLK,
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),
186 };