0001
0002
0003
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
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");