• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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