1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2021 Rockchip Electronics Co. Ltd.
4 * Author: Elaine Zhang <zhangqing@rock-chips.com>
5 */
6 #include <linux/clk-provider.h>
7 #include <linux/clkdev.h>
8 #include <linux/log2.h>
9
10 static int cru_debug;
11
12 #define PLL_RATE_MIN 30000000
13
14 #define cru_dbg(format, ...) do { \
15 if (cru_debug) \
16 pr_info("%s: " format, __func__, ## __VA_ARGS__); \
17 } while (0)
18
19 #define PNAME(x) static const char *const x[]
20
21 enum vop_clk_branch_type {
22 branch_mux,
23 branch_divider,
24 branch_factor,
25 branch_virtual,
26 };
27
28 #define VIR(cname) \
29 { \
30 .branch_type = branch_virtual, \
31 .name = cname, \
32 }
33
34
35 #define MUX(cname, pnames, f) \
36 { \
37 .branch_type = branch_mux, \
38 .name = cname, \
39 .parent_names = pnames, \
40 .num_parents = ARRAY_SIZE(pnames), \
41 .flags = f, \
42 }
43
44 #define FACTOR(cname, pname, f) \
45 { \
46 .branch_type = branch_factor, \
47 .name = cname, \
48 .parent_names = (const char *[]){ pname }, \
49 .num_parents = 1, \
50 .flags = f, \
51 }
52
53 #define DIV(cname, pname, f, w) \
54 { \
55 .branch_type = branch_divider, \
56 .name = cname, \
57 .parent_names = (const char *[]){ pname }, \
58 .num_parents = 1, \
59 .flags = f, \
60 .div_width = w, \
61 }
62
63 struct vop2_clk_branch {
64 enum vop_clk_branch_type branch_type;
65 const char *name;
66 const char *const *parent_names;
67 u8 num_parents;
68 unsigned long flags;
69 u8 div_shift;
70 u8 div_width;
71 u8 div_flags;
72 };
73
74 PNAME(mux_port0_dclk_src_p) = { "dclk0", "dclk1" };
75 PNAME(mux_port2_dclk_src_p) = { "dclk2", "dclk1" };
76 PNAME(mux_dp_pixclk_p) = { "dclk_out0", "dclk_out1", "dclk_out2" };
77 PNAME(mux_hdmi_edp_clk_src_p) = { "dclk0", "dclk1", "dclk2" };
78 PNAME(mux_mipi_clk_src_p) = { "dclk_out1", "dclk_out2", "dclk_out3" };
79 PNAME(mux_dsc_8k_clk_src_p) = { "dclk0", "dclk1", "dclk2", "dclk3" };
80 PNAME(mux_dsc_4k_clk_src_p) = { "dclk0", "dclk1", "dclk2", "dclk3" };
81
82 /*
83 * We only use this clk driver calculate the div
84 * of dclk_core/dclk_out/if_pixclk/if_dclk and
85 * the rate of the dclk from the soc.
86 *
87 * We don't touch the cru in the vop here, as
88 * these registers has special read andy write
89 * limits.
90 */
91 static struct vop2_clk_branch rk3588_vop_clk_branches[] = {
92 VIR("dclk0"),
93 VIR("dclk1"),
94 VIR("dclk2"),
95 VIR("dclk3"),
96
97 MUX("port0_dclk_src", mux_port0_dclk_src_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT),
98 DIV("dclk_core0", "port0_dclk_src", CLK_SET_RATE_PARENT, 2),
99 DIV("dclk_out0", "port0_dclk_src", CLK_SET_RATE_PARENT, 2),
100
101 FACTOR("port1_dclk_src", "dclk1", CLK_SET_RATE_PARENT),
102 DIV("dclk_core1", "port1_dclk_src", CLK_SET_RATE_PARENT, 2),
103 DIV("dclk_out1", "port1_dclk_src", CLK_SET_RATE_PARENT, 2),
104
105 MUX("port2_dclk_src", mux_port2_dclk_src_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT),
106 DIV("dclk_core2", "port2_dclk_src", CLK_SET_RATE_PARENT, 2),
107 DIV("dclk_out2", "port2_dclk_src", CLK_SET_RATE_PARENT, 2),
108
109 FACTOR("port3_dclk_src", "dclk3", CLK_SET_RATE_PARENT),
110 DIV("dclk_core3", "port3_dclk_src", CLK_SET_RATE_PARENT, 2),
111 DIV("dclk_out3", "port3_dclk_src", CLK_SET_RATE_PARENT, 2),
112
113 MUX("dp0_pixclk", mux_dp_pixclk_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT),
114 MUX("dp1_pixclk", mux_dp_pixclk_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT),
115
116 MUX("hdmi_edp0_clk_src", mux_hdmi_edp_clk_src_p,
117 CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT),
118 DIV("hdmi_edp0_dclk", "hdmi_edp0_clk_src", 0, 2),
119 DIV("hdmi_edp0_pixclk", "hdmi_edp0_clk_src", CLK_SET_RATE_PARENT, 1),
120
121 MUX("hdmi_edp1_clk_src", mux_hdmi_edp_clk_src_p,
122 CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT),
123 DIV("hdmi_edp1_dclk", "hdmi_edp1_clk_src", 0, 2),
124 DIV("hdmi_edp1_pixclk", "hdmi_edp1_clk_src", CLK_SET_RATE_PARENT, 1),
125
126 MUX("mipi0_clk_src", mux_mipi_clk_src_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT),
127 DIV("mipi0_pixclk", "mipi0_clk_src", CLK_SET_RATE_PARENT, 2),
128
129 MUX("mipi1_clk_src", mux_mipi_clk_src_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT),
130 DIV("mipi1_pixclk", "mipi1_clk_src", CLK_SET_RATE_PARENT, 2),
131
132 FACTOR("rgb_pixclk", "port3_dclk_src", CLK_SET_RATE_PARENT),
133
134 MUX("dsc_8k_txp_clk_src", mux_dsc_8k_clk_src_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT),
135 DIV("dsc_8k_txp_clk", "dsc_8k_txp_clk_src", 0, 2),
136 DIV("dsc_8k_pxl_clk", "dsc_8k_txp_clk_src", 0, 2),
137 DIV("dsc_8k_cds_clk", "dsc_8k_txp_clk_src", 0, 2),
138
139 MUX("dsc_4k_txp_clk_src", mux_dsc_4k_clk_src_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT),
140 DIV("dsc_4k_txp_clk", "dsc_4k_txp_clk_src", 0, 2),
141 DIV("dsc_4k_pxl_clk", "dsc_4k_txp_clk_src", 0, 2),
142 DIV("dsc_4k_cds_clk", "dsc_4k_txp_clk_src", 0, 2),
143 };
144
clk_virtual_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)145 static unsigned long clk_virtual_recalc_rate(struct clk_hw *hw,
146 unsigned long parent_rate)
147 {
148 struct vop2_clk *vop2_clk = to_vop2_clk(hw);
149
150 return (unsigned long)vop2_clk->rate;
151 }
152
clk_virtual_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * prate)153 static long clk_virtual_round_rate(struct clk_hw *hw, unsigned long rate,
154 unsigned long *prate)
155 {
156 struct vop2_clk *vop2_clk = to_vop2_clk(hw);
157
158 vop2_clk->rate = rate;
159
160 return rate;
161 }
162
clk_virtual_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)163 static int clk_virtual_set_rate(struct clk_hw *hw, unsigned long rate,
164 unsigned long parent_rate)
165 {
166 return 0;
167 }
168
169 const struct clk_ops clk_virtual_ops = {
170 .round_rate = clk_virtual_round_rate,
171 .set_rate = clk_virtual_set_rate,
172 .recalc_rate = clk_virtual_recalc_rate,
173 };
174
vop2_mux_get_parent(struct clk_hw * hw)175 static u8 vop2_mux_get_parent(struct clk_hw *hw)
176 {
177 struct vop2_clk *vop2_clk = to_vop2_clk(hw);
178
179 cru_dbg("%s index: %d\n", clk_hw_get_name(hw), vop2_clk->parent_index);
180 return vop2_clk->parent_index;
181 }
182
vop2_mux_set_parent(struct clk_hw * hw,u8 index)183 static int vop2_mux_set_parent(struct clk_hw *hw, u8 index)
184 {
185 struct vop2_clk *vop2_clk = to_vop2_clk(hw);
186
187 vop2_clk->parent_index = index;
188
189 cru_dbg("%s index: %d\n", clk_hw_get_name(hw), index);
190 return 0;
191 }
192
vop2_clk_mux_determine_rate(struct clk_hw * hw,struct clk_rate_request * req)193 static int vop2_clk_mux_determine_rate(struct clk_hw *hw,
194 struct clk_rate_request *req)
195 {
196 cru_dbg("%s %ld(min: %ld max: %ld)\n",
197 clk_hw_get_name(hw), req->rate, req->min_rate, req->max_rate);
198 return __clk_mux_determine_rate(hw, req);
199 }
200
201 static const struct clk_ops vop2_mux_clk_ops = {
202 .get_parent = vop2_mux_get_parent,
203 .set_parent = vop2_mux_set_parent,
204 .determine_rate = vop2_clk_mux_determine_rate,
205 };
206
207 #define div_mask(width) ((1 << (width)) - 1)
208
vop2_div_get_val(unsigned long rate,unsigned long parent_rate)209 static int vop2_div_get_val(unsigned long rate, unsigned long parent_rate)
210 {
211 unsigned int div, value;
212
213 div = DIV_ROUND_UP_ULL((u64)parent_rate, rate);
214
215 value = ilog2(div);
216
217 return value;
218 }
219
vop2_clk_div_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)220 static unsigned long vop2_clk_div_recalc_rate(struct clk_hw *hw,
221 unsigned long parent_rate)
222 {
223 struct vop2_clk *vop2_clk = to_vop2_clk(hw);
224 unsigned long rate;
225 unsigned int div;
226
227 div = 1 << vop2_clk->div_val;
228 rate = parent_rate / div;
229
230 cru_dbg("%s rate: %ld(prate: %ld)\n", clk_hw_get_name(hw), rate, parent_rate);
231
232 return rate;
233 }
234
vop2_clk_div_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * prate)235 static long vop2_clk_div_round_rate(struct clk_hw *hw, unsigned long rate,
236 unsigned long *prate)
237 {
238 struct vop2_clk *vop2_clk = to_vop2_clk(hw);
239
240 if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
241 if (*prate < rate)
242 *prate = rate;
243 if ((*prate >> vop2_clk->div.width) > rate)
244 *prate = rate;
245
246 if ((*prate % rate))
247 *prate = rate;
248
249 /* SOC PLL can't output a too low pll freq */
250 if (*prate < PLL_RATE_MIN)
251 *prate = rate << vop2_clk->div.width;
252 }
253
254 cru_dbg("%s rate: %ld(prate: %ld)\n", clk_hw_get_name(hw), rate, *prate);
255
256 return rate;
257 }
258
vop2_clk_div_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)259 static int vop2_clk_div_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate)
260 {
261 struct vop2_clk *vop2_clk = to_vop2_clk(hw);
262 int div_val;
263
264 div_val = vop2_div_get_val(rate, parent_rate);
265 vop2_clk->div_val = div_val;
266
267 cru_dbg("%s prate: %ld rate: %ld div_val: %d\n",
268 clk_hw_get_name(hw), parent_rate, rate, div_val);
269
270 return 0;
271 }
272
273 static const struct clk_ops vop2_div_clk_ops = {
274 .recalc_rate = vop2_clk_div_recalc_rate,
275 .round_rate = vop2_clk_div_round_rate,
276 .set_rate = vop2_clk_div_set_rate,
277 };
278
vop2_clk_register(struct vop2 * vop2,struct vop2_clk_branch * branch)279 static struct clk *vop2_clk_register(struct vop2 *vop2, struct vop2_clk_branch *branch)
280 {
281 struct clk_init_data init = {};
282 struct vop2_clk *vop2_clk;
283 struct clk *clk;
284
285 vop2_clk = devm_kzalloc(vop2->dev, sizeof(*vop2_clk), GFP_KERNEL);
286 if (!vop2_clk)
287 return ERR_PTR(-ENOMEM);
288
289 vop2_clk->vop2 = vop2;
290 vop2_clk->hw.init = &init;
291 vop2_clk->div.shift = branch->div_shift;
292 vop2_clk->div.width = branch->div_width;
293
294 init.name = branch->name;
295 init.flags = branch->flags;
296 init.num_parents = branch->num_parents;
297 init.parent_names = branch->parent_names;
298 if (branch->branch_type == branch_divider) {
299 init.ops = &vop2_div_clk_ops;
300 } else if (branch->branch_type == branch_virtual) {
301 init.ops = &clk_virtual_ops;
302 init.num_parents = 0;
303 init.parent_names = NULL;
304 } else {
305 init.ops = &vop2_mux_clk_ops;
306 }
307
308 clk = devm_clk_register(vop2->dev, &vop2_clk->hw);
309 if (!IS_ERR(clk))
310 list_add_tail(&vop2_clk->list, &vop2->clk_list_head);
311 else
312 DRM_DEV_ERROR(vop2->dev, "Register %s failed\n", branch->name);
313
314 return clk;
315 }
316
vop2_clk_init(struct vop2 * vop2)317 static int vop2_clk_init(struct vop2 *vop2)
318 {
319 struct vop2_clk_branch *branch = rk3588_vop_clk_branches;
320 unsigned int nr_clk = ARRAY_SIZE(rk3588_vop_clk_branches);
321 unsigned int idx;
322 struct vop2_clk *clk, *n;
323
324 INIT_LIST_HEAD(&vop2->clk_list_head);
325
326 if (vop2->version < VOP_VERSION_RK3588)
327 return 0;
328
329 list_for_each_entry_safe(clk, n, &vop2->clk_list_head, list) {
330 list_del(&clk->list);
331 }
332
333 for (idx = 0; idx < nr_clk; idx++, branch++)
334 vop2_clk_register(vop2, branch);
335
336 return 0;
337 }
338