xref: /OK3568_Linux_fs/kernel/drivers/gpu/drm/rockchip/rockchip_vop2_clk.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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