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