1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (c) 2020, The Linux Foundation. All rights reserved.
4 * Copyright (c) 2021, Linaro Ltd.
5 */
6
7 #include <linux/err.h>
8 #include <linux/kernel.h>
9 #include <linux/module.h>
10 #include <linux/of_device.h>
11 #include <linux/of.h>
12 #include <linux/regmap.h>
13
14 #include <dt-bindings/clock/qcom,dispcc-qcm2290.h>
15
16 #include "clk-alpha-pll.h"
17 #include "clk-branch.h"
18 #include "clk-rcg.h"
19 #include "clk-regmap.h"
20 #include "clk-regmap-divider.h"
21 #include "common.h"
22 #include "gdsc.h"
23
24 enum {
25 P_BI_TCXO,
26 P_BI_TCXO_AO,
27 P_DISP_CC_PLL0_OUT_MAIN,
28 P_DSI0_PHY_PLL_OUT_BYTECLK,
29 P_DSI0_PHY_PLL_OUT_DSICLK,
30 P_GPLL0_OUT_DIV,
31 P_GPLL0_OUT_MAIN,
32 P_SLEEP_CLK,
33 };
34
35 static const struct pll_vco spark_vco[] = {
36 { 500000000, 1000000000, 2 },
37 };
38
39 /* 768MHz configuration */
40 static const struct alpha_pll_config disp_cc_pll0_config = {
41 .l = 0x28,
42 .alpha = 0x0,
43 .alpha_en_mask = BIT(24),
44 .vco_val = 0x2 << 20,
45 .vco_mask = GENMASK(21, 20),
46 .main_output_mask = BIT(0),
47 .config_ctl_val = 0x4001055B,
48 };
49
50 static struct clk_alpha_pll disp_cc_pll0 = {
51 .offset = 0x0,
52 .vco_table = spark_vco,
53 .num_vco = ARRAY_SIZE(spark_vco),
54 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
55 .clkr = {
56 .hw.init = &(struct clk_init_data){
57 .name = "disp_cc_pll0",
58 .parent_data = &(const struct clk_parent_data){
59 .fw_name = "bi_tcxo",
60 },
61 .num_parents = 1,
62 .ops = &clk_alpha_pll_ops,
63 },
64 },
65 };
66
67 static const struct parent_map disp_cc_parent_map_0[] = {
68 { P_BI_TCXO, 0 },
69 { P_DSI0_PHY_PLL_OUT_BYTECLK, 1 },
70 };
71
72 static const struct clk_parent_data disp_cc_parent_data_0[] = {
73 { .fw_name = "bi_tcxo" },
74 { .fw_name = "dsi0_phy_pll_out_byteclk" },
75 };
76
77 static const struct parent_map disp_cc_parent_map_1[] = {
78 { P_BI_TCXO, 0 },
79 };
80
81 static const struct clk_parent_data disp_cc_parent_data_1[] = {
82 { .fw_name = "bi_tcxo" },
83 };
84
85 static const struct parent_map disp_cc_parent_map_2[] = {
86 { P_BI_TCXO_AO, 0 },
87 { P_GPLL0_OUT_DIV, 4 },
88 };
89
90 static const struct clk_parent_data disp_cc_parent_data_2[] = {
91 { .fw_name = "bi_tcxo_ao" },
92 { .fw_name = "gcc_disp_gpll0_div_clk_src" },
93 };
94
95 static const struct parent_map disp_cc_parent_map_3[] = {
96 { P_BI_TCXO, 0 },
97 { P_DISP_CC_PLL0_OUT_MAIN, 1 },
98 { P_GPLL0_OUT_MAIN, 4 },
99 };
100
101 static const struct clk_parent_data disp_cc_parent_data_3[] = {
102 { .fw_name = "bi_tcxo" },
103 { .hw = &disp_cc_pll0.clkr.hw },
104 { .fw_name = "gcc_disp_gpll0_clk_src" },
105 };
106
107 static const struct parent_map disp_cc_parent_map_4[] = {
108 { P_BI_TCXO, 0 },
109 { P_DSI0_PHY_PLL_OUT_DSICLK, 1 },
110 };
111
112 static const struct clk_parent_data disp_cc_parent_data_4[] = {
113 { .fw_name = "bi_tcxo" },
114 { .fw_name = "dsi0_phy_pll_out_dsiclk" },
115 };
116
117 static const struct parent_map disp_cc_parent_map_5[] = {
118 { P_SLEEP_CLK, 0 },
119 };
120
121 static const struct clk_parent_data disp_cc_parent_data_5[] = {
122 { .fw_name = "sleep_clk" },
123 };
124
125 static struct clk_rcg2 disp_cc_mdss_byte0_clk_src = {
126 .cmd_rcgr = 0x20a4,
127 .mnd_width = 0,
128 .hid_width = 5,
129 .parent_map = disp_cc_parent_map_0,
130 .clkr.hw.init = &(struct clk_init_data){
131 .name = "disp_cc_mdss_byte0_clk_src",
132 .parent_data = disp_cc_parent_data_0,
133 .num_parents = ARRAY_SIZE(disp_cc_parent_data_0),
134 /* For set_rate and set_parent to succeed, parent(s) must be enabled */
135 .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
136 .ops = &clk_byte2_ops,
137 },
138 };
139
140 static struct clk_regmap_div disp_cc_mdss_byte0_div_clk_src = {
141 .reg = 0x20bc,
142 .shift = 0,
143 .width = 2,
144 .clkr.hw.init = &(struct clk_init_data) {
145 .name = "disp_cc_mdss_byte0_div_clk_src",
146 .parent_hws = (const struct clk_hw*[]){
147 &disp_cc_mdss_byte0_clk_src.clkr.hw,
148 },
149 .num_parents = 1,
150 .ops = &clk_regmap_div_ops,
151 },
152 };
153
154 static const struct freq_tbl ftbl_disp_cc_mdss_ahb_clk_src[] = {
155 F(19200000, P_BI_TCXO_AO, 1, 0, 0),
156 F(37500000, P_GPLL0_OUT_DIV, 8, 0, 0),
157 F(75000000, P_GPLL0_OUT_DIV, 4, 0, 0),
158 { }
159 };
160
161 static struct clk_rcg2 disp_cc_mdss_ahb_clk_src = {
162 .cmd_rcgr = 0x2154,
163 .mnd_width = 0,
164 .hid_width = 5,
165 .parent_map = disp_cc_parent_map_2,
166 .freq_tbl = ftbl_disp_cc_mdss_ahb_clk_src,
167 .clkr.hw.init = &(struct clk_init_data){
168 .name = "disp_cc_mdss_ahb_clk_src",
169 .parent_data = disp_cc_parent_data_2,
170 .num_parents = ARRAY_SIZE(disp_cc_parent_data_2),
171 .ops = &clk_rcg2_shared_ops,
172 },
173 };
174
175 static const struct freq_tbl ftbl_disp_cc_mdss_esc0_clk_src[] = {
176 F(19200000, P_BI_TCXO, 1, 0, 0),
177 { }
178 };
179
180 static struct clk_rcg2 disp_cc_mdss_esc0_clk_src = {
181 .cmd_rcgr = 0x20c0,
182 .mnd_width = 0,
183 .hid_width = 5,
184 .parent_map = disp_cc_parent_map_0,
185 .freq_tbl = ftbl_disp_cc_mdss_esc0_clk_src,
186 .clkr.hw.init = &(struct clk_init_data){
187 .name = "disp_cc_mdss_esc0_clk_src",
188 .parent_data = disp_cc_parent_data_0,
189 .num_parents = ARRAY_SIZE(disp_cc_parent_data_0),
190 .ops = &clk_rcg2_ops,
191 },
192 };
193
194 static const struct freq_tbl ftbl_disp_cc_mdss_mdp_clk_src[] = {
195 F(19200000, P_BI_TCXO, 1, 0, 0),
196 F(192000000, P_DISP_CC_PLL0_OUT_MAIN, 4, 0, 0),
197 F(256000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0),
198 F(307200000, P_DISP_CC_PLL0_OUT_MAIN, 2.5, 0, 0),
199 F(384000000, P_DISP_CC_PLL0_OUT_MAIN, 2, 0, 0),
200 { }
201 };
202
203 static struct clk_rcg2 disp_cc_mdss_mdp_clk_src = {
204 .cmd_rcgr = 0x2074,
205 .mnd_width = 0,
206 .hid_width = 5,
207 .parent_map = disp_cc_parent_map_3,
208 .freq_tbl = ftbl_disp_cc_mdss_mdp_clk_src,
209 .clkr.hw.init = &(struct clk_init_data){
210 .name = "disp_cc_mdss_mdp_clk_src",
211 .parent_data = disp_cc_parent_data_3,
212 .num_parents = ARRAY_SIZE(disp_cc_parent_data_3),
213 .flags = CLK_SET_RATE_PARENT,
214 .ops = &clk_rcg2_shared_ops,
215 },
216 };
217
218 static struct clk_rcg2 disp_cc_mdss_pclk0_clk_src = {
219 .cmd_rcgr = 0x205c,
220 .mnd_width = 8,
221 .hid_width = 5,
222 .parent_map = disp_cc_parent_map_4,
223 .clkr.hw.init = &(struct clk_init_data){
224 .name = "disp_cc_mdss_pclk0_clk_src",
225 .parent_data = disp_cc_parent_data_4,
226 .num_parents = ARRAY_SIZE(disp_cc_parent_data_4),
227 /* For set_rate and set_parent to succeed, parent(s) must be enabled */
228 .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
229 .ops = &clk_pixel_ops,
230 },
231 };
232
233 static struct clk_rcg2 disp_cc_mdss_vsync_clk_src = {
234 .cmd_rcgr = 0x208c,
235 .mnd_width = 0,
236 .hid_width = 5,
237 .parent_map = disp_cc_parent_map_1,
238 .freq_tbl = ftbl_disp_cc_mdss_esc0_clk_src,
239 .clkr.hw.init = &(struct clk_init_data){
240 .name = "disp_cc_mdss_vsync_clk_src",
241 .parent_data = disp_cc_parent_data_1,
242 .num_parents = ARRAY_SIZE(disp_cc_parent_data_1),
243 .flags = CLK_SET_RATE_PARENT,
244 .ops = &clk_rcg2_shared_ops,
245 },
246 };
247
248 static const struct freq_tbl ftbl_disp_cc_sleep_clk_src[] = {
249 F(32764, P_SLEEP_CLK, 1, 0, 0),
250 { }
251 };
252
253 static struct clk_rcg2 disp_cc_sleep_clk_src = {
254 .cmd_rcgr = 0x6050,
255 .mnd_width = 0,
256 .hid_width = 5,
257 .parent_map = disp_cc_parent_map_5,
258 .freq_tbl = ftbl_disp_cc_sleep_clk_src,
259 .clkr.hw.init = &(struct clk_init_data){
260 .name = "disp_cc_sleep_clk_src",
261 .parent_data = disp_cc_parent_data_5,
262 .num_parents = ARRAY_SIZE(disp_cc_parent_data_5),
263 .ops = &clk_rcg2_ops,
264 },
265 };
266
267 static struct clk_branch disp_cc_mdss_ahb_clk = {
268 .halt_reg = 0x2044,
269 .halt_check = BRANCH_HALT,
270 .clkr = {
271 .enable_reg = 0x2044,
272 .enable_mask = BIT(0),
273 .hw.init = &(struct clk_init_data){
274 .name = "disp_cc_mdss_ahb_clk",
275 .parent_hws = (const struct clk_hw*[]){
276 &disp_cc_mdss_ahb_clk_src.clkr.hw,
277 },
278 .num_parents = 1,
279 .flags = CLK_SET_RATE_PARENT,
280 .ops = &clk_branch2_ops,
281 },
282 },
283 };
284
285 static struct clk_branch disp_cc_mdss_byte0_clk = {
286 .halt_reg = 0x201c,
287 .halt_check = BRANCH_HALT,
288 .clkr = {
289 .enable_reg = 0x201c,
290 .enable_mask = BIT(0),
291 .hw.init = &(struct clk_init_data){
292 .name = "disp_cc_mdss_byte0_clk",
293 .parent_hws = (const struct clk_hw*[]){
294 &disp_cc_mdss_byte0_clk_src.clkr.hw,
295 },
296 .num_parents = 1,
297 .flags = CLK_SET_RATE_PARENT,
298 .ops = &clk_branch2_ops,
299 },
300 },
301 };
302
303 static struct clk_branch disp_cc_mdss_byte0_intf_clk = {
304 .halt_reg = 0x2020,
305 .halt_check = BRANCH_HALT,
306 .clkr = {
307 .enable_reg = 0x2020,
308 .enable_mask = BIT(0),
309 .hw.init = &(struct clk_init_data){
310 .name = "disp_cc_mdss_byte0_intf_clk",
311 .parent_hws = (const struct clk_hw*[]){
312 &disp_cc_mdss_byte0_div_clk_src.clkr.hw,
313 },
314 .num_parents = 1,
315 .flags = CLK_SET_RATE_PARENT,
316 .ops = &clk_branch2_ops,
317 },
318 },
319 };
320
321 static struct clk_branch disp_cc_mdss_esc0_clk = {
322 .halt_reg = 0x2024,
323 .halt_check = BRANCH_HALT,
324 .clkr = {
325 .enable_reg = 0x2024,
326 .enable_mask = BIT(0),
327 .hw.init = &(struct clk_init_data){
328 .name = "disp_cc_mdss_esc0_clk",
329 .parent_hws = (const struct clk_hw*[]){
330 &disp_cc_mdss_esc0_clk_src.clkr.hw,
331 },
332 .num_parents = 1,
333 .flags = CLK_SET_RATE_PARENT,
334 .ops = &clk_branch2_ops,
335 },
336 },
337 };
338
339 static struct clk_branch disp_cc_mdss_mdp_clk = {
340 .halt_reg = 0x2008,
341 .halt_check = BRANCH_HALT,
342 .clkr = {
343 .enable_reg = 0x2008,
344 .enable_mask = BIT(0),
345 .hw.init = &(struct clk_init_data){
346 .name = "disp_cc_mdss_mdp_clk",
347 .parent_hws = (const struct clk_hw*[]){
348 &disp_cc_mdss_mdp_clk_src.clkr.hw,
349 },
350 .num_parents = 1,
351 .flags = CLK_SET_RATE_PARENT,
352 .ops = &clk_branch2_ops,
353 },
354 },
355 };
356
357 static struct clk_branch disp_cc_mdss_mdp_lut_clk = {
358 .halt_reg = 0x2010,
359 .halt_check = BRANCH_HALT_VOTED,
360 .clkr = {
361 .enable_reg = 0x2010,
362 .enable_mask = BIT(0),
363 .hw.init = &(struct clk_init_data){
364 .name = "disp_cc_mdss_mdp_lut_clk",
365 .parent_hws = (const struct clk_hw*[]){
366 &disp_cc_mdss_mdp_clk_src.clkr.hw,
367 },
368 .num_parents = 1,
369 .flags = CLK_SET_RATE_PARENT,
370 .ops = &clk_branch2_ops,
371 },
372 },
373 };
374
375 static struct clk_branch disp_cc_mdss_non_gdsc_ahb_clk = {
376 .halt_reg = 0x4004,
377 .halt_check = BRANCH_HALT_VOTED,
378 .clkr = {
379 .enable_reg = 0x4004,
380 .enable_mask = BIT(0),
381 .hw.init = &(struct clk_init_data){
382 .name = "disp_cc_mdss_non_gdsc_ahb_clk",
383 .parent_hws = (const struct clk_hw*[]){
384 &disp_cc_mdss_ahb_clk_src.clkr.hw,
385 },
386 .num_parents = 1,
387 .flags = CLK_SET_RATE_PARENT,
388 .ops = &clk_branch2_ops,
389 },
390 },
391 };
392
393 static struct clk_branch disp_cc_mdss_pclk0_clk = {
394 .halt_reg = 0x2004,
395 .halt_check = BRANCH_HALT,
396 .clkr = {
397 .enable_reg = 0x2004,
398 .enable_mask = BIT(0),
399 .hw.init = &(struct clk_init_data){
400 .name = "disp_cc_mdss_pclk0_clk",
401 .parent_hws = (const struct clk_hw*[]){
402 &disp_cc_mdss_pclk0_clk_src.clkr.hw,
403 },
404 .num_parents = 1,
405 .flags = CLK_SET_RATE_PARENT,
406 .ops = &clk_branch2_ops,
407 },
408 },
409 };
410
411 static struct clk_branch disp_cc_mdss_vsync_clk = {
412 .halt_reg = 0x2018,
413 .halt_check = BRANCH_HALT,
414 .clkr = {
415 .enable_reg = 0x2018,
416 .enable_mask = BIT(0),
417 .hw.init = &(struct clk_init_data){
418 .name = "disp_cc_mdss_vsync_clk",
419 .parent_hws = (const struct clk_hw*[]){
420 &disp_cc_mdss_vsync_clk_src.clkr.hw,
421 },
422 .num_parents = 1,
423 .flags = CLK_SET_RATE_PARENT,
424 .ops = &clk_branch2_ops,
425 },
426 },
427 };
428
429 static struct clk_branch disp_cc_sleep_clk = {
430 .halt_reg = 0x6068,
431 .halt_check = BRANCH_HALT,
432 .clkr = {
433 .enable_reg = 0x6068,
434 .enable_mask = BIT(0),
435 .hw.init = &(struct clk_init_data){
436 .name = "disp_cc_sleep_clk",
437 .parent_hws = (const struct clk_hw*[]){
438 &disp_cc_sleep_clk_src.clkr.hw,
439 },
440 .num_parents = 1,
441 .flags = CLK_SET_RATE_PARENT,
442 .ops = &clk_branch2_ops,
443 },
444 },
445 };
446
447 static struct gdsc mdss_gdsc = {
448 .gdscr = 0x3000,
449 .pd = {
450 .name = "mdss_gdsc",
451 },
452 .pwrsts = PWRSTS_OFF_ON,
453 .flags = HW_CTRL,
454 };
455
456 static struct gdsc *disp_cc_qcm2290_gdscs[] = {
457 [MDSS_GDSC] = &mdss_gdsc,
458 };
459
460 static struct clk_regmap *disp_cc_qcm2290_clocks[] = {
461 [DISP_CC_MDSS_AHB_CLK] = &disp_cc_mdss_ahb_clk.clkr,
462 [DISP_CC_MDSS_AHB_CLK_SRC] = &disp_cc_mdss_ahb_clk_src.clkr,
463 [DISP_CC_MDSS_BYTE0_CLK] = &disp_cc_mdss_byte0_clk.clkr,
464 [DISP_CC_MDSS_BYTE0_CLK_SRC] = &disp_cc_mdss_byte0_clk_src.clkr,
465 [DISP_CC_MDSS_BYTE0_DIV_CLK_SRC] = &disp_cc_mdss_byte0_div_clk_src.clkr,
466 [DISP_CC_MDSS_BYTE0_INTF_CLK] = &disp_cc_mdss_byte0_intf_clk.clkr,
467 [DISP_CC_MDSS_ESC0_CLK] = &disp_cc_mdss_esc0_clk.clkr,
468 [DISP_CC_MDSS_ESC0_CLK_SRC] = &disp_cc_mdss_esc0_clk_src.clkr,
469 [DISP_CC_MDSS_MDP_CLK] = &disp_cc_mdss_mdp_clk.clkr,
470 [DISP_CC_MDSS_MDP_CLK_SRC] = &disp_cc_mdss_mdp_clk_src.clkr,
471 [DISP_CC_MDSS_MDP_LUT_CLK] = &disp_cc_mdss_mdp_lut_clk.clkr,
472 [DISP_CC_MDSS_NON_GDSC_AHB_CLK] = &disp_cc_mdss_non_gdsc_ahb_clk.clkr,
473 [DISP_CC_MDSS_PCLK0_CLK] = &disp_cc_mdss_pclk0_clk.clkr,
474 [DISP_CC_MDSS_PCLK0_CLK_SRC] = &disp_cc_mdss_pclk0_clk_src.clkr,
475 [DISP_CC_MDSS_VSYNC_CLK] = &disp_cc_mdss_vsync_clk.clkr,
476 [DISP_CC_MDSS_VSYNC_CLK_SRC] = &disp_cc_mdss_vsync_clk_src.clkr,
477 [DISP_CC_PLL0] = &disp_cc_pll0.clkr,
478 [DISP_CC_SLEEP_CLK] = &disp_cc_sleep_clk.clkr,
479 [DISP_CC_SLEEP_CLK_SRC] = &disp_cc_sleep_clk_src.clkr,
480 };
481
482 static const struct regmap_config disp_cc_qcm2290_regmap_config = {
483 .reg_bits = 32,
484 .reg_stride = 4,
485 .val_bits = 32,
486 .max_register = 0x10000,
487 .fast_io = true,
488 };
489
490 static const struct qcom_cc_desc disp_cc_qcm2290_desc = {
491 .config = &disp_cc_qcm2290_regmap_config,
492 .clks = disp_cc_qcm2290_clocks,
493 .num_clks = ARRAY_SIZE(disp_cc_qcm2290_clocks),
494 .gdscs = disp_cc_qcm2290_gdscs,
495 .num_gdscs = ARRAY_SIZE(disp_cc_qcm2290_gdscs),
496 };
497
498 static const struct of_device_id disp_cc_qcm2290_match_table[] = {
499 { .compatible = "qcom,qcm2290-dispcc" },
500 { }
501 };
502 MODULE_DEVICE_TABLE(of, disp_cc_qcm2290_match_table);
503
disp_cc_qcm2290_probe(struct platform_device * pdev)504 static int disp_cc_qcm2290_probe(struct platform_device *pdev)
505 {
506 struct regmap *regmap;
507 int ret;
508
509 regmap = qcom_cc_map(pdev, &disp_cc_qcm2290_desc);
510 if (IS_ERR(regmap))
511 return PTR_ERR(regmap);
512
513 clk_alpha_pll_configure(&disp_cc_pll0, regmap, &disp_cc_pll0_config);
514
515 /* Keep DISP_CC_XO_CLK always-ON */
516 regmap_update_bits(regmap, 0x604c, BIT(0), BIT(0));
517
518 ret = qcom_cc_really_probe(pdev, &disp_cc_qcm2290_desc, regmap);
519 if (ret) {
520 dev_err(&pdev->dev, "Failed to register DISP CC clocks\n");
521 return ret;
522 }
523
524 return ret;
525 }
526
527 static struct platform_driver disp_cc_qcm2290_driver = {
528 .probe = disp_cc_qcm2290_probe,
529 .driver = {
530 .name = "dispcc-qcm2290",
531 .of_match_table = disp_cc_qcm2290_match_table,
532 },
533 };
534
disp_cc_qcm2290_init(void)535 static int __init disp_cc_qcm2290_init(void)
536 {
537 return platform_driver_register(&disp_cc_qcm2290_driver);
538 }
539 subsys_initcall(disp_cc_qcm2290_init);
540
disp_cc_qcm2290_exit(void)541 static void __exit disp_cc_qcm2290_exit(void)
542 {
543 platform_driver_unregister(&disp_cc_qcm2290_driver);
544 }
545 module_exit(disp_cc_qcm2290_exit);
546
547 MODULE_DESCRIPTION("QTI DISP_CC qcm2290 Driver");
548 MODULE_LICENSE("GPL v2");
549