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) 2018, The Linux Foundation. All rights reserved.
  4 * Copyright (c) 2024, Danila Tikhonov <danila@jiaxyga.com>
  5 */
  6
  7#include <linux/clk-provider.h>
  8#include <linux/mod_devicetable.h>
  9#include <linux/module.h>
 10#include <linux/platform_device.h>
 11#include <linux/regmap.h>
 12
 13#include <dt-bindings/clock/qcom,sm7150-videocc.h>
 14
 15#include "common.h"
 16#include "clk-alpha-pll.h"
 17#include "clk-branch.h"
 18#include "clk-rcg.h"
 19#include "clk-regmap.h"
 20#include "clk-pll.h"
 21#include "gdsc.h"
 22
 23enum {
 24	DT_BI_TCXO,
 25	DT_BI_TCXO_AO,
 26};
 27
 28enum {
 29	P_BI_TCXO,
 30	P_VIDEOCC_PLL0_OUT_EVEN,
 31	P_VIDEOCC_PLL0_OUT_MAIN,
 32	P_VIDEOCC_PLL0_OUT_ODD,
 33};
 34
 35static const struct pll_vco fabia_vco[] = {
 36	{ 249600000, 2000000000, 0 },
 37	{ 125000000, 1000000000, 1 },
 38};
 39
 40static struct alpha_pll_config videocc_pll0_config = {
 41	.l = 0x19,
 42	.alpha = 0x0,
 43	.config_ctl_val = 0x20485699,
 44	.config_ctl_hi_val = 0x00002067,
 45	.user_ctl_val = 0x00000001,
 46	.user_ctl_hi_val = 0x00004805,
 47	.test_ctl_hi_val = 0x40000000,
 48};
 49
 50static struct clk_alpha_pll videocc_pll0 = {
 51	.offset = 0x42c,
 52	.vco_table = fabia_vco,
 53	.num_vco = ARRAY_SIZE(fabia_vco),
 54	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
 55	.clkr = {
 56		.hw.init = &(const struct clk_init_data) {
 57			.name = "videocc_pll0",
 58			.parent_data = &(const struct clk_parent_data) {
 59				.index = DT_BI_TCXO,
 60			},
 61			.num_parents = 1,
 62			.ops = &clk_alpha_pll_fabia_ops,
 63		},
 64	},
 65};
 66
 67static const struct parent_map videocc_parent_map_0[] = {
 68	{ P_BI_TCXO, 0 },
 69	{ P_VIDEOCC_PLL0_OUT_MAIN, 1 },
 70	{ P_VIDEOCC_PLL0_OUT_EVEN, 2 },
 71	{ P_VIDEOCC_PLL0_OUT_ODD, 3 },
 72};
 73
 74static const struct clk_parent_data videocc_parent_data_0[] = {
 75	{ .index = DT_BI_TCXO },
 76	{ .hw = &videocc_pll0.clkr.hw },
 77	{ .hw = &videocc_pll0.clkr.hw },
 78	{ .hw = &videocc_pll0.clkr.hw },
 79};
 80
 81static const struct parent_map videocc_parent_map_1[] = {
 82	{ P_BI_TCXO, 0 },
 83};
 84
 85static const struct clk_parent_data videocc_parent_data_1[] = {
 86	{ .index = DT_BI_TCXO_AO },
 87};
 88
 89static const struct freq_tbl ftbl_videocc_iris_clk_src[] = {
 90	F(240000000, P_VIDEOCC_PLL0_OUT_MAIN, 2, 0, 0),
 91	F(338000000, P_VIDEOCC_PLL0_OUT_MAIN, 2, 0, 0),
 92	F(365000000, P_VIDEOCC_PLL0_OUT_MAIN, 2, 0, 0),
 93	F(444000000, P_VIDEOCC_PLL0_OUT_MAIN, 2, 0, 0),
 94	F(533000000, P_VIDEOCC_PLL0_OUT_MAIN, 2, 0, 0),
 95	{ }
 96};
 97
 98static struct clk_rcg2 videocc_iris_clk_src = {
 99	.cmd_rcgr = 0x7f0,
100	.mnd_width = 0,
101	.hid_width = 5,
102	.parent_map = videocc_parent_map_0,
103	.freq_tbl = ftbl_videocc_iris_clk_src,
104	.clkr.hw.init = &(const struct clk_init_data) {
105		.name = "videocc_iris_clk_src",
106		.parent_data = videocc_parent_data_0,
107		.num_parents = ARRAY_SIZE(videocc_parent_data_0),
108		.flags = CLK_SET_RATE_PARENT,
109		.ops = &clk_rcg2_shared_ops,
110	},
111};
112
113static const struct freq_tbl ftbl_videocc_xo_clk_src[] = {
114	F(19200000, P_BI_TCXO, 1, 0, 0),
115	{ }
116};
117
118static struct clk_rcg2 videocc_xo_clk_src = {
119	.cmd_rcgr = 0xa98,
120	.mnd_width = 0,
121	.hid_width = 5,
122	.parent_map = videocc_parent_map_1,
123	.freq_tbl = ftbl_videocc_xo_clk_src,
124	.clkr.hw.init = &(const struct clk_init_data) {
125		.name = "videocc_xo_clk_src",
126		.parent_data = videocc_parent_data_1,
127		.num_parents = ARRAY_SIZE(videocc_parent_data_1),
128		.ops = &clk_rcg2_ops,
129	},
130};
131
132static struct clk_branch videocc_iris_ahb_clk = {
133	.halt_reg = 0x8f4,
134	.halt_check = BRANCH_VOTED,
135	.clkr = {
136		.enable_reg = 0x8f4,
137		.enable_mask = BIT(0),
138		.hw.init = &(const struct clk_init_data) {
139			.name = "videocc_iris_ahb_clk",
140			.parent_data = &(const struct clk_parent_data) {
141				.hw = &videocc_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
150static struct clk_branch videocc_mvs0_axi_clk = {
151	.halt_reg = 0x9ec,
152	.halt_check = BRANCH_HALT,
153	.clkr = {
154		.enable_reg = 0x9ec,
155		.enable_mask = BIT(0),
156		.hw.init = &(const struct clk_init_data) {
157			.name = "videocc_mvs0_axi_clk",
158			.ops = &clk_branch2_ops,
159		},
160	},
161};
162
163static struct clk_branch videocc_mvs0_core_clk = {
164	.halt_reg = 0x890,
165	.halt_check = BRANCH_VOTED,
166	.clkr = {
167		.enable_reg = 0x890,
168		.enable_mask = BIT(0),
169		.hw.init = &(const struct clk_init_data) {
170			.name = "videocc_mvs0_core_clk",
171			.parent_data = &(const struct clk_parent_data) {
172				.hw = &videocc_iris_clk_src.clkr.hw,
173			},
174			.num_parents = 1,
175			.flags = CLK_SET_RATE_PARENT,
176			.ops = &clk_branch2_ops,
177		},
178	},
179};
180
181static struct clk_branch videocc_mvs1_axi_clk = {
182	.halt_reg = 0xa0c,
183	.halt_check = BRANCH_HALT,
184	.clkr = {
185		.enable_reg = 0xa0c,
186		.enable_mask = BIT(0),
187		.hw.init = &(const struct clk_init_data) {
188			.name = "videocc_mvs1_axi_clk",
189			.ops = &clk_branch2_ops,
190		},
191	},
192};
193
194static struct clk_branch videocc_mvs1_core_clk = {
195	.halt_reg = 0x8d0,
196	.halt_check = BRANCH_VOTED,
197	.clkr = {
198		.enable_reg = 0x8d0,
199		.enable_mask = BIT(0),
200		.hw.init = &(const struct clk_init_data) {
201			.name = "videocc_mvs1_core_clk",
202			.parent_data = &(const struct clk_parent_data) {
203				.hw = &videocc_iris_clk_src.clkr.hw,
204			},
205			.num_parents = 1,
206			.flags = CLK_SET_RATE_PARENT,
207			.ops = &clk_branch2_ops,
208		},
209	},
210};
211
212static struct clk_branch videocc_mvsc_core_clk = {
213	.halt_reg = 0x850,
214	.halt_check = BRANCH_HALT,
215	.clkr = {
216		.enable_reg = 0x850,
217		.enable_mask = BIT(0),
218		.hw.init = &(const struct clk_init_data) {
219			.name = "videocc_mvsc_core_clk",
220			.parent_data = &(const struct clk_parent_data) {
221				.hw = &videocc_iris_clk_src.clkr.hw,
222			},
223			.num_parents = 1,
224			.flags = CLK_SET_RATE_PARENT,
225			.ops = &clk_branch2_ops,
226		},
227	},
228};
229
230static struct clk_branch videocc_mvsc_ctl_axi_clk = {
231	.halt_reg = 0x9cc,
232	.halt_check = BRANCH_HALT,
233	.clkr = {
234		.enable_reg = 0x9cc,
235		.enable_mask = BIT(0),
236		.hw.init = &(const struct clk_init_data) {
237			.name = "videocc_mvsc_ctl_axi_clk",
238			.ops = &clk_branch2_ops,
239		},
240	},
241};
242
243static struct clk_branch videocc_venus_ahb_clk = {
244	.halt_reg = 0xa6c,
245	.halt_check = BRANCH_HALT,
246	.clkr = {
247		.enable_reg = 0xa6c,
248		.enable_mask = BIT(0),
249		.hw.init = &(const struct clk_init_data) {
250			.name = "videocc_venus_ahb_clk",
251			.ops = &clk_branch2_ops,
252		},
253	},
254};
255
256static struct gdsc venus_gdsc = {
257	.gdscr = 0x814,
258	.pd = {
259		.name = "venus_gdsc",
260	},
261	.cxcs = (unsigned int []){ 0x850, 0x9cc },
262	.cxc_count = 2,
263	.pwrsts = PWRSTS_OFF_ON,
264	.flags = POLL_CFG_GDSCR,
265};
266
267static struct gdsc vcodec0_gdsc = {
268	.gdscr = 0x874,
269	.pd = {
270		.name = "vcodec0_gdsc",
271	},
272	.cxcs = (unsigned int []){ 0x890, 0x9ec },
273	.cxc_count = 2,
274	.flags = HW_CTRL | POLL_CFG_GDSCR,
275	.pwrsts = PWRSTS_OFF_ON,
276};
277
278static struct gdsc vcodec1_gdsc = {
279	.gdscr = 0x8b4,
280	.pd = {
281		.name = "vcodec1_gdsc",
282	},
283	.cxcs = (unsigned int []){ 0x8d0, 0xa0c },
284	.cxc_count = 2,
285	.flags = HW_CTRL | POLL_CFG_GDSCR,
286	.pwrsts = PWRSTS_OFF_ON,
287};
288
289static struct clk_regmap *videocc_sm7150_clocks[] = {
290	[VIDEOCC_PLL0] = &videocc_pll0.clkr,
291	[VIDEOCC_IRIS_AHB_CLK] = &videocc_iris_ahb_clk.clkr,
292	[VIDEOCC_IRIS_CLK_SRC] = &videocc_iris_clk_src.clkr,
293	[VIDEOCC_MVS0_AXI_CLK] = &videocc_mvs0_axi_clk.clkr,
294	[VIDEOCC_MVS0_CORE_CLK] = &videocc_mvs0_core_clk.clkr,
295	[VIDEOCC_MVS1_AXI_CLK] = &videocc_mvs1_axi_clk.clkr,
296	[VIDEOCC_MVS1_CORE_CLK] = &videocc_mvs1_core_clk.clkr,
297	[VIDEOCC_MVSC_CORE_CLK] = &videocc_mvsc_core_clk.clkr,
298	[VIDEOCC_MVSC_CTL_AXI_CLK] = &videocc_mvsc_ctl_axi_clk.clkr,
299	[VIDEOCC_VENUS_AHB_CLK] = &videocc_venus_ahb_clk.clkr,
300	[VIDEOCC_XO_CLK_SRC] = &videocc_xo_clk_src.clkr,
301};
302
303static struct gdsc *videocc_sm7150_gdscs[] = {
304	[VENUS_GDSC] = &venus_gdsc,
305	[VCODEC0_GDSC] = &vcodec0_gdsc,
306	[VCODEC1_GDSC] = &vcodec1_gdsc,
307};
308
309static const struct regmap_config videocc_sm7150_regmap_config = {
310	.reg_bits	= 32,
311	.reg_stride	= 4,
312	.val_bits	= 32,
313	.max_register	= 0xb94,
314	.fast_io	= true,
315};
316
317static const struct qcom_cc_desc videocc_sm7150_desc = {
318	.config = &videocc_sm7150_regmap_config,
319	.clks = videocc_sm7150_clocks,
320	.num_clks = ARRAY_SIZE(videocc_sm7150_clocks),
321	.gdscs = videocc_sm7150_gdscs,
322	.num_gdscs = ARRAY_SIZE(videocc_sm7150_gdscs),
323};
324
325static const struct of_device_id videocc_sm7150_match_table[] = {
326	{ .compatible = "qcom,sm7150-videocc" },
327	{ }
328};
329MODULE_DEVICE_TABLE(of, videocc_sm7150_match_table);
330
331static int videocc_sm7150_probe(struct platform_device *pdev)
332{
333	struct regmap *regmap;
334
335	regmap = qcom_cc_map(pdev, &videocc_sm7150_desc);
336	if (IS_ERR(regmap))
337		return PTR_ERR(regmap);
338
339	clk_fabia_pll_configure(&videocc_pll0, regmap, &videocc_pll0_config);
340
341	/* Keep some clocks always-on */
342	qcom_branch_set_clk_en(regmap, 0x984); /* VIDEOCC_XO_CLK */
343
344	return qcom_cc_really_probe(&pdev->dev, &videocc_sm7150_desc, regmap);
345}
346
347static struct platform_driver videocc_sm7150_driver = {
348	.probe = videocc_sm7150_probe,
349	.driver = {
350		.name = "videocc-sm7150",
351		.of_match_table = videocc_sm7150_match_table,
352	},
353};
354module_platform_driver(videocc_sm7150_driver);
355
356MODULE_DESCRIPTION("Qualcomm SM7150 Video Clock Controller");
357MODULE_LICENSE("GPL");