1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2018, 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-sdm845.h> 12 13 #include "common.h" 14 #include "clk-alpha-pll.h" 15 #include "clk-branch.h" 16 #include "clk-rcg.h" 17 #include "clk-regmap.h" 18 #include "clk-pll.h" 19 #include "gdsc.h" 20 21 enum { 22 P_BI_TCXO, 23 P_CORE_BI_PLL_TEST_SE, 24 P_VIDEO_PLL0_OUT_EVEN, 25 P_VIDEO_PLL0_OUT_MAIN, 26 P_VIDEO_PLL0_OUT_ODD, 27 }; 28 29 static const struct parent_map video_cc_parent_map_0[] = { 30 { P_BI_TCXO, 0 }, 31 { P_VIDEO_PLL0_OUT_MAIN, 1 }, 32 { P_VIDEO_PLL0_OUT_EVEN, 2 }, 33 { P_VIDEO_PLL0_OUT_ODD, 3 }, 34 { P_CORE_BI_PLL_TEST_SE, 4 }, 35 }; 36 37 static const char * const video_cc_parent_names_0[] = { 38 "bi_tcxo", 39 "video_pll0", 40 "video_pll0_out_even", 41 "video_pll0_out_odd", 42 "core_bi_pll_test_se", 43 }; 44 45 static const struct alpha_pll_config video_pll0_config = { 46 .l = 0x10, 47 .alpha = 0xaaab, 48 }; 49 50 static struct clk_alpha_pll video_pll0 = { 51 .offset = 0x42c, 52 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], 53 .clkr = { 54 .hw.init = &(struct clk_init_data){ 55 .name = "video_pll0", 56 .parent_names = (const char *[]){ "bi_tcxo" }, 57 .num_parents = 1, 58 .ops = &clk_alpha_pll_fabia_ops, 59 }, 60 }, 61 }; 62 63 static const struct freq_tbl ftbl_video_cc_venus_clk_src[] = { 64 F(100000000, P_VIDEO_PLL0_OUT_MAIN, 4, 0, 0), 65 F(200000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), 66 F(330000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0), 67 F(404000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0), 68 F(444000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0), 69 F(533000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0), 70 { } 71 }; 72 73 static struct clk_rcg2 video_cc_venus_clk_src = { 74 .cmd_rcgr = 0x7f0, 75 .mnd_width = 0, 76 .hid_width = 5, 77 .parent_map = video_cc_parent_map_0, 78 .freq_tbl = ftbl_video_cc_venus_clk_src, 79 .clkr.hw.init = &(struct clk_init_data){ 80 .name = "video_cc_venus_clk_src", 81 .parent_names = video_cc_parent_names_0, 82 .num_parents = 5, 83 .flags = CLK_SET_RATE_PARENT, 84 .ops = &clk_rcg2_shared_ops, 85 }, 86 }; 87 88 static struct clk_branch video_cc_apb_clk = { 89 .halt_reg = 0x990, 90 .halt_check = BRANCH_HALT, 91 .clkr = { 92 .enable_reg = 0x990, 93 .enable_mask = BIT(0), 94 .hw.init = &(struct clk_init_data){ 95 .name = "video_cc_apb_clk", 96 .ops = &clk_branch2_ops, 97 }, 98 }, 99 }; 100 101 static struct clk_branch video_cc_at_clk = { 102 .halt_reg = 0x9f0, 103 .halt_check = BRANCH_HALT, 104 .clkr = { 105 .enable_reg = 0x9f0, 106 .enable_mask = BIT(0), 107 .hw.init = &(struct clk_init_data){ 108 .name = "video_cc_at_clk", 109 .ops = &clk_branch2_ops, 110 }, 111 }, 112 }; 113 114 static struct clk_branch video_cc_qdss_trig_clk = { 115 .halt_reg = 0x970, 116 .halt_check = BRANCH_HALT, 117 .clkr = { 118 .enable_reg = 0x970, 119 .enable_mask = BIT(0), 120 .hw.init = &(struct clk_init_data){ 121 .name = "video_cc_qdss_trig_clk", 122 .ops = &clk_branch2_ops, 123 }, 124 }, 125 }; 126 127 static struct clk_branch video_cc_qdss_tsctr_div8_clk = { 128 .halt_reg = 0x9d0, 129 .halt_check = BRANCH_HALT, 130 .clkr = { 131 .enable_reg = 0x9d0, 132 .enable_mask = BIT(0), 133 .hw.init = &(struct clk_init_data){ 134 .name = "video_cc_qdss_tsctr_div8_clk", 135 .ops = &clk_branch2_ops, 136 }, 137 }, 138 }; 139 140 static struct clk_branch video_cc_vcodec0_axi_clk = { 141 .halt_reg = 0x930, 142 .halt_check = BRANCH_HALT, 143 .clkr = { 144 .enable_reg = 0x930, 145 .enable_mask = BIT(0), 146 .hw.init = &(struct clk_init_data){ 147 .name = "video_cc_vcodec0_axi_clk", 148 .ops = &clk_branch2_ops, 149 }, 150 }, 151 }; 152 153 static struct clk_branch video_cc_vcodec0_core_clk = { 154 .halt_reg = 0x890, 155 .halt_check = BRANCH_VOTED, 156 .clkr = { 157 .enable_reg = 0x890, 158 .enable_mask = BIT(0), 159 .hw.init = &(struct clk_init_data){ 160 .name = "video_cc_vcodec0_core_clk", 161 .parent_names = (const char *[]){ 162 "video_cc_venus_clk_src", 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_vcodec1_axi_clk = { 172 .halt_reg = 0x950, 173 .halt_check = BRANCH_HALT, 174 .clkr = { 175 .enable_reg = 0x950, 176 .enable_mask = BIT(0), 177 .hw.init = &(struct clk_init_data){ 178 .name = "video_cc_vcodec1_axi_clk", 179 .ops = &clk_branch2_ops, 180 }, 181 }, 182 }; 183 184 static struct clk_branch video_cc_vcodec1_core_clk = { 185 .halt_reg = 0x8d0, 186 .halt_check = BRANCH_VOTED, 187 .clkr = { 188 .enable_reg = 0x8d0, 189 .enable_mask = BIT(0), 190 .hw.init = &(struct clk_init_data){ 191 .name = "video_cc_vcodec1_core_clk", 192 .parent_names = (const char *[]){ 193 "video_cc_venus_clk_src", 194 }, 195 .num_parents = 1, 196 .flags = CLK_SET_RATE_PARENT, 197 .ops = &clk_branch2_ops, 198 }, 199 }, 200 }; 201 202 static struct clk_branch video_cc_venus_ahb_clk = { 203 .halt_reg = 0x9b0, 204 .halt_check = BRANCH_HALT, 205 .clkr = { 206 .enable_reg = 0x9b0, 207 .enable_mask = BIT(0), 208 .hw.init = &(struct clk_init_data){ 209 .name = "video_cc_venus_ahb_clk", 210 .ops = &clk_branch2_ops, 211 }, 212 }, 213 }; 214 215 static struct clk_branch video_cc_venus_ctl_axi_clk = { 216 .halt_reg = 0x910, 217 .halt_check = BRANCH_HALT, 218 .clkr = { 219 .enable_reg = 0x910, 220 .enable_mask = BIT(0), 221 .hw.init = &(struct clk_init_data){ 222 .name = "video_cc_venus_ctl_axi_clk", 223 .ops = &clk_branch2_ops, 224 }, 225 }, 226 }; 227 228 static struct clk_branch video_cc_venus_ctl_core_clk = { 229 .halt_reg = 0x850, 230 .halt_check = BRANCH_HALT, 231 .clkr = { 232 .enable_reg = 0x850, 233 .enable_mask = BIT(0), 234 .hw.init = &(struct clk_init_data){ 235 .name = "video_cc_venus_ctl_core_clk", 236 .parent_names = (const char *[]){ 237 "video_cc_venus_clk_src", 238 }, 239 .num_parents = 1, 240 .flags = CLK_SET_RATE_PARENT, 241 .ops = &clk_branch2_ops, 242 }, 243 }, 244 }; 245 246 static struct gdsc venus_gdsc = { 247 .gdscr = 0x814, 248 .pd = { 249 .name = "venus_gdsc", 250 }, 251 .cxcs = (unsigned int []){ 0x850, 0x910 }, 252 .cxc_count = 2, 253 .pwrsts = PWRSTS_OFF_ON, 254 .flags = POLL_CFG_GDSCR, 255 }; 256 257 static struct gdsc vcodec0_gdsc = { 258 .gdscr = 0x874, 259 .pd = { 260 .name = "vcodec0_gdsc", 261 }, 262 .cxcs = (unsigned int []){ 0x890, 0x930 }, 263 .cxc_count = 2, 264 .flags = HW_CTRL | POLL_CFG_GDSCR, 265 .pwrsts = PWRSTS_OFF_ON, 266 }; 267 268 static struct gdsc vcodec1_gdsc = { 269 .gdscr = 0x8b4, 270 .pd = { 271 .name = "vcodec1_gdsc", 272 }, 273 .cxcs = (unsigned int []){ 0x8d0, 0x950 }, 274 .cxc_count = 2, 275 .flags = HW_CTRL | POLL_CFG_GDSCR, 276 .pwrsts = PWRSTS_OFF_ON, 277 }; 278 279 static struct clk_regmap *video_cc_sdm845_clocks[] = { 280 [VIDEO_CC_APB_CLK] = &video_cc_apb_clk.clkr, 281 [VIDEO_CC_AT_CLK] = &video_cc_at_clk.clkr, 282 [VIDEO_CC_QDSS_TRIG_CLK] = &video_cc_qdss_trig_clk.clkr, 283 [VIDEO_CC_QDSS_TSCTR_DIV8_CLK] = &video_cc_qdss_tsctr_div8_clk.clkr, 284 [VIDEO_CC_VCODEC0_AXI_CLK] = &video_cc_vcodec0_axi_clk.clkr, 285 [VIDEO_CC_VCODEC0_CORE_CLK] = &video_cc_vcodec0_core_clk.clkr, 286 [VIDEO_CC_VCODEC1_AXI_CLK] = &video_cc_vcodec1_axi_clk.clkr, 287 [VIDEO_CC_VCODEC1_CORE_CLK] = &video_cc_vcodec1_core_clk.clkr, 288 [VIDEO_CC_VENUS_AHB_CLK] = &video_cc_venus_ahb_clk.clkr, 289 [VIDEO_CC_VENUS_CLK_SRC] = &video_cc_venus_clk_src.clkr, 290 [VIDEO_CC_VENUS_CTL_AXI_CLK] = &video_cc_venus_ctl_axi_clk.clkr, 291 [VIDEO_CC_VENUS_CTL_CORE_CLK] = &video_cc_venus_ctl_core_clk.clkr, 292 [VIDEO_PLL0] = &video_pll0.clkr, 293 }; 294 295 static struct gdsc *video_cc_sdm845_gdscs[] = { 296 [VENUS_GDSC] = &venus_gdsc, 297 [VCODEC0_GDSC] = &vcodec0_gdsc, 298 [VCODEC1_GDSC] = &vcodec1_gdsc, 299 }; 300 301 static const struct regmap_config video_cc_sdm845_regmap_config = { 302 .reg_bits = 32, 303 .reg_stride = 4, 304 .val_bits = 32, 305 .max_register = 0xb90, 306 .fast_io = true, 307 }; 308 309 static const struct qcom_cc_desc video_cc_sdm845_desc = { 310 .config = &video_cc_sdm845_regmap_config, 311 .clks = video_cc_sdm845_clocks, 312 .num_clks = ARRAY_SIZE(video_cc_sdm845_clocks), 313 .gdscs = video_cc_sdm845_gdscs, 314 .num_gdscs = ARRAY_SIZE(video_cc_sdm845_gdscs), 315 }; 316 317 static const struct of_device_id video_cc_sdm845_match_table[] = { 318 { .compatible = "qcom,sdm845-videocc" }, 319 { } 320 }; 321 MODULE_DEVICE_TABLE(of, video_cc_sdm845_match_table); 322 323 static int video_cc_sdm845_probe(struct platform_device *pdev) 324 { 325 struct regmap *regmap; 326 327 regmap = qcom_cc_map(pdev, &video_cc_sdm845_desc); 328 if (IS_ERR(regmap)) 329 return PTR_ERR(regmap); 330 331 clk_fabia_pll_configure(&video_pll0, regmap, &video_pll0_config); 332 333 return qcom_cc_really_probe(pdev, &video_cc_sdm845_desc, regmap); 334 } 335 336 static struct platform_driver video_cc_sdm845_driver = { 337 .probe = video_cc_sdm845_probe, 338 .driver = { 339 .name = "sdm845-videocc", 340 .of_match_table = video_cc_sdm845_match_table, 341 }, 342 }; 343 344 static int __init video_cc_sdm845_init(void) 345 { 346 return platform_driver_register(&video_cc_sdm845_driver); 347 } 348 subsys_initcall(video_cc_sdm845_init); 349 350 static void __exit video_cc_sdm845_exit(void) 351 { 352 platform_driver_unregister(&video_cc_sdm845_driver); 353 } 354 module_exit(video_cc_sdm845_exit); 355 356 MODULE_LICENSE("GPL v2"); 357