1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (c) 2021, 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-sc7280.h>
12
13#include "clk-alpha-pll.h"
14#include "clk-branch.h"
15#include "clk-rcg.h"
16#include "common.h"
17#include "reset.h"
18#include "gdsc.h"
19
20enum {
21	P_BI_TCXO,
22	P_SLEEP_CLK,
23	P_VIDEO_PLL0_OUT_EVEN,
24};
25
26static const struct pll_vco lucid_vco[] = {
27	{ 249600000, 2000000000, 0 },
28};
29
30/* 400MHz Configuration */
31static const struct alpha_pll_config video_pll0_config = {
32	.l = 0x14,
33	.alpha = 0xD555,
34	.config_ctl_val = 0x20485699,
35	.config_ctl_hi_val = 0x00002261,
36	.config_ctl_hi1_val = 0x329A299C,
37	.user_ctl_val = 0x00000001,
38	.user_ctl_hi_val = 0x00000805,
39	.user_ctl_hi1_val = 0x00000000,
40};
41
42static struct clk_alpha_pll video_pll0 = {
43	.offset = 0x0,
44	.vco_table = lucid_vco,
45	.num_vco = ARRAY_SIZE(lucid_vco),
46	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
47	.clkr = {
48		.hw.init = &(struct clk_init_data){
49			.name = "video_pll0",
50			.parent_data = &(const struct clk_parent_data){
51				.fw_name = "bi_tcxo",
52			},
53			.num_parents = 1,
54			.ops = &clk_alpha_pll_lucid_ops,
55		},
56	},
57};
58
59static const struct parent_map video_cc_parent_map_0[] = {
60	{ P_BI_TCXO, 0 },
61	{ P_VIDEO_PLL0_OUT_EVEN, 3 },
62};
63
64static const struct clk_parent_data video_cc_parent_data_0[] = {
65	{ .fw_name = "bi_tcxo" },
66	{ .hw = &video_pll0.clkr.hw },
67};
68
69static const struct parent_map video_cc_parent_map_1[] = {
70	{ P_SLEEP_CLK, 0 },
71};
72
73static const struct clk_parent_data video_cc_parent_data_1[] = {
74	{ .fw_name = "sleep_clk" },
75};
76
77static const struct freq_tbl ftbl_video_cc_iris_clk_src[] = {
78	F(133333333, P_VIDEO_PLL0_OUT_EVEN, 3, 0, 0),
79	F(240000000, P_VIDEO_PLL0_OUT_EVEN, 2, 0, 0),
80	F(335000000, P_VIDEO_PLL0_OUT_EVEN, 2, 0, 0),
81	F(424000000, P_VIDEO_PLL0_OUT_EVEN, 2, 0, 0),
82	F(460000000, P_VIDEO_PLL0_OUT_EVEN, 2, 0, 0),
83	{ }
84};
85
86static struct clk_rcg2 video_cc_iris_clk_src = {
87	.cmd_rcgr = 0x1000,
88	.mnd_width = 0,
89	.hid_width = 5,
90	.parent_map = video_cc_parent_map_0,
91	.freq_tbl = ftbl_video_cc_iris_clk_src,
92	.clkr.hw.init = &(struct clk_init_data){
93		.name = "video_cc_iris_clk_src",
94		.parent_data = video_cc_parent_data_0,
95		.num_parents = ARRAY_SIZE(video_cc_parent_data_0),
96		.flags = CLK_SET_RATE_PARENT,
97		.ops = &clk_rcg2_shared_ops,
98	},
99};
100
101static const struct freq_tbl ftbl_video_cc_sleep_clk_src[] = {
102	F(32000, P_SLEEP_CLK, 1, 0, 0),
103	{ }
104};
105
106static struct clk_rcg2 video_cc_sleep_clk_src = {
107	.cmd_rcgr = 0x701c,
108	.mnd_width = 0,
109	.hid_width = 5,
110	.parent_map = video_cc_parent_map_1,
111	.freq_tbl = ftbl_video_cc_sleep_clk_src,
112	.clkr.hw.init = &(struct clk_init_data){
113		.name = "video_cc_sleep_clk_src",
114		.parent_data = video_cc_parent_data_1,
115		.num_parents = ARRAY_SIZE(video_cc_parent_data_1),
116		.ops = &clk_rcg2_ops,
117	},
118};
119
120static struct clk_branch video_cc_iris_ahb_clk = {
121	.halt_reg = 0x5004,
122	.halt_check = BRANCH_HALT_VOTED,
123	.clkr = {
124		.enable_reg = 0x5004,
125		.enable_mask = BIT(0),
126		.hw.init = &(struct clk_init_data){
127			.name = "video_cc_iris_ahb_clk",
128			.parent_hws = (const struct clk_hw*[]){
129				&video_cc_iris_clk_src.clkr.hw,
130			},
131			.num_parents = 1,
132			.flags = CLK_SET_RATE_PARENT,
133			.ops = &clk_branch2_ops,
134		},
135	},
136};
137
138static struct clk_branch video_cc_mvs0_axi_clk = {
139	.halt_reg = 0x800c,
140	.halt_check = BRANCH_HALT,
141	.clkr = {
142		.enable_reg = 0x800c,
143		.enable_mask = BIT(0),
144		.hw.init = &(struct clk_init_data){
145			.name = "video_cc_mvs0_axi_clk",
146			.ops = &clk_branch2_ops,
147		},
148	},
149};
150
151static struct clk_branch video_cc_mvs0_core_clk = {
152	.halt_reg = 0x3010,
153	.halt_check = BRANCH_HALT_VOTED,
154	.hwcg_reg = 0x3010,
155	.hwcg_bit = 1,
156	.clkr = {
157		.enable_reg = 0x3010,
158		.enable_mask = BIT(0),
159		.hw.init = &(struct clk_init_data){
160			.name = "video_cc_mvs0_core_clk",
161			.parent_hws = (const struct clk_hw*[]){
162				&video_cc_iris_clk_src.clkr.hw,
163			},
164			.num_parents = 1,
165			.flags = CLK_SET_RATE_PARENT,
166			.ops = &clk_branch2_ops,
167		},
168	},
169};
170
171static struct clk_branch video_cc_mvsc_core_clk = {
172	.halt_reg = 0x2014,
173	.halt_check = BRANCH_HALT,
174	.clkr = {
175		.enable_reg = 0x2014,
176		.enable_mask = BIT(0),
177		.hw.init = &(struct clk_init_data){
178			.name = "video_cc_mvsc_core_clk",
179			.parent_hws = (const struct clk_hw*[]){
180				&video_cc_iris_clk_src.clkr.hw,
181			},
182			.num_parents = 1,
183			.flags = CLK_SET_RATE_PARENT,
184			.ops = &clk_branch2_ops,
185		},
186	},
187};
188
189static struct clk_branch video_cc_mvsc_ctl_axi_clk = {
190	.halt_reg = 0x8004,
191	.halt_check = BRANCH_HALT,
192	.clkr = {
193		.enable_reg = 0x8004,
194		.enable_mask = BIT(0),
195		.hw.init = &(struct clk_init_data){
196			.name = "video_cc_mvsc_ctl_axi_clk",
197			.ops = &clk_branch2_ops,
198		},
199	},
200};
201
202static struct clk_branch video_cc_sleep_clk = {
203	.halt_reg = 0x7034,
204	.halt_check = BRANCH_HALT,
205	.clkr = {
206		.enable_reg = 0x7034,
207		.enable_mask = BIT(0),
208		.hw.init = &(struct clk_init_data){
209			.name = "video_cc_sleep_clk",
210			.parent_hws = (const struct clk_hw*[]){
211				&video_cc_sleep_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_venus_ahb_clk = {
221	.halt_reg = 0x801c,
222	.halt_check = BRANCH_HALT,
223	.clkr = {
224		.enable_reg = 0x801c,
225		.enable_mask = BIT(0),
226		.hw.init = &(struct clk_init_data){
227			.name = "video_cc_venus_ahb_clk",
228			.ops = &clk_branch2_ops,
229		},
230	},
231};
232
233static struct gdsc mvs0_gdsc = {
234	.gdscr = 0x3004,
235	.pd = {
236		.name = "mvs0_gdsc",
237	},
238	.pwrsts = PWRSTS_OFF_ON,
239	.flags = HW_CTRL | RETAIN_FF_ENABLE,
240};
241
242static struct gdsc mvsc_gdsc = {
243	.gdscr = 0x2004,
244	.pd = {
245		.name = "mvsc_gdsc",
246	},
247	.flags = RETAIN_FF_ENABLE,
248	.pwrsts = PWRSTS_OFF_ON,
249};
250
251static struct clk_regmap *video_cc_sc7280_clocks[] = {
252	[VIDEO_CC_IRIS_AHB_CLK] = &video_cc_iris_ahb_clk.clkr,
253	[VIDEO_CC_IRIS_CLK_SRC] = &video_cc_iris_clk_src.clkr,
254	[VIDEO_CC_MVS0_AXI_CLK] = &video_cc_mvs0_axi_clk.clkr,
255	[VIDEO_CC_MVS0_CORE_CLK] = &video_cc_mvs0_core_clk.clkr,
256	[VIDEO_CC_MVSC_CORE_CLK] = &video_cc_mvsc_core_clk.clkr,
257	[VIDEO_CC_MVSC_CTL_AXI_CLK] = &video_cc_mvsc_ctl_axi_clk.clkr,
258	[VIDEO_CC_SLEEP_CLK] = &video_cc_sleep_clk.clkr,
259	[VIDEO_CC_SLEEP_CLK_SRC] = &video_cc_sleep_clk_src.clkr,
260	[VIDEO_CC_VENUS_AHB_CLK] = &video_cc_venus_ahb_clk.clkr,
261	[VIDEO_PLL0] = &video_pll0.clkr,
262};
263
264static struct gdsc *video_cc_sc7280_gdscs[] = {
265	[MVS0_GDSC] = &mvs0_gdsc,
266	[MVSC_GDSC] = &mvsc_gdsc,
267};
268
269static const struct regmap_config video_cc_sc7280_regmap_config = {
270	.reg_bits = 32,
271	.reg_stride = 4,
272	.val_bits = 32,
273	.max_register = 0xb000,
274	.fast_io = true,
275};
276
277static const struct qcom_cc_desc video_cc_sc7280_desc = {
278	.config = &video_cc_sc7280_regmap_config,
279	.clks = video_cc_sc7280_clocks,
280	.num_clks = ARRAY_SIZE(video_cc_sc7280_clocks),
281	.gdscs = video_cc_sc7280_gdscs,
282	.num_gdscs = ARRAY_SIZE(video_cc_sc7280_gdscs),
283};
284
285static const struct of_device_id video_cc_sc7280_match_table[] = {
286	{ .compatible = "qcom,sc7280-videocc" },
287	{ }
288};
289MODULE_DEVICE_TABLE(of, video_cc_sc7280_match_table);
290
291static int video_cc_sc7280_probe(struct platform_device *pdev)
292{
293	struct regmap *regmap;
294
295	regmap = qcom_cc_map(pdev, &video_cc_sc7280_desc);
296	if (IS_ERR(regmap))
297		return PTR_ERR(regmap);
298
299	clk_lucid_pll_configure(&video_pll0, regmap, &video_pll0_config);
300
301	return qcom_cc_really_probe(pdev, &video_cc_sc7280_desc, regmap);
302}
303
304static struct platform_driver video_cc_sc7280_driver = {
305	.probe = video_cc_sc7280_probe,
306	.driver = {
307		.name = "video_cc-sc7280",
308		.of_match_table = video_cc_sc7280_match_table,
309	},
310};
311
312module_platform_driver(video_cc_sc7280_driver);
313
314MODULE_DESCRIPTION("QTI VIDEO_CC sc7280 Driver");
315MODULE_LICENSE("GPL v2");
316