1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. 4 * Copyright (c) 2025, Luca Weiss <luca.weiss@fairphone.com> 5 */ 6 7 #include <linux/clk-provider.h> 8 #include <linux/mod_devicetable.h> 9 #include <linux/module.h> 10 #include <linux/platform_device.h> 11 #include <linux/regmap.h> 12 13 #include <dt-bindings/clock/qcom,milos-videocc.h> 14 15 #include "clk-alpha-pll.h" 16 #include "clk-branch.h" 17 #include "clk-rcg.h" 18 #include "clk-regmap.h" 19 #include "clk-regmap-divider.h" 20 #include "common.h" 21 #include "gdsc.h" 22 #include "reset.h" 23 24 /* Need to match the order of clocks in DT binding */ 25 enum { 26 DT_BI_TCXO, 27 DT_BI_TCXO_AO, 28 DT_SLEEP_CLK, 29 DT_IFACE, 30 }; 31 32 enum { 33 P_BI_TCXO, 34 P_SLEEP_CLK, 35 P_VIDEO_CC_PLL0_OUT_MAIN, 36 }; 37 38 static const struct pll_vco lucid_ole_vco[] = { 39 { 249600000, 2300000000, 0 }, 40 }; 41 42 /* 604.8 MHz Configuration */ 43 static const struct alpha_pll_config video_cc_pll0_config = { 44 .l = 0x1f, 45 .alpha = 0x8000, 46 .config_ctl_val = 0x20485699, 47 .config_ctl_hi_val = 0x00182261, 48 .config_ctl_hi1_val = 0x82aa299c, 49 .test_ctl_val = 0x00000000, 50 .test_ctl_hi_val = 0x00000003, 51 .test_ctl_hi1_val = 0x00009000, 52 .test_ctl_hi2_val = 0x00000034, 53 .user_ctl_val = 0x00000000, 54 .user_ctl_hi_val = 0x00000005, 55 }; 56 57 static struct clk_alpha_pll video_cc_pll0 = { 58 .offset = 0x0, 59 .config = &video_cc_pll0_config, 60 .vco_table = lucid_ole_vco, 61 .num_vco = ARRAY_SIZE(lucid_ole_vco), 62 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], 63 .clkr = { 64 .hw.init = &(const struct clk_init_data) { 65 .name = "video_cc_pll0", 66 .parent_data = &(const struct clk_parent_data) { 67 .index = DT_BI_TCXO, 68 }, 69 .num_parents = 1, 70 .ops = &clk_alpha_pll_lucid_evo_ops, 71 }, 72 }, 73 }; 74 75 static const struct parent_map video_cc_parent_map_0[] = { 76 { P_BI_TCXO, 0 }, 77 }; 78 79 static const struct clk_parent_data video_cc_parent_data_0[] = { 80 { .index = DT_BI_TCXO }, 81 }; 82 83 static const struct clk_parent_data video_cc_parent_data_0_ao[] = { 84 { .index = DT_BI_TCXO_AO }, 85 }; 86 87 static const struct parent_map video_cc_parent_map_1[] = { 88 { P_BI_TCXO, 0 }, 89 { P_VIDEO_CC_PLL0_OUT_MAIN, 1 }, 90 }; 91 92 static const struct clk_parent_data video_cc_parent_data_1[] = { 93 { .index = DT_BI_TCXO }, 94 { .hw = &video_cc_pll0.clkr.hw }, 95 }; 96 97 static const struct parent_map video_cc_parent_map_2[] = { 98 { P_SLEEP_CLK, 0 }, 99 }; 100 101 static const struct clk_parent_data video_cc_parent_data_2_ao[] = { 102 { .index = DT_SLEEP_CLK }, 103 }; 104 105 static const struct freq_tbl ftbl_video_cc_ahb_clk_src[] = { 106 F(19200000, P_BI_TCXO, 1, 0, 0), 107 { } 108 }; 109 110 static struct clk_rcg2 video_cc_ahb_clk_src = { 111 .cmd_rcgr = 0x8030, 112 .mnd_width = 0, 113 .hid_width = 5, 114 .parent_map = video_cc_parent_map_0, 115 .freq_tbl = ftbl_video_cc_ahb_clk_src, 116 .clkr.hw.init = &(const struct clk_init_data) { 117 .name = "video_cc_ahb_clk_src", 118 .parent_data = video_cc_parent_data_0_ao, 119 .num_parents = ARRAY_SIZE(video_cc_parent_data_0_ao), 120 .flags = CLK_SET_RATE_PARENT, 121 .ops = &clk_rcg2_shared_ops, 122 }, 123 }; 124 125 static const struct freq_tbl ftbl_video_cc_mvs0_clk_src[] = { 126 F(604800000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0), 127 F(720000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0), 128 F(1014000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0), 129 F(1098000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0), 130 F(1332000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0), 131 F(1656000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0), 132 { } 133 }; 134 135 static struct clk_rcg2 video_cc_mvs0_clk_src = { 136 .cmd_rcgr = 0x8000, 137 .mnd_width = 0, 138 .hid_width = 5, 139 .parent_map = video_cc_parent_map_1, 140 .freq_tbl = ftbl_video_cc_mvs0_clk_src, 141 .clkr.hw.init = &(const struct clk_init_data) { 142 .name = "video_cc_mvs0_clk_src", 143 .parent_data = video_cc_parent_data_1, 144 .num_parents = ARRAY_SIZE(video_cc_parent_data_1), 145 .flags = CLK_SET_RATE_PARENT, 146 .ops = &clk_rcg2_shared_ops, 147 }, 148 }; 149 150 static const struct freq_tbl ftbl_video_cc_sleep_clk_src[] = { 151 F(32000, P_SLEEP_CLK, 1, 0, 0), 152 { } 153 }; 154 155 static struct clk_rcg2 video_cc_sleep_clk_src = { 156 .cmd_rcgr = 0x8128, 157 .mnd_width = 0, 158 .hid_width = 5, 159 .parent_map = video_cc_parent_map_2, 160 .freq_tbl = ftbl_video_cc_sleep_clk_src, 161 .clkr.hw.init = &(const struct clk_init_data) { 162 .name = "video_cc_sleep_clk_src", 163 .parent_data = video_cc_parent_data_2_ao, 164 .num_parents = ARRAY_SIZE(video_cc_parent_data_2_ao), 165 .flags = CLK_SET_RATE_PARENT, 166 .ops = &clk_rcg2_ops, 167 }, 168 }; 169 170 static struct clk_rcg2 video_cc_xo_clk_src = { 171 .cmd_rcgr = 0x810c, 172 .mnd_width = 0, 173 .hid_width = 5, 174 .parent_map = video_cc_parent_map_0, 175 .freq_tbl = ftbl_video_cc_ahb_clk_src, 176 .clkr.hw.init = &(const struct clk_init_data) { 177 .name = "video_cc_xo_clk_src", 178 .parent_data = video_cc_parent_data_0, 179 .num_parents = ARRAY_SIZE(video_cc_parent_data_0), 180 .flags = CLK_SET_RATE_PARENT, 181 .ops = &clk_rcg2_ops, 182 }, 183 }; 184 185 static struct clk_regmap_div video_cc_mvs0_div_clk_src = { 186 .reg = 0x80c4, 187 .shift = 0, 188 .width = 4, 189 .clkr.hw.init = &(const struct clk_init_data) { 190 .name = "video_cc_mvs0_div_clk_src", 191 .parent_hws = (const struct clk_hw*[]) { 192 &video_cc_mvs0_clk_src.clkr.hw, 193 }, 194 .num_parents = 1, 195 .flags = CLK_SET_RATE_PARENT, 196 .ops = &clk_regmap_div_ro_ops, 197 }, 198 }; 199 200 static struct clk_regmap_div video_cc_mvs0c_div2_div_clk_src = { 201 .reg = 0x8070, 202 .shift = 0, 203 .width = 4, 204 .clkr.hw.init = &(const struct clk_init_data) { 205 .name = "video_cc_mvs0c_div2_div_clk_src", 206 .parent_hws = (const struct clk_hw*[]) { 207 &video_cc_mvs0_clk_src.clkr.hw, 208 }, 209 .num_parents = 1, 210 .flags = CLK_SET_RATE_PARENT, 211 .ops = &clk_regmap_div_ro_ops, 212 }, 213 }; 214 215 static struct clk_branch video_cc_mvs0_clk = { 216 .halt_reg = 0x80b8, 217 .halt_check = BRANCH_HALT_VOTED, 218 .hwcg_reg = 0x80b8, 219 .hwcg_bit = 1, 220 .clkr = { 221 .enable_reg = 0x80b8, 222 .enable_mask = BIT(0), 223 .hw.init = &(const struct clk_init_data) { 224 .name = "video_cc_mvs0_clk", 225 .parent_hws = (const struct clk_hw*[]) { 226 &video_cc_mvs0_div_clk_src.clkr.hw, 227 }, 228 .num_parents = 1, 229 .flags = CLK_SET_RATE_PARENT, 230 .ops = &clk_branch2_ops, 231 }, 232 }, 233 }; 234 235 static struct clk_branch video_cc_mvs0_shift_clk = { 236 .halt_reg = 0x8144, 237 .halt_check = BRANCH_HALT_VOTED, 238 .hwcg_reg = 0x8144, 239 .hwcg_bit = 1, 240 .clkr = { 241 .enable_reg = 0x8144, 242 .enable_mask = BIT(0), 243 .hw.init = &(const struct clk_init_data) { 244 .name = "video_cc_mvs0_shift_clk", 245 .parent_hws = (const struct clk_hw*[]) { 246 &video_cc_xo_clk_src.clkr.hw, 247 }, 248 .num_parents = 1, 249 .flags = CLK_SET_RATE_PARENT, 250 .ops = &clk_branch2_ops, 251 }, 252 }, 253 }; 254 255 static struct clk_branch video_cc_mvs0c_clk = { 256 .halt_reg = 0x8064, 257 .halt_check = BRANCH_HALT, 258 .clkr = { 259 .enable_reg = 0x8064, 260 .enable_mask = BIT(0), 261 .hw.init = &(const struct clk_init_data) { 262 .name = "video_cc_mvs0c_clk", 263 .parent_hws = (const struct clk_hw*[]) { 264 &video_cc_mvs0c_div2_div_clk_src.clkr.hw, 265 }, 266 .num_parents = 1, 267 .flags = CLK_SET_RATE_PARENT, 268 .ops = &clk_branch2_ops, 269 }, 270 }, 271 }; 272 273 static struct clk_branch video_cc_mvs0c_shift_clk = { 274 .halt_reg = 0x8148, 275 .halt_check = BRANCH_HALT_VOTED, 276 .hwcg_reg = 0x8148, 277 .hwcg_bit = 1, 278 .clkr = { 279 .enable_reg = 0x8148, 280 .enable_mask = BIT(0), 281 .hw.init = &(const struct clk_init_data) { 282 .name = "video_cc_mvs0c_shift_clk", 283 .parent_hws = (const struct clk_hw*[]) { 284 &video_cc_xo_clk_src.clkr.hw, 285 }, 286 .num_parents = 1, 287 .flags = CLK_SET_RATE_PARENT, 288 .ops = &clk_branch2_ops, 289 }, 290 }, 291 }; 292 293 static struct gdsc video_cc_mvs0c_gdsc = { 294 .gdscr = 0x804c, 295 .en_rest_wait_val = 0x2, 296 .en_few_wait_val = 0x2, 297 .clk_dis_wait_val = 0x6, 298 .pd = { 299 .name = "video_cc_mvs0c_gdsc", 300 }, 301 .pwrsts = PWRSTS_OFF_ON, 302 .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, 303 }; 304 305 static struct gdsc video_cc_mvs0_gdsc = { 306 .gdscr = 0x80a4, 307 .en_rest_wait_val = 0x2, 308 .en_few_wait_val = 0x2, 309 .clk_dis_wait_val = 0x6, 310 .pd = { 311 .name = "video_cc_mvs0_gdsc", 312 }, 313 .pwrsts = PWRSTS_OFF_ON, 314 .parent = &video_cc_mvs0c_gdsc.pd, 315 .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | HW_CTRL_TRIGGER, 316 }; 317 318 static struct clk_regmap *video_cc_milos_clocks[] = { 319 [VIDEO_CC_AHB_CLK_SRC] = &video_cc_ahb_clk_src.clkr, 320 [VIDEO_CC_MVS0_CLK] = &video_cc_mvs0_clk.clkr, 321 [VIDEO_CC_MVS0_CLK_SRC] = &video_cc_mvs0_clk_src.clkr, 322 [VIDEO_CC_MVS0_DIV_CLK_SRC] = &video_cc_mvs0_div_clk_src.clkr, 323 [VIDEO_CC_MVS0_SHIFT_CLK] = &video_cc_mvs0_shift_clk.clkr, 324 [VIDEO_CC_MVS0C_CLK] = &video_cc_mvs0c_clk.clkr, 325 [VIDEO_CC_MVS0C_DIV2_DIV_CLK_SRC] = &video_cc_mvs0c_div2_div_clk_src.clkr, 326 [VIDEO_CC_MVS0C_SHIFT_CLK] = &video_cc_mvs0c_shift_clk.clkr, 327 [VIDEO_CC_PLL0] = &video_cc_pll0.clkr, 328 [VIDEO_CC_SLEEP_CLK_SRC] = &video_cc_sleep_clk_src.clkr, 329 [VIDEO_CC_XO_CLK_SRC] = &video_cc_xo_clk_src.clkr, 330 }; 331 332 static struct gdsc *video_cc_milos_gdscs[] = { 333 [VIDEO_CC_MVS0C_GDSC] = &video_cc_mvs0c_gdsc, 334 [VIDEO_CC_MVS0_GDSC] = &video_cc_mvs0_gdsc, 335 }; 336 337 static const struct qcom_reset_map video_cc_milos_resets[] = { 338 [VIDEO_CC_INTERFACE_BCR] = { 0x80f0 }, 339 [VIDEO_CC_MVS0_BCR] = { 0x80a0 }, 340 [VIDEO_CC_MVS0C_CLK_ARES] = { 0x8064, 2 }, 341 [VIDEO_CC_MVS0C_BCR] = { 0x8048 }, 342 }; 343 344 static struct clk_alpha_pll *video_cc_milos_plls[] = { 345 &video_cc_pll0, 346 }; 347 348 static u32 video_cc_milos_critical_cbcrs[] = { 349 0x80f4, /* VIDEO_CC_AHB_CLK */ 350 0x8140, /* VIDEO_CC_SLEEP_CLK */ 351 0x8124, /* VIDEO_CC_XO_CLK */ 352 }; 353 354 static const struct regmap_config video_cc_milos_regmap_config = { 355 .reg_bits = 32, 356 .reg_stride = 4, 357 .val_bits = 32, 358 .max_register = 0x9f50, 359 .fast_io = true, 360 }; 361 362 static struct qcom_cc_driver_data video_cc_milos_driver_data = { 363 .alpha_plls = video_cc_milos_plls, 364 .num_alpha_plls = ARRAY_SIZE(video_cc_milos_plls), 365 .clk_cbcrs = video_cc_milos_critical_cbcrs, 366 .num_clk_cbcrs = ARRAY_SIZE(video_cc_milos_critical_cbcrs), 367 }; 368 369 static struct qcom_cc_desc video_cc_milos_desc = { 370 .config = &video_cc_milos_regmap_config, 371 .clks = video_cc_milos_clocks, 372 .num_clks = ARRAY_SIZE(video_cc_milos_clocks), 373 .resets = video_cc_milos_resets, 374 .num_resets = ARRAY_SIZE(video_cc_milos_resets), 375 .gdscs = video_cc_milos_gdscs, 376 .num_gdscs = ARRAY_SIZE(video_cc_milos_gdscs), 377 .use_rpm = true, 378 .driver_data = &video_cc_milos_driver_data, 379 }; 380 381 static const struct of_device_id video_cc_milos_match_table[] = { 382 { .compatible = "qcom,milos-videocc" }, 383 { } 384 }; 385 MODULE_DEVICE_TABLE(of, video_cc_milos_match_table); 386 387 static int video_cc_milos_probe(struct platform_device *pdev) 388 { 389 return qcom_cc_probe(pdev, &video_cc_milos_desc); 390 } 391 392 static struct platform_driver video_cc_milos_driver = { 393 .probe = video_cc_milos_probe, 394 .driver = { 395 .name = "video_cc-milos", 396 .of_match_table = video_cc_milos_match_table, 397 }, 398 }; 399 400 module_platform_driver(video_cc_milos_driver); 401 402 MODULE_DESCRIPTION("QTI VIDEO_CC Milos Driver"); 403 MODULE_LICENSE("GPL"); 404