1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (c) 2018, 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-sdm845.h> |
12 | |
13 | #include "common.h" |
14 | #include "clk-alpha-pll.h" |
15 | #include "clk-branch.h" |
16 | #include "clk-rcg.h" |
17 | #include "clk-regmap.h" |
18 | #include "clk-pll.h" |
19 | #include "gdsc.h" |
20 | |
21 | enum { |
22 | P_BI_TCXO, |
23 | P_VIDEO_PLL0_OUT_MAIN, |
24 | /* P_VIDEO_PLL0_OUT_EVEN, */ |
25 | /* P_VIDEO_PLL0_OUT_ODD, */ |
26 | }; |
27 | |
28 | static const struct alpha_pll_config video_pll0_config = { |
29 | .l = 0x10, |
30 | .alpha = 0xaaab, |
31 | }; |
32 | |
33 | static struct clk_alpha_pll video_pll0 = { |
34 | .offset = 0x42c, |
35 | .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], |
36 | .clkr = { |
37 | .hw.init = &(struct clk_init_data){ |
38 | .name = "video_pll0" , |
39 | .parent_data = &(const struct clk_parent_data){ |
40 | .fw_name = "bi_tcxo" , .name = "bi_tcxo" , |
41 | }, |
42 | .num_parents = 1, |
43 | .ops = &clk_alpha_pll_fabia_ops, |
44 | }, |
45 | }, |
46 | }; |
47 | |
48 | static const struct parent_map video_cc_parent_map_0[] = { |
49 | { P_BI_TCXO, 0 }, |
50 | { P_VIDEO_PLL0_OUT_MAIN, 1 }, |
51 | /* { P_VIDEO_PLL0_OUT_EVEN, 2 }, */ |
52 | /* { P_VIDEO_PLL0_OUT_ODD, 3 }, */ |
53 | }; |
54 | |
55 | static const struct clk_parent_data video_cc_parent_data_0[] = { |
56 | { .fw_name = "bi_tcxo" , .name = "bi_tcxo" }, |
57 | { .hw = &video_pll0.clkr.hw }, |
58 | /* { .name = "video_pll0_out_even" }, */ |
59 | /* { .name = "video_pll0_out_odd" }, */ |
60 | }; |
61 | |
62 | static const struct freq_tbl ftbl_video_cc_venus_clk_src[] = { |
63 | F(100000000, P_VIDEO_PLL0_OUT_MAIN, 4, 0, 0), |
64 | F(200000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), |
65 | F(330000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0), |
66 | F(404000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0), |
67 | F(444000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0), |
68 | F(533000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0), |
69 | { } |
70 | }; |
71 | |
72 | static struct clk_rcg2 video_cc_venus_clk_src = { |
73 | .cmd_rcgr = 0x7f0, |
74 | .mnd_width = 0, |
75 | .hid_width = 5, |
76 | .parent_map = video_cc_parent_map_0, |
77 | .freq_tbl = ftbl_video_cc_venus_clk_src, |
78 | .clkr.hw.init = &(struct clk_init_data){ |
79 | .name = "video_cc_venus_clk_src" , |
80 | .parent_data = video_cc_parent_data_0, |
81 | .num_parents = ARRAY_SIZE(video_cc_parent_data_0), |
82 | .flags = CLK_SET_RATE_PARENT, |
83 | .ops = &clk_rcg2_shared_ops, |
84 | }, |
85 | }; |
86 | |
87 | static struct clk_branch video_cc_apb_clk = { |
88 | .halt_reg = 0x990, |
89 | .halt_check = BRANCH_HALT, |
90 | .clkr = { |
91 | .enable_reg = 0x990, |
92 | .enable_mask = BIT(0), |
93 | .hw.init = &(struct clk_init_data){ |
94 | .name = "video_cc_apb_clk" , |
95 | .ops = &clk_branch2_ops, |
96 | }, |
97 | }, |
98 | }; |
99 | |
100 | static struct clk_branch video_cc_at_clk = { |
101 | .halt_reg = 0x9f0, |
102 | .halt_check = BRANCH_HALT, |
103 | .clkr = { |
104 | .enable_reg = 0x9f0, |
105 | .enable_mask = BIT(0), |
106 | .hw.init = &(struct clk_init_data){ |
107 | .name = "video_cc_at_clk" , |
108 | .ops = &clk_branch2_ops, |
109 | }, |
110 | }, |
111 | }; |
112 | |
113 | static struct clk_branch video_cc_qdss_trig_clk = { |
114 | .halt_reg = 0x970, |
115 | .halt_check = BRANCH_HALT, |
116 | .clkr = { |
117 | .enable_reg = 0x970, |
118 | .enable_mask = BIT(0), |
119 | .hw.init = &(struct clk_init_data){ |
120 | .name = "video_cc_qdss_trig_clk" , |
121 | .ops = &clk_branch2_ops, |
122 | }, |
123 | }, |
124 | }; |
125 | |
126 | static struct clk_branch video_cc_qdss_tsctr_div8_clk = { |
127 | .halt_reg = 0x9d0, |
128 | .halt_check = BRANCH_HALT, |
129 | .clkr = { |
130 | .enable_reg = 0x9d0, |
131 | .enable_mask = BIT(0), |
132 | .hw.init = &(struct clk_init_data){ |
133 | .name = "video_cc_qdss_tsctr_div8_clk" , |
134 | .ops = &clk_branch2_ops, |
135 | }, |
136 | }, |
137 | }; |
138 | |
139 | static struct clk_branch video_cc_vcodec0_axi_clk = { |
140 | .halt_reg = 0x930, |
141 | .halt_check = BRANCH_HALT, |
142 | .clkr = { |
143 | .enable_reg = 0x930, |
144 | .enable_mask = BIT(0), |
145 | .hw.init = &(struct clk_init_data){ |
146 | .name = "video_cc_vcodec0_axi_clk" , |
147 | .ops = &clk_branch2_ops, |
148 | }, |
149 | }, |
150 | }; |
151 | |
152 | static struct clk_branch video_cc_vcodec0_core_clk = { |
153 | .halt_reg = 0x890, |
154 | .halt_check = BRANCH_VOTED, |
155 | .clkr = { |
156 | .enable_reg = 0x890, |
157 | .enable_mask = BIT(0), |
158 | .hw.init = &(struct clk_init_data){ |
159 | .name = "video_cc_vcodec0_core_clk" , |
160 | .parent_hws = (const struct clk_hw*[]){ |
161 | &video_cc_venus_clk_src.clkr.hw, |
162 | }, |
163 | .num_parents = 1, |
164 | .flags = CLK_SET_RATE_PARENT, |
165 | .ops = &clk_branch2_ops, |
166 | }, |
167 | }, |
168 | }; |
169 | |
170 | static struct clk_branch video_cc_vcodec1_axi_clk = { |
171 | .halt_reg = 0x950, |
172 | .halt_check = BRANCH_HALT, |
173 | .clkr = { |
174 | .enable_reg = 0x950, |
175 | .enable_mask = BIT(0), |
176 | .hw.init = &(struct clk_init_data){ |
177 | .name = "video_cc_vcodec1_axi_clk" , |
178 | .ops = &clk_branch2_ops, |
179 | }, |
180 | }, |
181 | }; |
182 | |
183 | static struct clk_branch video_cc_vcodec1_core_clk = { |
184 | .halt_reg = 0x8d0, |
185 | .halt_check = BRANCH_VOTED, |
186 | .clkr = { |
187 | .enable_reg = 0x8d0, |
188 | .enable_mask = BIT(0), |
189 | .hw.init = &(struct clk_init_data){ |
190 | .name = "video_cc_vcodec1_core_clk" , |
191 | .parent_hws = (const struct clk_hw*[]){ |
192 | &video_cc_venus_clk_src.clkr.hw, |
193 | }, |
194 | .num_parents = 1, |
195 | .flags = CLK_SET_RATE_PARENT, |
196 | .ops = &clk_branch2_ops, |
197 | }, |
198 | }, |
199 | }; |
200 | |
201 | static struct clk_branch video_cc_venus_ahb_clk = { |
202 | .halt_reg = 0x9b0, |
203 | .halt_check = BRANCH_HALT, |
204 | .clkr = { |
205 | .enable_reg = 0x9b0, |
206 | .enable_mask = BIT(0), |
207 | .hw.init = &(struct clk_init_data){ |
208 | .name = "video_cc_venus_ahb_clk" , |
209 | .ops = &clk_branch2_ops, |
210 | }, |
211 | }, |
212 | }; |
213 | |
214 | static struct clk_branch video_cc_venus_ctl_axi_clk = { |
215 | .halt_reg = 0x910, |
216 | .halt_check = BRANCH_HALT, |
217 | .clkr = { |
218 | .enable_reg = 0x910, |
219 | .enable_mask = BIT(0), |
220 | .hw.init = &(struct clk_init_data){ |
221 | .name = "video_cc_venus_ctl_axi_clk" , |
222 | .ops = &clk_branch2_ops, |
223 | }, |
224 | }, |
225 | }; |
226 | |
227 | static struct clk_branch video_cc_venus_ctl_core_clk = { |
228 | .halt_reg = 0x850, |
229 | .halt_check = BRANCH_HALT, |
230 | .clkr = { |
231 | .enable_reg = 0x850, |
232 | .enable_mask = BIT(0), |
233 | .hw.init = &(struct clk_init_data){ |
234 | .name = "video_cc_venus_ctl_core_clk" , |
235 | .parent_hws = (const struct clk_hw*[]){ |
236 | &video_cc_venus_clk_src.clkr.hw, |
237 | }, |
238 | .num_parents = 1, |
239 | .flags = CLK_SET_RATE_PARENT, |
240 | .ops = &clk_branch2_ops, |
241 | }, |
242 | }, |
243 | }; |
244 | |
245 | static struct gdsc venus_gdsc = { |
246 | .gdscr = 0x814, |
247 | .pd = { |
248 | .name = "venus_gdsc" , |
249 | }, |
250 | .cxcs = (unsigned int []){ 0x850, 0x910 }, |
251 | .cxc_count = 2, |
252 | .pwrsts = PWRSTS_OFF_ON, |
253 | .flags = POLL_CFG_GDSCR, |
254 | }; |
255 | |
256 | static struct gdsc vcodec0_gdsc = { |
257 | .gdscr = 0x874, |
258 | .pd = { |
259 | .name = "vcodec0_gdsc" , |
260 | }, |
261 | .cxcs = (unsigned int []){ 0x890, 0x930 }, |
262 | .cxc_count = 2, |
263 | .flags = HW_CTRL | POLL_CFG_GDSCR, |
264 | .pwrsts = PWRSTS_OFF_ON, |
265 | }; |
266 | |
267 | static struct gdsc vcodec1_gdsc = { |
268 | .gdscr = 0x8b4, |
269 | .pd = { |
270 | .name = "vcodec1_gdsc" , |
271 | }, |
272 | .cxcs = (unsigned int []){ 0x8d0, 0x950 }, |
273 | .cxc_count = 2, |
274 | .flags = HW_CTRL | POLL_CFG_GDSCR, |
275 | .pwrsts = PWRSTS_OFF_ON, |
276 | }; |
277 | |
278 | static struct clk_regmap *video_cc_sdm845_clocks[] = { |
279 | [VIDEO_CC_APB_CLK] = &video_cc_apb_clk.clkr, |
280 | [VIDEO_CC_AT_CLK] = &video_cc_at_clk.clkr, |
281 | [VIDEO_CC_QDSS_TRIG_CLK] = &video_cc_qdss_trig_clk.clkr, |
282 | [VIDEO_CC_QDSS_TSCTR_DIV8_CLK] = &video_cc_qdss_tsctr_div8_clk.clkr, |
283 | [VIDEO_CC_VCODEC0_AXI_CLK] = &video_cc_vcodec0_axi_clk.clkr, |
284 | [VIDEO_CC_VCODEC0_CORE_CLK] = &video_cc_vcodec0_core_clk.clkr, |
285 | [VIDEO_CC_VCODEC1_AXI_CLK] = &video_cc_vcodec1_axi_clk.clkr, |
286 | [VIDEO_CC_VCODEC1_CORE_CLK] = &video_cc_vcodec1_core_clk.clkr, |
287 | [VIDEO_CC_VENUS_AHB_CLK] = &video_cc_venus_ahb_clk.clkr, |
288 | [VIDEO_CC_VENUS_CLK_SRC] = &video_cc_venus_clk_src.clkr, |
289 | [VIDEO_CC_VENUS_CTL_AXI_CLK] = &video_cc_venus_ctl_axi_clk.clkr, |
290 | [VIDEO_CC_VENUS_CTL_CORE_CLK] = &video_cc_venus_ctl_core_clk.clkr, |
291 | [VIDEO_PLL0] = &video_pll0.clkr, |
292 | }; |
293 | |
294 | static struct gdsc *video_cc_sdm845_gdscs[] = { |
295 | [VENUS_GDSC] = &venus_gdsc, |
296 | [VCODEC0_GDSC] = &vcodec0_gdsc, |
297 | [VCODEC1_GDSC] = &vcodec1_gdsc, |
298 | }; |
299 | |
300 | static const struct regmap_config video_cc_sdm845_regmap_config = { |
301 | .reg_bits = 32, |
302 | .reg_stride = 4, |
303 | .val_bits = 32, |
304 | .max_register = 0xb90, |
305 | .fast_io = true, |
306 | }; |
307 | |
308 | static const struct qcom_cc_desc video_cc_sdm845_desc = { |
309 | .config = &video_cc_sdm845_regmap_config, |
310 | .clks = video_cc_sdm845_clocks, |
311 | .num_clks = ARRAY_SIZE(video_cc_sdm845_clocks), |
312 | .gdscs = video_cc_sdm845_gdscs, |
313 | .num_gdscs = ARRAY_SIZE(video_cc_sdm845_gdscs), |
314 | }; |
315 | |
316 | static const struct of_device_id video_cc_sdm845_match_table[] = { |
317 | { .compatible = "qcom,sdm845-videocc" }, |
318 | { } |
319 | }; |
320 | MODULE_DEVICE_TABLE(of, video_cc_sdm845_match_table); |
321 | |
322 | static int video_cc_sdm845_probe(struct platform_device *pdev) |
323 | { |
324 | struct regmap *regmap; |
325 | |
326 | regmap = qcom_cc_map(pdev, desc: &video_cc_sdm845_desc); |
327 | if (IS_ERR(ptr: regmap)) |
328 | return PTR_ERR(ptr: regmap); |
329 | |
330 | clk_fabia_pll_configure(pll: &video_pll0, regmap, config: &video_pll0_config); |
331 | |
332 | return qcom_cc_really_probe(pdev, desc: &video_cc_sdm845_desc, regmap); |
333 | } |
334 | |
335 | static struct platform_driver video_cc_sdm845_driver = { |
336 | .probe = video_cc_sdm845_probe, |
337 | .driver = { |
338 | .name = "sdm845-videocc" , |
339 | .of_match_table = video_cc_sdm845_match_table, |
340 | }, |
341 | }; |
342 | |
343 | module_platform_driver(video_cc_sdm845_driver); |
344 | |
345 | MODULE_LICENSE("GPL v2" ); |
346 | |