Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.5.6.
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
  4 */
  5
  6#include <linux/clk-provider.h>
  7#include <linux/mod_devicetable.h>
  8#include <linux/module.h>
  9#include <linux/platform_device.h>
 10#include <linux/pm_runtime.h>
 11#include <linux/regmap.h>
 12
 13#include <dt-bindings/clock/qcom,sm8450-videocc.h>
 14
 15#include "clk-alpha-pll.h"
 16#include "clk-branch.h"
 17#include "clk-rcg.h"
 18#include "clk-regmap.h"
 19#include "clk-regmap-divider.h"
 20#include "common.h"
 21#include "gdsc.h"
 22#include "reset.h"
 23
 24enum {
 25	DT_BI_TCXO,
 26};
 27
 28enum {
 29	P_BI_TCXO,
 30	P_VIDEO_CC_PLL0_OUT_MAIN,
 31	P_VIDEO_CC_PLL1_OUT_MAIN,
 32};
 33
 34static const struct pll_vco lucid_evo_vco[] = {
 35	{ 249600000, 2020000000, 0 },
 36};
 37
 38static const struct alpha_pll_config video_cc_pll0_config = {
 39	/* .l includes CAL_L_VAL, L_VAL fields */
 40	.l = 0x0044001e,
 41	.alpha = 0x0,
 42	.config_ctl_val = 0x20485699,
 43	.config_ctl_hi_val = 0x00182261,
 44	.config_ctl_hi1_val = 0x32aa299c,
 45	.user_ctl_val = 0x00000000,
 46	.user_ctl_hi_val = 0x00000805,
 47};
 48
 49static const struct alpha_pll_config sm8475_video_cc_pll0_config = {
 50	/* .l includes CAL_L_VAL, L_VAL fields */
 51	.l = 0x1e,
 52	.alpha = 0x0,
 53	.config_ctl_val = 0x20485699,
 54	.config_ctl_hi_val = 0x00182261,
 55	.config_ctl_hi1_val = 0x82aa299c,
 56	.test_ctl_val = 0x00000000,
 57	.test_ctl_hi_val = 0x00000003,
 58	.test_ctl_hi1_val = 0x00009000,
 59	.test_ctl_hi2_val = 0x00000034,
 60	.user_ctl_val = 0x00000000,
 61	.user_ctl_hi_val = 0x00000005,
 62};
 63
 64static struct clk_alpha_pll video_cc_pll0 = {
 65	.offset = 0x0,
 66	.vco_table = lucid_evo_vco,
 67	.num_vco = ARRAY_SIZE(lucid_evo_vco),
 68	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
 69	.clkr = {
 70		.hw.init = &(const struct clk_init_data) {
 71			.name = "video_cc_pll0",
 72			.parent_data = &(const struct clk_parent_data) {
 73				.index = DT_BI_TCXO,
 74			},
 75			.num_parents = 1,
 76			.ops = &clk_alpha_pll_lucid_evo_ops,
 77		},
 78	},
 79};
 80
 81static const struct alpha_pll_config video_cc_pll1_config = {
 82	/* .l includes CAL_L_VAL, L_VAL fields */
 83	.l = 0x0044002b,
 84	.alpha = 0xc000,
 85	.config_ctl_val = 0x20485699,
 86	.config_ctl_hi_val = 0x00182261,
 87	.config_ctl_hi1_val = 0x32aa299c,
 88	.user_ctl_val = 0x00000000,
 89	.user_ctl_hi_val = 0x00000805,
 90};
 91
 92static const struct alpha_pll_config sm8475_video_cc_pll1_config = {
 93	/* .l includes CAL_L_VAL, L_VAL fields */
 94	.l = 0x2b,
 95	.alpha = 0xc000,
 96	.config_ctl_val = 0x20485699,
 97	.config_ctl_hi_val = 0x00182261,
 98	.config_ctl_hi1_val = 0x82aa299c,
 99	.test_ctl_val = 0x00000000,
100	.test_ctl_hi_val = 0x00000003,
101	.test_ctl_hi1_val = 0x00009000,
102	.test_ctl_hi2_val = 0x00000034,
103	.user_ctl_val = 0x00000000,
104	.user_ctl_hi_val = 0x00000005,
105};
106
107static struct clk_alpha_pll video_cc_pll1 = {
108	.offset = 0x1000,
109	.vco_table = lucid_evo_vco,
110	.num_vco = ARRAY_SIZE(lucid_evo_vco),
111	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
112	.clkr = {
113		.hw.init = &(const struct clk_init_data) {
114			.name = "video_cc_pll1",
115			.parent_data = &(const struct clk_parent_data) {
116				.index = DT_BI_TCXO,
117			},
118			.num_parents = 1,
119			.ops = &clk_alpha_pll_lucid_evo_ops,
120		},
121	},
122};
123
124static const struct parent_map video_cc_parent_map_0[] = {
125	{ P_BI_TCXO, 0 },
126	{ P_VIDEO_CC_PLL0_OUT_MAIN, 1 },
127};
128
129static const struct clk_parent_data video_cc_parent_data_0[] = {
130	{ .index = DT_BI_TCXO },
131	{ .hw = &video_cc_pll0.clkr.hw },
132};
133
134static const struct parent_map video_cc_parent_map_1[] = {
135	{ P_BI_TCXO, 0 },
136	{ P_VIDEO_CC_PLL1_OUT_MAIN, 1 },
137};
138
139static const struct clk_parent_data video_cc_parent_data_1[] = {
140	{ .index = DT_BI_TCXO },
141	{ .hw = &video_cc_pll1.clkr.hw },
142};
143
144static const struct freq_tbl ftbl_video_cc_mvs0_clk_src[] = {
145	F(576000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),
146	F(720000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),
147	F(1014000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),
148	F(1098000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),
149	F(1332000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),
150	{ }
151};
152
153static struct clk_rcg2 video_cc_mvs0_clk_src = {
154	.cmd_rcgr = 0x8000,
155	.mnd_width = 0,
156	.hid_width = 5,
157	.parent_map = video_cc_parent_map_0,
158	.freq_tbl = ftbl_video_cc_mvs0_clk_src,
159	.clkr.hw.init = &(const struct clk_init_data) {
160		.name = "video_cc_mvs0_clk_src",
161		.parent_data = video_cc_parent_data_0,
162		.num_parents = ARRAY_SIZE(video_cc_parent_data_0),
163		.flags = CLK_SET_RATE_PARENT,
164		.ops = &clk_rcg2_shared_ops,
165	},
166};
167
168static const struct freq_tbl ftbl_video_cc_mvs1_clk_src[] = {
169	F(840000000, P_VIDEO_CC_PLL1_OUT_MAIN, 1, 0, 0),
170	F(1050000000, P_VIDEO_CC_PLL1_OUT_MAIN, 1, 0, 0),
171	F(1350000000, P_VIDEO_CC_PLL1_OUT_MAIN, 1, 0, 0),
172	F(1500000000, P_VIDEO_CC_PLL1_OUT_MAIN, 1, 0, 0),
173	F(1650000000, P_VIDEO_CC_PLL1_OUT_MAIN, 1, 0, 0),
174	{ }
175};
176
177static struct clk_rcg2 video_cc_mvs1_clk_src = {
178	.cmd_rcgr = 0x8018,
179	.mnd_width = 0,
180	.hid_width = 5,
181	.parent_map = video_cc_parent_map_1,
182	.freq_tbl = ftbl_video_cc_mvs1_clk_src,
183	.clkr.hw.init = &(const struct clk_init_data) {
184		.name = "video_cc_mvs1_clk_src",
185		.parent_data = video_cc_parent_data_1,
186		.num_parents = ARRAY_SIZE(video_cc_parent_data_1),
187		.flags = CLK_SET_RATE_PARENT,
188		.ops = &clk_rcg2_shared_ops,
189	},
190};
191
192static struct clk_regmap_div video_cc_mvs0_div_clk_src = {
193	.reg = 0x80b8,
194	.shift = 0,
195	.width = 4,
196	.clkr.hw.init = &(const struct clk_init_data) {
197		.name = "video_cc_mvs0_div_clk_src",
198		.parent_hws = (const struct clk_hw*[]) {
199			&video_cc_mvs0_clk_src.clkr.hw,
200		},
201		.num_parents = 1,
202		.flags = CLK_SET_RATE_PARENT,
203		.ops = &clk_regmap_div_ro_ops,
204	},
205};
206
207static struct clk_regmap_div video_cc_mvs0c_div2_div_clk_src = {
208	.reg = 0x806c,
209	.shift = 0,
210	.width = 4,
211	.clkr.hw.init = &(const struct clk_init_data) {
212		.name = "video_cc_mvs0c_div2_div_clk_src",
213		.parent_hws = (const struct clk_hw*[]) {
214			&video_cc_mvs0_clk_src.clkr.hw,
215		},
216		.num_parents = 1,
217		.flags = CLK_SET_RATE_PARENT,
218		.ops = &clk_regmap_div_ro_ops,
219	},
220};
221
222static struct clk_regmap_div video_cc_mvs1_div_clk_src = {
223	.reg = 0x80dc,
224	.shift = 0,
225	.width = 4,
226	.clkr.hw.init = &(const struct clk_init_data) {
227		.name = "video_cc_mvs1_div_clk_src",
228		.parent_hws = (const struct clk_hw*[]) {
229			&video_cc_mvs1_clk_src.clkr.hw,
230		},
231		.num_parents = 1,
232		.flags = CLK_SET_RATE_PARENT,
233		.ops = &clk_regmap_div_ro_ops,
234	},
235};
236
237static struct clk_regmap_div video_cc_mvs1c_div2_div_clk_src = {
238	.reg = 0x8094,
239	.shift = 0,
240	.width = 4,
241	.clkr.hw.init = &(const struct clk_init_data) {
242		.name = "video_cc_mvs1c_div2_div_clk_src",
243		.parent_hws = (const struct clk_hw*[]) {
244			&video_cc_mvs1_clk_src.clkr.hw,
245		},
246		.num_parents = 1,
247		.flags = CLK_SET_RATE_PARENT,
248		.ops = &clk_regmap_div_ro_ops,
249	},
250};
251
252static struct clk_branch video_cc_mvs0_clk = {
253	.halt_reg = 0x80b0,
254	.halt_check = BRANCH_HALT_SKIP,
255	.hwcg_reg = 0x80b0,
256	.hwcg_bit = 1,
257	.clkr = {
258		.enable_reg = 0x80b0,
259		.enable_mask = BIT(0),
260		.hw.init = &(const struct clk_init_data) {
261			.name = "video_cc_mvs0_clk",
262			.parent_hws = (const struct clk_hw*[]) {
263				&video_cc_mvs0_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
272static struct clk_branch video_cc_mvs0c_clk = {
273	.halt_reg = 0x8064,
274	.halt_check = BRANCH_HALT,
275	.clkr = {
276		.enable_reg = 0x8064,
277		.enable_mask = BIT(0),
278		.hw.init = &(const struct clk_init_data) {
279			.name = "video_cc_mvs0c_clk",
280			.parent_hws = (const struct clk_hw*[]) {
281				&video_cc_mvs0c_div2_div_clk_src.clkr.hw,
282			},
283			.num_parents = 1,
284			.flags = CLK_SET_RATE_PARENT,
285			.ops = &clk_branch2_ops,
286		},
287	},
288};
289
290static struct clk_branch video_cc_mvs1_clk = {
291	.halt_reg = 0x80d4,
292	.halt_check = BRANCH_HALT_SKIP,
293	.hwcg_reg = 0x80d4,
294	.hwcg_bit = 1,
295	.clkr = {
296		.enable_reg = 0x80d4,
297		.enable_mask = BIT(0),
298		.hw.init = &(const struct clk_init_data) {
299			.name = "video_cc_mvs1_clk",
300			.parent_hws = (const struct clk_hw*[]) {
301				&video_cc_mvs1_div_clk_src.clkr.hw,
302			},
303			.num_parents = 1,
304			.flags = CLK_SET_RATE_PARENT,
305			.ops = &clk_branch2_ops,
306		},
307	},
308};
309
310static struct clk_branch video_cc_mvs1c_clk = {
311	.halt_reg = 0x808c,
312	.halt_check = BRANCH_HALT,
313	.clkr = {
314		.enable_reg = 0x808c,
315		.enable_mask = BIT(0),
316		.hw.init = &(const struct clk_init_data) {
317			.name = "video_cc_mvs1c_clk",
318			.parent_hws = (const struct clk_hw*[]) {
319				&video_cc_mvs1c_div2_div_clk_src.clkr.hw,
320			},
321			.num_parents = 1,
322			.flags = CLK_SET_RATE_PARENT,
323			.ops = &clk_branch2_ops,
324		},
325	},
326};
327
328static struct gdsc video_cc_mvs0c_gdsc = {
329	.gdscr = 0x804c,
330	.en_rest_wait_val = 0x2,
331	.en_few_wait_val = 0x2,
332	.clk_dis_wait_val = 0x6,
333	.pd = {
334		.name = "video_cc_mvs0c_gdsc",
335	},
336	.pwrsts = PWRSTS_OFF_ON,
337	.flags = RETAIN_FF_ENABLE,
338};
339
340static struct gdsc video_cc_mvs0_gdsc = {
341	.gdscr = 0x809c,
342	.en_rest_wait_val = 0x2,
343	.en_few_wait_val = 0x2,
344	.clk_dis_wait_val = 0x6,
345	.pd = {
346		.name = "video_cc_mvs0_gdsc",
347	},
348	.pwrsts = PWRSTS_OFF_ON,
349	.parent = &video_cc_mvs0c_gdsc.pd,
350	.flags = RETAIN_FF_ENABLE | HW_CTRL,
351};
352
353static struct gdsc video_cc_mvs1c_gdsc = {
354	.gdscr = 0x8074,
355	.en_rest_wait_val = 0x2,
356	.en_few_wait_val = 0x2,
357	.clk_dis_wait_val = 0x6,
358	.pd = {
359		.name = "video_cc_mvs1c_gdsc",
360	},
361	.pwrsts = PWRSTS_OFF_ON,
362	.flags = RETAIN_FF_ENABLE,
363};
364
365static struct gdsc video_cc_mvs1_gdsc = {
366	.gdscr = 0x80c0,
367	.en_rest_wait_val = 0x2,
368	.en_few_wait_val = 0x2,
369	.clk_dis_wait_val = 0x6,
370	.pd = {
371		.name = "video_cc_mvs1_gdsc",
372	},
373	.pwrsts = PWRSTS_OFF_ON,
374	.parent = &video_cc_mvs1c_gdsc.pd,
375	.flags = RETAIN_FF_ENABLE | HW_CTRL,
376};
377
378static struct clk_regmap *video_cc_sm8450_clocks[] = {
379	[VIDEO_CC_MVS0_CLK] = &video_cc_mvs0_clk.clkr,
380	[VIDEO_CC_MVS0_CLK_SRC] = &video_cc_mvs0_clk_src.clkr,
381	[VIDEO_CC_MVS0_DIV_CLK_SRC] = &video_cc_mvs0_div_clk_src.clkr,
382	[VIDEO_CC_MVS0C_CLK] = &video_cc_mvs0c_clk.clkr,
383	[VIDEO_CC_MVS0C_DIV2_DIV_CLK_SRC] = &video_cc_mvs0c_div2_div_clk_src.clkr,
384	[VIDEO_CC_MVS1_CLK] = &video_cc_mvs1_clk.clkr,
385	[VIDEO_CC_MVS1_CLK_SRC] = &video_cc_mvs1_clk_src.clkr,
386	[VIDEO_CC_MVS1_DIV_CLK_SRC] = &video_cc_mvs1_div_clk_src.clkr,
387	[VIDEO_CC_MVS1C_CLK] = &video_cc_mvs1c_clk.clkr,
388	[VIDEO_CC_MVS1C_DIV2_DIV_CLK_SRC] = &video_cc_mvs1c_div2_div_clk_src.clkr,
389	[VIDEO_CC_PLL0] = &video_cc_pll0.clkr,
390	[VIDEO_CC_PLL1] = &video_cc_pll1.clkr,
391};
392
393static struct gdsc *video_cc_sm8450_gdscs[] = {
394	[VIDEO_CC_MVS0C_GDSC] = &video_cc_mvs0c_gdsc,
395	[VIDEO_CC_MVS0_GDSC] = &video_cc_mvs0_gdsc,
396	[VIDEO_CC_MVS1C_GDSC] = &video_cc_mvs1c_gdsc,
397	[VIDEO_CC_MVS1_GDSC] = &video_cc_mvs1_gdsc,
398};
399
400static const struct qcom_reset_map video_cc_sm8450_resets[] = {
401	[CVP_VIDEO_CC_INTERFACE_BCR] = { 0x80e0 },
402	[CVP_VIDEO_CC_MVS0_BCR] = { 0x8098 },
403	[CVP_VIDEO_CC_MVS0C_BCR] = { 0x8048 },
404	[CVP_VIDEO_CC_MVS1_BCR] = { 0x80bc },
405	[CVP_VIDEO_CC_MVS1C_BCR] = { 0x8070 },
406	[VIDEO_CC_MVS0C_CLK_ARES] = { .reg = 0x8064, .bit = 2, .udelay = 1000 },
407	[VIDEO_CC_MVS1C_CLK_ARES] = { .reg = 0x808c, .bit = 2, .udelay = 1000 },
408};
409
410static const struct regmap_config video_cc_sm8450_regmap_config = {
411	.reg_bits = 32,
412	.reg_stride = 4,
413	.val_bits = 32,
414	.max_register = 0x9f4c,
415	.fast_io = true,
416};
417
418static struct qcom_cc_desc video_cc_sm8450_desc = {
419	.config = &video_cc_sm8450_regmap_config,
420	.clks = video_cc_sm8450_clocks,
421	.num_clks = ARRAY_SIZE(video_cc_sm8450_clocks),
422	.resets = video_cc_sm8450_resets,
423	.num_resets = ARRAY_SIZE(video_cc_sm8450_resets),
424	.gdscs = video_cc_sm8450_gdscs,
425	.num_gdscs = ARRAY_SIZE(video_cc_sm8450_gdscs),
426};
427
428static const struct of_device_id video_cc_sm8450_match_table[] = {
429	{ .compatible = "qcom,sm8450-videocc" },
430	{ .compatible = "qcom,sm8475-videocc" },
431	{ }
432};
433MODULE_DEVICE_TABLE(of, video_cc_sm8450_match_table);
434
435static int video_cc_sm8450_probe(struct platform_device *pdev)
436{
437	struct regmap *regmap;
438	int ret;
439
440	ret = devm_pm_runtime_enable(&pdev->dev);
441	if (ret)
442		return ret;
443
444	ret = pm_runtime_resume_and_get(&pdev->dev);
445	if (ret)
446		return ret;
447
448	regmap = qcom_cc_map(pdev, &video_cc_sm8450_desc);
449	if (IS_ERR(regmap)) {
450		pm_runtime_put(&pdev->dev);
451		return PTR_ERR(regmap);
452	}
453
454	if (of_device_is_compatible(pdev->dev.of_node, "qcom,sm8475-videocc")) {
455		/* Update VideoCC PLL0 */
456		video_cc_pll0.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE];
457
458		/* Update VideoCC PLL1 */
459		video_cc_pll1.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE];
460
461		clk_lucid_ole_pll_configure(&video_cc_pll0, regmap, &sm8475_video_cc_pll0_config);
462		clk_lucid_ole_pll_configure(&video_cc_pll1, regmap, &sm8475_video_cc_pll1_config);
463	} else {
464		clk_lucid_evo_pll_configure(&video_cc_pll0, regmap, &video_cc_pll0_config);
465		clk_lucid_evo_pll_configure(&video_cc_pll1, regmap, &video_cc_pll1_config);
466	}
467
468	/* Keep some clocks always-on */
469	qcom_branch_set_clk_en(regmap, 0x80e4); /* VIDEO_CC_AHB_CLK */
470	qcom_branch_set_clk_en(regmap, 0x8130); /* VIDEO_CC_SLEEP_CLK */
471	qcom_branch_set_clk_en(regmap, 0x8114); /* VIDEO_CC_XO_CLK */
472
473	ret = qcom_cc_really_probe(&pdev->dev, &video_cc_sm8450_desc, regmap);
474
475	pm_runtime_put(&pdev->dev);
476
477	return ret;
478}
479
480static struct platform_driver video_cc_sm8450_driver = {
481	.probe = video_cc_sm8450_probe,
482	.driver = {
483		.name = "video_cc-sm8450",
484		.of_match_table = video_cc_sm8450_match_table,
485	},
486};
487
488module_platform_driver(video_cc_sm8450_driver);
489
490MODULE_DESCRIPTION("QTI VIDEOCC SM8450 / SM8475 Driver");
491MODULE_LICENSE("GPL");