450 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.4 */5 6#include <linux/clk-provider.h>7#include <linux/mod_devicetable.h>8#include <linux/module.h>9#include <linux/platform_device.h>10#include <linux/pm_runtime.h>11#include <linux/regmap.h>12 13#include <dt-bindings/clock/qcom,sm8450-videocc.h>14 15#include "clk-alpha-pll.h"16#include "clk-branch.h"17#include "clk-rcg.h"18#include "clk-regmap.h"19#include "clk-regmap-divider.h"20#include "common.h"21#include "gdsc.h"22#include "reset.h"23 24enum {25 DT_BI_TCXO,26};27 28enum {29 P_BI_TCXO,30 P_VIDEO_CC_PLL0_OUT_MAIN,31 P_VIDEO_CC_PLL1_OUT_MAIN,32};33 34static const struct pll_vco lucid_evo_vco[] = {35 { 249600000, 2020000000, 0 },36};37 38static const struct alpha_pll_config video_cc_pll0_config = {39 /* .l includes CAL_L_VAL, L_VAL fields */40 .l = 0x0044001e,41 .alpha = 0x0,42 .config_ctl_val = 0x20485699,43 .config_ctl_hi_val = 0x00182261,44 .config_ctl_hi1_val = 0x32aa299c,45 .user_ctl_val = 0x00000000,46 .user_ctl_hi_val = 0x00000805,47};48 49static struct clk_alpha_pll video_cc_pll0 = {50 .offset = 0x0,51 .vco_table = lucid_evo_vco,52 .num_vco = ARRAY_SIZE(lucid_evo_vco),53 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],54 .clkr = {55 .hw.init = &(const struct clk_init_data) {56 .name = "video_cc_pll0",57 .parent_data = &(const struct clk_parent_data) {58 .index = DT_BI_TCXO,59 },60 .num_parents = 1,61 .ops = &clk_alpha_pll_lucid_evo_ops,62 },63 },64};65 66static const struct alpha_pll_config video_cc_pll1_config = {67 /* .l includes CAL_L_VAL, L_VAL fields */68 .l = 0x0044002b,69 .alpha = 0xc000,70 .config_ctl_val = 0x20485699,71 .config_ctl_hi_val = 0x00182261,72 .config_ctl_hi1_val = 0x32aa299c,73 .user_ctl_val = 0x00000000,74 .user_ctl_hi_val = 0x00000805,75};76 77static struct clk_alpha_pll video_cc_pll1 = {78 .offset = 0x1000,79 .vco_table = lucid_evo_vco,80 .num_vco = ARRAY_SIZE(lucid_evo_vco),81 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],82 .clkr = {83 .hw.init = &(const struct clk_init_data) {84 .name = "video_cc_pll1",85 .parent_data = &(const struct clk_parent_data) {86 .index = DT_BI_TCXO,87 },88 .num_parents = 1,89 .ops = &clk_alpha_pll_lucid_evo_ops,90 },91 },92};93 94static const struct parent_map video_cc_parent_map_0[] = {95 { P_BI_TCXO, 0 },96 { P_VIDEO_CC_PLL0_OUT_MAIN, 1 },97};98 99static const struct clk_parent_data video_cc_parent_data_0[] = {100 { .index = DT_BI_TCXO },101 { .hw = &video_cc_pll0.clkr.hw },102};103 104static const struct parent_map video_cc_parent_map_1[] = {105 { P_BI_TCXO, 0 },106 { P_VIDEO_CC_PLL1_OUT_MAIN, 1 },107};108 109static const struct clk_parent_data video_cc_parent_data_1[] = {110 { .index = DT_BI_TCXO },111 { .hw = &video_cc_pll1.clkr.hw },112};113 114static const struct freq_tbl ftbl_video_cc_mvs0_clk_src[] = {115 F(576000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),116 F(720000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),117 F(1014000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),118 F(1098000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),119 F(1332000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),120 { }121};122 123static struct clk_rcg2 video_cc_mvs0_clk_src = {124 .cmd_rcgr = 0x8000,125 .mnd_width = 0,126 .hid_width = 5,127 .parent_map = video_cc_parent_map_0,128 .freq_tbl = ftbl_video_cc_mvs0_clk_src,129 .clkr.hw.init = &(const struct clk_init_data) {130 .name = "video_cc_mvs0_clk_src",131 .parent_data = video_cc_parent_data_0,132 .num_parents = ARRAY_SIZE(video_cc_parent_data_0),133 .flags = CLK_SET_RATE_PARENT,134 .ops = &clk_rcg2_shared_ops,135 },136};137 138static const struct freq_tbl ftbl_video_cc_mvs1_clk_src[] = {139 F(840000000, P_VIDEO_CC_PLL1_OUT_MAIN, 1, 0, 0),140 F(1050000000, P_VIDEO_CC_PLL1_OUT_MAIN, 1, 0, 0),141 F(1350000000, P_VIDEO_CC_PLL1_OUT_MAIN, 1, 0, 0),142 F(1500000000, P_VIDEO_CC_PLL1_OUT_MAIN, 1, 0, 0),143 F(1650000000, P_VIDEO_CC_PLL1_OUT_MAIN, 1, 0, 0),144 { }145};146 147static struct clk_rcg2 video_cc_mvs1_clk_src = {148 .cmd_rcgr = 0x8018,149 .mnd_width = 0,150 .hid_width = 5,151 .parent_map = video_cc_parent_map_1,152 .freq_tbl = ftbl_video_cc_mvs1_clk_src,153 .clkr.hw.init = &(const struct clk_init_data) {154 .name = "video_cc_mvs1_clk_src",155 .parent_data = video_cc_parent_data_1,156 .num_parents = ARRAY_SIZE(video_cc_parent_data_1),157 .flags = CLK_SET_RATE_PARENT,158 .ops = &clk_rcg2_shared_ops,159 },160};161 162static struct clk_regmap_div video_cc_mvs0_div_clk_src = {163 .reg = 0x80b8,164 .shift = 0,165 .width = 4,166 .clkr.hw.init = &(const struct clk_init_data) {167 .name = "video_cc_mvs0_div_clk_src",168 .parent_hws = (const struct clk_hw*[]) {169 &video_cc_mvs0_clk_src.clkr.hw,170 },171 .num_parents = 1,172 .flags = CLK_SET_RATE_PARENT,173 .ops = &clk_regmap_div_ro_ops,174 },175};176 177static struct clk_regmap_div video_cc_mvs0c_div2_div_clk_src = {178 .reg = 0x806c,179 .shift = 0,180 .width = 4,181 .clkr.hw.init = &(const struct clk_init_data) {182 .name = "video_cc_mvs0c_div2_div_clk_src",183 .parent_hws = (const struct clk_hw*[]) {184 &video_cc_mvs0_clk_src.clkr.hw,185 },186 .num_parents = 1,187 .flags = CLK_SET_RATE_PARENT,188 .ops = &clk_regmap_div_ro_ops,189 },190};191 192static struct clk_regmap_div video_cc_mvs1_div_clk_src = {193 .reg = 0x80dc,194 .shift = 0,195 .width = 4,196 .clkr.hw.init = &(const struct clk_init_data) {197 .name = "video_cc_mvs1_div_clk_src",198 .parent_hws = (const struct clk_hw*[]) {199 &video_cc_mvs1_clk_src.clkr.hw,200 },201 .num_parents = 1,202 .flags = CLK_SET_RATE_PARENT,203 .ops = &clk_regmap_div_ro_ops,204 },205};206 207static struct clk_regmap_div video_cc_mvs1c_div2_div_clk_src = {208 .reg = 0x8094,209 .shift = 0,210 .width = 4,211 .clkr.hw.init = &(const struct clk_init_data) {212 .name = "video_cc_mvs1c_div2_div_clk_src",213 .parent_hws = (const struct clk_hw*[]) {214 &video_cc_mvs1_clk_src.clkr.hw,215 },216 .num_parents = 1,217 .flags = CLK_SET_RATE_PARENT,218 .ops = &clk_regmap_div_ro_ops,219 },220};221 222static struct clk_branch video_cc_mvs0_clk = {223 .halt_reg = 0x80b0,224 .halt_check = BRANCH_HALT_SKIP,225 .hwcg_reg = 0x80b0,226 .hwcg_bit = 1,227 .clkr = {228 .enable_reg = 0x80b0,229 .enable_mask = BIT(0),230 .hw.init = &(const struct clk_init_data) {231 .name = "video_cc_mvs0_clk",232 .parent_hws = (const struct clk_hw*[]) {233 &video_cc_mvs0_div_clk_src.clkr.hw,234 },235 .num_parents = 1,236 .flags = CLK_SET_RATE_PARENT,237 .ops = &clk_branch2_ops,238 },239 },240};241 242static struct clk_branch video_cc_mvs0c_clk = {243 .halt_reg = 0x8064,244 .halt_check = BRANCH_HALT,245 .clkr = {246 .enable_reg = 0x8064,247 .enable_mask = BIT(0),248 .hw.init = &(const struct clk_init_data) {249 .name = "video_cc_mvs0c_clk",250 .parent_hws = (const struct clk_hw*[]) {251 &video_cc_mvs0c_div2_div_clk_src.clkr.hw,252 },253 .num_parents = 1,254 .flags = CLK_SET_RATE_PARENT,255 .ops = &clk_branch2_ops,256 },257 },258};259 260static struct clk_branch video_cc_mvs1_clk = {261 .halt_reg = 0x80d4,262 .halt_check = BRANCH_HALT_SKIP,263 .hwcg_reg = 0x80d4,264 .hwcg_bit = 1,265 .clkr = {266 .enable_reg = 0x80d4,267 .enable_mask = BIT(0),268 .hw.init = &(const struct clk_init_data) {269 .name = "video_cc_mvs1_clk",270 .parent_hws = (const struct clk_hw*[]) {271 &video_cc_mvs1_div_clk_src.clkr.hw,272 },273 .num_parents = 1,274 .flags = CLK_SET_RATE_PARENT,275 .ops = &clk_branch2_ops,276 },277 },278};279 280static struct clk_branch video_cc_mvs1c_clk = {281 .halt_reg = 0x808c,282 .halt_check = BRANCH_HALT,283 .clkr = {284 .enable_reg = 0x808c,285 .enable_mask = BIT(0),286 .hw.init = &(const struct clk_init_data) {287 .name = "video_cc_mvs1c_clk",288 .parent_hws = (const struct clk_hw*[]) {289 &video_cc_mvs1c_div2_div_clk_src.clkr.hw,290 },291 .num_parents = 1,292 .flags = CLK_SET_RATE_PARENT,293 .ops = &clk_branch2_ops,294 },295 },296};297 298static struct gdsc video_cc_mvs0c_gdsc = {299 .gdscr = 0x804c,300 .en_rest_wait_val = 0x2,301 .en_few_wait_val = 0x2,302 .clk_dis_wait_val = 0x6,303 .pd = {304 .name = "video_cc_mvs0c_gdsc",305 },306 .pwrsts = PWRSTS_OFF_ON,307 .flags = RETAIN_FF_ENABLE,308};309 310static struct gdsc video_cc_mvs0_gdsc = {311 .gdscr = 0x809c,312 .en_rest_wait_val = 0x2,313 .en_few_wait_val = 0x2,314 .clk_dis_wait_val = 0x6,315 .pd = {316 .name = "video_cc_mvs0_gdsc",317 },318 .pwrsts = PWRSTS_OFF_ON,319 .parent = &video_cc_mvs0c_gdsc.pd,320 .flags = RETAIN_FF_ENABLE | HW_CTRL,321};322 323static struct gdsc video_cc_mvs1c_gdsc = {324 .gdscr = 0x8074,325 .en_rest_wait_val = 0x2,326 .en_few_wait_val = 0x2,327 .clk_dis_wait_val = 0x6,328 .pd = {329 .name = "video_cc_mvs1c_gdsc",330 },331 .pwrsts = PWRSTS_OFF_ON,332 .flags = RETAIN_FF_ENABLE,333};334 335static struct gdsc video_cc_mvs1_gdsc = {336 .gdscr = 0x80c0,337 .en_rest_wait_val = 0x2,338 .en_few_wait_val = 0x2,339 .clk_dis_wait_val = 0x6,340 .pd = {341 .name = "video_cc_mvs1_gdsc",342 },343 .pwrsts = PWRSTS_OFF_ON,344 .parent = &video_cc_mvs1c_gdsc.pd,345 .flags = RETAIN_FF_ENABLE | HW_CTRL,346};347 348static struct clk_regmap *video_cc_sm8450_clocks[] = {349 [VIDEO_CC_MVS0_CLK] = &video_cc_mvs0_clk.clkr,350 [VIDEO_CC_MVS0_CLK_SRC] = &video_cc_mvs0_clk_src.clkr,351 [VIDEO_CC_MVS0_DIV_CLK_SRC] = &video_cc_mvs0_div_clk_src.clkr,352 [VIDEO_CC_MVS0C_CLK] = &video_cc_mvs0c_clk.clkr,353 [VIDEO_CC_MVS0C_DIV2_DIV_CLK_SRC] = &video_cc_mvs0c_div2_div_clk_src.clkr,354 [VIDEO_CC_MVS1_CLK] = &video_cc_mvs1_clk.clkr,355 [VIDEO_CC_MVS1_CLK_SRC] = &video_cc_mvs1_clk_src.clkr,356 [VIDEO_CC_MVS1_DIV_CLK_SRC] = &video_cc_mvs1_div_clk_src.clkr,357 [VIDEO_CC_MVS1C_CLK] = &video_cc_mvs1c_clk.clkr,358 [VIDEO_CC_MVS1C_DIV2_DIV_CLK_SRC] = &video_cc_mvs1c_div2_div_clk_src.clkr,359 [VIDEO_CC_PLL0] = &video_cc_pll0.clkr,360 [VIDEO_CC_PLL1] = &video_cc_pll1.clkr,361};362 363static struct gdsc *video_cc_sm8450_gdscs[] = {364 [VIDEO_CC_MVS0C_GDSC] = &video_cc_mvs0c_gdsc,365 [VIDEO_CC_MVS0_GDSC] = &video_cc_mvs0_gdsc,366 [VIDEO_CC_MVS1C_GDSC] = &video_cc_mvs1c_gdsc,367 [VIDEO_CC_MVS1_GDSC] = &video_cc_mvs1_gdsc,368};369 370static const struct qcom_reset_map video_cc_sm8450_resets[] = {371 [CVP_VIDEO_CC_INTERFACE_BCR] = { 0x80e0 },372 [CVP_VIDEO_CC_MVS0_BCR] = { 0x8098 },373 [CVP_VIDEO_CC_MVS0C_BCR] = { 0x8048 },374 [CVP_VIDEO_CC_MVS1_BCR] = { 0x80bc },375 [CVP_VIDEO_CC_MVS1C_BCR] = { 0x8070 },376 [VIDEO_CC_MVS0C_CLK_ARES] = { .reg = 0x8064, .bit = 2, .udelay = 1000 },377 [VIDEO_CC_MVS1C_CLK_ARES] = { .reg = 0x808c, .bit = 2, .udelay = 1000 },378};379 380static const struct regmap_config video_cc_sm8450_regmap_config = {381 .reg_bits = 32,382 .reg_stride = 4,383 .val_bits = 32,384 .max_register = 0x9f4c,385 .fast_io = true,386};387 388static struct qcom_cc_desc video_cc_sm8450_desc = {389 .config = &video_cc_sm8450_regmap_config,390 .clks = video_cc_sm8450_clocks,391 .num_clks = ARRAY_SIZE(video_cc_sm8450_clocks),392 .resets = video_cc_sm8450_resets,393 .num_resets = ARRAY_SIZE(video_cc_sm8450_resets),394 .gdscs = video_cc_sm8450_gdscs,395 .num_gdscs = ARRAY_SIZE(video_cc_sm8450_gdscs),396};397 398static const struct of_device_id video_cc_sm8450_match_table[] = {399 { .compatible = "qcom,sm8450-videocc" },400 { }401};402MODULE_DEVICE_TABLE(of, video_cc_sm8450_match_table);403 404static int video_cc_sm8450_probe(struct platform_device *pdev)405{406 struct regmap *regmap;407 int ret;408 409 ret = devm_pm_runtime_enable(&pdev->dev);410 if (ret)411 return ret;412 413 ret = pm_runtime_resume_and_get(&pdev->dev);414 if (ret)415 return ret;416 417 regmap = qcom_cc_map(pdev, &video_cc_sm8450_desc);418 if (IS_ERR(regmap)) {419 pm_runtime_put(&pdev->dev);420 return PTR_ERR(regmap);421 }422 423 clk_lucid_evo_pll_configure(&video_cc_pll0, regmap, &video_cc_pll0_config);424 clk_lucid_evo_pll_configure(&video_cc_pll1, regmap, &video_cc_pll1_config);425 426 /* Keep some clocks always-on */427 qcom_branch_set_clk_en(regmap, 0x80e4); /* VIDEO_CC_AHB_CLK */428 qcom_branch_set_clk_en(regmap, 0x8130); /* VIDEO_CC_SLEEP_CLK */429 qcom_branch_set_clk_en(regmap, 0x8114); /* VIDEO_CC_XO_CLK */430 431 ret = qcom_cc_really_probe(&pdev->dev, &video_cc_sm8450_desc, regmap);432 433 pm_runtime_put(&pdev->dev);434 435 return ret;436}437 438static struct platform_driver video_cc_sm8450_driver = {439 .probe = video_cc_sm8450_probe,440 .driver = {441 .name = "video_cc-sm8450",442 .of_match_table = video_cc_sm8450_match_table,443 },444};445 446module_platform_driver(video_cc_sm8450_driver);447 448MODULE_DESCRIPTION("QTI VIDEOCC SM8450 Driver");449MODULE_LICENSE("GPL");450