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