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
6 Refine scpsys driver common code to support multiple SoC / platform.
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>
12 drivers/soc/mediatek/mtk-scpsys.c | 348 +++++++++++++++++++++++---------------
13 1 file changed, 210 insertions(+), 138 deletions(-)
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
20 * GNU General Public License for more details.
22 #include <linux/clk.h>
23 -#include <linux/delay.h>
24 +#include <linux/init.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>
37 #include <dt-bindings/power/mt8173-power.h>
39 #define SPM_VDE_PWR_CON 0x0210
41 #define SPM_MFG_2D_PWR_CON 0x02c0
42 #define SPM_MFG_ASYNC_PWR_CON 0x02c4
43 #define SPM_USB_PWR_CON 0x02cc
45 #define SPM_PWR_STATUS 0x060c
46 #define SPM_PWR_STATUS_2ND 0x0610
49 #define PWR_STATUS_USB BIT(25)
66 +static const char * const clk_names[] = {
76 @@ -76,98 +84,6 @@ struct scp_domain_data {
80 -static const struct scp_domain_data scp_domain_data[] = {
81 - [MT8173_POWER_DOMAIN_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},
89 - [MT8173_POWER_DOMAIN_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},
97 - [MT8173_POWER_DOMAIN_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},
105 - [MT8173_POWER_DOMAIN_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,
115 - [MT8173_POWER_DOMAIN_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},
123 - [MT8173_POWER_DOMAIN_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},
131 - [MT8173_POWER_DOMAIN_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,
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},
148 - [MT8173_POWER_DOMAIN_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},
156 - [MT8173_POWER_DOMAIN_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,
170 -#define NUM_DOMAINS ARRAY_SIZE(scp_domain_data)
175 @@ -179,7 +95,7 @@ struct scp_domain {
179 - struct scp_domain domains[NUM_DOMAINS];
180 + struct scp_domain *domains;
181 struct genpd_onecell_data pd_data;
184 @@ -408,57 +324,55 @@ static bool scpsys_active_wakeup(struct device *dev)
185 return scpd->data->active_wakeup;
188 -static int scpsys_probe(struct platform_device *pdev)
189 +static void init_clks(struct platform_device *pdev, struct clk **clk)
193 + for (i = CLK_NONE + 1; i < CLK_MAX; i++)
194 + clk[i] = devm_clk_get(&pdev->dev, clk_names[i]);
197 +static struct scp *init_scp(struct platform_device *pdev,
198 + const struct scp_domain_data *scp_domain_data, int num)
200 struct genpd_onecell_data *pd_data;
201 struct resource *res;
205 - struct clk *clk[MT8173_CLK_MAX];
206 + struct clk *clk[CLK_MAX];
208 scp = devm_kzalloc(&pdev->dev, sizeof(*scp), GFP_KERNEL);
211 + return ERR_PTR(-ENOMEM);
213 scp->dev = &pdev->dev;
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);
221 + scp->domains = devm_kzalloc(&pdev->dev,
222 + sizeof(*scp->domains) * num, GFP_KERNEL);
224 + return ERR_PTR(-ENOMEM);
226 pd_data = &scp->pd_data;
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)
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]);
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]);
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]);
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);
251 scp->infracfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
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);
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];
265 @@ -467,13 +381,15 @@ static int scpsys_probe(struct platform_device *pdev)
266 if (PTR_ERR(scpd->supply) == -ENODEV)
269 - return PTR_ERR(scpd->supply);
270 + return ERR_CAST(scpd->supply);
274 - pd_data->num_domains = NUM_DOMAINS;
275 + pd_data->num_domains = num;
277 - for (i = 0; i < NUM_DOMAINS; i++) {
278 + init_clks(pdev, clk);
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)
288 - for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++)
289 - scpd->clk[j] = clk[data->clk_id[j]];
291 + for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) {
292 + struct clk *c = clk[data->clk_id[j]];
295 + dev_err(&pdev->dev, "%s: clk unavailable\n",
297 + return ERR_CAST(c);
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;
312 +static void mtk_register_power_domains(struct platform_device *pdev,
313 + struct scp *scp, int num)
315 + struct genpd_onecell_data *pd_data;
318 + for (i = 0; i < num; i++) {
319 + struct scp_domain *scpd = &scp->domains[i];
320 + struct generic_pm_domain *genpd = &scpd->genpd;
323 * Initially turn on all domains to make the domains usable
324 @@ -507,6 +447,123 @@ static int scpsys_probe(struct platform_device *pdev)
328 + pd_data = &scp->pd_data;
330 + ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data);
332 + dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret);
336 + * MT8173 power domain support
339 +static const struct scp_domain_data scp_domain_data_mt8173[] = {
340 + [MT8173_POWER_DOMAIN_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},
348 + [MT8173_POWER_DOMAIN_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},
356 + [MT8173_POWER_DOMAIN_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},
364 + [MT8173_POWER_DOMAIN_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,
374 + [MT8173_POWER_DOMAIN_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},
382 + [MT8173_POWER_DOMAIN_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},
390 + [MT8173_POWER_DOMAIN_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,
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},
407 + [MT8173_POWER_DOMAIN_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},
415 + [MT8173_POWER_DOMAIN_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,
429 +#define NUM_DOMAINS_MT8173 ARRAY_SIZE(scp_domain_data_mt8173)
431 +static int __init scpsys_probe_mt8173(struct platform_device *pdev)
434 + struct genpd_onecell_data *pd_data;
437 + scp = init_scp(pdev, scp_domain_data_mt8173, NUM_DOMAINS_MT8173);
439 + return PTR_ERR(scp);
441 + mtk_register_power_domains(pdev, scp, NUM_DOMAINS_MT8173);
443 + pd_data = &scp->pd_data;
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);
452 - ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data);
454 - dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret);
460 + * scpsys driver init
463 static const struct of_device_id of_scpsys_match_tbl[] = {
465 .compatible = "mediatek,mt8173-scpsys",
466 + .data = scpsys_probe_mt8173,
472 +static int scpsys_probe(struct platform_device *pdev)
474 + int (*probe)(struct platform_device *);
475 + const struct of_device_id *of_id;
477 + of_id = of_match_node(of_scpsys_match_tbl, pdev->dev.of_node);
478 + if (!of_id || !of_id->data)
481 + probe = of_id->data;
483 + return probe(pdev);
486 static struct platform_driver scpsys_drv = {
487 .probe = scpsys_probe,