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