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 .alpha_en_mask
= BIT(24),
54 .vco_mask
= GENMASK(21, 20),
55 .main_output_mask
= BIT(0),
56 .config_ctl_val
= 0x4001055B,
59 static struct clk_alpha_pll disp_cc_pll0
= {
61 .vco_table
= spark_vco
,
62 .num_vco
= ARRAY_SIZE(spark_vco
),
63 .regs
= clk_alpha_pll_regs
[CLK_ALPHA_PLL_TYPE_DEFAULT
],
65 .hw
.init
= &(struct clk_init_data
){
66 .name
= "disp_cc_pll0",
67 .parent_data
= &parent_data_tcxo
,
69 .ops
= &clk_alpha_pll_ops
,
74 static const struct clk_div_table post_div_table_disp_cc_pll0_out_main
[] = {
78 static struct clk_alpha_pll_postdiv disp_cc_pll0_out_main
= {
81 .post_div_table
= post_div_table_disp_cc_pll0_out_main
,
82 .num_post_div
= ARRAY_SIZE(post_div_table_disp_cc_pll0_out_main
),
84 .regs
= clk_alpha_pll_regs
[CLK_ALPHA_PLL_TYPE_DEFAULT
],
85 .clkr
.hw
.init
= &(struct clk_init_data
){
86 .name
= "disp_cc_pll0_out_main",
87 .parent_hws
= (const struct clk_hw
*[]){
88 &disp_cc_pll0
.clkr
.hw
,
91 .flags
= CLK_SET_RATE_PARENT
,
92 .ops
= &clk_alpha_pll_postdiv_ops
,
96 static const struct parent_map disp_cc_parent_map_0
[] = {
98 { P_DSI0_PHY_PLL_OUT_BYTECLK
, 1 },
101 static const struct clk_parent_data disp_cc_parent_data_0
[] = {
102 { .index
= DT_BI_TCXO
},
103 { .index
= DT_DSI0_PHY_PLL_OUT_BYTECLK
},
106 static const struct parent_map disp_cc_parent_map_1
[] = {
110 static const struct clk_parent_data disp_cc_parent_data_1
[] = {
111 { .index
= DT_BI_TCXO
},
114 static const struct parent_map disp_cc_parent_map_2
[] = {
116 { P_GPLL0_OUT_MAIN
, 4 },
119 static const struct clk_parent_data disp_cc_parent_data_2
[] = {
120 { .index
= DT_BI_TCXO
},
121 { .index
= DT_GPLL0_DISP_DIV
},
124 static const struct parent_map disp_cc_parent_map_3
[] = {
126 { P_DISP_CC_PLL0_OUT_MAIN
, 1 },
129 static const struct clk_parent_data disp_cc_parent_data_3
[] = {
130 { .index
= DT_BI_TCXO
},
131 { .hw
= &disp_cc_pll0_out_main
.clkr
.hw
},
134 static const struct parent_map disp_cc_parent_map_4
[] = {
136 { P_DSI0_PHY_PLL_OUT_DSICLK
, 1 },
139 static const struct clk_parent_data disp_cc_parent_data_4
[] = {
140 { .index
= DT_BI_TCXO
},
141 { .index
= DT_DSI0_PHY_PLL_OUT_DSICLK
},
144 static const struct parent_map disp_cc_parent_map_5
[] = {
148 static const struct clk_parent_data disp_cc_parent_data_5
[] = {
149 { .index
= DT_SLEEP_CLK
, },
152 static struct clk_rcg2 disp_cc_mdss_byte0_clk_src
= {
156 .parent_map
= disp_cc_parent_map_0
,
157 .clkr
.hw
.init
= &(struct clk_init_data
){
158 .name
= "disp_cc_mdss_byte0_clk_src",
159 .parent_data
= disp_cc_parent_data_0
,
160 .num_parents
= ARRAY_SIZE(disp_cc_parent_data_0
),
161 /* For set_rate and set_parent to succeed, parent(s) must be enabled */
162 .flags
= CLK_SET_RATE_PARENT
| CLK_OPS_PARENT_ENABLE
| CLK_GET_RATE_NOCACHE
,
163 .ops
= &clk_byte2_ops
,
167 static struct clk_regmap_div disp_cc_mdss_byte0_div_clk_src
= {
171 .clkr
.hw
.init
= &(struct clk_init_data
) {
172 .name
= "disp_cc_mdss_byte0_div_clk_src",
173 .parent_hws
= (const struct clk_hw
*[]){
174 &disp_cc_mdss_byte0_clk_src
.clkr
.hw
,
177 .ops
= &clk_regmap_div_ops
,
181 static const struct freq_tbl ftbl_disp_cc_mdss_ahb_clk_src
[] = {
182 F(19200000, P_BI_TCXO
, 1, 0, 0),
183 F(37500000, P_GPLL0_OUT_MAIN
, 8, 0, 0),
184 F(75000000, P_GPLL0_OUT_MAIN
, 4, 0, 0),
188 static struct clk_rcg2 disp_cc_mdss_ahb_clk_src
= {
192 .parent_map
= disp_cc_parent_map_2
,
193 .freq_tbl
= ftbl_disp_cc_mdss_ahb_clk_src
,
194 .clkr
.hw
.init
= &(struct clk_init_data
){
195 .name
= "disp_cc_mdss_ahb_clk_src",
196 .parent_data
= disp_cc_parent_data_2
,
197 .num_parents
= ARRAY_SIZE(disp_cc_parent_data_2
),
198 .ops
= &clk_rcg2_shared_ops
,
202 static const struct freq_tbl ftbl_disp_cc_mdss_esc0_clk_src
[] = {
203 F(19200000, P_BI_TCXO
, 1, 0, 0),
207 static struct clk_rcg2 disp_cc_mdss_esc0_clk_src
= {
211 .parent_map
= disp_cc_parent_map_0
,
212 .freq_tbl
= ftbl_disp_cc_mdss_esc0_clk_src
,
213 .clkr
.hw
.init
= &(struct clk_init_data
){
214 .name
= "disp_cc_mdss_esc0_clk_src",
215 .parent_data
= disp_cc_parent_data_0
,
216 .num_parents
= ARRAY_SIZE(disp_cc_parent_data_0
),
217 .ops
= &clk_rcg2_ops
,
221 static const struct freq_tbl ftbl_disp_cc_mdss_mdp_clk_src
[] = {
222 F(19200000, P_BI_TCXO
, 1, 0, 0),
223 F(192000000, P_DISP_CC_PLL0_OUT_MAIN
, 4, 0, 0),
224 F(256000000, P_DISP_CC_PLL0_OUT_MAIN
, 3, 0, 0),
225 F(307200000, P_DISP_CC_PLL0_OUT_MAIN
, 2.5, 0, 0),
226 F(384000000, P_DISP_CC_PLL0_OUT_MAIN
, 2, 0, 0),
230 static struct clk_rcg2 disp_cc_mdss_mdp_clk_src
= {
234 .parent_map
= disp_cc_parent_map_3
,
235 .freq_tbl
= ftbl_disp_cc_mdss_mdp_clk_src
,
236 .clkr
.hw
.init
= &(struct clk_init_data
){
237 .name
= "disp_cc_mdss_mdp_clk_src",
238 .parent_data
= disp_cc_parent_data_3
,
239 .num_parents
= ARRAY_SIZE(disp_cc_parent_data_3
),
240 .flags
= CLK_SET_RATE_PARENT
,
241 .ops
= &clk_rcg2_shared_ops
,
245 static struct clk_rcg2 disp_cc_mdss_pclk0_clk_src
= {
249 .parent_map
= disp_cc_parent_map_4
,
250 .clkr
.hw
.init
= &(struct clk_init_data
){
251 .name
= "disp_cc_mdss_pclk0_clk_src",
252 .parent_data
= disp_cc_parent_data_4
,
253 .num_parents
= ARRAY_SIZE(disp_cc_parent_data_4
),
254 /* For set_rate and set_parent to succeed, parent(s) must be enabled */
255 .flags
= CLK_SET_RATE_PARENT
| CLK_OPS_PARENT_ENABLE
| CLK_GET_RATE_NOCACHE
,
256 .ops
= &clk_pixel_ops
,
260 static const struct freq_tbl ftbl_disp_cc_mdss_rot_clk_src
[] = {
261 F(19200000, P_BI_TCXO
, 1, 0, 0),
262 F(192000000, P_DISP_CC_PLL0_OUT_MAIN
, 4, 0, 0),
263 F(256000000, P_DISP_CC_PLL0_OUT_MAIN
, 3, 0, 0),
264 F(307200000, P_DISP_CC_PLL0_OUT_MAIN
, 2.5, 0, 0),
268 static struct clk_rcg2 disp_cc_mdss_rot_clk_src
= {
272 .parent_map
= disp_cc_parent_map_3
,
273 .freq_tbl
= ftbl_disp_cc_mdss_rot_clk_src
,
274 .clkr
.hw
.init
= &(struct clk_init_data
){
275 .name
= "disp_cc_mdss_rot_clk_src",
276 .parent_data
= disp_cc_parent_data_3
,
277 .num_parents
= ARRAY_SIZE(disp_cc_parent_data_3
),
278 .flags
= CLK_SET_RATE_PARENT
,
279 .ops
= &clk_rcg2_shared_ops
,
283 static struct clk_rcg2 disp_cc_mdss_vsync_clk_src
= {
287 .parent_map
= disp_cc_parent_map_1
,
288 .freq_tbl
= ftbl_disp_cc_mdss_esc0_clk_src
,
289 .clkr
.hw
.init
= &(struct clk_init_data
){
290 .name
= "disp_cc_mdss_vsync_clk_src",
291 .parent_data
= disp_cc_parent_data_1
,
292 .num_parents
= ARRAY_SIZE(disp_cc_parent_data_1
),
293 .flags
= CLK_SET_RATE_PARENT
,
294 .ops
= &clk_rcg2_shared_ops
,
298 static const struct freq_tbl ftbl_disp_cc_sleep_clk_src
[] = {
299 F(32764, P_SLEEP_CLK
, 1, 0, 0),
303 static struct clk_rcg2 disp_cc_sleep_clk_src
= {
307 .parent_map
= disp_cc_parent_map_5
,
308 .freq_tbl
= ftbl_disp_cc_sleep_clk_src
,
309 .clkr
.hw
.init
= &(struct clk_init_data
){
310 .name
= "disp_cc_sleep_clk_src",
311 .parent_data
= disp_cc_parent_data_5
,
312 .num_parents
= ARRAY_SIZE(disp_cc_parent_data_5
),
313 .ops
= &clk_rcg2_ops
,
317 static struct clk_branch disp_cc_mdss_ahb_clk
= {
319 .halt_check
= BRANCH_HALT
,
321 .enable_reg
= 0x2044,
322 .enable_mask
= BIT(0),
323 .hw
.init
= &(struct clk_init_data
){
324 .name
= "disp_cc_mdss_ahb_clk",
325 .parent_hws
= (const struct clk_hw
*[]){
326 &disp_cc_mdss_ahb_clk_src
.clkr
.hw
,
329 .flags
= CLK_SET_RATE_PARENT
,
330 .ops
= &clk_branch2_ops
,
335 static struct clk_branch disp_cc_mdss_byte0_clk
= {
337 .halt_check
= BRANCH_HALT
,
339 .enable_reg
= 0x2024,
340 .enable_mask
= BIT(0),
341 .hw
.init
= &(struct clk_init_data
){
342 .name
= "disp_cc_mdss_byte0_clk",
343 .parent_hws
= (const struct clk_hw
*[]){
344 &disp_cc_mdss_byte0_clk_src
.clkr
.hw
,
347 .flags
= CLK_SET_RATE_PARENT
| CLK_GET_RATE_NOCACHE
,
348 .ops
= &clk_branch2_ops
,
353 static struct clk_branch disp_cc_mdss_byte0_intf_clk
= {
355 .halt_check
= BRANCH_HALT
,
357 .enable_reg
= 0x2028,
358 .enable_mask
= BIT(0),
359 .hw
.init
= &(struct clk_init_data
){
360 .name
= "disp_cc_mdss_byte0_intf_clk",
361 .parent_hws
= (const struct clk_hw
*[]){
362 &disp_cc_mdss_byte0_div_clk_src
.clkr
.hw
,
365 .flags
= CLK_SET_RATE_PARENT
| CLK_GET_RATE_NOCACHE
,
366 .ops
= &clk_branch2_ops
,
371 static struct clk_branch disp_cc_mdss_esc0_clk
= {
373 .halt_check
= BRANCH_HALT
,
375 .enable_reg
= 0x202c,
376 .enable_mask
= BIT(0),
377 .hw
.init
= &(struct clk_init_data
){
378 .name
= "disp_cc_mdss_esc0_clk",
379 .parent_hws
= (const struct clk_hw
*[]){
380 &disp_cc_mdss_esc0_clk_src
.clkr
.hw
,
383 .flags
= CLK_SET_RATE_PARENT
,
384 .ops
= &clk_branch2_ops
,
389 static struct clk_branch disp_cc_mdss_mdp_clk
= {
391 .halt_check
= BRANCH_HALT
,
393 .enable_reg
= 0x2008,
394 .enable_mask
= BIT(0),
395 .hw
.init
= &(struct clk_init_data
){
396 .name
= "disp_cc_mdss_mdp_clk",
397 .parent_hws
= (const struct clk_hw
*[]){
398 &disp_cc_mdss_mdp_clk_src
.clkr
.hw
,
401 .flags
= CLK_SET_RATE_PARENT
,
402 .ops
= &clk_branch2_ops
,
407 static struct clk_branch disp_cc_mdss_mdp_lut_clk
= {
409 .halt_check
= BRANCH_HALT_VOTED
,
411 .enable_reg
= 0x2018,
412 .enable_mask
= BIT(0),
413 .hw
.init
= &(struct clk_init_data
){
414 .name
= "disp_cc_mdss_mdp_lut_clk",
415 .parent_hws
= (const struct clk_hw
*[]){
416 &disp_cc_mdss_mdp_clk_src
.clkr
.hw
,
419 .flags
= CLK_SET_RATE_PARENT
,
420 .ops
= &clk_branch2_ops
,
425 static struct clk_branch disp_cc_mdss_non_gdsc_ahb_clk
= {
427 .halt_check
= BRANCH_HALT_VOTED
,
429 .enable_reg
= 0x4004,
430 .enable_mask
= BIT(0),
431 .hw
.init
= &(struct clk_init_data
){
432 .name
= "disp_cc_mdss_non_gdsc_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_pclk0_clk
= {
445 .halt_check
= BRANCH_HALT
,
447 .enable_reg
= 0x2004,
448 .enable_mask
= BIT(0),
449 .hw
.init
= &(struct clk_init_data
){
450 .name
= "disp_cc_mdss_pclk0_clk",
451 .parent_hws
= (const struct clk_hw
*[]){
452 &disp_cc_mdss_pclk0_clk_src
.clkr
.hw
,
455 .flags
= CLK_SET_RATE_PARENT
| CLK_GET_RATE_NOCACHE
,
456 .ops
= &clk_branch2_ops
,
461 static struct clk_branch disp_cc_mdss_rot_clk
= {
463 .halt_check
= BRANCH_HALT
,
465 .enable_reg
= 0x2010,
466 .enable_mask
= BIT(0),
467 .hw
.init
= &(struct clk_init_data
){
468 .name
= "disp_cc_mdss_rot_clk",
469 .parent_hws
= (const struct clk_hw
*[]) {
470 &disp_cc_mdss_rot_clk_src
.clkr
.hw
,
473 .flags
= CLK_SET_RATE_PARENT
,
474 .ops
= &clk_branch2_ops
,
479 static struct clk_branch disp_cc_mdss_vsync_clk
= {
481 .halt_check
= BRANCH_HALT
,
483 .enable_reg
= 0x2020,
484 .enable_mask
= BIT(0),
485 .hw
.init
= &(struct clk_init_data
){
486 .name
= "disp_cc_mdss_vsync_clk",
487 .parent_hws
= (const struct clk_hw
*[]){
488 &disp_cc_mdss_vsync_clk_src
.clkr
.hw
,
491 .flags
= CLK_SET_RATE_PARENT
,
492 .ops
= &clk_branch2_ops
,
497 static struct clk_branch disp_cc_sleep_clk
= {
499 .halt_check
= BRANCH_HALT
,
501 .enable_reg
= 0x6068,
502 .enable_mask
= BIT(0),
503 .hw
.init
= &(struct clk_init_data
){
504 .name
= "disp_cc_sleep_clk",
505 .parent_hws
= (const struct clk_hw
*[]){
506 &disp_cc_sleep_clk_src
.clkr
.hw
,
509 .flags
= CLK_SET_RATE_PARENT
,
510 .ops
= &clk_branch2_ops
,
515 static struct gdsc mdss_gdsc
= {
520 .pwrsts
= PWRSTS_OFF_ON
,
524 static struct gdsc
*disp_cc_sm6115_gdscs
[] = {
525 [MDSS_GDSC
] = &mdss_gdsc
,
528 static struct clk_regmap
*disp_cc_sm6115_clocks
[] = {
529 [DISP_CC_PLL0
] = &disp_cc_pll0
.clkr
,
530 [DISP_CC_PLL0_OUT_MAIN
] = &disp_cc_pll0_out_main
.clkr
,
531 [DISP_CC_MDSS_AHB_CLK
] = &disp_cc_mdss_ahb_clk
.clkr
,
532 [DISP_CC_MDSS_AHB_CLK_SRC
] = &disp_cc_mdss_ahb_clk_src
.clkr
,
533 [DISP_CC_MDSS_BYTE0_CLK
] = &disp_cc_mdss_byte0_clk
.clkr
,
534 [DISP_CC_MDSS_BYTE0_CLK_SRC
] = &disp_cc_mdss_byte0_clk_src
.clkr
,
535 [DISP_CC_MDSS_BYTE0_DIV_CLK_SRC
] = &disp_cc_mdss_byte0_div_clk_src
.clkr
,
536 [DISP_CC_MDSS_BYTE0_INTF_CLK
] = &disp_cc_mdss_byte0_intf_clk
.clkr
,
537 [DISP_CC_MDSS_ESC0_CLK
] = &disp_cc_mdss_esc0_clk
.clkr
,
538 [DISP_CC_MDSS_ESC0_CLK_SRC
] = &disp_cc_mdss_esc0_clk_src
.clkr
,
539 [DISP_CC_MDSS_MDP_CLK
] = &disp_cc_mdss_mdp_clk
.clkr
,
540 [DISP_CC_MDSS_MDP_CLK_SRC
] = &disp_cc_mdss_mdp_clk_src
.clkr
,
541 [DISP_CC_MDSS_MDP_LUT_CLK
] = &disp_cc_mdss_mdp_lut_clk
.clkr
,
542 [DISP_CC_MDSS_NON_GDSC_AHB_CLK
] = &disp_cc_mdss_non_gdsc_ahb_clk
.clkr
,
543 [DISP_CC_MDSS_PCLK0_CLK
] = &disp_cc_mdss_pclk0_clk
.clkr
,
544 [DISP_CC_MDSS_PCLK0_CLK_SRC
] = &disp_cc_mdss_pclk0_clk_src
.clkr
,
545 [DISP_CC_MDSS_ROT_CLK
] = &disp_cc_mdss_rot_clk
.clkr
,
546 [DISP_CC_MDSS_ROT_CLK_SRC
] = &disp_cc_mdss_rot_clk_src
.clkr
,
547 [DISP_CC_MDSS_VSYNC_CLK
] = &disp_cc_mdss_vsync_clk
.clkr
,
548 [DISP_CC_MDSS_VSYNC_CLK_SRC
] = &disp_cc_mdss_vsync_clk_src
.clkr
,
549 [DISP_CC_SLEEP_CLK
] = &disp_cc_sleep_clk
.clkr
,
550 [DISP_CC_SLEEP_CLK_SRC
] = &disp_cc_sleep_clk_src
.clkr
,
553 static const struct regmap_config disp_cc_sm6115_regmap_config
= {
557 .max_register
= 0x10000,
561 static const struct qcom_cc_desc disp_cc_sm6115_desc
= {
562 .config
= &disp_cc_sm6115_regmap_config
,
563 .clks
= disp_cc_sm6115_clocks
,
564 .num_clks
= ARRAY_SIZE(disp_cc_sm6115_clocks
),
565 .gdscs
= disp_cc_sm6115_gdscs
,
566 .num_gdscs
= ARRAY_SIZE(disp_cc_sm6115_gdscs
),
569 static const struct of_device_id disp_cc_sm6115_match_table
[] = {
570 { .compatible
= "qcom,sm6115-dispcc" },
573 MODULE_DEVICE_TABLE(of
, disp_cc_sm6115_match_table
);
575 static int disp_cc_sm6115_probe(struct platform_device
*pdev
)
577 struct regmap
*regmap
;
580 regmap
= qcom_cc_map(pdev
, &disp_cc_sm6115_desc
);
582 return PTR_ERR(regmap
);
584 clk_alpha_pll_configure(&disp_cc_pll0
, regmap
, &disp_cc_pll0_config
);
586 /* Keep some clocks always-on */
587 qcom_branch_set_clk_en(regmap
, 0x604c); /* DISP_CC_XO_CLK */
589 ret
= qcom_cc_really_probe(&pdev
->dev
, &disp_cc_sm6115_desc
, regmap
);
591 dev_err(&pdev
->dev
, "Failed to register DISP CC clocks\n");
598 static struct platform_driver disp_cc_sm6115_driver
= {
599 .probe
= disp_cc_sm6115_probe
,
601 .name
= "dispcc-sm6115",
602 .of_match_table
= disp_cc_sm6115_match_table
,
606 module_platform_driver(disp_cc_sm6115_driver
);
607 MODULE_DESCRIPTION("Qualcomm SM6115 Display Clock controller");
608 MODULE_LICENSE("GPL");