1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2019, 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-sc7180.h> 12 13 #include "clk-alpha-pll.h" 14 #include "clk-branch.h" 15 #include "clk-rcg.h" 16 #include "clk-regmap.h" 17 #include "common.h" 18 #include "gdsc.h" 19 20 enum { 21 P_BI_TCXO, 22 P_CHIP_SLEEP_CLK, 23 P_CORE_BI_PLL_TEST_SE, 24 P_VIDEO_PLL0_OUT_EVEN, 25 P_VIDEO_PLL0_OUT_MAIN, 26 P_VIDEO_PLL0_OUT_ODD, 27 }; 28 29 static const struct pll_vco fabia_vco[] = { 30 { 249600000, 2000000000, 0 }, 31 }; 32 33 static struct clk_alpha_pll video_pll0 = { 34 .offset = 0x42c, 35 .vco_table = fabia_vco, 36 .num_vco = ARRAY_SIZE(fabia_vco), 37 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], 38 .clkr = { 39 .hw.init = &(struct clk_init_data){ 40 .name = "video_pll0", 41 .parent_data = &(const struct clk_parent_data){ 42 .fw_name = "bi_tcxo", 43 }, 44 .num_parents = 1, 45 .ops = &clk_alpha_pll_fabia_ops, 46 }, 47 }, 48 }; 49 50 static const struct parent_map video_cc_parent_map_1[] = { 51 { P_BI_TCXO, 0 }, 52 { P_VIDEO_PLL0_OUT_MAIN, 1 }, 53 }; 54 55 static const struct clk_parent_data video_cc_parent_data_1[] = { 56 { .fw_name = "bi_tcxo" }, 57 { .hw = &video_pll0.clkr.hw }, 58 }; 59 60 static const struct freq_tbl ftbl_video_cc_venus_clk_src[] = { 61 F(19200000, P_BI_TCXO, 1, 0, 0), 62 F(150000000, P_VIDEO_PLL0_OUT_MAIN, 4, 0, 0), 63 F(270000000, P_VIDEO_PLL0_OUT_MAIN, 2.5, 0, 0), 64 F(340000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), 65 F(434000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), 66 F(500000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), 67 { } 68 }; 69 70 static struct clk_rcg2 video_cc_venus_clk_src = { 71 .cmd_rcgr = 0x7f0, 72 .mnd_width = 0, 73 .hid_width = 5, 74 .parent_map = video_cc_parent_map_1, 75 .freq_tbl = ftbl_video_cc_venus_clk_src, 76 .clkr.hw.init = &(struct clk_init_data){ 77 .name = "video_cc_venus_clk_src", 78 .parent_data = video_cc_parent_data_1, 79 .num_parents = ARRAY_SIZE(video_cc_parent_data_1), 80 .flags = CLK_SET_RATE_PARENT, 81 .ops = &clk_rcg2_shared_ops, 82 }, 83 }; 84 85 static struct clk_branch video_cc_vcodec0_axi_clk = { 86 .halt_reg = 0x9ec, 87 .halt_check = BRANCH_HALT, 88 .clkr = { 89 .enable_reg = 0x9ec, 90 .enable_mask = BIT(0), 91 .hw.init = &(struct clk_init_data){ 92 .name = "video_cc_vcodec0_axi_clk", 93 .ops = &clk_branch2_ops, 94 }, 95 }, 96 }; 97 98 static struct clk_branch video_cc_vcodec0_core_clk = { 99 .halt_reg = 0x890, 100 .halt_check = BRANCH_HALT_VOTED, 101 .clkr = { 102 .enable_reg = 0x890, 103 .enable_mask = BIT(0), 104 .hw.init = &(struct clk_init_data){ 105 .name = "video_cc_vcodec0_core_clk", 106 .parent_data = &(const struct clk_parent_data){ 107 .hw = &video_cc_venus_clk_src.clkr.hw, 108 }, 109 .num_parents = 1, 110 .flags = CLK_SET_RATE_PARENT, 111 .ops = &clk_branch2_ops, 112 }, 113 }, 114 }; 115 116 static struct clk_branch video_cc_venus_ahb_clk = { 117 .halt_reg = 0xa4c, 118 .halt_check = BRANCH_HALT, 119 .clkr = { 120 .enable_reg = 0xa4c, 121 .enable_mask = BIT(0), 122 .hw.init = &(struct clk_init_data){ 123 .name = "video_cc_venus_ahb_clk", 124 .ops = &clk_branch2_ops, 125 }, 126 }, 127 }; 128 129 static struct clk_branch video_cc_venus_ctl_axi_clk = { 130 .halt_reg = 0x9cc, 131 .halt_check = BRANCH_HALT, 132 .clkr = { 133 .enable_reg = 0x9cc, 134 .enable_mask = BIT(0), 135 .hw.init = &(struct clk_init_data){ 136 .name = "video_cc_venus_ctl_axi_clk", 137 .ops = &clk_branch2_ops, 138 }, 139 }, 140 }; 141 142 static struct clk_branch video_cc_venus_ctl_core_clk = { 143 .halt_reg = 0x850, 144 .halt_check = BRANCH_HALT, 145 .clkr = { 146 .enable_reg = 0x850, 147 .enable_mask = BIT(0), 148 .hw.init = &(struct clk_init_data){ 149 .name = "video_cc_venus_ctl_core_clk", 150 .parent_data = &(const struct clk_parent_data){ 151 .hw = &video_cc_venus_clk_src.clkr.hw, 152 }, 153 .num_parents = 1, 154 .flags = CLK_SET_RATE_PARENT, 155 .ops = &clk_branch2_ops, 156 }, 157 }, 158 }; 159 160 static struct gdsc venus_gdsc = { 161 .gdscr = 0x814, 162 .pd = { 163 .name = "venus_gdsc", 164 }, 165 .pwrsts = PWRSTS_OFF_ON, 166 }; 167 168 static struct gdsc vcodec0_gdsc = { 169 .gdscr = 0x874, 170 .pd = { 171 .name = "vcodec0_gdsc", 172 }, 173 .flags = HW_CTRL, 174 .pwrsts = PWRSTS_OFF_ON, 175 }; 176 177 static struct clk_regmap *video_cc_sc7180_clocks[] = { 178 [VIDEO_CC_VCODEC0_AXI_CLK] = &video_cc_vcodec0_axi_clk.clkr, 179 [VIDEO_CC_VCODEC0_CORE_CLK] = &video_cc_vcodec0_core_clk.clkr, 180 [VIDEO_CC_VENUS_AHB_CLK] = &video_cc_venus_ahb_clk.clkr, 181 [VIDEO_CC_VENUS_CLK_SRC] = &video_cc_venus_clk_src.clkr, 182 [VIDEO_CC_VENUS_CTL_AXI_CLK] = &video_cc_venus_ctl_axi_clk.clkr, 183 [VIDEO_CC_VENUS_CTL_CORE_CLK] = &video_cc_venus_ctl_core_clk.clkr, 184 [VIDEO_PLL0] = &video_pll0.clkr, 185 }; 186 187 static struct gdsc *video_cc_sc7180_gdscs[] = { 188 [VENUS_GDSC] = &venus_gdsc, 189 [VCODEC0_GDSC] = &vcodec0_gdsc, 190 }; 191 192 static const struct regmap_config video_cc_sc7180_regmap_config = { 193 .reg_bits = 32, 194 .reg_stride = 4, 195 .val_bits = 32, 196 .max_register = 0xb94, 197 .fast_io = true, 198 }; 199 200 static const struct qcom_cc_desc video_cc_sc7180_desc = { 201 .config = &video_cc_sc7180_regmap_config, 202 .clks = video_cc_sc7180_clocks, 203 .num_clks = ARRAY_SIZE(video_cc_sc7180_clocks), 204 .gdscs = video_cc_sc7180_gdscs, 205 .num_gdscs = ARRAY_SIZE(video_cc_sc7180_gdscs), 206 }; 207 208 static const struct of_device_id video_cc_sc7180_match_table[] = { 209 { .compatible = "qcom,sc7180-videocc" }, 210 { } 211 }; 212 MODULE_DEVICE_TABLE(of, video_cc_sc7180_match_table); 213 214 static int video_cc_sc7180_probe(struct platform_device *pdev) 215 { 216 struct regmap *regmap; 217 struct alpha_pll_config video_pll0_config = {}; 218 219 regmap = qcom_cc_map(pdev, &video_cc_sc7180_desc); 220 if (IS_ERR(regmap)) 221 return PTR_ERR(regmap); 222 223 video_pll0_config.l = 0x1f; 224 video_pll0_config.alpha = 0x4000; 225 video_pll0_config.user_ctl_val = 0x00000001; 226 video_pll0_config.user_ctl_hi_val = 0x00004805; 227 228 clk_fabia_pll_configure(&video_pll0, regmap, &video_pll0_config); 229 230 /* Keep VIDEO_CC_XO_CLK ALWAYS-ON */ 231 regmap_update_bits(regmap, 0x984, 0x1, 0x1); 232 233 return qcom_cc_really_probe(pdev, &video_cc_sc7180_desc, regmap); 234 } 235 236 static struct platform_driver video_cc_sc7180_driver = { 237 .probe = video_cc_sc7180_probe, 238 .driver = { 239 .name = "sc7180-videocc", 240 .of_match_table = video_cc_sc7180_match_table, 241 }, 242 }; 243 244 static int __init video_cc_sc7180_init(void) 245 { 246 return platform_driver_register(&video_cc_sc7180_driver); 247 } 248 subsys_initcall(video_cc_sc7180_init); 249 250 static void __exit video_cc_sc7180_exit(void) 251 { 252 platform_driver_unregister(&video_cc_sc7180_driver); 253 } 254 module_exit(video_cc_sc7180_exit); 255 256 MODULE_LICENSE("GPL v2"); 257 MODULE_DESCRIPTION("QTI VIDEOCC SC7180 Driver"); 258