ipq806x: add support for GL.iNet GL-B1300
[openwrt/openwrt.git] / target / linux / mediatek / patches-4.9 / 0008-soc-mediatek-Refine-scpsys-to-support-multiple-platf.patch
1 From b5a1e520d8039c242b2157b511f684ce464d6e21 Mon Sep 17 00:00:00 2001
2 From: James Liao <jamesjj.liao@mediatek.com>
3 Date: Thu, 20 Oct 2016 16:56:35 +0800
4 Subject: [PATCH 08/57] soc: mediatek: Refine scpsys to support multiple
5 platform
6
7 Refine scpsys driver common code to support multiple SoC / platform.
8
9 Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
10 Reviewed-by: Kevin Hilman <khilman@baylibre.com>
11 Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
12 ---
13 drivers/soc/mediatek/mtk-scpsys.c | 348 +++++++++++++++++++++++---------------
14 1 file changed, 210 insertions(+), 138 deletions(-)
15
16 --- a/drivers/soc/mediatek/mtk-scpsys.c
17 +++ b/drivers/soc/mediatek/mtk-scpsys.c
18 @@ -11,17 +11,15 @@
19 * GNU General Public License for more details.
20 */
21 #include <linux/clk.h>
22 -#include <linux/delay.h>
23 +#include <linux/init.h>
24 #include <linux/io.h>
25 -#include <linux/kernel.h>
26 #include <linux/mfd/syscon.h>
27 -#include <linux/init.h>
28 #include <linux/of_device.h>
29 #include <linux/platform_device.h>
30 #include <linux/pm_domain.h>
31 -#include <linux/regmap.h>
32 -#include <linux/soc/mediatek/infracfg.h>
33 #include <linux/regulator/consumer.h>
34 +#include <linux/soc/mediatek/infracfg.h>
35 +
36 #include <dt-bindings/power/mt8173-power.h>
37
38 #define SPM_VDE_PWR_CON 0x0210
39 @@ -34,6 +32,7 @@
40 #define SPM_MFG_2D_PWR_CON 0x02c0
41 #define SPM_MFG_ASYNC_PWR_CON 0x02c4
42 #define SPM_USB_PWR_CON 0x02cc
43 +
44 #define SPM_PWR_STATUS 0x060c
45 #define SPM_PWR_STATUS_2ND 0x0610
46
47 @@ -55,12 +54,21 @@
48 #define PWR_STATUS_USB BIT(25)
49
50 enum clk_id {
51 - MT8173_CLK_NONE,
52 - MT8173_CLK_MM,
53 - MT8173_CLK_MFG,
54 - MT8173_CLK_VENC,
55 - MT8173_CLK_VENC_LT,
56 - MT8173_CLK_MAX,
57 + CLK_NONE,
58 + CLK_MM,
59 + CLK_MFG,
60 + CLK_VENC,
61 + CLK_VENC_LT,
62 + CLK_MAX,
63 +};
64 +
65 +static const char * const clk_names[] = {
66 + NULL,
67 + "mm",
68 + "mfg",
69 + "venc",
70 + "venc_lt",
71 + NULL,
72 };
73
74 #define MAX_CLKS 2
75 @@ -76,98 +84,6 @@ struct scp_domain_data {
76 bool active_wakeup;
77 };
78
79 -static const struct scp_domain_data scp_domain_data[] = {
80 - [MT8173_POWER_DOMAIN_VDEC] = {
81 - .name = "vdec",
82 - .sta_mask = PWR_STATUS_VDEC,
83 - .ctl_offs = SPM_VDE_PWR_CON,
84 - .sram_pdn_bits = GENMASK(11, 8),
85 - .sram_pdn_ack_bits = GENMASK(12, 12),
86 - .clk_id = {MT8173_CLK_MM},
87 - },
88 - [MT8173_POWER_DOMAIN_VENC] = {
89 - .name = "venc",
90 - .sta_mask = PWR_STATUS_VENC,
91 - .ctl_offs = SPM_VEN_PWR_CON,
92 - .sram_pdn_bits = GENMASK(11, 8),
93 - .sram_pdn_ack_bits = GENMASK(15, 12),
94 - .clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC},
95 - },
96 - [MT8173_POWER_DOMAIN_ISP] = {
97 - .name = "isp",
98 - .sta_mask = PWR_STATUS_ISP,
99 - .ctl_offs = SPM_ISP_PWR_CON,
100 - .sram_pdn_bits = GENMASK(11, 8),
101 - .sram_pdn_ack_bits = GENMASK(13, 12),
102 - .clk_id = {MT8173_CLK_MM},
103 - },
104 - [MT8173_POWER_DOMAIN_MM] = {
105 - .name = "mm",
106 - .sta_mask = PWR_STATUS_DISP,
107 - .ctl_offs = SPM_DIS_PWR_CON,
108 - .sram_pdn_bits = GENMASK(11, 8),
109 - .sram_pdn_ack_bits = GENMASK(12, 12),
110 - .clk_id = {MT8173_CLK_MM},
111 - .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 |
112 - MT8173_TOP_AXI_PROT_EN_MM_M1,
113 - },
114 - [MT8173_POWER_DOMAIN_VENC_LT] = {
115 - .name = "venc_lt",
116 - .sta_mask = PWR_STATUS_VENC_LT,
117 - .ctl_offs = SPM_VEN2_PWR_CON,
118 - .sram_pdn_bits = GENMASK(11, 8),
119 - .sram_pdn_ack_bits = GENMASK(15, 12),
120 - .clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC_LT},
121 - },
122 - [MT8173_POWER_DOMAIN_AUDIO] = {
123 - .name = "audio",
124 - .sta_mask = PWR_STATUS_AUDIO,
125 - .ctl_offs = SPM_AUDIO_PWR_CON,
126 - .sram_pdn_bits = GENMASK(11, 8),
127 - .sram_pdn_ack_bits = GENMASK(15, 12),
128 - .clk_id = {MT8173_CLK_NONE},
129 - },
130 - [MT8173_POWER_DOMAIN_USB] = {
131 - .name = "usb",
132 - .sta_mask = PWR_STATUS_USB,
133 - .ctl_offs = SPM_USB_PWR_CON,
134 - .sram_pdn_bits = GENMASK(11, 8),
135 - .sram_pdn_ack_bits = GENMASK(15, 12),
136 - .clk_id = {MT8173_CLK_NONE},
137 - .active_wakeup = true,
138 - },
139 - [MT8173_POWER_DOMAIN_MFG_ASYNC] = {
140 - .name = "mfg_async",
141 - .sta_mask = PWR_STATUS_MFG_ASYNC,
142 - .ctl_offs = SPM_MFG_ASYNC_PWR_CON,
143 - .sram_pdn_bits = GENMASK(11, 8),
144 - .sram_pdn_ack_bits = 0,
145 - .clk_id = {MT8173_CLK_MFG},
146 - },
147 - [MT8173_POWER_DOMAIN_MFG_2D] = {
148 - .name = "mfg_2d",
149 - .sta_mask = PWR_STATUS_MFG_2D,
150 - .ctl_offs = SPM_MFG_2D_PWR_CON,
151 - .sram_pdn_bits = GENMASK(11, 8),
152 - .sram_pdn_ack_bits = GENMASK(13, 12),
153 - .clk_id = {MT8173_CLK_NONE},
154 - },
155 - [MT8173_POWER_DOMAIN_MFG] = {
156 - .name = "mfg",
157 - .sta_mask = PWR_STATUS_MFG,
158 - .ctl_offs = SPM_MFG_PWR_CON,
159 - .sram_pdn_bits = GENMASK(13, 8),
160 - .sram_pdn_ack_bits = GENMASK(21, 16),
161 - .clk_id = {MT8173_CLK_NONE},
162 - .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S |
163 - MT8173_TOP_AXI_PROT_EN_MFG_M0 |
164 - MT8173_TOP_AXI_PROT_EN_MFG_M1 |
165 - MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT,
166 - },
167 -};
168 -
169 -#define NUM_DOMAINS ARRAY_SIZE(scp_domain_data)
170 -
171 struct scp;
172
173 struct scp_domain {
174 @@ -179,7 +95,7 @@ struct scp_domain {
175 };
176
177 struct scp {
178 - struct scp_domain domains[NUM_DOMAINS];
179 + struct scp_domain *domains;
180 struct genpd_onecell_data pd_data;
181 struct device *dev;
182 void __iomem *base;
183 @@ -408,57 +324,55 @@ static bool scpsys_active_wakeup(struct
184 return scpd->data->active_wakeup;
185 }
186
187 -static int scpsys_probe(struct platform_device *pdev)
188 +static void init_clks(struct platform_device *pdev, struct clk **clk)
189 +{
190 + int i;
191 +
192 + for (i = CLK_NONE + 1; i < CLK_MAX; i++)
193 + clk[i] = devm_clk_get(&pdev->dev, clk_names[i]);
194 +}
195 +
196 +static struct scp *init_scp(struct platform_device *pdev,
197 + const struct scp_domain_data *scp_domain_data, int num)
198 {
199 struct genpd_onecell_data *pd_data;
200 struct resource *res;
201 - int i, j, ret;
202 + int i, j;
203 struct scp *scp;
204 - struct clk *clk[MT8173_CLK_MAX];
205 + struct clk *clk[CLK_MAX];
206
207 scp = devm_kzalloc(&pdev->dev, sizeof(*scp), GFP_KERNEL);
208 if (!scp)
209 - return -ENOMEM;
210 + return ERR_PTR(-ENOMEM);
211
212 scp->dev = &pdev->dev;
213
214 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
215 scp->base = devm_ioremap_resource(&pdev->dev, res);
216 if (IS_ERR(scp->base))
217 - return PTR_ERR(scp->base);
218 + return ERR_CAST(scp->base);
219 +
220 + scp->domains = devm_kzalloc(&pdev->dev,
221 + sizeof(*scp->domains) * num, GFP_KERNEL);
222 + if (!scp->domains)
223 + return ERR_PTR(-ENOMEM);
224
225 pd_data = &scp->pd_data;
226
227 pd_data->domains = devm_kzalloc(&pdev->dev,
228 - sizeof(*pd_data->domains) * NUM_DOMAINS, GFP_KERNEL);
229 + sizeof(*pd_data->domains) * num, GFP_KERNEL);
230 if (!pd_data->domains)
231 - return -ENOMEM;
232 -
233 - clk[MT8173_CLK_MM] = devm_clk_get(&pdev->dev, "mm");
234 - if (IS_ERR(clk[MT8173_CLK_MM]))
235 - return PTR_ERR(clk[MT8173_CLK_MM]);
236 -
237 - clk[MT8173_CLK_MFG] = devm_clk_get(&pdev->dev, "mfg");
238 - if (IS_ERR(clk[MT8173_CLK_MFG]))
239 - return PTR_ERR(clk[MT8173_CLK_MFG]);
240 -
241 - clk[MT8173_CLK_VENC] = devm_clk_get(&pdev->dev, "venc");
242 - if (IS_ERR(clk[MT8173_CLK_VENC]))
243 - return PTR_ERR(clk[MT8173_CLK_VENC]);
244 -
245 - clk[MT8173_CLK_VENC_LT] = devm_clk_get(&pdev->dev, "venc_lt");
246 - if (IS_ERR(clk[MT8173_CLK_VENC_LT]))
247 - return PTR_ERR(clk[MT8173_CLK_VENC_LT]);
248 + return ERR_PTR(-ENOMEM);
249
250 scp->infracfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
251 "infracfg");
252 if (IS_ERR(scp->infracfg)) {
253 dev_err(&pdev->dev, "Cannot find infracfg controller: %ld\n",
254 PTR_ERR(scp->infracfg));
255 - return PTR_ERR(scp->infracfg);
256 + return ERR_CAST(scp->infracfg);
257 }
258
259 - for (i = 0; i < NUM_DOMAINS; i++) {
260 + for (i = 0; i < num; i++) {
261 struct scp_domain *scpd = &scp->domains[i];
262 const struct scp_domain_data *data = &scp_domain_data[i];
263
264 @@ -467,13 +381,15 @@ static int scpsys_probe(struct platform_
265 if (PTR_ERR(scpd->supply) == -ENODEV)
266 scpd->supply = NULL;
267 else
268 - return PTR_ERR(scpd->supply);
269 + return ERR_CAST(scpd->supply);
270 }
271 }
272
273 - pd_data->num_domains = NUM_DOMAINS;
274 + pd_data->num_domains = num;
275 +
276 + init_clks(pdev, clk);
277
278 - for (i = 0; i < NUM_DOMAINS; i++) {
279 + for (i = 0; i < num; i++) {
280 struct scp_domain *scpd = &scp->domains[i];
281 struct generic_pm_domain *genpd = &scpd->genpd;
282 const struct scp_domain_data *data = &scp_domain_data[i];
283 @@ -482,13 +398,37 @@ static int scpsys_probe(struct platform_
284 scpd->scp = scp;
285
286 scpd->data = data;
287 - for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++)
288 - scpd->clk[j] = clk[data->clk_id[j]];
289 +
290 + for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) {
291 + struct clk *c = clk[data->clk_id[j]];
292 +
293 + if (IS_ERR(c)) {
294 + dev_err(&pdev->dev, "%s: clk unavailable\n",
295 + data->name);
296 + return ERR_CAST(c);
297 + }
298 +
299 + scpd->clk[j] = c;
300 + }
301
302 genpd->name = data->name;
303 genpd->power_off = scpsys_power_off;
304 genpd->power_on = scpsys_power_on;
305 genpd->dev_ops.active_wakeup = scpsys_active_wakeup;
306 + }
307 +
308 + return scp;
309 +}
310 +
311 +static void mtk_register_power_domains(struct platform_device *pdev,
312 + struct scp *scp, int num)
313 +{
314 + struct genpd_onecell_data *pd_data;
315 + int i, ret;
316 +
317 + for (i = 0; i < num; i++) {
318 + struct scp_domain *scpd = &scp->domains[i];
319 + struct generic_pm_domain *genpd = &scpd->genpd;
320
321 /*
322 * Initially turn on all domains to make the domains usable
323 @@ -507,6 +447,123 @@ static int scpsys_probe(struct platform_
324 * valid.
325 */
326
327 + pd_data = &scp->pd_data;
328 +
329 + ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data);
330 + if (ret)
331 + dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret);
332 +}
333 +
334 +/*
335 + * MT8173 power domain support
336 + */
337 +
338 +static const struct scp_domain_data scp_domain_data_mt8173[] = {
339 + [MT8173_POWER_DOMAIN_VDEC] = {
340 + .name = "vdec",
341 + .sta_mask = PWR_STATUS_VDEC,
342 + .ctl_offs = SPM_VDE_PWR_CON,
343 + .sram_pdn_bits = GENMASK(11, 8),
344 + .sram_pdn_ack_bits = GENMASK(12, 12),
345 + .clk_id = {CLK_MM},
346 + },
347 + [MT8173_POWER_DOMAIN_VENC] = {
348 + .name = "venc",
349 + .sta_mask = PWR_STATUS_VENC,
350 + .ctl_offs = SPM_VEN_PWR_CON,
351 + .sram_pdn_bits = GENMASK(11, 8),
352 + .sram_pdn_ack_bits = GENMASK(15, 12),
353 + .clk_id = {CLK_MM, CLK_VENC},
354 + },
355 + [MT8173_POWER_DOMAIN_ISP] = {
356 + .name = "isp",
357 + .sta_mask = PWR_STATUS_ISP,
358 + .ctl_offs = SPM_ISP_PWR_CON,
359 + .sram_pdn_bits = GENMASK(11, 8),
360 + .sram_pdn_ack_bits = GENMASK(13, 12),
361 + .clk_id = {CLK_MM},
362 + },
363 + [MT8173_POWER_DOMAIN_MM] = {
364 + .name = "mm",
365 + .sta_mask = PWR_STATUS_DISP,
366 + .ctl_offs = SPM_DIS_PWR_CON,
367 + .sram_pdn_bits = GENMASK(11, 8),
368 + .sram_pdn_ack_bits = GENMASK(12, 12),
369 + .clk_id = {CLK_MM},
370 + .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 |
371 + MT8173_TOP_AXI_PROT_EN_MM_M1,
372 + },
373 + [MT8173_POWER_DOMAIN_VENC_LT] = {
374 + .name = "venc_lt",
375 + .sta_mask = PWR_STATUS_VENC_LT,
376 + .ctl_offs = SPM_VEN2_PWR_CON,
377 + .sram_pdn_bits = GENMASK(11, 8),
378 + .sram_pdn_ack_bits = GENMASK(15, 12),
379 + .clk_id = {CLK_MM, CLK_VENC_LT},
380 + },
381 + [MT8173_POWER_DOMAIN_AUDIO] = {
382 + .name = "audio",
383 + .sta_mask = PWR_STATUS_AUDIO,
384 + .ctl_offs = SPM_AUDIO_PWR_CON,
385 + .sram_pdn_bits = GENMASK(11, 8),
386 + .sram_pdn_ack_bits = GENMASK(15, 12),
387 + .clk_id = {CLK_NONE},
388 + },
389 + [MT8173_POWER_DOMAIN_USB] = {
390 + .name = "usb",
391 + .sta_mask = PWR_STATUS_USB,
392 + .ctl_offs = SPM_USB_PWR_CON,
393 + .sram_pdn_bits = GENMASK(11, 8),
394 + .sram_pdn_ack_bits = GENMASK(15, 12),
395 + .clk_id = {CLK_NONE},
396 + .active_wakeup = true,
397 + },
398 + [MT8173_POWER_DOMAIN_MFG_ASYNC] = {
399 + .name = "mfg_async",
400 + .sta_mask = PWR_STATUS_MFG_ASYNC,
401 + .ctl_offs = SPM_MFG_ASYNC_PWR_CON,
402 + .sram_pdn_bits = GENMASK(11, 8),
403 + .sram_pdn_ack_bits = 0,
404 + .clk_id = {CLK_MFG},
405 + },
406 + [MT8173_POWER_DOMAIN_MFG_2D] = {
407 + .name = "mfg_2d",
408 + .sta_mask = PWR_STATUS_MFG_2D,
409 + .ctl_offs = SPM_MFG_2D_PWR_CON,
410 + .sram_pdn_bits = GENMASK(11, 8),
411 + .sram_pdn_ack_bits = GENMASK(13, 12),
412 + .clk_id = {CLK_NONE},
413 + },
414 + [MT8173_POWER_DOMAIN_MFG] = {
415 + .name = "mfg",
416 + .sta_mask = PWR_STATUS_MFG,
417 + .ctl_offs = SPM_MFG_PWR_CON,
418 + .sram_pdn_bits = GENMASK(13, 8),
419 + .sram_pdn_ack_bits = GENMASK(21, 16),
420 + .clk_id = {CLK_NONE},
421 + .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S |
422 + MT8173_TOP_AXI_PROT_EN_MFG_M0 |
423 + MT8173_TOP_AXI_PROT_EN_MFG_M1 |
424 + MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT,
425 + },
426 +};
427 +
428 +#define NUM_DOMAINS_MT8173 ARRAY_SIZE(scp_domain_data_mt8173)
429 +
430 +static int __init scpsys_probe_mt8173(struct platform_device *pdev)
431 +{
432 + struct scp *scp;
433 + struct genpd_onecell_data *pd_data;
434 + int ret;
435 +
436 + scp = init_scp(pdev, scp_domain_data_mt8173, NUM_DOMAINS_MT8173);
437 + if (IS_ERR(scp))
438 + return PTR_ERR(scp);
439 +
440 + mtk_register_power_domains(pdev, scp, NUM_DOMAINS_MT8173);
441 +
442 + pd_data = &scp->pd_data;
443 +
444 ret = pm_genpd_add_subdomain(pd_data->domains[MT8173_POWER_DOMAIN_MFG_ASYNC],
445 pd_data->domains[MT8173_POWER_DOMAIN_MFG_2D]);
446 if (ret && IS_ENABLED(CONFIG_PM))
447 @@ -517,21 +574,36 @@ static int scpsys_probe(struct platform_
448 if (ret && IS_ENABLED(CONFIG_PM))
449 dev_err(&pdev->dev, "Failed to add subdomain: %d\n", ret);
450
451 - ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data);
452 - if (ret)
453 - dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret);
454 -
455 return 0;
456 }
457
458 +/*
459 + * scpsys driver init
460 + */
461 +
462 static const struct of_device_id of_scpsys_match_tbl[] = {
463 {
464 .compatible = "mediatek,mt8173-scpsys",
465 + .data = scpsys_probe_mt8173,
466 }, {
467 /* sentinel */
468 }
469 };
470
471 +static int scpsys_probe(struct platform_device *pdev)
472 +{
473 + int (*probe)(struct platform_device *);
474 + const struct of_device_id *of_id;
475 +
476 + of_id = of_match_node(of_scpsys_match_tbl, pdev->dev.of_node);
477 + if (!of_id || !of_id->data)
478 + return -EINVAL;
479 +
480 + probe = of_id->data;
481 +
482 + return probe(pdev);
483 +}
484 +
485 static struct platform_driver scpsys_drv = {
486 .probe = scpsys_probe,
487 .driver = {