File Index
Files and directories
Sign in
FILE

videocc-sm6350.c

File preview with syntax highlighting.

linux-6.19.14/drivers/clk/qcom/videocc-sm6350.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (c) 2021, The Linux Foundation. All rights reserved.
  4 * Copyright (c) 2021, Konrad Dybcio <konrad.dybcio@somainline.org>
  5 * Copyright (c) 2025, Luca Weiss <luca.weiss@fairphone.com>
  6 */
  7
  8#include <linux/clk-provider.h>
  9#include <linux/module.h>
 10#include <linux/platform_device.h>
 11#include <linux/regmap.h>
 12
 13#include <dt-bindings/clock/qcom,sm6350-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 "common.h"
 20#include "gdsc.h"
 21
 22enum {
 23	DT_IFACE,
 24	DT_BI_TCXO,
 25	DT_SLEEP_CLK,
 26};
 27
 28enum {
 29	P_BI_TCXO,
 30	P_CHIP_SLEEP_CLK,
 31	P_VIDEO_PLL0_OUT_EVEN,
 32};
 33
 34static const struct pll_vco fabia_vco[] = {
 35	{ 125000000, 1000000000, 1 },
 36};
 37
 38/* 600 MHz */
 39static const struct alpha_pll_config video_pll0_config = {
 40	.l = 0x1f,
 41	.alpha = 0x4000,
 42	.config_ctl_val = 0x20485699,
 43	.config_ctl_hi_val = 0x00002067,
 44	.test_ctl_val = 0x40000000,
 45	.test_ctl_hi_val = 0x00000002,
 46	.user_ctl_val = 0x00000101,
 47	.user_ctl_hi_val = 0x00004005,
 48};
 49
 50static struct clk_alpha_pll video_pll0 = {
 51	.offset = 0x0,
 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 = "video_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 clk_div_table post_div_table_video_pll0_out_even[] = {
 68	{ 0x1, 2 },
 69	{ }
 70};
 71
 72static struct clk_alpha_pll_postdiv video_pll0_out_even = {
 73	.offset = 0x0,
 74	.post_div_shift = 8,
 75	.post_div_table = post_div_table_video_pll0_out_even,
 76	.num_post_div = ARRAY_SIZE(post_div_table_video_pll0_out_even),
 77	.width = 4,
 78	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
 79	.clkr.hw.init = &(const struct clk_init_data) {
 80		.name = "video_pll0_out_even",
 81		.parent_hws = (const struct clk_hw*[]) {
 82			&video_pll0.clkr.hw,
 83		},
 84		.num_parents = 1,
 85		.flags = CLK_SET_RATE_PARENT,
 86		.ops = &clk_alpha_pll_postdiv_fabia_ops,
 87	},
 88};
 89
 90static const struct parent_map video_cc_parent_map_0[] = {
 91	{ P_BI_TCXO, 0 },
 92	{ P_VIDEO_PLL0_OUT_EVEN, 3 },
 93};
 94
 95static const struct clk_parent_data video_cc_parent_data_0[] = {
 96	{ .index = DT_BI_TCXO },
 97	{ .hw = &video_pll0_out_even.clkr.hw },
 98};
 99
100static const struct parent_map video_cc_parent_map_1[] = {
101	{ P_CHIP_SLEEP_CLK, 0 },
102};
103
104static const struct clk_parent_data video_cc_parent_data_1[] = {
105	{ .index = DT_SLEEP_CLK },
106};
107
108static const struct freq_tbl ftbl_video_cc_iris_clk_src[] = {
109	F(133250000, P_VIDEO_PLL0_OUT_EVEN, 2, 0, 0),
110	F(240000000, P_VIDEO_PLL0_OUT_EVEN, 1.5, 0, 0),
111	F(300000000, P_VIDEO_PLL0_OUT_EVEN, 1, 0, 0),
112	F(380000000, P_VIDEO_PLL0_OUT_EVEN, 1, 0, 0),
113	F(460000000, P_VIDEO_PLL0_OUT_EVEN, 1, 0, 0),
114	{ }
115};
116
117static struct clk_rcg2 video_cc_iris_clk_src = {
118	.cmd_rcgr = 0x1000,
119	.mnd_width = 0,
120	.hid_width = 5,
121	.parent_map = video_cc_parent_map_0,
122	.freq_tbl = ftbl_video_cc_iris_clk_src,
123	.clkr.hw.init = &(const struct clk_init_data) {
124		.name = "video_cc_iris_clk_src",
125		.parent_data = video_cc_parent_data_0,
126		.num_parents = ARRAY_SIZE(video_cc_parent_data_0),
127		.flags = CLK_SET_RATE_PARENT,
128		.ops = &clk_rcg2_shared_ops,
129	},
130};
131
132static const struct freq_tbl ftbl_video_cc_sleep_clk_src[] = {
133	F(32764, P_CHIP_SLEEP_CLK, 1, 0, 0),
134	{ }
135};
136
137static struct clk_rcg2 video_cc_sleep_clk_src = {
138	.cmd_rcgr = 0x701c,
139	.mnd_width = 0,
140	.hid_width = 5,
141	.parent_map = video_cc_parent_map_1,
142	.freq_tbl = ftbl_video_cc_sleep_clk_src,
143	.clkr.hw.init = &(const struct clk_init_data) {
144		.name = "video_cc_sleep_clk_src",
145		.parent_data = video_cc_parent_data_1,
146		.num_parents = ARRAY_SIZE(video_cc_parent_data_1),
147		.ops = &clk_rcg2_ops,
148	},
149};
150
151static struct clk_branch video_cc_iris_ahb_clk = {
152	.halt_reg = 0x5004,
153	.halt_check = BRANCH_VOTED,
154	.clkr = {
155		.enable_reg = 0x5004,
156		.enable_mask = BIT(0),
157		.hw.init = &(const struct clk_init_data) {
158			.name = "video_cc_iris_ahb_clk",
159			.parent_hws = (const struct clk_hw*[]) {
160				&video_cc_iris_clk_src.clkr.hw,
161			},
162			.num_parents = 1,
163			.flags = CLK_SET_RATE_PARENT,
164			.ops = &clk_branch2_ops,
165		},
166	},
167};
168
169static struct clk_branch video_cc_mvs0_axi_clk = {
170	.halt_reg = 0x800c,
171	.halt_check = BRANCH_HALT,
172	.clkr = {
173		.enable_reg = 0x800c,
174		.enable_mask = BIT(0),
175		.hw.init = &(const struct clk_init_data) {
176			.name = "video_cc_mvs0_axi_clk",
177			.ops = &clk_branch2_ops,
178		},
179	},
180};
181
182static struct clk_branch video_cc_mvs0_core_clk = {
183	.halt_reg = 0x3010,
184	.halt_check = BRANCH_VOTED,
185	.hwcg_reg = 0x3010,
186	.hwcg_bit = 1,
187	.clkr = {
188		.enable_reg = 0x3010,
189		.enable_mask = BIT(0),
190		.hw.init = &(const struct clk_init_data) {
191			.name = "video_cc_mvs0_core_clk",
192			.parent_hws = (const struct clk_hw*[]) {
193				&video_cc_iris_clk_src.clkr.hw,
194			},
195			.num_parents = 1,
196			.flags = CLK_SET_RATE_PARENT,
197			.ops = &clk_branch2_ops,
198		},
199	},
200};
201
202static struct clk_branch video_cc_mvsc_core_clk = {
203	.halt_reg = 0x2014,
204	.halt_check = BRANCH_HALT,
205	.clkr = {
206		.enable_reg = 0x2014,
207		.enable_mask = BIT(0),
208		.hw.init = &(const struct clk_init_data) {
209			.name = "video_cc_mvsc_core_clk",
210			.parent_hws = (const struct clk_hw*[]) {
211				&video_cc_iris_clk_src.clkr.hw,
212			},
213			.num_parents = 1,
214			.flags = CLK_SET_RATE_PARENT,
215			.ops = &clk_branch2_ops,
216		},
217	},
218};
219
220static struct clk_branch video_cc_mvsc_ctl_axi_clk = {
221	.halt_reg = 0x8004,
222	.halt_check = BRANCH_HALT,
223	.clkr = {
224		.enable_reg = 0x8004,
225		.enable_mask = BIT(0),
226		.hw.init = &(const struct clk_init_data) {
227			.name = "video_cc_mvsc_ctl_axi_clk",
228			.ops = &clk_branch2_ops,
229		},
230	},
231};
232
233static struct clk_branch video_cc_sleep_clk = {
234	.halt_reg = 0x7034,
235	.halt_check = BRANCH_HALT,
236	.clkr = {
237		.enable_reg = 0x7034,
238		.enable_mask = BIT(0),
239		.hw.init = &(const struct clk_init_data) {
240			.name = "video_cc_sleep_clk",
241			.parent_hws = (const struct clk_hw*[]) {
242				&video_cc_sleep_clk_src.clkr.hw,
243			},
244			.num_parents = 1,
245			.flags = CLK_SET_RATE_PARENT,
246			.ops = &clk_branch2_ops,
247		},
248	},
249};
250
251static struct clk_branch video_cc_venus_ahb_clk = {
252	.halt_reg = 0x801c,
253	.halt_check = BRANCH_HALT,
254	.clkr = {
255		.enable_reg = 0x801c,
256		.enable_mask = BIT(0),
257		.hw.init = &(const struct clk_init_data) {
258			.name = "video_cc_venus_ahb_clk",
259			.ops = &clk_branch2_ops,
260		},
261	},
262};
263
264static struct gdsc mvsc_gdsc = {
265	.gdscr = 0x2004,
266	.en_rest_wait_val = 0x2,
267	.en_few_wait_val = 0x2,
268	.clk_dis_wait_val = 0x6,
269	.pd = {
270		.name = "mvsc_gdsc",
271	},
272	.pwrsts = PWRSTS_OFF_ON,
273};
274
275static struct gdsc mvs0_gdsc = {
276	.gdscr = 0x3004,
277	.en_rest_wait_val = 0x2,
278	.en_few_wait_val = 0x2,
279	.clk_dis_wait_val = 0x6,
280	.pd = {
281		.name = "mvs0_gdsc",
282	},
283	.pwrsts = PWRSTS_OFF_ON,
284	.flags = HW_CTRL_TRIGGER,
285};
286
287static struct gdsc *video_cc_sm6350_gdscs[] = {
288	[MVSC_GDSC] = &mvsc_gdsc,
289	[MVS0_GDSC] = &mvs0_gdsc,
290};
291
292static struct clk_regmap *video_cc_sm6350_clocks[] = {
293	[VIDEO_CC_IRIS_AHB_CLK] = &video_cc_iris_ahb_clk.clkr,
294	[VIDEO_CC_IRIS_CLK_SRC] = &video_cc_iris_clk_src.clkr,
295	[VIDEO_CC_MVS0_AXI_CLK] = &video_cc_mvs0_axi_clk.clkr,
296	[VIDEO_CC_MVS0_CORE_CLK] = &video_cc_mvs0_core_clk.clkr,
297	[VIDEO_CC_MVSC_CORE_CLK] = &video_cc_mvsc_core_clk.clkr,
298	[VIDEO_CC_MVSC_CTL_AXI_CLK] = &video_cc_mvsc_ctl_axi_clk.clkr,
299	[VIDEO_CC_SLEEP_CLK] = &video_cc_sleep_clk.clkr,
300	[VIDEO_CC_SLEEP_CLK_SRC] = &video_cc_sleep_clk_src.clkr,
301	[VIDEO_CC_VENUS_AHB_CLK] = &video_cc_venus_ahb_clk.clkr,
302	[VIDEO_PLL0] = &video_pll0.clkr,
303	[VIDEO_PLL0_OUT_EVEN] = &video_pll0_out_even.clkr,
304};
305
306static const struct regmap_config video_cc_sm6350_regmap_config = {
307	.reg_bits = 32,
308	.reg_stride = 4,
309	.val_bits = 32,
310	.max_register = 0xb000,
311	.fast_io = true,
312};
313
314static const struct qcom_cc_desc video_cc_sm6350_desc = {
315	.config = &video_cc_sm6350_regmap_config,
316	.clks = video_cc_sm6350_clocks,
317	.num_clks = ARRAY_SIZE(video_cc_sm6350_clocks),
318	.gdscs = video_cc_sm6350_gdscs,
319	.num_gdscs = ARRAY_SIZE(video_cc_sm6350_gdscs),
320};
321
322static const struct of_device_id video_cc_sm6350_match_table[] = {
323	{ .compatible = "qcom,sm6350-videocc" },
324	{ }
325};
326MODULE_DEVICE_TABLE(of, video_cc_sm6350_match_table);
327
328static int video_cc_sm6350_probe(struct platform_device *pdev)
329{
330	struct regmap *regmap;
331
332	regmap = qcom_cc_map(pdev, &video_cc_sm6350_desc);
333	if (IS_ERR(regmap))
334		return PTR_ERR(regmap);
335
336	clk_fabia_pll_configure(&video_pll0, regmap, &video_pll0_config);
337
338	/* Keep some clocks always-on */
339	qcom_branch_set_clk_en(regmap, 0x7018); /* VIDEO_CC_XO_CLK */
340
341	return qcom_cc_really_probe(&pdev->dev, &video_cc_sm6350_desc, regmap);
342}
343
344static struct platform_driver video_cc_sm6350_driver = {
345	.probe = video_cc_sm6350_probe,
346	.driver = {
347		.name = "video_cc-sm6350",
348		.of_match_table = video_cc_sm6350_match_table,
349	},
350};
351
352module_platform_driver(video_cc_sm6350_driver);
353
354MODULE_DESCRIPTION("QTI VIDEO_CC SM6350 Driver");
355MODULE_LICENSE("GPL");
~/ Read-only file preview.