1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2021, The Linux Foundation. All rights reserved. 4 */ 5 6 #include <linux/clk-provider.h> 7 #include <linux/module.h> 8 #include <linux/platform_device.h> 9 #include <linux/regmap.h> 10 11 #include <dt-bindings/clock/qcom,videocc-sc7280.h> 12 13 #include "clk-alpha-pll.h" 14 #include "clk-branch.h" 15 #include "clk-rcg.h" 16 #include "common.h" 17 #include "reset.h" 18 #include "gdsc.h" 19 20 enum { 21 P_BI_TCXO, 22 P_SLEEP_CLK, 23 P_VIDEO_PLL0_OUT_EVEN, 24 }; 25 26 static const struct pll_vco lucid_vco[] = { 27 { 249600000, 2000000000, 0 }, 28 }; 29 30 /* 400MHz Configuration */ 31 static const struct alpha_pll_config video_pll0_config = { 32 .l = 0x14, 33 .alpha = 0xD555, 34 .config_ctl_val = 0x20485699, 35 .config_ctl_hi_val = 0x00002261, 36 .config_ctl_hi1_val = 0x329A299C, 37 .user_ctl_val = 0x00000001, 38 .user_ctl_hi_val = 0x00000805, 39 .user_ctl_hi1_val = 0x00000000, 40 }; 41 42 static struct clk_alpha_pll video_pll0 = { 43 .offset = 0x0, 44 .vco_table = lucid_vco, 45 .num_vco = ARRAY_SIZE(lucid_vco), 46 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], 47 .clkr = { 48 .hw.init = &(struct clk_init_data){ 49 .name = "video_pll0", 50 .parent_data = &(const struct clk_parent_data){ 51 .fw_name = "bi_tcxo", 52 }, 53 .num_parents = 1, 54 .ops = &clk_alpha_pll_lucid_ops, 55 }, 56 }, 57 }; 58 59 static const struct parent_map video_cc_parent_map_0[] = { 60 { P_BI_TCXO, 0 }, 61 { P_VIDEO_PLL0_OUT_EVEN, 3 }, 62 }; 63 64 static const struct clk_parent_data video_cc_parent_data_0[] = { 65 { .fw_name = "bi_tcxo" }, 66 { .hw = &video_pll0.clkr.hw }, 67 }; 68 69 static const struct parent_map video_cc_parent_map_1[] = { 70 { P_SLEEP_CLK, 0 }, 71 }; 72 73 static const struct clk_parent_data video_cc_parent_data_1[] = { 74 { .fw_name = "sleep_clk" }, 75 }; 76 77 static const struct freq_tbl ftbl_video_cc_iris_clk_src[] = { 78 F(133333333, P_VIDEO_PLL0_OUT_EVEN, 3, 0, 0), 79 F(240000000, P_VIDEO_PLL0_OUT_EVEN, 2, 0, 0), 80 F(335000000, P_VIDEO_PLL0_OUT_EVEN, 2, 0, 0), 81 F(424000000, P_VIDEO_PLL0_OUT_EVEN, 2, 0, 0), 82 F(460000000, P_VIDEO_PLL0_OUT_EVEN, 2, 0, 0), 83 { } 84 }; 85 86 static struct clk_rcg2 video_cc_iris_clk_src = { 87 .cmd_rcgr = 0x1000, 88 .mnd_width = 0, 89 .hid_width = 5, 90 .parent_map = video_cc_parent_map_0, 91 .freq_tbl = ftbl_video_cc_iris_clk_src, 92 .clkr.hw.init = &(struct clk_init_data){ 93 .name = "video_cc_iris_clk_src", 94 .parent_data = video_cc_parent_data_0, 95 .num_parents = ARRAY_SIZE(video_cc_parent_data_0), 96 .flags = CLK_SET_RATE_PARENT, 97 .ops = &clk_rcg2_shared_ops, 98 }, 99 }; 100 101 static const struct freq_tbl ftbl_video_cc_sleep_clk_src[] = { 102 F(32000, P_SLEEP_CLK, 1, 0, 0), 103 { } 104 }; 105 106 static struct clk_rcg2 video_cc_sleep_clk_src = { 107 .cmd_rcgr = 0x701c, 108 .mnd_width = 0, 109 .hid_width = 5, 110 .parent_map = video_cc_parent_map_1, 111 .freq_tbl = ftbl_video_cc_sleep_clk_src, 112 .clkr.hw.init = &(struct clk_init_data){ 113 .name = "video_cc_sleep_clk_src", 114 .parent_data = video_cc_parent_data_1, 115 .num_parents = ARRAY_SIZE(video_cc_parent_data_1), 116 .ops = &clk_rcg2_ops, 117 }, 118 }; 119 120 static struct clk_branch video_cc_iris_ahb_clk = { 121 .halt_reg = 0x5004, 122 .halt_check = BRANCH_HALT_VOTED, 123 .clkr = { 124 .enable_reg = 0x5004, 125 .enable_mask = BIT(0), 126 .hw.init = &(struct clk_init_data){ 127 .name = "video_cc_iris_ahb_clk", 128 .parent_hws = (const struct clk_hw*[]){ 129 &video_cc_iris_clk_src.clkr.hw, 130 }, 131 .num_parents = 1, 132 .flags = CLK_SET_RATE_PARENT, 133 .ops = &clk_branch2_ops, 134 }, 135 }, 136 }; 137 138 static struct clk_branch video_cc_mvs0_axi_clk = { 139 .halt_reg = 0x800c, 140 .halt_check = BRANCH_HALT, 141 .clkr = { 142 .enable_reg = 0x800c, 143 .enable_mask = BIT(0), 144 .hw.init = &(struct clk_init_data){ 145 .name = "video_cc_mvs0_axi_clk", 146 .ops = &clk_branch2_ops, 147 }, 148 }, 149 }; 150 151 static struct clk_branch video_cc_mvs0_core_clk = { 152 .halt_reg = 0x3010, 153 .halt_check = BRANCH_HALT_VOTED, 154 .hwcg_reg = 0x3010, 155 .hwcg_bit = 1, 156 .clkr = { 157 .enable_reg = 0x3010, 158 .enable_mask = BIT(0), 159 .hw.init = &(struct clk_init_data){ 160 .name = "video_cc_mvs0_core_clk", 161 .parent_hws = (const struct clk_hw*[]){ 162 &video_cc_iris_clk_src.clkr.hw, 163 }, 164 .num_parents = 1, 165 .flags = CLK_SET_RATE_PARENT, 166 .ops = &clk_branch2_ops, 167 }, 168 }, 169 }; 170 171 static struct clk_branch video_cc_mvsc_core_clk = { 172 .halt_reg = 0x2014, 173 .halt_check = BRANCH_HALT, 174 .clkr = { 175 .enable_reg = 0x2014, 176 .enable_mask = BIT(0), 177 .hw.init = &(struct clk_init_data){ 178 .name = "video_cc_mvsc_core_clk", 179 .parent_hws = (const struct clk_hw*[]){ 180 &video_cc_iris_clk_src.clkr.hw, 181 }, 182 .num_parents = 1, 183 .flags = CLK_SET_RATE_PARENT, 184 .ops = &clk_branch2_ops, 185 }, 186 }, 187 }; 188 189 static struct clk_branch video_cc_mvsc_ctl_axi_clk = { 190 .halt_reg = 0x8004, 191 .halt_check = BRANCH_HALT, 192 .clkr = { 193 .enable_reg = 0x8004, 194 .enable_mask = BIT(0), 195 .hw.init = &(struct clk_init_data){ 196 .name = "video_cc_mvsc_ctl_axi_clk", 197 .ops = &clk_branch2_ops, 198 }, 199 }, 200 }; 201 202 static struct clk_branch video_cc_sleep_clk = { 203 .halt_reg = 0x7034, 204 .halt_check = BRANCH_HALT, 205 .clkr = { 206 .enable_reg = 0x7034, 207 .enable_mask = BIT(0), 208 .hw.init = &(struct clk_init_data){ 209 .name = "video_cc_sleep_clk", 210 .parent_hws = (const struct clk_hw*[]){ 211 &video_cc_sleep_clk_src.clkr.hw, 212 }, 213 .num_parents = 1, 214 .flags = CLK_SET_RATE_PARENT, 215 .ops = &clk_branch2_ops, 216 }, 217 }, 218 }; 219 220 static struct clk_branch video_cc_venus_ahb_clk = { 221 .halt_reg = 0x801c, 222 .halt_check = BRANCH_HALT, 223 .clkr = { 224 .enable_reg = 0x801c, 225 .enable_mask = BIT(0), 226 .hw.init = &(struct clk_init_data){ 227 .name = "video_cc_venus_ahb_clk", 228 .ops = &clk_branch2_ops, 229 }, 230 }, 231 }; 232 233 static struct gdsc mvs0_gdsc = { 234 .gdscr = 0x3004, 235 .pd = { 236 .name = "mvs0_gdsc", 237 }, 238 .pwrsts = PWRSTS_OFF_ON, 239 .flags = HW_CTRL | RETAIN_FF_ENABLE, 240 }; 241 242 static struct gdsc mvsc_gdsc = { 243 .gdscr = 0x2004, 244 .pd = { 245 .name = "mvsc_gdsc", 246 }, 247 .flags = RETAIN_FF_ENABLE, 248 .pwrsts = PWRSTS_OFF_ON, 249 }; 250 251 static struct clk_regmap *video_cc_sc7280_clocks[] = { 252 [VIDEO_CC_IRIS_AHB_CLK] = &video_cc_iris_ahb_clk.clkr, 253 [VIDEO_CC_IRIS_CLK_SRC] = &video_cc_iris_clk_src.clkr, 254 [VIDEO_CC_MVS0_AXI_CLK] = &video_cc_mvs0_axi_clk.clkr, 255 [VIDEO_CC_MVS0_CORE_CLK] = &video_cc_mvs0_core_clk.clkr, 256 [VIDEO_CC_MVSC_CORE_CLK] = &video_cc_mvsc_core_clk.clkr, 257 [VIDEO_CC_MVSC_CTL_AXI_CLK] = &video_cc_mvsc_ctl_axi_clk.clkr, 258 [VIDEO_CC_SLEEP_CLK] = &video_cc_sleep_clk.clkr, 259 [VIDEO_CC_SLEEP_CLK_SRC] = &video_cc_sleep_clk_src.clkr, 260 [VIDEO_CC_VENUS_AHB_CLK] = &video_cc_venus_ahb_clk.clkr, 261 [VIDEO_PLL0] = &video_pll0.clkr, 262 }; 263 264 static struct gdsc *video_cc_sc7280_gdscs[] = { 265 [MVS0_GDSC] = &mvs0_gdsc, 266 [MVSC_GDSC] = &mvsc_gdsc, 267 }; 268 269 static const struct regmap_config video_cc_sc7280_regmap_config = { 270 .reg_bits = 32, 271 .reg_stride = 4, 272 .val_bits = 32, 273 .max_register = 0xb000, 274 .fast_io = true, 275 }; 276 277 static const struct qcom_cc_desc video_cc_sc7280_desc = { 278 .config = &video_cc_sc7280_regmap_config, 279 .clks = video_cc_sc7280_clocks, 280 .num_clks = ARRAY_SIZE(video_cc_sc7280_clocks), 281 .gdscs = video_cc_sc7280_gdscs, 282 .num_gdscs = ARRAY_SIZE(video_cc_sc7280_gdscs), 283 }; 284 285 static const struct of_device_id video_cc_sc7280_match_table[] = { 286 { .compatible = "qcom,sc7280-videocc" }, 287 { } 288 }; 289 MODULE_DEVICE_TABLE(of, video_cc_sc7280_match_table); 290 291 static int video_cc_sc7280_probe(struct platform_device *pdev) 292 { 293 struct regmap *regmap; 294 295 regmap = qcom_cc_map(pdev, &video_cc_sc7280_desc); 296 if (IS_ERR(regmap)) 297 return PTR_ERR(regmap); 298 299 clk_lucid_pll_configure(&video_pll0, regmap, &video_pll0_config); 300 301 return qcom_cc_really_probe(pdev, &video_cc_sc7280_desc, regmap); 302 } 303 304 static struct platform_driver video_cc_sc7280_driver = { 305 .probe = video_cc_sc7280_probe, 306 .driver = { 307 .name = "video_cc-sc7280", 308 .of_match_table = video_cc_sc7280_match_table, 309 }, 310 }; 311 312 static int __init video_cc_sc7280_init(void) 313 { 314 return platform_driver_register(&video_cc_sc7280_driver); 315 } 316 subsys_initcall(video_cc_sc7280_init); 317 318 static void __exit video_cc_sc7280_exit(void) 319 { 320 platform_driver_unregister(&video_cc_sc7280_driver); 321 } 322 module_exit(video_cc_sc7280_exit); 323 324 MODULE_DESCRIPTION("QTI VIDEO_CC sc7280 Driver"); 325 MODULE_LICENSE("GPL v2"); 326