Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
0004  */
0005 
0006 #include <linux/clk-provider.h>
0007 #include <linux/module.h>
0008 #include <linux/platform_device.h>
0009 #include <linux/pm_runtime.h>
0010 #include <linux/regmap.h>
0011 
0012 #include <dt-bindings/clock/qcom,videocc-sm8250.h>
0013 
0014 #include "clk-alpha-pll.h"
0015 #include "clk-branch.h"
0016 #include "clk-rcg.h"
0017 #include "clk-regmap.h"
0018 #include "clk-regmap-divider.h"
0019 #include "common.h"
0020 #include "reset.h"
0021 #include "gdsc.h"
0022 
0023 enum {
0024     P_BI_TCXO,
0025     P_VIDEO_PLL0_OUT_MAIN,
0026     P_VIDEO_PLL1_OUT_MAIN,
0027 };
0028 
0029 static struct pll_vco lucid_vco[] = {
0030     { 249600000, 2000000000, 0 },
0031 };
0032 
0033 static const struct alpha_pll_config video_pll0_config = {
0034     .l = 0x25,
0035     .alpha = 0x8000,
0036     .config_ctl_val = 0x20485699,
0037     .config_ctl_hi_val = 0x00002261,
0038     .config_ctl_hi1_val = 0x329A699C,
0039     .user_ctl_val = 0x00000000,
0040     .user_ctl_hi_val = 0x00000805,
0041     .user_ctl_hi1_val = 0x00000000,
0042 };
0043 
0044 static struct clk_alpha_pll video_pll0 = {
0045     .offset = 0x42c,
0046     .vco_table = lucid_vco,
0047     .num_vco = ARRAY_SIZE(lucid_vco),
0048     .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
0049     .clkr = {
0050         .hw.init = &(struct clk_init_data){
0051             .name = "video_pll0",
0052             .parent_data = &(const struct clk_parent_data){
0053                 .fw_name = "bi_tcxo",
0054             },
0055             .num_parents = 1,
0056             .ops = &clk_alpha_pll_lucid_ops,
0057         },
0058     },
0059 };
0060 
0061 static const struct alpha_pll_config video_pll1_config = {
0062     .l = 0x2B,
0063     .alpha = 0xC000,
0064     .config_ctl_val = 0x20485699,
0065     .config_ctl_hi_val = 0x00002261,
0066     .config_ctl_hi1_val = 0x329A699C,
0067     .user_ctl_val = 0x00000000,
0068     .user_ctl_hi_val = 0x00000805,
0069     .user_ctl_hi1_val = 0x00000000,
0070 };
0071 
0072 static struct clk_alpha_pll video_pll1 = {
0073     .offset = 0x7d0,
0074     .vco_table = lucid_vco,
0075     .num_vco = ARRAY_SIZE(lucid_vco),
0076     .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
0077     .clkr = {
0078         .hw.init = &(struct clk_init_data){
0079             .name = "video_pll1",
0080             .parent_data = &(const struct clk_parent_data){
0081                 .fw_name = "bi_tcxo",
0082             },
0083             .num_parents = 1,
0084             .ops = &clk_alpha_pll_lucid_ops,
0085         },
0086     },
0087 };
0088 
0089 static const struct parent_map video_cc_parent_map_1[] = {
0090     { P_BI_TCXO, 0 },
0091     { P_VIDEO_PLL0_OUT_MAIN, 1 },
0092 };
0093 
0094 static const struct clk_parent_data video_cc_parent_data_1[] = {
0095     { .fw_name = "bi_tcxo" },
0096     { .hw = &video_pll0.clkr.hw },
0097 };
0098 
0099 static const struct parent_map video_cc_parent_map_2[] = {
0100     { P_BI_TCXO, 0 },
0101     { P_VIDEO_PLL1_OUT_MAIN, 1 },
0102 };
0103 
0104 static const struct clk_parent_data video_cc_parent_data_2[] = {
0105     { .fw_name = "bi_tcxo" },
0106     { .hw = &video_pll1.clkr.hw },
0107 };
0108 
0109 static const struct freq_tbl ftbl_video_cc_mvs0_clk_src[] = {
0110     F(19200000, P_BI_TCXO, 1, 0, 0),
0111     F(720000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0),
0112     F(1014000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0),
0113     F(1098000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0),
0114     F(1332000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0),
0115     { }
0116 };
0117 
0118 static struct clk_rcg2 video_cc_mvs0_clk_src = {
0119     .cmd_rcgr = 0xb94,
0120     .mnd_width = 0,
0121     .hid_width = 5,
0122     .parent_map = video_cc_parent_map_1,
0123     .freq_tbl = ftbl_video_cc_mvs0_clk_src,
0124     .clkr.hw.init = &(struct clk_init_data){
0125         .name = "video_cc_mvs0_clk_src",
0126         .parent_data = video_cc_parent_data_1,
0127         .num_parents = ARRAY_SIZE(video_cc_parent_data_1),
0128         .flags = CLK_SET_RATE_PARENT,
0129         .ops = &clk_rcg2_shared_ops,
0130     },
0131 };
0132 
0133 static const struct freq_tbl ftbl_video_cc_mvs1_clk_src[] = {
0134     F(19200000, P_BI_TCXO, 1, 0, 0),
0135     F(840000000, P_VIDEO_PLL1_OUT_MAIN, 1, 0, 0),
0136     F(1098000000, P_VIDEO_PLL1_OUT_MAIN, 1, 0, 0),
0137     F(1332000000, P_VIDEO_PLL1_OUT_MAIN, 1, 0, 0),
0138     { }
0139 };
0140 
0141 static struct clk_rcg2 video_cc_mvs1_clk_src = {
0142     .cmd_rcgr = 0xbb4,
0143     .mnd_width = 0,
0144     .hid_width = 5,
0145     .parent_map = video_cc_parent_map_2,
0146     .freq_tbl = ftbl_video_cc_mvs1_clk_src,
0147     .clkr.hw.init = &(struct clk_init_data){
0148         .name = "video_cc_mvs1_clk_src",
0149         .parent_data = video_cc_parent_data_2,
0150         .num_parents = ARRAY_SIZE(video_cc_parent_data_2),
0151         .flags = CLK_SET_RATE_PARENT,
0152         .ops = &clk_rcg2_shared_ops,
0153     },
0154 };
0155 
0156 static struct clk_regmap_div video_cc_mvs0c_div2_div_clk_src = {
0157     .reg = 0xc54,
0158     .shift = 0,
0159     .width = 2,
0160     .clkr.hw.init = &(struct clk_init_data) {
0161         .name = "video_cc_mvs0c_div2_div_clk_src",
0162         .parent_hws = (const struct clk_hw*[]){
0163             &video_cc_mvs0_clk_src.clkr.hw,
0164         },
0165         .num_parents = 1,
0166         .flags = CLK_SET_RATE_PARENT,
0167         .ops = &clk_regmap_div_ro_ops,
0168     },
0169 };
0170 
0171 static struct clk_regmap_div video_cc_mvs0_div_clk_src = {
0172     .reg = 0xd54,
0173     .shift = 0,
0174     .width = 2,
0175     .clkr.hw.init = &(struct clk_init_data) {
0176         .name = "video_cc_mvs0_div_clk_src",
0177         .parent_hws = (const struct clk_hw*[]){
0178             &video_cc_mvs0_clk_src.clkr.hw,
0179         },
0180         .num_parents = 1,
0181         .flags = CLK_SET_RATE_PARENT,
0182         .ops = &clk_regmap_div_ro_ops,
0183     },
0184 };
0185 
0186 static struct clk_regmap_div video_cc_mvs1c_div2_div_clk_src = {
0187     .reg = 0xcf4,
0188     .shift = 0,
0189     .width = 2,
0190     .clkr.hw.init = &(struct clk_init_data) {
0191         .name = "video_cc_mvs1c_div2_div_clk_src",
0192         .parent_hws = (const struct clk_hw*[]){
0193             &video_cc_mvs1_clk_src.clkr.hw,
0194         },
0195         .num_parents = 1,
0196         .flags = CLK_SET_RATE_PARENT,
0197         .ops = &clk_regmap_div_ro_ops,
0198     },
0199 };
0200 
0201 static struct clk_branch video_cc_mvs0c_clk = {
0202     .halt_reg = 0xc34,
0203     .halt_check = BRANCH_HALT,
0204     .clkr = {
0205         .enable_reg = 0xc34,
0206         .enable_mask = BIT(0),
0207         .hw.init = &(struct clk_init_data){
0208             .name = "video_cc_mvs0c_clk",
0209             .parent_hws = (const struct clk_hw*[]){
0210                 &video_cc_mvs0c_div2_div_clk_src.clkr.hw,
0211             },
0212             .num_parents = 1,
0213             .flags = CLK_SET_RATE_PARENT,
0214             .ops = &clk_branch2_ops,
0215         },
0216     },
0217 };
0218 
0219 static struct clk_branch video_cc_mvs0_clk = {
0220     .halt_reg = 0xd34,
0221     .halt_check = BRANCH_HALT_VOTED,
0222     .clkr = {
0223         .enable_reg = 0xd34,
0224         .enable_mask = BIT(0),
0225         .hw.init = &(struct clk_init_data){
0226             .name = "video_cc_mvs0_clk",
0227             .parent_hws = (const struct clk_hw*[]){
0228                 &video_cc_mvs0_div_clk_src.clkr.hw,
0229             },
0230             .num_parents = 1,
0231             .flags = CLK_SET_RATE_PARENT,
0232             .ops = &clk_branch2_ops,
0233         },
0234     },
0235 };
0236 
0237 static struct clk_branch video_cc_mvs1_div2_clk = {
0238     .halt_reg = 0xdf4,
0239     .halt_check = BRANCH_HALT_VOTED,
0240     .clkr = {
0241         .enable_reg = 0xdf4,
0242         .enable_mask = BIT(0),
0243         .hw.init = &(struct clk_init_data){
0244             .name = "video_cc_mvs1_div2_clk",
0245             .parent_hws = (const struct clk_hw*[]){
0246                 &video_cc_mvs1c_div2_div_clk_src.clkr.hw,
0247             },
0248             .num_parents = 1,
0249             .flags = CLK_SET_RATE_PARENT,
0250             .ops = &clk_branch2_ops,
0251         },
0252     },
0253 };
0254 
0255 static struct clk_branch video_cc_mvs1c_clk = {
0256     .halt_reg = 0xcd4,
0257     .halt_check = BRANCH_HALT_VOTED,
0258     .clkr = {
0259         .enable_reg = 0xcd4,
0260         .enable_mask = BIT(0),
0261         .hw.init = &(struct clk_init_data){
0262             .name = "video_cc_mvs1c_clk",
0263             .parent_hws = (const struct clk_hw*[]){
0264                 &video_cc_mvs1c_div2_div_clk_src.clkr.hw,
0265             },
0266             .num_parents = 1,
0267             .flags = CLK_SET_RATE_PARENT,
0268             .ops = &clk_branch2_ops,
0269         },
0270     },
0271 };
0272 
0273 static struct gdsc mvs0c_gdsc = {
0274     .gdscr = 0xbf8,
0275     .pd = {
0276         .name = "mvs0c_gdsc",
0277     },
0278     .flags = 0,
0279     .pwrsts = PWRSTS_OFF_ON,
0280 };
0281 
0282 static struct gdsc mvs1c_gdsc = {
0283     .gdscr = 0xc98,
0284     .pd = {
0285         .name = "mvs1c_gdsc",
0286     },
0287     .flags = 0,
0288     .pwrsts = PWRSTS_OFF_ON,
0289 };
0290 
0291 static struct gdsc mvs0_gdsc = {
0292     .gdscr = 0xd18,
0293     .pd = {
0294         .name = "mvs0_gdsc",
0295     },
0296     .flags = HW_CTRL,
0297     .pwrsts = PWRSTS_OFF_ON,
0298 };
0299 
0300 static struct gdsc mvs1_gdsc = {
0301     .gdscr = 0xd98,
0302     .pd = {
0303         .name = "mvs1_gdsc",
0304     },
0305     .flags = HW_CTRL,
0306     .pwrsts = PWRSTS_OFF_ON,
0307 };
0308 
0309 static struct clk_regmap *video_cc_sm8250_clocks[] = {
0310     [VIDEO_CC_MVS0_CLK] = &video_cc_mvs0_clk.clkr,
0311     [VIDEO_CC_MVS0_CLK_SRC] = &video_cc_mvs0_clk_src.clkr,
0312     [VIDEO_CC_MVS0_DIV_CLK_SRC] = &video_cc_mvs0_div_clk_src.clkr,
0313     [VIDEO_CC_MVS0C_CLK] = &video_cc_mvs0c_clk.clkr,
0314     [VIDEO_CC_MVS0C_DIV2_DIV_CLK_SRC] = &video_cc_mvs0c_div2_div_clk_src.clkr,
0315     [VIDEO_CC_MVS1_CLK_SRC] = &video_cc_mvs1_clk_src.clkr,
0316     [VIDEO_CC_MVS1_DIV2_CLK] = &video_cc_mvs1_div2_clk.clkr,
0317     [VIDEO_CC_MVS1C_CLK] = &video_cc_mvs1c_clk.clkr,
0318     [VIDEO_CC_MVS1C_DIV2_DIV_CLK_SRC] = &video_cc_mvs1c_div2_div_clk_src.clkr,
0319     [VIDEO_CC_PLL0] = &video_pll0.clkr,
0320     [VIDEO_CC_PLL1] = &video_pll1.clkr,
0321 };
0322 
0323 static const struct qcom_reset_map video_cc_sm8250_resets[] = {
0324     [VIDEO_CC_CVP_INTERFACE_BCR] = { 0xe54 },
0325     [VIDEO_CC_CVP_MVS0_BCR] = { 0xd14 },
0326     [VIDEO_CC_MVS0C_CLK_ARES] = { 0xc34, 2 },
0327     [VIDEO_CC_CVP_MVS0C_BCR] = { 0xbf4 },
0328     [VIDEO_CC_CVP_MVS1_BCR] = { 0xd94 },
0329     [VIDEO_CC_MVS1C_CLK_ARES] = { 0xcd4, 2 },
0330     [VIDEO_CC_CVP_MVS1C_BCR] = { 0xc94 },
0331 };
0332 
0333 static struct gdsc *video_cc_sm8250_gdscs[] = {
0334     [MVS0C_GDSC] = &mvs0c_gdsc,
0335     [MVS1C_GDSC] = &mvs1c_gdsc,
0336     [MVS0_GDSC] = &mvs0_gdsc,
0337     [MVS1_GDSC] = &mvs1_gdsc,
0338 };
0339 
0340 static const struct regmap_config video_cc_sm8250_regmap_config = {
0341     .reg_bits = 32,
0342     .reg_stride = 4,
0343     .val_bits = 32,
0344     .max_register = 0xf4c,
0345     .fast_io = true,
0346 };
0347 
0348 static const struct qcom_cc_desc video_cc_sm8250_desc = {
0349     .config = &video_cc_sm8250_regmap_config,
0350     .clks = video_cc_sm8250_clocks,
0351     .num_clks = ARRAY_SIZE(video_cc_sm8250_clocks),
0352     .resets = video_cc_sm8250_resets,
0353     .num_resets = ARRAY_SIZE(video_cc_sm8250_resets),
0354     .gdscs = video_cc_sm8250_gdscs,
0355     .num_gdscs = ARRAY_SIZE(video_cc_sm8250_gdscs),
0356 };
0357 
0358 static const struct of_device_id video_cc_sm8250_match_table[] = {
0359     { .compatible = "qcom,sm8250-videocc" },
0360     { }
0361 };
0362 MODULE_DEVICE_TABLE(of, video_cc_sm8250_match_table);
0363 
0364 static void video_cc_sm8250_pm_runtime_disable(void *data)
0365 {
0366     pm_runtime_disable(data);
0367 }
0368 
0369 static int video_cc_sm8250_probe(struct platform_device *pdev)
0370 {
0371     struct regmap *regmap;
0372     int ret;
0373 
0374     pm_runtime_enable(&pdev->dev);
0375 
0376     ret = devm_add_action_or_reset(&pdev->dev, video_cc_sm8250_pm_runtime_disable, &pdev->dev);
0377     if (ret)
0378         return ret;
0379 
0380     ret = pm_runtime_resume_and_get(&pdev->dev);
0381     if (ret)
0382         return ret;
0383 
0384     regmap = qcom_cc_map(pdev, &video_cc_sm8250_desc);
0385     if (IS_ERR(regmap)) {
0386         pm_runtime_put(&pdev->dev);
0387         return PTR_ERR(regmap);
0388     }
0389 
0390     clk_lucid_pll_configure(&video_pll0, regmap, &video_pll0_config);
0391     clk_lucid_pll_configure(&video_pll1, regmap, &video_pll1_config);
0392 
0393     /* Keep VIDEO_CC_AHB_CLK and VIDEO_CC_XO_CLK ALWAYS-ON */
0394     regmap_update_bits(regmap, 0xe58, BIT(0), BIT(0));
0395     regmap_update_bits(regmap, 0xeec, BIT(0), BIT(0));
0396 
0397     ret = qcom_cc_really_probe(pdev, &video_cc_sm8250_desc, regmap);
0398 
0399     pm_runtime_put(&pdev->dev);
0400 
0401     return ret;
0402 }
0403 
0404 static struct platform_driver video_cc_sm8250_driver = {
0405     .probe  = video_cc_sm8250_probe,
0406     .driver = {
0407         .name = "sm8250-videocc",
0408         .of_match_table = video_cc_sm8250_match_table,
0409     },
0410 };
0411 
0412 static int __init video_cc_sm8250_init(void)
0413 {
0414     return platform_driver_register(&video_cc_sm8250_driver);
0415 }
0416 subsys_initcall(video_cc_sm8250_init);
0417 
0418 static void __exit video_cc_sm8250_exit(void)
0419 {
0420     platform_driver_unregister(&video_cc_sm8250_driver);
0421 }
0422 module_exit(video_cc_sm8250_exit);
0423 
0424 MODULE_LICENSE("GPL v2");
0425 MODULE_DESCRIPTION("QTI VIDEOCC SM8250 Driver");