589 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.4 * Copyright (c) 2023, Linaro Limited5 */6 7#include <linux/clk-provider.h>8#include <linux/module.h>9#include <linux/platform_device.h>10#include <linux/pm_clock.h>11#include <linux/pm_runtime.h>12#include <linux/regmap.h>13 14#include <dt-bindings/clock/qcom,sm8350-videocc.h>15#include <dt-bindings/reset/qcom,sm8350-videocc.h>16 17#include "clk-alpha-pll.h"18#include "clk-branch.h"19#include "clk-rcg.h"20#include "clk-regmap.h"21#include "clk-regmap-divider.h"22#include "common.h"23#include "reset.h"24#include "gdsc.h"25 26enum {27 DT_BI_TCXO,28 DT_BI_TCXO_AO,29 DT_SLEEP_CLK,30};31 32enum {33 P_BI_TCXO,34 P_BI_TCXO_AO,35 P_SLEEP_CLK,36 P_VIDEO_PLL0_OUT_MAIN,37 P_VIDEO_PLL1_OUT_MAIN,38};39 40static const struct pll_vco lucid_5lpe_vco[] = {41 { 249600000, 1750000000, 0 },42};43 44static const struct pll_vco lucid_5lpe_vco_8280xp[] = {45 { 249600000, 1800000000, 0 },46};47 48static const struct alpha_pll_config video_pll0_config = {49 .l = 0x25,50 .alpha = 0x8000,51 .config_ctl_val = 0x20485699,52 .config_ctl_hi_val = 0x00002261,53 .config_ctl_hi1_val = 0x2a9a699c,54 .test_ctl_val = 0x00000000,55 .test_ctl_hi_val = 0x00000000,56 .test_ctl_hi1_val = 0x01800000,57 .user_ctl_val = 0x00000000,58 .user_ctl_hi_val = 0x00000805,59 .user_ctl_hi1_val = 0x00000000,60};61 62static struct clk_alpha_pll video_pll0 = {63 .offset = 0x42c,64 .vco_table = lucid_5lpe_vco,65 .num_vco = ARRAY_SIZE(lucid_5lpe_vco),66 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],67 .clkr = {68 .hw.init = &(const struct clk_init_data) {69 .name = "video_pll0",70 .parent_data = &(const struct clk_parent_data){71 .index = DT_BI_TCXO,72 },73 .num_parents = 1,74 .ops = &clk_alpha_pll_lucid_5lpe_ops,75 },76 },77};78 79static const struct alpha_pll_config video_pll1_config = {80 .l = 0x2b,81 .alpha = 0xc000,82 .config_ctl_val = 0x20485699,83 .config_ctl_hi_val = 0x00002261,84 .config_ctl_hi1_val = 0x2a9a699c,85 .test_ctl_val = 0x00000000,86 .test_ctl_hi_val = 0x00000000,87 .test_ctl_hi1_val = 0x01800000,88 .user_ctl_val = 0x00000000,89 .user_ctl_hi_val = 0x00000805,90 .user_ctl_hi1_val = 0x00000000,91};92 93static struct clk_alpha_pll video_pll1 = {94 .offset = 0x7d0,95 .vco_table = lucid_5lpe_vco,96 .num_vco = ARRAY_SIZE(lucid_5lpe_vco),97 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],98 .clkr = {99 .hw.init = &(const struct clk_init_data) {100 .name = "video_pll1",101 .parent_data = &(const struct clk_parent_data){102 .index = DT_BI_TCXO,103 },104 .num_parents = 1,105 .ops = &clk_alpha_pll_lucid_5lpe_ops,106 },107 },108};109 110static const struct parent_map video_cc_parent_map_0[] = {111 { P_BI_TCXO_AO, 0 },112};113 114static const struct clk_parent_data video_cc_parent_data_0[] = {115 { .index = DT_BI_TCXO_AO },116};117 118static const struct parent_map video_cc_parent_map_1[] = {119 { P_BI_TCXO, 0 },120 { P_VIDEO_PLL0_OUT_MAIN, 1 },121};122 123static const struct clk_parent_data video_cc_parent_data_1[] = {124 { .index = DT_BI_TCXO },125 { .hw = &video_pll0.clkr.hw },126};127 128static const struct parent_map video_cc_parent_map_2[] = {129 { P_BI_TCXO, 0 },130 { P_VIDEO_PLL1_OUT_MAIN, 1 },131};132 133static const struct clk_parent_data video_cc_parent_data_2[] = {134 { .index = DT_BI_TCXO },135 { .hw = &video_pll1.clkr.hw },136};137 138static const struct freq_tbl ftbl_video_cc_ahb_clk_src[] = {139 F(19200000, P_BI_TCXO, 1, 0, 0),140 { }141};142 143static struct clk_rcg2 video_cc_ahb_clk_src = {144 .cmd_rcgr = 0xbd4,145 .mnd_width = 0,146 .hid_width = 5,147 .parent_map = video_cc_parent_map_0,148 .freq_tbl = ftbl_video_cc_ahb_clk_src,149 .clkr.hw.init = &(const struct clk_init_data) {150 .name = "video_cc_ahb_clk_src",151 .parent_data = video_cc_parent_data_0,152 .num_parents = ARRAY_SIZE(video_cc_parent_data_0),153 .flags = CLK_SET_RATE_PARENT,154 .ops = &clk_rcg2_shared_ops,155 },156};157 158static const struct freq_tbl ftbl_video_cc_mvs0_clk_src[] = {159 F(720000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0),160 F(1014000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0),161 F(1098000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0),162 F(1332000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0),163 { }164};165 166static const struct freq_tbl ftbl_video_cc_mvs0_clk_src_8280xp[] = {167 F(720000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0),168 F(1014000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0),169 F(1098000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0),170 F(1332000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0),171 F(1599000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0),172 F(1680000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0),173 { }174};175 176static struct clk_rcg2 video_cc_mvs0_clk_src = {177 .cmd_rcgr = 0xb94,178 .mnd_width = 0,179 .hid_width = 5,180 .parent_map = video_cc_parent_map_1,181 .freq_tbl = ftbl_video_cc_mvs0_clk_src,182 .clkr.hw.init = &(const struct clk_init_data) {183 .name = "video_cc_mvs0_clk_src",184 .parent_data = video_cc_parent_data_1,185 .num_parents = ARRAY_SIZE(video_cc_parent_data_1),186 .flags = CLK_SET_RATE_PARENT,187 .ops = &clk_rcg2_shared_ops,188 },189};190 191static const struct freq_tbl ftbl_video_cc_mvs1_clk_src[] = {192 F(840000000, P_VIDEO_PLL1_OUT_MAIN, 1, 0, 0),193 F(1098000000, P_VIDEO_PLL1_OUT_MAIN, 1, 0, 0),194 F(1332000000, P_VIDEO_PLL1_OUT_MAIN, 1, 0, 0),195 { }196};197 198static const struct freq_tbl ftbl_video_cc_mvs1_clk_src_8280xp[] = {199 F(840000000, P_VIDEO_PLL1_OUT_MAIN, 1, 0, 0),200 F(1098000000, P_VIDEO_PLL1_OUT_MAIN, 1, 0, 0),201 F(1332000000, P_VIDEO_PLL1_OUT_MAIN, 1, 0, 0),202 F(1600000000, P_VIDEO_PLL1_OUT_MAIN, 1, 0, 0),203 F(1800000000, P_VIDEO_PLL1_OUT_MAIN, 1, 0, 0),204 { }205};206 207static struct clk_rcg2 video_cc_mvs1_clk_src = {208 .cmd_rcgr = 0xbb4,209 .mnd_width = 0,210 .hid_width = 5,211 .parent_map = video_cc_parent_map_2,212 .freq_tbl = ftbl_video_cc_mvs1_clk_src,213 .clkr.hw.init = &(const struct clk_init_data) {214 .name = "video_cc_mvs1_clk_src",215 .parent_data = video_cc_parent_data_2,216 .num_parents = ARRAY_SIZE(video_cc_parent_data_2),217 .flags = CLK_SET_RATE_PARENT,218 .ops = &clk_rcg2_shared_ops,219 },220};221 222static const struct freq_tbl ftbl_video_cc_sleep_clk_src[] = {223 F(32000, P_SLEEP_CLK, 1, 0, 0),224 { }225};226 227static struct clk_rcg2 video_cc_sleep_clk_src = {228 .cmd_rcgr = 0xef0,229 .mnd_width = 0,230 .hid_width = 5,231 .freq_tbl = ftbl_video_cc_sleep_clk_src,232 .clkr.hw.init = &(const struct clk_init_data) {233 .name = "video_cc_sleep_clk_src",234 .parent_data = &(const struct clk_parent_data){235 .index = DT_SLEEP_CLK,236 },237 .num_parents = 1,238 .flags = CLK_SET_RATE_PARENT,239 .ops = &clk_rcg2_ops,240 },241};242 243static struct clk_rcg2 video_cc_xo_clk_src = {244 .cmd_rcgr = 0xecc,245 .mnd_width = 0,246 .hid_width = 5,247 .parent_map = video_cc_parent_map_0,248 .freq_tbl = ftbl_video_cc_ahb_clk_src,249 .clkr.hw.init = &(const struct clk_init_data) {250 .name = "video_cc_xo_clk_src",251 .parent_data = video_cc_parent_data_0,252 .num_parents = ARRAY_SIZE(video_cc_parent_data_0),253 .flags = CLK_SET_RATE_PARENT,254 .ops = &clk_rcg2_ops,255 },256};257 258static struct clk_regmap_div video_cc_mvs0_div_clk_src = {259 .reg = 0xd54,260 .shift = 0,261 .width = 4,262 .clkr.hw.init = &(const struct clk_init_data) {263 .name = "video_cc_mvs0_div_clk_src",264 .parent_hws = (const struct clk_hw*[]){265 &video_cc_mvs0_clk_src.clkr.hw,266 },267 .num_parents = 1,268 .flags = CLK_SET_RATE_PARENT,269 .ops = &clk_regmap_div_ro_ops,270 },271};272 273static struct clk_regmap_div video_cc_mvs0c_div2_div_clk_src = {274 .reg = 0xc54,275 .shift = 0,276 .width = 4,277 .clkr.hw.init = &(const struct clk_init_data) {278 .name = "video_cc_mvs0c_div2_div_clk_src",279 .parent_hws = (const struct clk_hw*[]){280 &video_cc_mvs0_clk_src.clkr.hw,281 },282 .num_parents = 1,283 .flags = CLK_SET_RATE_PARENT,284 .ops = &clk_regmap_div_ro_ops,285 },286};287 288static struct clk_regmap_div video_cc_mvs1_div_clk_src = {289 .reg = 0xdd4,290 .shift = 0,291 .width = 4,292 .clkr.hw.init = &(const struct clk_init_data) {293 .name = "video_cc_mvs1_div_clk_src",294 .parent_hws = (const struct clk_hw*[]){295 &video_cc_mvs1_clk_src.clkr.hw,296 },297 .num_parents = 1,298 .flags = CLK_SET_RATE_PARENT,299 .ops = &clk_regmap_div_ro_ops,300 },301};302 303static struct clk_regmap_div video_cc_mvs1c_div2_div_clk_src = {304 .reg = 0xcf4,305 .shift = 0,306 .width = 4,307 .clkr.hw.init = &(const struct clk_init_data) {308 .name = "video_cc_mvs1c_div2_div_clk_src",309 .parent_hws = (const struct clk_hw*[]){310 &video_cc_mvs1_clk_src.clkr.hw,311 },312 .num_parents = 1,313 .flags = CLK_SET_RATE_PARENT,314 .ops = &clk_regmap_div_ro_ops,315 },316};317 318static struct clk_branch video_cc_mvs0_clk = {319 .halt_reg = 0xd34,320 .halt_check = BRANCH_HALT_VOTED,321 .hwcg_reg = 0xd34,322 .hwcg_bit = 1,323 .clkr = {324 .enable_reg = 0xd34,325 .enable_mask = BIT(0),326 .hw.init = &(const struct clk_init_data) {327 .name = "video_cc_mvs0_clk",328 .parent_hws = (const struct clk_hw*[]){329 &video_cc_mvs0_div_clk_src.clkr.hw,330 },331 .num_parents = 1,332 .flags = CLK_SET_RATE_PARENT,333 .ops = &clk_branch2_ops,334 },335 },336};337 338static struct clk_branch video_cc_mvs0c_clk = {339 .halt_reg = 0xc34,340 .halt_check = BRANCH_HALT,341 .clkr = {342 .enable_reg = 0xc34,343 .enable_mask = BIT(0),344 .hw.init = &(const struct clk_init_data) {345 .name = "video_cc_mvs0c_clk",346 .parent_hws = (const struct clk_hw*[]){347 &video_cc_mvs0c_div2_div_clk_src.clkr.hw,348 },349 .num_parents = 1,350 .flags = CLK_SET_RATE_PARENT,351 .ops = &clk_branch2_ops,352 },353 },354};355 356static struct clk_branch video_cc_mvs1_clk = {357 .halt_reg = 0xdb4,358 .halt_check = BRANCH_HALT_VOTED,359 .hwcg_reg = 0xdb4,360 .hwcg_bit = 1,361 .clkr = {362 .enable_reg = 0xdb4,363 .enable_mask = BIT(0),364 .hw.init = &(const struct clk_init_data) {365 .name = "video_cc_mvs1_clk",366 .parent_hws = (const struct clk_hw*[]){367 &video_cc_mvs1_div_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 video_cc_mvs1_div2_clk = {377 .halt_reg = 0xdf4,378 .halt_check = BRANCH_HALT_VOTED,379 .hwcg_reg = 0xdf4,380 .hwcg_bit = 1,381 .clkr = {382 .enable_reg = 0xdf4,383 .enable_mask = BIT(0),384 .hw.init = &(const struct clk_init_data) {385 .name = "video_cc_mvs1_div2_clk",386 .parent_hws = (const struct clk_hw*[]){387 &video_cc_mvs1c_div2_div_clk_src.clkr.hw,388 },389 .num_parents = 1,390 .flags = CLK_SET_RATE_PARENT,391 .ops = &clk_branch2_ops,392 },393 },394};395 396static struct clk_branch video_cc_mvs1c_clk = {397 .halt_reg = 0xcd4,398 .halt_check = BRANCH_HALT,399 .clkr = {400 .enable_reg = 0xcd4,401 .enable_mask = BIT(0),402 .hw.init = &(const struct clk_init_data) {403 .name = "video_cc_mvs1c_clk",404 .parent_hws = (const struct clk_hw*[]){405 &video_cc_mvs1c_div2_div_clk_src.clkr.hw,406 },407 .num_parents = 1,408 .flags = CLK_SET_RATE_PARENT,409 .ops = &clk_branch2_ops,410 },411 },412};413 414static struct clk_branch video_cc_sleep_clk = {415 .halt_reg = 0xf10,416 .halt_check = BRANCH_HALT,417 .clkr = {418 .enable_reg = 0xf10,419 .enable_mask = BIT(0),420 .hw.init = &(const struct clk_init_data) {421 .name = "video_cc_sleep_clk",422 .parent_hws = (const struct clk_hw*[]){423 &video_cc_sleep_clk_src.clkr.hw,424 },425 .num_parents = 1,426 .flags = CLK_SET_RATE_PARENT,427 .ops = &clk_branch2_ops,428 },429 },430};431 432static struct gdsc mvs0c_gdsc = {433 .gdscr = 0xbf8,434 .pd = {435 .name = "mvs0c_gdsc",436 },437 .flags = RETAIN_FF_ENABLE,438 .pwrsts = PWRSTS_OFF_ON,439};440 441static struct gdsc mvs1c_gdsc = {442 .gdscr = 0xc98,443 .pd = {444 .name = "mvs1c_gdsc",445 },446 .flags = RETAIN_FF_ENABLE,447 .pwrsts = PWRSTS_OFF_ON,448};449 450static struct gdsc mvs0_gdsc = {451 .gdscr = 0xd18,452 .pd = {453 .name = "mvs0_gdsc",454 },455 .flags = HW_CTRL_TRIGGER | RETAIN_FF_ENABLE,456 .pwrsts = PWRSTS_OFF_ON,457};458 459static struct gdsc mvs1_gdsc = {460 .gdscr = 0xd98,461 .pd = {462 .name = "mvs1_gdsc",463 },464 .flags = HW_CTRL_TRIGGER | RETAIN_FF_ENABLE,465 .pwrsts = PWRSTS_OFF_ON,466};467 468static struct clk_regmap *video_cc_sm8350_clocks[] = {469 [VIDEO_CC_AHB_CLK_SRC] = &video_cc_ahb_clk_src.clkr,470 [VIDEO_CC_MVS0_CLK] = &video_cc_mvs0_clk.clkr,471 [VIDEO_CC_MVS0_CLK_SRC] = &video_cc_mvs0_clk_src.clkr,472 [VIDEO_CC_MVS0_DIV_CLK_SRC] = &video_cc_mvs0_div_clk_src.clkr,473 [VIDEO_CC_MVS0C_CLK] = &video_cc_mvs0c_clk.clkr,474 [VIDEO_CC_MVS0C_DIV2_DIV_CLK_SRC] = &video_cc_mvs0c_div2_div_clk_src.clkr,475 [VIDEO_CC_MVS1_CLK] = &video_cc_mvs1_clk.clkr,476 [VIDEO_CC_MVS1_CLK_SRC] = &video_cc_mvs1_clk_src.clkr,477 [VIDEO_CC_MVS1_DIV2_CLK] = &video_cc_mvs1_div2_clk.clkr,478 [VIDEO_CC_MVS1_DIV_CLK_SRC] = &video_cc_mvs1_div_clk_src.clkr,479 [VIDEO_CC_MVS1C_CLK] = &video_cc_mvs1c_clk.clkr,480 [VIDEO_CC_MVS1C_DIV2_DIV_CLK_SRC] = &video_cc_mvs1c_div2_div_clk_src.clkr,481 [VIDEO_CC_SLEEP_CLK] = &video_cc_sleep_clk.clkr,482 [VIDEO_CC_SLEEP_CLK_SRC] = &video_cc_sleep_clk_src.clkr,483 [VIDEO_CC_XO_CLK_SRC] = &video_cc_xo_clk_src.clkr,484 [VIDEO_PLL0] = &video_pll0.clkr,485 [VIDEO_PLL1] = &video_pll1.clkr,486};487 488static const struct qcom_reset_map video_cc_sm8350_resets[] = {489 [VIDEO_CC_CVP_INTERFACE_BCR] = { 0xe54 },490 [VIDEO_CC_CVP_MVS0_BCR] = { 0xd14 },491 [VIDEO_CC_MVS0C_CLK_ARES] = { .reg = 0xc34, .bit = 2, .udelay = 400 },492 [VIDEO_CC_CVP_MVS0C_BCR] = { 0xbf4 },493 [VIDEO_CC_CVP_MVS1_BCR] = { 0xd94 },494 [VIDEO_CC_MVS1C_CLK_ARES] = { .reg = 0xcd4, .bit = 2, .udelay = 400 },495 [VIDEO_CC_CVP_MVS1C_BCR] = { 0xc94 },496};497 498static struct gdsc *video_cc_sm8350_gdscs[] = {499 [MVS0C_GDSC] = &mvs0c_gdsc,500 [MVS1C_GDSC] = &mvs1c_gdsc,501 [MVS0_GDSC] = &mvs0_gdsc,502 [MVS1_GDSC] = &mvs1_gdsc,503};504 505static const struct regmap_config video_cc_sm8350_regmap_config = {506 .reg_bits = 32,507 .reg_stride = 4,508 .val_bits = 32,509 .max_register = 0x10000,510 .fast_io = true,511};512 513static struct qcom_cc_desc video_cc_sm8350_desc = {514 .config = &video_cc_sm8350_regmap_config,515 .clks = video_cc_sm8350_clocks,516 .num_clks = ARRAY_SIZE(video_cc_sm8350_clocks),517 .resets = video_cc_sm8350_resets,518 .num_resets = ARRAY_SIZE(video_cc_sm8350_resets),519 .gdscs = video_cc_sm8350_gdscs,520 .num_gdscs = ARRAY_SIZE(video_cc_sm8350_gdscs),521};522 523static int video_cc_sm8350_probe(struct platform_device *pdev)524{525 u32 video_cc_xo_clk_cbcr = 0xeec;526 struct regmap *regmap;527 int ret;528 529 ret = devm_pm_runtime_enable(&pdev->dev);530 if (ret)531 return ret;532 533 ret = pm_runtime_resume_and_get(&pdev->dev);534 if (ret)535 return ret;536 537 if (of_device_is_compatible(pdev->dev.of_node, "qcom,sc8280xp-videocc")) {538 video_cc_sleep_clk_src.cmd_rcgr = 0xf38;539 video_cc_sleep_clk.halt_reg = 0xf58;540 video_cc_sleep_clk.clkr.enable_reg = 0xf58;541 video_cc_xo_clk_src.cmd_rcgr = 0xf14;542 video_cc_xo_clk_cbcr = 0xf34;543 544 video_pll0.vco_table = video_pll1.vco_table = lucid_5lpe_vco_8280xp;545 /* No change, but assign it for completeness */546 video_pll0.num_vco = video_pll1.num_vco = ARRAY_SIZE(lucid_5lpe_vco_8280xp);547 548 video_cc_mvs0_clk_src.freq_tbl = ftbl_video_cc_mvs0_clk_src_8280xp;549 video_cc_mvs1_clk_src.freq_tbl = ftbl_video_cc_mvs1_clk_src_8280xp;550 }551 552 regmap = qcom_cc_map(pdev, &video_cc_sm8350_desc);553 if (IS_ERR(regmap)) {554 pm_runtime_put(&pdev->dev);555 return PTR_ERR(regmap);556 }557 558 clk_lucid_pll_configure(&video_pll0, regmap, &video_pll0_config);559 clk_lucid_pll_configure(&video_pll1, regmap, &video_pll1_config);560 561 /* Keep some clocks always-on */562 qcom_branch_set_clk_en(regmap, 0xe58); /* VIDEO_CC_AHB_CLK */563 qcom_branch_set_clk_en(regmap, video_cc_xo_clk_cbcr); /* VIDEO_CC_XO_CLK */564 565 ret = qcom_cc_really_probe(&pdev->dev, &video_cc_sm8350_desc, regmap);566 pm_runtime_put(&pdev->dev);567 568 return ret;569}570 571static const struct of_device_id video_cc_sm8350_match_table[] = {572 { .compatible = "qcom,sc8280xp-videocc" },573 { .compatible = "qcom,sm8350-videocc" },574 { }575};576MODULE_DEVICE_TABLE(of, video_cc_sm8350_match_table);577 578static struct platform_driver video_cc_sm8350_driver = {579 .probe = video_cc_sm8350_probe,580 .driver = {581 .name = "sm8350-videocc",582 .of_match_table = video_cc_sm8350_match_table,583 },584};585module_platform_driver(video_cc_sm8350_driver);586 587MODULE_DESCRIPTION("QTI SM8350 VIDEOCC Driver");588MODULE_LICENSE("GPL");589