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