1 // SPDX-License-Identifier: GPL-2.0-only
3 * Based on dispcc-qcm2290.c
4 * Copyright (c) 2020, The Linux Foundation. All rights reserved.
5 * Copyright (c) 2021, Linaro Ltd.
9 #include <linux/kernel.h>
10 #include <linux/module.h>
12 #include <linux/platform_device.h>
13 #include <linux/regmap.h>
15 #include <dt-bindings/clock/qcom,sm6115-dispcc.h>
17 #include "clk-alpha-pll.h"
18 #include "clk-branch.h"
20 #include "clk-regmap.h"
21 #include "clk-regmap-divider.h"
28 DT_DSI0_PHY_PLL_OUT_BYTECLK
,
29 DT_DSI0_PHY_PLL_OUT_DSICLK
,
35 P_DISP_CC_PLL0_OUT_MAIN
,
36 P_DSI0_PHY_PLL_OUT_BYTECLK
,
37 P_DSI0_PHY_PLL_OUT_DSICLK
,
42 static const struct clk_parent_data parent_data_tcxo
= { .index
= DT_BI_TCXO
};
44 static const struct pll_vco spark_vco
[] = {
45 { 500000000, 1000000000, 2 },
48 /* 768MHz configuration */
49 static const struct alpha_pll_config disp_cc_pll0_config
= {
52 .vco_mask
= GENMASK(21, 20),
53 .main_output_mask
= BIT(0),
54 .config_ctl_val
= 0x4001055B,
57 static struct clk_alpha_pll disp_cc_pll0
= {
59 .vco_table
= spark_vco
,
60 .num_vco
= ARRAY_SIZE(spark_vco
),
61 .regs
= clk_alpha_pll_regs
[CLK_ALPHA_PLL_TYPE_DEFAULT
],
63 .hw
.init
= &(struct clk_init_data
){
64 .name
= "disp_cc_pll0",
65 .parent_data
= &parent_data_tcxo
,
67 .ops
= &clk_alpha_pll_ops
,
72 static const struct clk_div_table post_div_table_disp_cc_pll0_out_main
[] = {
76 static struct clk_alpha_pll_postdiv disp_cc_pll0_out_main
= {
79 .post_div_table
= post_div_table_disp_cc_pll0_out_main
,
80 .num_post_div
= ARRAY_SIZE(post_div_table_disp_cc_pll0_out_main
),
82 .regs
= clk_alpha_pll_regs
[CLK_ALPHA_PLL_TYPE_DEFAULT
],
83 .clkr
.hw
.init
= &(struct clk_init_data
){
84 .name
= "disp_cc_pll0_out_main",
85 .parent_hws
= (const struct clk_hw
*[]){
86 &disp_cc_pll0
.clkr
.hw
,
89 .flags
= CLK_SET_RATE_PARENT
,
90 .ops
= &clk_alpha_pll_postdiv_ops
,
94 static const struct parent_map disp_cc_parent_map_0
[] = {
96 { P_DSI0_PHY_PLL_OUT_BYTECLK
, 1 },
99 static const struct clk_parent_data disp_cc_parent_data_0
[] = {
100 { .index
= DT_BI_TCXO
},
101 { .index
= DT_DSI0_PHY_PLL_OUT_BYTECLK
},
104 static const struct parent_map disp_cc_parent_map_1
[] = {
108 static const struct clk_parent_data disp_cc_parent_data_1
[] = {
109 { .index
= DT_BI_TCXO
},
112 static const struct parent_map disp_cc_parent_map_2
[] = {
114 { P_GPLL0_OUT_MAIN
, 4 },
117 static const struct clk_parent_data disp_cc_parent_data_2
[] = {
118 { .index
= DT_BI_TCXO
},
119 { .index
= DT_GPLL0_DISP_DIV
},
122 static const struct parent_map disp_cc_parent_map_3
[] = {
124 { P_DISP_CC_PLL0_OUT_MAIN
, 1 },
127 static const struct clk_parent_data disp_cc_parent_data_3
[] = {
128 { .index
= DT_BI_TCXO
},
129 { .hw
= &disp_cc_pll0_out_main
.clkr
.hw
},
132 static const struct parent_map disp_cc_parent_map_4
[] = {
134 { P_DSI0_PHY_PLL_OUT_DSICLK
, 1 },
137 static const struct clk_parent_data disp_cc_parent_data_4
[] = {
138 { .index
= DT_BI_TCXO
},
139 { .index
= DT_DSI0_PHY_PLL_OUT_DSICLK
},
142 static const struct parent_map disp_cc_parent_map_5
[] = {
146 static const struct clk_parent_data disp_cc_parent_data_5
[] = {
147 { .index
= DT_SLEEP_CLK
, },
150 static struct clk_rcg2 disp_cc_mdss_byte0_clk_src
= {
154 .parent_map
= disp_cc_parent_map_0
,
155 .clkr
.hw
.init
= &(struct clk_init_data
){
156 .name
= "disp_cc_mdss_byte0_clk_src",
157 .parent_data
= disp_cc_parent_data_0
,
158 .num_parents
= ARRAY_SIZE(disp_cc_parent_data_0
),
159 /* For set_rate and set_parent to succeed, parent(s) must be enabled */
160 .flags
= CLK_SET_RATE_PARENT
| CLK_OPS_PARENT_ENABLE
| CLK_GET_RATE_NOCACHE
,
161 .ops
= &clk_byte2_ops
,
165 static struct clk_regmap_div disp_cc_mdss_byte0_div_clk_src
= {
169 .clkr
.hw
.init
= &(struct clk_init_data
) {
170 .name
= "disp_cc_mdss_byte0_div_clk_src",
171 .parent_hws
= (const struct clk_hw
*[]){
172 &disp_cc_mdss_byte0_clk_src
.clkr
.hw
,
175 .ops
= &clk_regmap_div_ops
,
179 static const struct freq_tbl ftbl_disp_cc_mdss_ahb_clk_src
[] = {
180 F(19200000, P_BI_TCXO
, 1, 0, 0),
181 F(37500000, P_GPLL0_OUT_MAIN
, 8, 0, 0),
182 F(75000000, P_GPLL0_OUT_MAIN
, 4, 0, 0),
186 static struct clk_rcg2 disp_cc_mdss_ahb_clk_src
= {
190 .parent_map
= disp_cc_parent_map_2
,
191 .freq_tbl
= ftbl_disp_cc_mdss_ahb_clk_src
,
192 .clkr
.hw
.init
= &(struct clk_init_data
){
193 .name
= "disp_cc_mdss_ahb_clk_src",
194 .parent_data
= disp_cc_parent_data_2
,
195 .num_parents
= ARRAY_SIZE(disp_cc_parent_data_2
),
196 .ops
= &clk_rcg2_shared_ops
,
200 static const struct freq_tbl ftbl_disp_cc_mdss_esc0_clk_src
[] = {
201 F(19200000, P_BI_TCXO
, 1, 0, 0),
205 static struct clk_rcg2 disp_cc_mdss_esc0_clk_src
= {
209 .parent_map
= disp_cc_parent_map_0
,
210 .freq_tbl
= ftbl_disp_cc_mdss_esc0_clk_src
,
211 .clkr
.hw
.init
= &(struct clk_init_data
){
212 .name
= "disp_cc_mdss_esc0_clk_src",
213 .parent_data
= disp_cc_parent_data_0
,
214 .num_parents
= ARRAY_SIZE(disp_cc_parent_data_0
),
215 .ops
= &clk_rcg2_ops
,
219 static const struct freq_tbl ftbl_disp_cc_mdss_mdp_clk_src
[] = {
220 F(19200000, P_BI_TCXO
, 1, 0, 0),
221 F(192000000, P_DISP_CC_PLL0_OUT_MAIN
, 4, 0, 0),
222 F(256000000, P_DISP_CC_PLL0_OUT_MAIN
, 3, 0, 0),
223 F(307200000, P_DISP_CC_PLL0_OUT_MAIN
, 2.5, 0, 0),
224 F(384000000, P_DISP_CC_PLL0_OUT_MAIN
, 2, 0, 0),
228 static struct clk_rcg2 disp_cc_mdss_mdp_clk_src
= {
232 .parent_map
= disp_cc_parent_map_3
,
233 .freq_tbl
= ftbl_disp_cc_mdss_mdp_clk_src
,
234 .clkr
.hw
.init
= &(struct clk_init_data
){
235 .name
= "disp_cc_mdss_mdp_clk_src",
236 .parent_data
= disp_cc_parent_data_3
,
237 .num_parents
= ARRAY_SIZE(disp_cc_parent_data_3
),
238 .flags
= CLK_SET_RATE_PARENT
,
239 .ops
= &clk_rcg2_shared_ops
,
243 static struct clk_rcg2 disp_cc_mdss_pclk0_clk_src
= {
247 .parent_map
= disp_cc_parent_map_4
,
248 .clkr
.hw
.init
= &(struct clk_init_data
){
249 .name
= "disp_cc_mdss_pclk0_clk_src",
250 .parent_data
= disp_cc_parent_data_4
,
251 .num_parents
= ARRAY_SIZE(disp_cc_parent_data_4
),
252 /* For set_rate and set_parent to succeed, parent(s) must be enabled */
253 .flags
= CLK_SET_RATE_PARENT
| CLK_OPS_PARENT_ENABLE
| CLK_GET_RATE_NOCACHE
,
254 .ops
= &clk_pixel_ops
,
258 static const struct freq_tbl ftbl_disp_cc_mdss_rot_clk_src
[] = {
259 F(19200000, P_BI_TCXO
, 1, 0, 0),
260 F(192000000, P_DISP_CC_PLL0_OUT_MAIN
, 4, 0, 0),
261 F(256000000, P_DISP_CC_PLL0_OUT_MAIN
, 3, 0, 0),
262 F(307200000, P_DISP_CC_PLL0_OUT_MAIN
, 2.5, 0, 0),
266 static struct clk_rcg2 disp_cc_mdss_rot_clk_src
= {
270 .parent_map
= disp_cc_parent_map_3
,
271 .freq_tbl
= ftbl_disp_cc_mdss_rot_clk_src
,
272 .clkr
.hw
.init
= &(struct clk_init_data
){
273 .name
= "disp_cc_mdss_rot_clk_src",
274 .parent_data
= disp_cc_parent_data_3
,
275 .num_parents
= ARRAY_SIZE(disp_cc_parent_data_3
),
276 .flags
= CLK_SET_RATE_PARENT
,
277 .ops
= &clk_rcg2_shared_ops
,
281 static struct clk_rcg2 disp_cc_mdss_vsync_clk_src
= {
285 .parent_map
= disp_cc_parent_map_1
,
286 .freq_tbl
= ftbl_disp_cc_mdss_esc0_clk_src
,
287 .clkr
.hw
.init
= &(struct clk_init_data
){
288 .name
= "disp_cc_mdss_vsync_clk_src",
289 .parent_data
= disp_cc_parent_data_1
,
290 .num_parents
= ARRAY_SIZE(disp_cc_parent_data_1
),
291 .flags
= CLK_SET_RATE_PARENT
,
292 .ops
= &clk_rcg2_shared_ops
,
296 static const struct freq_tbl ftbl_disp_cc_sleep_clk_src
[] = {
297 F(32764, P_SLEEP_CLK
, 1, 0, 0),
301 static struct clk_rcg2 disp_cc_sleep_clk_src
= {
305 .parent_map
= disp_cc_parent_map_5
,
306 .freq_tbl
= ftbl_disp_cc_sleep_clk_src
,
307 .clkr
.hw
.init
= &(struct clk_init_data
){
308 .name
= "disp_cc_sleep_clk_src",
309 .parent_data
= disp_cc_parent_data_5
,
310 .num_parents
= ARRAY_SIZE(disp_cc_parent_data_5
),
311 .ops
= &clk_rcg2_ops
,
315 static struct clk_branch disp_cc_mdss_ahb_clk
= {
317 .halt_check
= BRANCH_HALT
,
319 .enable_reg
= 0x2044,
320 .enable_mask
= BIT(0),
321 .hw
.init
= &(struct clk_init_data
){
322 .name
= "disp_cc_mdss_ahb_clk",
323 .parent_hws
= (const struct clk_hw
*[]){
324 &disp_cc_mdss_ahb_clk_src
.clkr
.hw
,
327 .flags
= CLK_SET_RATE_PARENT
,
328 .ops
= &clk_branch2_ops
,
333 static struct clk_branch disp_cc_mdss_byte0_clk
= {
335 .halt_check
= BRANCH_HALT
,
337 .enable_reg
= 0x2024,
338 .enable_mask
= BIT(0),
339 .hw
.init
= &(struct clk_init_data
){
340 .name
= "disp_cc_mdss_byte0_clk",
341 .parent_hws
= (const struct clk_hw
*[]){
342 &disp_cc_mdss_byte0_clk_src
.clkr
.hw
,
345 .flags
= CLK_SET_RATE_PARENT
| CLK_GET_RATE_NOCACHE
,
346 .ops
= &clk_branch2_ops
,
351 static struct clk_branch disp_cc_mdss_byte0_intf_clk
= {
353 .halt_check
= BRANCH_HALT
,
355 .enable_reg
= 0x2028,
356 .enable_mask
= BIT(0),
357 .hw
.init
= &(struct clk_init_data
){
358 .name
= "disp_cc_mdss_byte0_intf_clk",
359 .parent_hws
= (const struct clk_hw
*[]){
360 &disp_cc_mdss_byte0_div_clk_src
.clkr
.hw
,
363 .flags
= CLK_SET_RATE_PARENT
| CLK_GET_RATE_NOCACHE
,
364 .ops
= &clk_branch2_ops
,
369 static struct clk_branch disp_cc_mdss_esc0_clk
= {
371 .halt_check
= BRANCH_HALT
,
373 .enable_reg
= 0x202c,
374 .enable_mask
= BIT(0),
375 .hw
.init
= &(struct clk_init_data
){
376 .name
= "disp_cc_mdss_esc0_clk",
377 .parent_hws
= (const struct clk_hw
*[]){
378 &disp_cc_mdss_esc0_clk_src
.clkr
.hw
,
381 .flags
= CLK_SET_RATE_PARENT
,
382 .ops
= &clk_branch2_ops
,
387 static struct clk_branch disp_cc_mdss_mdp_clk
= {
389 .halt_check
= BRANCH_HALT
,
391 .enable_reg
= 0x2008,
392 .enable_mask
= BIT(0),
393 .hw
.init
= &(struct clk_init_data
){
394 .name
= "disp_cc_mdss_mdp_clk",
395 .parent_hws
= (const struct clk_hw
*[]){
396 &disp_cc_mdss_mdp_clk_src
.clkr
.hw
,
399 .flags
= CLK_SET_RATE_PARENT
,
400 .ops
= &clk_branch2_ops
,
405 static struct clk_branch disp_cc_mdss_mdp_lut_clk
= {
407 .halt_check
= BRANCH_HALT_VOTED
,
409 .enable_reg
= 0x2018,
410 .enable_mask
= BIT(0),
411 .hw
.init
= &(struct clk_init_data
){
412 .name
= "disp_cc_mdss_mdp_lut_clk",
413 .parent_hws
= (const struct clk_hw
*[]){
414 &disp_cc_mdss_mdp_clk_src
.clkr
.hw
,
417 .flags
= CLK_SET_RATE_PARENT
,
418 .ops
= &clk_branch2_ops
,
423 static struct clk_branch disp_cc_mdss_non_gdsc_ahb_clk
= {
425 .halt_check
= BRANCH_HALT_VOTED
,
427 .enable_reg
= 0x4004,
428 .enable_mask
= BIT(0),
429 .hw
.init
= &(struct clk_init_data
){
430 .name
= "disp_cc_mdss_non_gdsc_ahb_clk",
431 .parent_hws
= (const struct clk_hw
*[]){
432 &disp_cc_mdss_ahb_clk_src
.clkr
.hw
,
435 .flags
= CLK_SET_RATE_PARENT
,
436 .ops
= &clk_branch2_ops
,
441 static struct clk_branch disp_cc_mdss_pclk0_clk
= {
443 .halt_check
= BRANCH_HALT
,
445 .enable_reg
= 0x2004,
446 .enable_mask
= BIT(0),
447 .hw
.init
= &(struct clk_init_data
){
448 .name
= "disp_cc_mdss_pclk0_clk",
449 .parent_hws
= (const struct clk_hw
*[]){
450 &disp_cc_mdss_pclk0_clk_src
.clkr
.hw
,
453 .flags
= CLK_SET_RATE_PARENT
| CLK_GET_RATE_NOCACHE
,
454 .ops
= &clk_branch2_ops
,
459 static struct clk_branch disp_cc_mdss_rot_clk
= {
461 .halt_check
= BRANCH_HALT
,
463 .enable_reg
= 0x2010,
464 .enable_mask
= BIT(0),
465 .hw
.init
= &(struct clk_init_data
){
466 .name
= "disp_cc_mdss_rot_clk",
467 .parent_hws
= (const struct clk_hw
*[]) {
468 &disp_cc_mdss_rot_clk_src
.clkr
.hw
,
471 .flags
= CLK_SET_RATE_PARENT
,
472 .ops
= &clk_branch2_ops
,
477 static struct clk_branch disp_cc_mdss_vsync_clk
= {
479 .halt_check
= BRANCH_HALT
,
481 .enable_reg
= 0x2020,
482 .enable_mask
= BIT(0),
483 .hw
.init
= &(struct clk_init_data
){
484 .name
= "disp_cc_mdss_vsync_clk",
485 .parent_hws
= (const struct clk_hw
*[]){
486 &disp_cc_mdss_vsync_clk_src
.clkr
.hw
,
489 .flags
= CLK_SET_RATE_PARENT
,
490 .ops
= &clk_branch2_ops
,
495 static struct clk_branch disp_cc_sleep_clk
= {
497 .halt_check
= BRANCH_HALT
,
499 .enable_reg
= 0x6068,
500 .enable_mask
= BIT(0),
501 .hw
.init
= &(struct clk_init_data
){
502 .name
= "disp_cc_sleep_clk",
503 .parent_hws
= (const struct clk_hw
*[]){
504 &disp_cc_sleep_clk_src
.clkr
.hw
,
507 .flags
= CLK_SET_RATE_PARENT
,
508 .ops
= &clk_branch2_ops
,
513 static struct gdsc mdss_gdsc
= {
518 .pwrsts
= PWRSTS_OFF_ON
,
522 static struct gdsc
*disp_cc_sm6115_gdscs
[] = {
523 [MDSS_GDSC
] = &mdss_gdsc
,
526 static struct clk_regmap
*disp_cc_sm6115_clocks
[] = {
527 [DISP_CC_PLL0
] = &disp_cc_pll0
.clkr
,
528 [DISP_CC_PLL0_OUT_MAIN
] = &disp_cc_pll0_out_main
.clkr
,
529 [DISP_CC_MDSS_AHB_CLK
] = &disp_cc_mdss_ahb_clk
.clkr
,
530 [DISP_CC_MDSS_AHB_CLK_SRC
] = &disp_cc_mdss_ahb_clk_src
.clkr
,
531 [DISP_CC_MDSS_BYTE0_CLK
] = &disp_cc_mdss_byte0_clk
.clkr
,
532 [DISP_CC_MDSS_BYTE0_CLK_SRC
] = &disp_cc_mdss_byte0_clk_src
.clkr
,
533 [DISP_CC_MDSS_BYTE0_DIV_CLK_SRC
] = &disp_cc_mdss_byte0_div_clk_src
.clkr
,
534 [DISP_CC_MDSS_BYTE0_INTF_CLK
] = &disp_cc_mdss_byte0_intf_clk
.clkr
,
535 [DISP_CC_MDSS_ESC0_CLK
] = &disp_cc_mdss_esc0_clk
.clkr
,
536 [DISP_CC_MDSS_ESC0_CLK_SRC
] = &disp_cc_mdss_esc0_clk_src
.clkr
,
537 [DISP_CC_MDSS_MDP_CLK
] = &disp_cc_mdss_mdp_clk
.clkr
,
538 [DISP_CC_MDSS_MDP_CLK_SRC
] = &disp_cc_mdss_mdp_clk_src
.clkr
,
539 [DISP_CC_MDSS_MDP_LUT_CLK
] = &disp_cc_mdss_mdp_lut_clk
.clkr
,
540 [DISP_CC_MDSS_NON_GDSC_AHB_CLK
] = &disp_cc_mdss_non_gdsc_ahb_clk
.clkr
,
541 [DISP_CC_MDSS_PCLK0_CLK
] = &disp_cc_mdss_pclk0_clk
.clkr
,
542 [DISP_CC_MDSS_PCLK0_CLK_SRC
] = &disp_cc_mdss_pclk0_clk_src
.clkr
,
543 [DISP_CC_MDSS_ROT_CLK
] = &disp_cc_mdss_rot_clk
.clkr
,
544 [DISP_CC_MDSS_ROT_CLK_SRC
] = &disp_cc_mdss_rot_clk_src
.clkr
,
545 [DISP_CC_MDSS_VSYNC_CLK
] = &disp_cc_mdss_vsync_clk
.clkr
,
546 [DISP_CC_MDSS_VSYNC_CLK_SRC
] = &disp_cc_mdss_vsync_clk_src
.clkr
,
547 [DISP_CC_SLEEP_CLK
] = &disp_cc_sleep_clk
.clkr
,
548 [DISP_CC_SLEEP_CLK_SRC
] = &disp_cc_sleep_clk_src
.clkr
,
551 static const struct regmap_config disp_cc_sm6115_regmap_config
= {
555 .max_register
= 0x10000,
559 static const struct qcom_cc_desc disp_cc_sm6115_desc
= {
560 .config
= &disp_cc_sm6115_regmap_config
,
561 .clks
= disp_cc_sm6115_clocks
,
562 .num_clks
= ARRAY_SIZE(disp_cc_sm6115_clocks
),
563 .gdscs
= disp_cc_sm6115_gdscs
,
564 .num_gdscs
= ARRAY_SIZE(disp_cc_sm6115_gdscs
),
567 static const struct of_device_id disp_cc_sm6115_match_table
[] = {
568 { .compatible
= "qcom,sm6115-dispcc" },
571 MODULE_DEVICE_TABLE(of
, disp_cc_sm6115_match_table
);
573 static int disp_cc_sm6115_probe(struct platform_device
*pdev
)
575 struct regmap
*regmap
;
578 regmap
= qcom_cc_map(pdev
, &disp_cc_sm6115_desc
);
580 return PTR_ERR(regmap
);
582 clk_alpha_pll_configure(&disp_cc_pll0
, regmap
, &disp_cc_pll0_config
);
584 /* Keep some clocks always-on */
585 qcom_branch_set_clk_en(regmap
, 0x604c); /* DISP_CC_XO_CLK */
587 ret
= qcom_cc_really_probe(&pdev
->dev
, &disp_cc_sm6115_desc
, regmap
);
589 dev_err(&pdev
->dev
, "Failed to register DISP CC clocks\n");
596 static struct platform_driver disp_cc_sm6115_driver
= {
597 .probe
= disp_cc_sm6115_probe
,
599 .name
= "dispcc-sm6115",
600 .of_match_table
= disp_cc_sm6115_match_table
,
604 module_platform_driver(disp_cc_sm6115_driver
);
605 MODULE_DESCRIPTION("Qualcomm SM6115 Display Clock controller");
606 MODULE_LICENSE("GPL");