1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2021, The Linux Foundation. All rights reserved.
4 * Copyright (c) 2022, Linaro Limited
7 #include <linux/clk-provider.h>
8 #include <linux/module.h>
9 #include <linux/platform_device.h>
10 #include <linux/regmap.h>
12 #include <dt-bindings/clock/qcom,sm6375-dispcc.h>
14 #include "clk-alpha-pll.h"
15 #include "clk-branch.h"
17 #include "clk-regmap-divider.h"
24 DT_GCC_DISP_GPLL0_CLK
,
25 DT_DSI0_PHY_PLL_OUT_BYTECLK
,
26 DT_DSI0_PHY_PLL_OUT_DSICLK
,
31 P_DISP_CC_PLL0_OUT_EVEN
,
32 P_DISP_CC_PLL0_OUT_MAIN
,
33 P_DSI0_PHY_PLL_OUT_BYTECLK
,
34 P_DSI0_PHY_PLL_OUT_DSICLK
,
38 static const struct pll_vco lucid_vco
[] = {
39 { 249600000, 2000000000, 0 },
43 static const struct alpha_pll_config disp_cc_pll0_config
= {
46 .config_ctl_val
= 0x20485699,
47 .config_ctl_hi_val
= 0x00002261,
48 .config_ctl_hi1_val
= 0x329a299c,
49 .user_ctl_val
= 0x00000001,
50 .user_ctl_hi_val
= 0x00000805,
51 .user_ctl_hi1_val
= 0x00000000,
54 static struct clk_alpha_pll disp_cc_pll0
= {
56 .vco_table
= lucid_vco
,
57 .num_vco
= ARRAY_SIZE(lucid_vco
),
58 .regs
= clk_alpha_pll_regs
[CLK_ALPHA_PLL_TYPE_LUCID
],
60 .hw
.init
= &(struct clk_init_data
){
61 .name
= "disp_cc_pll0",
62 .parent_data
= &(const struct clk_parent_data
){
66 .ops
= &clk_alpha_pll_lucid_ops
,
71 static const struct parent_map disp_cc_parent_map_0
[] = {
73 { P_DSI0_PHY_PLL_OUT_BYTECLK
, 1 },
76 static const struct clk_parent_data disp_cc_parent_data_0
[] = {
77 { .index
= DT_BI_TCXO
},
78 { .index
= DT_DSI0_PHY_PLL_OUT_BYTECLK
},
81 static const struct parent_map disp_cc_parent_map_1
[] = {
83 { P_DISP_CC_PLL0_OUT_MAIN
, 1 },
84 { P_GCC_DISP_GPLL0_CLK
, 4 },
85 { P_DISP_CC_PLL0_OUT_EVEN
, 5 },
88 static const struct clk_parent_data disp_cc_parent_data_1
[] = {
89 { .index
= DT_BI_TCXO
},
90 { .hw
= &disp_cc_pll0
.clkr
.hw
},
91 { .index
= DT_GCC_DISP_GPLL0_CLK
},
92 { .hw
= &disp_cc_pll0
.clkr
.hw
},
95 static const struct parent_map disp_cc_parent_map_2
[] = {
97 { P_GCC_DISP_GPLL0_CLK
, 4 },
100 static const struct clk_parent_data disp_cc_parent_data_2
[] = {
101 { .index
= DT_BI_TCXO
},
102 { .index
= DT_GCC_DISP_GPLL0_CLK
},
105 static const struct parent_map disp_cc_parent_map_3
[] = {
107 { P_DSI0_PHY_PLL_OUT_DSICLK
, 1 },
110 static const struct clk_parent_data disp_cc_parent_data_3
[] = {
111 { .index
= DT_BI_TCXO
},
112 { .index
= DT_DSI0_PHY_PLL_OUT_DSICLK
},
115 static const struct parent_map disp_cc_parent_map_4
[] = {
119 static const struct clk_parent_data disp_cc_parent_data_4
[] = {
120 { .index
= DT_BI_TCXO
},
123 static const struct freq_tbl ftbl_disp_cc_mdss_ahb_clk_src
[] = {
124 F(19200000, P_BI_TCXO
, 1, 0, 0),
125 F(37500000, P_GCC_DISP_GPLL0_CLK
, 8, 0, 0),
126 F(75000000, P_GCC_DISP_GPLL0_CLK
, 4, 0, 0),
130 static struct clk_rcg2 disp_cc_mdss_ahb_clk_src
= {
134 .parent_map
= disp_cc_parent_map_2
,
135 .freq_tbl
= ftbl_disp_cc_mdss_ahb_clk_src
,
136 .clkr
.hw
.init
= &(struct clk_init_data
){
137 .name
= "disp_cc_mdss_ahb_clk_src",
138 .parent_data
= disp_cc_parent_data_2
,
139 .num_parents
= ARRAY_SIZE(disp_cc_parent_data_2
),
140 .ops
= &clk_rcg2_shared_ops
,
144 static struct clk_rcg2 disp_cc_mdss_byte0_clk_src
= {
148 .parent_map
= disp_cc_parent_map_0
,
149 .clkr
.hw
.init
= &(struct clk_init_data
){
150 .name
= "disp_cc_mdss_byte0_clk_src",
151 .parent_data
= disp_cc_parent_data_0
,
152 .num_parents
= ARRAY_SIZE(disp_cc_parent_data_0
),
153 .flags
= CLK_SET_RATE_PARENT
| CLK_OPS_PARENT_ENABLE
,
154 .ops
= &clk_byte2_ops
,
158 static const struct freq_tbl ftbl_disp_cc_mdss_esc0_clk_src
[] = {
159 F(19200000, P_BI_TCXO
, 1, 0, 0),
163 static struct clk_rcg2 disp_cc_mdss_esc0_clk_src
= {
167 .parent_map
= disp_cc_parent_map_0
,
168 .freq_tbl
= ftbl_disp_cc_mdss_esc0_clk_src
,
169 .clkr
.hw
.init
= &(struct clk_init_data
){
170 .name
= "disp_cc_mdss_esc0_clk_src",
171 .parent_data
= disp_cc_parent_data_0
,
172 .num_parents
= ARRAY_SIZE(disp_cc_parent_data_0
),
173 .ops
= &clk_rcg2_shared_ops
,
177 static const struct freq_tbl ftbl_disp_cc_mdss_mdp_clk_src
[] = {
178 F(200000000, P_GCC_DISP_GPLL0_CLK
, 1.5, 0, 0),
179 F(300000000, P_GCC_DISP_GPLL0_CLK
, 1, 0, 0),
180 F(373500000, P_DISP_CC_PLL0_OUT_MAIN
, 2, 0, 0),
181 F(470000000, P_DISP_CC_PLL0_OUT_MAIN
, 2, 0, 0),
182 F(560000000, P_DISP_CC_PLL0_OUT_MAIN
, 2, 0, 0),
186 static struct clk_rcg2 disp_cc_mdss_mdp_clk_src
= {
190 .parent_map
= disp_cc_parent_map_1
,
191 .freq_tbl
= ftbl_disp_cc_mdss_mdp_clk_src
,
192 .clkr
.hw
.init
= &(struct clk_init_data
){
193 .name
= "disp_cc_mdss_mdp_clk_src",
194 .parent_data
= disp_cc_parent_data_1
,
195 .num_parents
= ARRAY_SIZE(disp_cc_parent_data_1
),
196 .flags
= CLK_SET_RATE_PARENT
,
197 .ops
= &clk_rcg2_shared_ops
,
201 static struct clk_rcg2 disp_cc_mdss_pclk0_clk_src
= {
205 .parent_map
= disp_cc_parent_map_3
,
206 .clkr
.hw
.init
= &(struct clk_init_data
){
207 .name
= "disp_cc_mdss_pclk0_clk_src",
208 .parent_data
= disp_cc_parent_data_3
,
209 .num_parents
= ARRAY_SIZE(disp_cc_parent_data_3
),
210 .flags
= CLK_SET_RATE_PARENT
| CLK_OPS_PARENT_ENABLE
,
211 .ops
= &clk_pixel_ops
,
215 static const struct freq_tbl ftbl_disp_cc_mdss_rot_clk_src
[] = {
216 F(200000000, P_GCC_DISP_GPLL0_CLK
, 1.5, 0, 0),
217 F(300000000, P_GCC_DISP_GPLL0_CLK
, 1, 0, 0),
221 static struct clk_rcg2 disp_cc_mdss_rot_clk_src
= {
225 .parent_map
= disp_cc_parent_map_1
,
226 .freq_tbl
= ftbl_disp_cc_mdss_rot_clk_src
,
227 .clkr
.hw
.init
= &(struct clk_init_data
){
228 .name
= "disp_cc_mdss_rot_clk_src",
229 .parent_data
= disp_cc_parent_data_1
,
230 .num_parents
= ARRAY_SIZE(disp_cc_parent_data_1
),
231 .ops
= &clk_rcg2_shared_ops
,
235 static struct clk_rcg2 disp_cc_mdss_vsync_clk_src
= {
239 .parent_map
= disp_cc_parent_map_4
,
240 .freq_tbl
= ftbl_disp_cc_mdss_esc0_clk_src
,
241 .clkr
.hw
.init
= &(struct clk_init_data
){
242 .name
= "disp_cc_mdss_vsync_clk_src",
243 .parent_data
= disp_cc_parent_data_4
,
244 .num_parents
= ARRAY_SIZE(disp_cc_parent_data_4
),
245 .ops
= &clk_rcg2_ops
,
249 static struct clk_regmap_div disp_cc_mdss_byte0_div_clk_src
= {
253 .clkr
.hw
.init
= &(struct clk_init_data
) {
254 .name
= "disp_cc_mdss_byte0_div_clk_src",
255 .parent_hws
= (const struct clk_hw
*[]) {
256 &disp_cc_mdss_byte0_clk_src
.clkr
.hw
,
259 .ops
= &clk_regmap_div_ops
,
263 static struct clk_branch disp_cc_mdss_ahb_clk
= {
265 .halt_check
= BRANCH_HALT
,
267 .enable_reg
= 0x104c,
268 .enable_mask
= BIT(0),
269 .hw
.init
= &(struct clk_init_data
){
270 .name
= "disp_cc_mdss_ahb_clk",
271 .parent_hws
= (const struct clk_hw
*[]){
272 &disp_cc_mdss_ahb_clk_src
.clkr
.hw
,
275 .flags
= CLK_SET_RATE_PARENT
,
276 .ops
= &clk_branch2_ops
,
281 static struct clk_branch disp_cc_mdss_byte0_clk
= {
283 .halt_check
= BRANCH_HALT
,
285 .enable_reg
= 0x102c,
286 .enable_mask
= BIT(0),
287 .hw
.init
= &(struct clk_init_data
){
288 .name
= "disp_cc_mdss_byte0_clk",
289 .parent_hws
= (const struct clk_hw
*[]){
290 &disp_cc_mdss_byte0_clk_src
.clkr
.hw
,
293 .flags
= CLK_SET_RATE_PARENT
,
294 .ops
= &clk_branch2_ops
,
299 static struct clk_branch disp_cc_mdss_byte0_intf_clk
= {
301 .halt_check
= BRANCH_HALT
,
303 .enable_reg
= 0x1030,
304 .enable_mask
= BIT(0),
305 .hw
.init
= &(struct clk_init_data
){
306 .name
= "disp_cc_mdss_byte0_intf_clk",
307 .parent_hws
= (const struct clk_hw
*[]){
308 &disp_cc_mdss_byte0_div_clk_src
.clkr
.hw
,
311 .flags
= CLK_SET_RATE_PARENT
,
312 .ops
= &clk_branch2_ops
,
317 static struct clk_branch disp_cc_mdss_esc0_clk
= {
319 .halt_check
= BRANCH_HALT
,
321 .enable_reg
= 0x1034,
322 .enable_mask
= BIT(0),
323 .hw
.init
= &(struct clk_init_data
){
324 .name
= "disp_cc_mdss_esc0_clk",
325 .parent_hws
= (const struct clk_hw
*[]){
326 &disp_cc_mdss_esc0_clk_src
.clkr
.hw
,
329 .flags
= CLK_SET_RATE_PARENT
,
330 .ops
= &clk_branch2_ops
,
335 static struct clk_branch disp_cc_mdss_mdp_clk
= {
337 .halt_check
= BRANCH_HALT
,
339 .enable_reg
= 0x1010,
340 .enable_mask
= BIT(0),
341 .hw
.init
= &(struct clk_init_data
){
342 .name
= "disp_cc_mdss_mdp_clk",
343 .parent_hws
= (const struct clk_hw
*[]){
344 &disp_cc_mdss_mdp_clk_src
.clkr
.hw
,
347 .flags
= CLK_SET_RATE_PARENT
,
348 .ops
= &clk_branch2_ops
,
353 static struct clk_branch disp_cc_mdss_mdp_lut_clk
= {
355 .halt_check
= BRANCH_HALT_VOTED
,
357 .enable_reg
= 0x1020,
358 .enable_mask
= BIT(0),
359 .hw
.init
= &(struct clk_init_data
){
360 .name
= "disp_cc_mdss_mdp_lut_clk",
361 .parent_hws
= (const struct clk_hw
*[]){
362 &disp_cc_mdss_mdp_clk_src
.clkr
.hw
,
365 .flags
= CLK_SET_RATE_PARENT
,
366 .ops
= &clk_branch2_ops
,
371 static struct clk_branch disp_cc_mdss_non_gdsc_ahb_clk
= {
373 .halt_check
= BRANCH_HALT_VOTED
,
375 .enable_reg
= 0x2004,
376 .enable_mask
= BIT(0),
377 .hw
.init
= &(struct clk_init_data
){
378 .name
= "disp_cc_mdss_non_gdsc_ahb_clk",
379 .parent_hws
= (const struct clk_hw
*[]){
380 &disp_cc_mdss_ahb_clk_src
.clkr
.hw
,
383 .flags
= CLK_SET_RATE_PARENT
,
384 .ops
= &clk_branch2_ops
,
389 static struct clk_branch disp_cc_mdss_pclk0_clk
= {
391 .halt_check
= BRANCH_HALT
,
393 .enable_reg
= 0x1168,
394 .enable_mask
= BIT(0),
395 .hw
.init
= &(struct clk_init_data
){
396 .name
= "disp_cc_mdss_pclk0_clk",
397 .parent_hws
= (const struct clk_hw
*[]){
398 &disp_cc_mdss_pclk0_clk_src
.clkr
.hw
,
401 .flags
= CLK_SET_RATE_PARENT
,
402 .ops
= &clk_branch2_ops
,
407 static struct clk_branch disp_cc_mdss_rot_clk
= {
409 .halt_check
= BRANCH_HALT
,
411 .enable_reg
= 0x1018,
412 .enable_mask
= BIT(0),
413 .hw
.init
= &(struct clk_init_data
){
414 .name
= "disp_cc_mdss_rot_clk",
415 .parent_hws
= (const struct clk_hw
*[]){
416 &disp_cc_mdss_rot_clk_src
.clkr
.hw
,
419 .flags
= CLK_SET_RATE_PARENT
,
420 .ops
= &clk_branch2_ops
,
425 static struct clk_branch disp_cc_mdss_rscc_ahb_clk
= {
427 .halt_check
= BRANCH_HALT
,
429 .enable_reg
= 0x200c,
430 .enable_mask
= BIT(0),
431 .hw
.init
= &(struct clk_init_data
){
432 .name
= "disp_cc_mdss_rscc_ahb_clk",
433 .parent_hws
= (const struct clk_hw
*[]){
434 &disp_cc_mdss_ahb_clk_src
.clkr
.hw
,
437 .flags
= CLK_SET_RATE_PARENT
,
438 .ops
= &clk_branch2_ops
,
443 static struct clk_branch disp_cc_mdss_rscc_vsync_clk
= {
445 .halt_check
= BRANCH_HALT
,
447 .enable_reg
= 0x2008,
448 .enable_mask
= BIT(0),
449 .hw
.init
= &(struct clk_init_data
){
450 .name
= "disp_cc_mdss_rscc_vsync_clk",
451 .parent_hws
= (const struct clk_hw
*[]){
452 &disp_cc_mdss_vsync_clk_src
.clkr
.hw
,
455 .flags
= CLK_SET_RATE_PARENT
,
456 .ops
= &clk_branch2_ops
,
461 static struct clk_branch disp_cc_mdss_vsync_clk
= {
463 .halt_check
= BRANCH_HALT
,
465 .enable_reg
= 0x1028,
466 .enable_mask
= BIT(0),
467 .hw
.init
= &(struct clk_init_data
){
468 .name
= "disp_cc_mdss_vsync_clk",
469 .parent_hws
= (const struct clk_hw
*[]){
470 &disp_cc_mdss_vsync_clk_src
.clkr
.hw
,
473 .flags
= CLK_SET_RATE_PARENT
,
474 .ops
= &clk_branch2_ops
,
479 static struct clk_branch disp_cc_sleep_clk
= {
480 .halt_check
= BRANCH_HALT
,
482 .enable_reg
= 0x5004,
483 .enable_mask
= BIT(0),
484 .hw
.init
= &(struct clk_init_data
){
485 .name
= "disp_cc_sleep_clk",
486 .flags
= CLK_IS_CRITICAL
,
487 .ops
= &clk_branch2_ops
,
492 static struct clk_branch disp_cc_xo_clk
= {
493 .halt_check
= BRANCH_HALT
,
495 .enable_reg
= 0x5008,
496 .enable_mask
= BIT(0),
497 .hw
.init
= &(struct clk_init_data
){
498 .name
= "disp_cc_xo_clk",
499 .flags
= CLK_IS_CRITICAL
,
500 .ops
= &clk_branch2_ops
,
505 static struct gdsc mdss_gdsc
= {
507 .en_rest_wait_val
= 0x2,
508 .en_few_wait_val
= 0x2,
509 .clk_dis_wait_val
= 0xf,
513 .pwrsts
= PWRSTS_OFF_ON
,
517 static struct clk_regmap
*disp_cc_sm6375_clocks
[] = {
518 [DISP_CC_MDSS_AHB_CLK
] = &disp_cc_mdss_ahb_clk
.clkr
,
519 [DISP_CC_MDSS_AHB_CLK_SRC
] = &disp_cc_mdss_ahb_clk_src
.clkr
,
520 [DISP_CC_MDSS_BYTE0_CLK
] = &disp_cc_mdss_byte0_clk
.clkr
,
521 [DISP_CC_MDSS_BYTE0_CLK_SRC
] = &disp_cc_mdss_byte0_clk_src
.clkr
,
522 [DISP_CC_MDSS_BYTE0_DIV_CLK_SRC
] = &disp_cc_mdss_byte0_div_clk_src
.clkr
,
523 [DISP_CC_MDSS_BYTE0_INTF_CLK
] = &disp_cc_mdss_byte0_intf_clk
.clkr
,
524 [DISP_CC_MDSS_ESC0_CLK
] = &disp_cc_mdss_esc0_clk
.clkr
,
525 [DISP_CC_MDSS_ESC0_CLK_SRC
] = &disp_cc_mdss_esc0_clk_src
.clkr
,
526 [DISP_CC_MDSS_MDP_CLK
] = &disp_cc_mdss_mdp_clk
.clkr
,
527 [DISP_CC_MDSS_MDP_CLK_SRC
] = &disp_cc_mdss_mdp_clk_src
.clkr
,
528 [DISP_CC_MDSS_MDP_LUT_CLK
] = &disp_cc_mdss_mdp_lut_clk
.clkr
,
529 [DISP_CC_MDSS_NON_GDSC_AHB_CLK
] = &disp_cc_mdss_non_gdsc_ahb_clk
.clkr
,
530 [DISP_CC_MDSS_PCLK0_CLK
] = &disp_cc_mdss_pclk0_clk
.clkr
,
531 [DISP_CC_MDSS_PCLK0_CLK_SRC
] = &disp_cc_mdss_pclk0_clk_src
.clkr
,
532 [DISP_CC_MDSS_ROT_CLK
] = &disp_cc_mdss_rot_clk
.clkr
,
533 [DISP_CC_MDSS_ROT_CLK_SRC
] = &disp_cc_mdss_rot_clk_src
.clkr
,
534 [DISP_CC_MDSS_RSCC_AHB_CLK
] = &disp_cc_mdss_rscc_ahb_clk
.clkr
,
535 [DISP_CC_MDSS_RSCC_VSYNC_CLK
] = &disp_cc_mdss_rscc_vsync_clk
.clkr
,
536 [DISP_CC_MDSS_VSYNC_CLK
] = &disp_cc_mdss_vsync_clk
.clkr
,
537 [DISP_CC_MDSS_VSYNC_CLK_SRC
] = &disp_cc_mdss_vsync_clk_src
.clkr
,
538 [DISP_CC_PLL0
] = &disp_cc_pll0
.clkr
,
539 [DISP_CC_SLEEP_CLK
] = &disp_cc_sleep_clk
.clkr
,
540 [DISP_CC_XO_CLK
] = &disp_cc_xo_clk
.clkr
,
543 static const struct qcom_reset_map disp_cc_sm6375_resets
[] = {
544 [DISP_CC_MDSS_CORE_BCR
] = { 0x1000 },
545 [DISP_CC_MDSS_RSCC_BCR
] = { 0x2000 },
548 static struct gdsc
*disp_cc_sm6375_gdscs
[] = {
549 [MDSS_GDSC
] = &mdss_gdsc
,
552 static const struct regmap_config disp_cc_sm6375_regmap_config
= {
556 .max_register
= 0x10000,
560 static const struct qcom_cc_desc disp_cc_sm6375_desc
= {
561 .config
= &disp_cc_sm6375_regmap_config
,
562 .clks
= disp_cc_sm6375_clocks
,
563 .num_clks
= ARRAY_SIZE(disp_cc_sm6375_clocks
),
564 .resets
= disp_cc_sm6375_resets
,
565 .num_resets
= ARRAY_SIZE(disp_cc_sm6375_resets
),
566 .gdscs
= disp_cc_sm6375_gdscs
,
567 .num_gdscs
= ARRAY_SIZE(disp_cc_sm6375_gdscs
),
570 static const struct of_device_id disp_cc_sm6375_match_table
[] = {
571 { .compatible
= "qcom,sm6375-dispcc" },
574 MODULE_DEVICE_TABLE(of
, disp_cc_sm6375_match_table
);
576 static int disp_cc_sm6375_probe(struct platform_device
*pdev
)
578 struct regmap
*regmap
;
580 regmap
= qcom_cc_map(pdev
, &disp_cc_sm6375_desc
);
582 return PTR_ERR(regmap
);
584 clk_lucid_pll_configure(&disp_cc_pll0
, regmap
, &disp_cc_pll0_config
);
586 return qcom_cc_really_probe(&pdev
->dev
, &disp_cc_sm6375_desc
, regmap
);
589 static struct platform_driver disp_cc_sm6375_driver
= {
590 .probe
= disp_cc_sm6375_probe
,
592 .name
= "disp_cc-sm6375",
593 .of_match_table
= disp_cc_sm6375_match_table
,
597 module_platform_driver(disp_cc_sm6375_driver
);
599 MODULE_DESCRIPTION("QTI DISPCC SM6375 Driver");
600 MODULE_LICENSE("GPL");