1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2018, The Linux Foundation. All rights reserved. 4 * Copyright (c) 2024, Danila Tikhonov <danila@jiaxyga.com> 5 */ 6 7 #include <linux/clk-provider.h> 8 #include <linux/module.h> 9 #include <linux/platform_device.h> 10 #include <linux/regmap.h> 11 12 #include <dt-bindings/clock/qcom,sm7150-videocc.h> 13 14 #include "common.h" 15 #include "clk-alpha-pll.h" 16 #include "clk-branch.h" 17 #include "clk-rcg.h" 18 #include "clk-regmap.h" 19 #include "clk-pll.h" 20 #include "gdsc.h" 21 22 enum { 23 DT_BI_TCXO, 24 DT_BI_TCXO_AO, 25 }; 26 27 enum { 28 P_BI_TCXO, 29 P_VIDEOCC_PLL0_OUT_EVEN, 30 P_VIDEOCC_PLL0_OUT_MAIN, 31 P_VIDEOCC_PLL0_OUT_ODD, 32 }; 33 34 static const struct pll_vco fabia_vco[] = { 35 { 249600000, 2000000000, 0 }, 36 { 125000000, 1000000000, 1 }, 37 }; 38 39 static struct alpha_pll_config videocc_pll0_config = { 40 .l = 0x19, 41 .alpha = 0x0, 42 .config_ctl_val = 0x20485699, 43 .config_ctl_hi_val = 0x00002067, 44 .user_ctl_val = 0x00000001, 45 .user_ctl_hi_val = 0x00004805, 46 .test_ctl_hi_val = 0x40000000, 47 }; 48 49 static struct clk_alpha_pll videocc_pll0 = { 50 .offset = 0x42c, 51 .vco_table = fabia_vco, 52 .num_vco = ARRAY_SIZE(fabia_vco), 53 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], 54 .clkr = { 55 .hw.init = &(const struct clk_init_data) { 56 .name = "videocc_pll0", 57 .parent_data = &(const struct clk_parent_data) { 58 .index = DT_BI_TCXO, 59 }, 60 .num_parents = 1, 61 .ops = &clk_alpha_pll_fabia_ops, 62 }, 63 }, 64 }; 65 66 static const struct parent_map videocc_parent_map_0[] = { 67 { P_BI_TCXO, 0 }, 68 { P_VIDEOCC_PLL0_OUT_MAIN, 1 }, 69 { P_VIDEOCC_PLL0_OUT_EVEN, 2 }, 70 { P_VIDEOCC_PLL0_OUT_ODD, 3 }, 71 }; 72 73 static const struct clk_parent_data videocc_parent_data_0[] = { 74 { .index = DT_BI_TCXO }, 75 { .hw = &videocc_pll0.clkr.hw }, 76 { .hw = &videocc_pll0.clkr.hw }, 77 { .hw = &videocc_pll0.clkr.hw }, 78 }; 79 80 static const struct parent_map videocc_parent_map_1[] = { 81 { P_BI_TCXO, 0 }, 82 }; 83 84 static const struct clk_parent_data videocc_parent_data_1[] = { 85 { .index = DT_BI_TCXO_AO }, 86 }; 87 88 static const struct freq_tbl ftbl_videocc_iris_clk_src[] = { 89 F(240000000, P_VIDEOCC_PLL0_OUT_MAIN, 2, 0, 0), 90 F(338000000, P_VIDEOCC_PLL0_OUT_MAIN, 2, 0, 0), 91 F(365000000, P_VIDEOCC_PLL0_OUT_MAIN, 2, 0, 0), 92 F(444000000, P_VIDEOCC_PLL0_OUT_MAIN, 2, 0, 0), 93 F(533000000, P_VIDEOCC_PLL0_OUT_MAIN, 2, 0, 0), 94 { } 95 }; 96 97 static struct clk_rcg2 videocc_iris_clk_src = { 98 .cmd_rcgr = 0x7f0, 99 .mnd_width = 0, 100 .hid_width = 5, 101 .parent_map = videocc_parent_map_0, 102 .freq_tbl = ftbl_videocc_iris_clk_src, 103 .clkr.hw.init = &(const struct clk_init_data) { 104 .name = "videocc_iris_clk_src", 105 .parent_data = videocc_parent_data_0, 106 .num_parents = ARRAY_SIZE(videocc_parent_data_0), 107 .flags = CLK_SET_RATE_PARENT, 108 .ops = &clk_rcg2_shared_ops, 109 }, 110 }; 111 112 static const struct freq_tbl ftbl_videocc_xo_clk_src[] = { 113 F(19200000, P_BI_TCXO, 1, 0, 0), 114 { } 115 }; 116 117 static struct clk_rcg2 videocc_xo_clk_src = { 118 .cmd_rcgr = 0xa98, 119 .mnd_width = 0, 120 .hid_width = 5, 121 .parent_map = videocc_parent_map_1, 122 .freq_tbl = ftbl_videocc_xo_clk_src, 123 .clkr.hw.init = &(const struct clk_init_data) { 124 .name = "videocc_xo_clk_src", 125 .parent_data = videocc_parent_data_1, 126 .num_parents = ARRAY_SIZE(videocc_parent_data_1), 127 .ops = &clk_rcg2_ops, 128 }, 129 }; 130 131 static struct clk_branch videocc_iris_ahb_clk = { 132 .halt_reg = 0x8f4, 133 .halt_check = BRANCH_VOTED, 134 .clkr = { 135 .enable_reg = 0x8f4, 136 .enable_mask = BIT(0), 137 .hw.init = &(const struct clk_init_data) { 138 .name = "videocc_iris_ahb_clk", 139 .parent_data = &(const struct clk_parent_data) { 140 .hw = &videocc_iris_clk_src.clkr.hw, 141 }, 142 .num_parents = 1, 143 .flags = CLK_SET_RATE_PARENT, 144 .ops = &clk_branch2_ops, 145 }, 146 }, 147 }; 148 149 static struct clk_branch videocc_mvs0_axi_clk = { 150 .halt_reg = 0x9ec, 151 .halt_check = BRANCH_HALT, 152 .clkr = { 153 .enable_reg = 0x9ec, 154 .enable_mask = BIT(0), 155 .hw.init = &(const struct clk_init_data) { 156 .name = "videocc_mvs0_axi_clk", 157 .ops = &clk_branch2_ops, 158 }, 159 }, 160 }; 161 162 static struct clk_branch videocc_mvs0_core_clk = { 163 .halt_reg = 0x890, 164 .halt_check = BRANCH_VOTED, 165 .clkr = { 166 .enable_reg = 0x890, 167 .enable_mask = BIT(0), 168 .hw.init = &(const struct clk_init_data) { 169 .name = "videocc_mvs0_core_clk", 170 .parent_data = &(const struct clk_parent_data) { 171 .hw = &videocc_iris_clk_src.clkr.hw, 172 }, 173 .num_parents = 1, 174 .flags = CLK_SET_RATE_PARENT, 175 .ops = &clk_branch2_ops, 176 }, 177 }, 178 }; 179 180 static struct clk_branch videocc_mvs1_axi_clk = { 181 .halt_reg = 0xa0c, 182 .halt_check = BRANCH_HALT, 183 .clkr = { 184 .enable_reg = 0xa0c, 185 .enable_mask = BIT(0), 186 .hw.init = &(const struct clk_init_data) { 187 .name = "videocc_mvs1_axi_clk", 188 .ops = &clk_branch2_ops, 189 }, 190 }, 191 }; 192 193 static struct clk_branch videocc_mvs1_core_clk = { 194 .halt_reg = 0x8d0, 195 .halt_check = BRANCH_VOTED, 196 .clkr = { 197 .enable_reg = 0x8d0, 198 .enable_mask = BIT(0), 199 .hw.init = &(const struct clk_init_data) { 200 .name = "videocc_mvs1_core_clk", 201 .parent_data = &(const struct clk_parent_data) { 202 .hw = &videocc_iris_clk_src.clkr.hw, 203 }, 204 .num_parents = 1, 205 .flags = CLK_SET_RATE_PARENT, 206 .ops = &clk_branch2_ops, 207 }, 208 }, 209 }; 210 211 static struct clk_branch videocc_mvsc_core_clk = { 212 .halt_reg = 0x850, 213 .halt_check = BRANCH_HALT, 214 .clkr = { 215 .enable_reg = 0x850, 216 .enable_mask = BIT(0), 217 .hw.init = &(const struct clk_init_data) { 218 .name = "videocc_mvsc_core_clk", 219 .parent_data = &(const struct clk_parent_data) { 220 .hw = &videocc_iris_clk_src.clkr.hw, 221 }, 222 .num_parents = 1, 223 .flags = CLK_SET_RATE_PARENT, 224 .ops = &clk_branch2_ops, 225 }, 226 }, 227 }; 228 229 static struct clk_branch videocc_mvsc_ctl_axi_clk = { 230 .halt_reg = 0x9cc, 231 .halt_check = BRANCH_HALT, 232 .clkr = { 233 .enable_reg = 0x9cc, 234 .enable_mask = BIT(0), 235 .hw.init = &(const struct clk_init_data) { 236 .name = "videocc_mvsc_ctl_axi_clk", 237 .ops = &clk_branch2_ops, 238 }, 239 }, 240 }; 241 242 static struct clk_branch videocc_venus_ahb_clk = { 243 .halt_reg = 0xa6c, 244 .halt_check = BRANCH_HALT, 245 .clkr = { 246 .enable_reg = 0xa6c, 247 .enable_mask = BIT(0), 248 .hw.init = &(const struct clk_init_data) { 249 .name = "videocc_venus_ahb_clk", 250 .ops = &clk_branch2_ops, 251 }, 252 }, 253 }; 254 255 static struct gdsc venus_gdsc = { 256 .gdscr = 0x814, 257 .pd = { 258 .name = "venus_gdsc", 259 }, 260 .cxcs = (unsigned int []){ 0x850, 0x9cc }, 261 .cxc_count = 2, 262 .pwrsts = PWRSTS_OFF_ON, 263 .flags = POLL_CFG_GDSCR, 264 }; 265 266 static struct gdsc vcodec0_gdsc = { 267 .gdscr = 0x874, 268 .pd = { 269 .name = "vcodec0_gdsc", 270 }, 271 .cxcs = (unsigned int []){ 0x890, 0x9ec }, 272 .cxc_count = 2, 273 .flags = HW_CTRL_TRIGGER | POLL_CFG_GDSCR, 274 .pwrsts = PWRSTS_OFF_ON, 275 }; 276 277 static struct gdsc vcodec1_gdsc = { 278 .gdscr = 0x8b4, 279 .pd = { 280 .name = "vcodec1_gdsc", 281 }, 282 .cxcs = (unsigned int []){ 0x8d0, 0xa0c }, 283 .cxc_count = 2, 284 .flags = HW_CTRL_TRIGGER | POLL_CFG_GDSCR, 285 .pwrsts = PWRSTS_OFF_ON, 286 }; 287 288 static struct clk_regmap *videocc_sm7150_clocks[] = { 289 [VIDEOCC_PLL0] = &videocc_pll0.clkr, 290 [VIDEOCC_IRIS_AHB_CLK] = &videocc_iris_ahb_clk.clkr, 291 [VIDEOCC_IRIS_CLK_SRC] = &videocc_iris_clk_src.clkr, 292 [VIDEOCC_MVS0_AXI_CLK] = &videocc_mvs0_axi_clk.clkr, 293 [VIDEOCC_MVS0_CORE_CLK] = &videocc_mvs0_core_clk.clkr, 294 [VIDEOCC_MVS1_AXI_CLK] = &videocc_mvs1_axi_clk.clkr, 295 [VIDEOCC_MVS1_CORE_CLK] = &videocc_mvs1_core_clk.clkr, 296 [VIDEOCC_MVSC_CORE_CLK] = &videocc_mvsc_core_clk.clkr, 297 [VIDEOCC_MVSC_CTL_AXI_CLK] = &videocc_mvsc_ctl_axi_clk.clkr, 298 [VIDEOCC_VENUS_AHB_CLK] = &videocc_venus_ahb_clk.clkr, 299 [VIDEOCC_XO_CLK_SRC] = &videocc_xo_clk_src.clkr, 300 }; 301 302 static struct gdsc *videocc_sm7150_gdscs[] = { 303 [VENUS_GDSC] = &venus_gdsc, 304 [VCODEC0_GDSC] = &vcodec0_gdsc, 305 [VCODEC1_GDSC] = &vcodec1_gdsc, 306 }; 307 308 static const struct regmap_config videocc_sm7150_regmap_config = { 309 .reg_bits = 32, 310 .reg_stride = 4, 311 .val_bits = 32, 312 .max_register = 0xb94, 313 .fast_io = true, 314 }; 315 316 static const struct qcom_cc_desc videocc_sm7150_desc = { 317 .config = &videocc_sm7150_regmap_config, 318 .clks = videocc_sm7150_clocks, 319 .num_clks = ARRAY_SIZE(videocc_sm7150_clocks), 320 .gdscs = videocc_sm7150_gdscs, 321 .num_gdscs = ARRAY_SIZE(videocc_sm7150_gdscs), 322 }; 323 324 static const struct of_device_id videocc_sm7150_match_table[] = { 325 { .compatible = "qcom,sm7150-videocc" }, 326 { } 327 }; 328 MODULE_DEVICE_TABLE(of, videocc_sm7150_match_table); 329 330 static int videocc_sm7150_probe(struct platform_device *pdev) 331 { 332 struct regmap *regmap; 333 334 regmap = qcom_cc_map(pdev, &videocc_sm7150_desc); 335 if (IS_ERR(regmap)) 336 return PTR_ERR(regmap); 337 338 clk_fabia_pll_configure(&videocc_pll0, regmap, &videocc_pll0_config); 339 340 /* Keep some clocks always-on */ 341 qcom_branch_set_clk_en(regmap, 0x984); /* VIDEOCC_XO_CLK */ 342 343 return qcom_cc_really_probe(&pdev->dev, &videocc_sm7150_desc, regmap); 344 } 345 346 static struct platform_driver videocc_sm7150_driver = { 347 .probe = videocc_sm7150_probe, 348 .driver = { 349 .name = "videocc-sm7150", 350 .of_match_table = videocc_sm7150_match_table, 351 }, 352 }; 353 module_platform_driver(videocc_sm7150_driver); 354 355 MODULE_DESCRIPTION("Qualcomm SM7150 Video Clock Controller"); 356 MODULE_LICENSE("GPL"); 357