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