1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2017-2020, 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/pm_runtime.h> 10 #include <linux/regmap.h> 11 12 #include <dt-bindings/clock/qcom,videocc-sm8150.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 "reset.h" 20 #include "gdsc.h" 21 22 enum { 23 P_BI_TCXO, 24 P_VIDEO_PLL0_OUT_MAIN, 25 }; 26 27 static const struct pll_vco trion_vco[] = { 28 { 249600000, 2000000000, 0 }, 29 }; 30 31 static struct alpha_pll_config video_pll0_config = { 32 .l = 0x14, 33 .alpha = 0xD555, 34 .config_ctl_val = 0x20485699, 35 .config_ctl_hi_val = 0x00002267, 36 .config_ctl_hi1_val = 0x00000024, 37 .test_ctl_hi1_val = 0x00000020, 38 .user_ctl_val = 0x00000000, 39 .user_ctl_hi_val = 0x00000805, 40 .user_ctl_hi1_val = 0x000000D0, 41 }; 42 43 static struct clk_alpha_pll video_pll0 = { 44 .offset = 0x42c, 45 .vco_table = trion_vco, 46 .num_vco = ARRAY_SIZE(trion_vco), 47 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TRION], 48 .clkr = { 49 .hw.init = &(struct clk_init_data){ 50 .name = "video_pll0", 51 .parent_data = &(const struct clk_parent_data){ 52 .fw_name = "bi_tcxo", 53 }, 54 .num_parents = 1, 55 .ops = &clk_alpha_pll_trion_ops, 56 }, 57 }, 58 }; 59 60 static const struct parent_map video_cc_parent_map_0[] = { 61 { P_BI_TCXO, 0 }, 62 { P_VIDEO_PLL0_OUT_MAIN, 1 }, 63 }; 64 65 static const struct clk_parent_data video_cc_parent_data_0[] = { 66 { .fw_name = "bi_tcxo" }, 67 { .hw = &video_pll0.clkr.hw }, 68 }; 69 70 static const struct freq_tbl ftbl_video_cc_iris_clk_src[] = { 71 F(19200000, P_BI_TCXO, 1, 0, 0), 72 F(200000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), 73 F(240000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), 74 F(338000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), 75 F(365000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), 76 F(444000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), 77 F(533000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), 78 { } 79 }; 80 81 static struct clk_rcg2 video_cc_iris_clk_src = { 82 .cmd_rcgr = 0x7f0, 83 .mnd_width = 0, 84 .hid_width = 5, 85 .parent_map = video_cc_parent_map_0, 86 .freq_tbl = ftbl_video_cc_iris_clk_src, 87 .clkr.hw.init = &(struct clk_init_data){ 88 .name = "video_cc_iris_clk_src", 89 .parent_data = video_cc_parent_data_0, 90 .num_parents = ARRAY_SIZE(video_cc_parent_data_0), 91 .flags = CLK_SET_RATE_PARENT, 92 .ops = &clk_rcg2_shared_ops, 93 }, 94 }; 95 96 static struct clk_branch video_cc_iris_ahb_clk = { 97 .halt_reg = 0x8f4, 98 .halt_check = BRANCH_VOTED, 99 .clkr = { 100 .enable_reg = 0x8f4, 101 .enable_mask = BIT(0), 102 .hw.init = &(struct clk_init_data){ 103 .name = "video_cc_iris_ahb_clk", 104 .parent_hws = (const struct clk_hw*[]){ 105 &video_cc_iris_clk_src.clkr.hw, 106 }, 107 .num_parents = 1, 108 .flags = CLK_SET_RATE_PARENT, 109 .ops = &clk_branch2_ops, 110 }, 111 }, 112 }; 113 114 static struct clk_branch video_cc_mvs0_core_clk = { 115 .halt_reg = 0x890, 116 .halt_check = BRANCH_VOTED, 117 .clkr = { 118 .enable_reg = 0x890, 119 .enable_mask = BIT(0), 120 .hw.init = &(struct clk_init_data){ 121 .name = "video_cc_mvs0_core_clk", 122 .parent_hws = (const struct clk_hw*[]){ 123 &video_cc_iris_clk_src.clkr.hw, 124 }, 125 .num_parents = 1, 126 .flags = CLK_SET_RATE_PARENT, 127 .ops = &clk_branch2_ops, 128 }, 129 }, 130 }; 131 132 static struct clk_branch video_cc_mvs1_core_clk = { 133 .halt_reg = 0x8d0, 134 .halt_check = BRANCH_VOTED, 135 .clkr = { 136 .enable_reg = 0x8d0, 137 .enable_mask = BIT(0), 138 .hw.init = &(struct clk_init_data){ 139 .name = "video_cc_mvs1_core_clk", 140 .parent_hws = (const struct clk_hw*[]){ 141 &video_cc_iris_clk_src.clkr.hw, 142 }, 143 .num_parents = 1, 144 .flags = CLK_SET_RATE_PARENT, 145 .ops = &clk_branch2_ops, 146 }, 147 }, 148 }; 149 150 static struct clk_branch video_cc_mvsc_core_clk = { 151 .halt_reg = 0x850, 152 .halt_check = BRANCH_HALT, 153 .clkr = { 154 .enable_reg = 0x850, 155 .enable_mask = BIT(0), 156 .hw.init = &(struct clk_init_data){ 157 .name = "video_cc_mvsc_core_clk", 158 .parent_hws = (const struct clk_hw*[]){ 159 &video_cc_iris_clk_src.clkr.hw, 160 }, 161 .num_parents = 1, 162 .flags = CLK_SET_RATE_PARENT, 163 .ops = &clk_branch2_ops, 164 }, 165 }, 166 }; 167 168 static struct gdsc venus_gdsc = { 169 .gdscr = 0x814, 170 .pd = { 171 .name = "venus_gdsc", 172 }, 173 .flags = 0, 174 .pwrsts = PWRSTS_OFF_ON, 175 }; 176 177 static struct gdsc vcodec0_gdsc = { 178 .gdscr = 0x874, 179 .pd = { 180 .name = "vcodec0_gdsc", 181 }, 182 .flags = HW_CTRL, 183 .pwrsts = PWRSTS_OFF_ON, 184 }; 185 186 static struct gdsc vcodec1_gdsc = { 187 .gdscr = 0x8b4, 188 .pd = { 189 .name = "vcodec1_gdsc", 190 }, 191 .flags = HW_CTRL, 192 .pwrsts = PWRSTS_OFF_ON, 193 }; 194 static struct clk_regmap *video_cc_sm8150_clocks[] = { 195 [VIDEO_CC_IRIS_AHB_CLK] = &video_cc_iris_ahb_clk.clkr, 196 [VIDEO_CC_IRIS_CLK_SRC] = &video_cc_iris_clk_src.clkr, 197 [VIDEO_CC_MVS0_CORE_CLK] = &video_cc_mvs0_core_clk.clkr, 198 [VIDEO_CC_MVS1_CORE_CLK] = &video_cc_mvs1_core_clk.clkr, 199 [VIDEO_CC_MVSC_CORE_CLK] = &video_cc_mvsc_core_clk.clkr, 200 [VIDEO_CC_PLL0] = &video_pll0.clkr, 201 }; 202 203 static struct gdsc *video_cc_sm8150_gdscs[] = { 204 [VENUS_GDSC] = &venus_gdsc, 205 [VCODEC0_GDSC] = &vcodec0_gdsc, 206 [VCODEC1_GDSC] = &vcodec1_gdsc, 207 }; 208 209 static const struct regmap_config video_cc_sm8150_regmap_config = { 210 .reg_bits = 32, 211 .reg_stride = 4, 212 .val_bits = 32, 213 .max_register = 0xb94, 214 .fast_io = true, 215 }; 216 217 static const struct qcom_reset_map video_cc_sm8150_resets[] = { 218 [VIDEO_CC_MVSC_CORE_CLK_BCR] = { .reg = 0x850, .bit = 2, .udelay = 150 }, 219 [VIDEO_CC_INTERFACE_BCR] = { 0x8f0 }, 220 [VIDEO_CC_MVS0_BCR] = { 0x870 }, 221 [VIDEO_CC_MVS1_BCR] = { 0x8b0 }, 222 [VIDEO_CC_MVSC_BCR] = { 0x810 }, 223 }; 224 225 static const struct qcom_cc_desc video_cc_sm8150_desc = { 226 .config = &video_cc_sm8150_regmap_config, 227 .clks = video_cc_sm8150_clocks, 228 .num_clks = ARRAY_SIZE(video_cc_sm8150_clocks), 229 .resets = video_cc_sm8150_resets, 230 .num_resets = ARRAY_SIZE(video_cc_sm8150_resets), 231 .gdscs = video_cc_sm8150_gdscs, 232 .num_gdscs = ARRAY_SIZE(video_cc_sm8150_gdscs), 233 }; 234 235 static const struct of_device_id video_cc_sm8150_match_table[] = { 236 { .compatible = "qcom,sm8150-videocc" }, 237 { } 238 }; 239 MODULE_DEVICE_TABLE(of, video_cc_sm8150_match_table); 240 241 static int video_cc_sm8150_probe(struct platform_device *pdev) 242 { 243 struct regmap *regmap; 244 int ret; 245 246 ret = devm_pm_runtime_enable(&pdev->dev); 247 if (ret) 248 return ret; 249 250 ret = pm_runtime_resume_and_get(&pdev->dev); 251 if (ret) 252 return ret; 253 254 regmap = qcom_cc_map(pdev, &video_cc_sm8150_desc); 255 if (IS_ERR(regmap)) { 256 pm_runtime_put_sync(&pdev->dev); 257 return PTR_ERR(regmap); 258 } 259 260 clk_trion_pll_configure(&video_pll0, regmap, &video_pll0_config); 261 262 /* Keep VIDEO_CC_XO_CLK ALWAYS-ON */ 263 regmap_update_bits(regmap, 0x984, 0x1, 0x1); 264 265 ret = qcom_cc_really_probe(&pdev->dev, &video_cc_sm8150_desc, regmap); 266 267 pm_runtime_put_sync(&pdev->dev); 268 269 return ret; 270 } 271 272 static struct platform_driver video_cc_sm8150_driver = { 273 .probe = video_cc_sm8150_probe, 274 .driver = { 275 .name = "video_cc-sm8150", 276 .of_match_table = video_cc_sm8150_match_table, 277 }, 278 }; 279 280 module_platform_driver(video_cc_sm8150_driver); 281 282 MODULE_LICENSE("GPL v2"); 283 MODULE_DESCRIPTION("QTI VIDEOCC SM8150 Driver"); 284