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