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, desc: &video_cc_sc7280_desc);
296 if (IS_ERR(ptr: regmap))
297 return PTR_ERR(ptr: regmap);
298
299 clk_lucid_pll_configure(&video_pll0, regmap, &video_pll0_config);
300
301 return qcom_cc_really_probe(pdev, desc: &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

source code of linux/drivers/clk/qcom/videocc-sc7280.c