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