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
7 Refine scpsys driver common code to support multiple SoC / platform.
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>
13 drivers/soc/mediatek/mtk-scpsys.c | 348 +++++++++++++++++++++++---------------
14 1 file changed, 210 insertions(+), 138 deletions(-)
16 --- a/drivers/soc/mediatek/mtk-scpsys.c
17 +++ b/drivers/soc/mediatek/mtk-scpsys.c
19 * GNU General Public License for more details.
21 #include <linux/clk.h>
22 -#include <linux/delay.h>
23 +#include <linux/init.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>
36 #include <dt-bindings/power/mt8173-power.h>
38 #define SPM_VDE_PWR_CON 0x0210
40 #define SPM_MFG_2D_PWR_CON 0x02c0
41 #define SPM_MFG_ASYNC_PWR_CON 0x02c4
42 #define SPM_USB_PWR_CON 0x02cc
44 #define SPM_PWR_STATUS 0x060c
45 #define SPM_PWR_STATUS_2ND 0x0610
48 #define PWR_STATUS_USB BIT(25)
65 +static const char * const clk_names[] = {
75 @@ -76,98 +84,6 @@ struct scp_domain_data {
79 -static const struct scp_domain_data scp_domain_data[] = {
80 - [MT8173_POWER_DOMAIN_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},
88 - [MT8173_POWER_DOMAIN_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},
96 - [MT8173_POWER_DOMAIN_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},
104 - [MT8173_POWER_DOMAIN_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,
114 - [MT8173_POWER_DOMAIN_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},
122 - [MT8173_POWER_DOMAIN_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},
130 - [MT8173_POWER_DOMAIN_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,
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},
147 - [MT8173_POWER_DOMAIN_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},
155 - [MT8173_POWER_DOMAIN_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,
169 -#define NUM_DOMAINS ARRAY_SIZE(scp_domain_data)
174 @@ -179,7 +95,7 @@ struct scp_domain {
178 - struct scp_domain domains[NUM_DOMAINS];
179 + struct scp_domain *domains;
180 struct genpd_onecell_data pd_data;
183 @@ -408,57 +324,55 @@ static bool scpsys_active_wakeup(struct
184 return scpd->data->active_wakeup;
187 -static int scpsys_probe(struct platform_device *pdev)
188 +static void init_clks(struct platform_device *pdev, struct clk **clk)
192 + for (i = CLK_NONE + 1; i < CLK_MAX; i++)
193 + clk[i] = devm_clk_get(&pdev->dev, clk_names[i]);
196 +static struct scp *init_scp(struct platform_device *pdev,
197 + const struct scp_domain_data *scp_domain_data, int num)
199 struct genpd_onecell_data *pd_data;
200 struct resource *res;
204 - struct clk *clk[MT8173_CLK_MAX];
205 + struct clk *clk[CLK_MAX];
207 scp = devm_kzalloc(&pdev->dev, sizeof(*scp), GFP_KERNEL);
210 + return ERR_PTR(-ENOMEM);
212 scp->dev = &pdev->dev;
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);
220 + scp->domains = devm_kzalloc(&pdev->dev,
221 + sizeof(*scp->domains) * num, GFP_KERNEL);
223 + return ERR_PTR(-ENOMEM);
225 pd_data = &scp->pd_data;
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)
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]);
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]);
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]);
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);
250 scp->infracfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
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);
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];
264 @@ -467,13 +381,15 @@ static int scpsys_probe(struct platform_
265 if (PTR_ERR(scpd->supply) == -ENODEV)
268 - return PTR_ERR(scpd->supply);
269 + return ERR_CAST(scpd->supply);
273 - pd_data->num_domains = NUM_DOMAINS;
274 + pd_data->num_domains = num;
276 + init_clks(pdev, clk);
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_
287 - for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++)
288 - scpd->clk[j] = clk[data->clk_id[j]];
290 + for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) {
291 + struct clk *c = clk[data->clk_id[j]];
294 + dev_err(&pdev->dev, "%s: clk unavailable\n",
296 + return ERR_CAST(c);
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;
311 +static void mtk_register_power_domains(struct platform_device *pdev,
312 + struct scp *scp, int num)
314 + struct genpd_onecell_data *pd_data;
317 + for (i = 0; i < num; i++) {
318 + struct scp_domain *scpd = &scp->domains[i];
319 + struct generic_pm_domain *genpd = &scpd->genpd;
322 * Initially turn on all domains to make the domains usable
323 @@ -507,6 +447,123 @@ static int scpsys_probe(struct platform_
327 + pd_data = &scp->pd_data;
329 + ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data);
331 + dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret);
335 + * MT8173 power domain support
338 +static const struct scp_domain_data scp_domain_data_mt8173[] = {
339 + [MT8173_POWER_DOMAIN_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},
347 + [MT8173_POWER_DOMAIN_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},
355 + [MT8173_POWER_DOMAIN_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},
363 + [MT8173_POWER_DOMAIN_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,
373 + [MT8173_POWER_DOMAIN_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},
381 + [MT8173_POWER_DOMAIN_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},
389 + [MT8173_POWER_DOMAIN_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,
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},
406 + [MT8173_POWER_DOMAIN_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},
414 + [MT8173_POWER_DOMAIN_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,
428 +#define NUM_DOMAINS_MT8173 ARRAY_SIZE(scp_domain_data_mt8173)
430 +static int __init scpsys_probe_mt8173(struct platform_device *pdev)
433 + struct genpd_onecell_data *pd_data;
436 + scp = init_scp(pdev, scp_domain_data_mt8173, NUM_DOMAINS_MT8173);
438 + return PTR_ERR(scp);
440 + mtk_register_power_domains(pdev, scp, NUM_DOMAINS_MT8173);
442 + pd_data = &scp->pd_data;
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);
451 - ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data);
453 - dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret);
459 + * scpsys driver init
462 static const struct of_device_id of_scpsys_match_tbl[] = {
464 .compatible = "mediatek,mt8173-scpsys",
465 + .data = scpsys_probe_mt8173,
471 +static int scpsys_probe(struct platform_device *pdev)
473 + int (*probe)(struct platform_device *);
474 + const struct of_device_id *of_id;
476 + of_id = of_match_node(of_scpsys_match_tbl, pdev->dev.of_node);
477 + if (!of_id || !of_id->data)
480 + probe = of_id->data;
482 + return probe(pdev);
485 static struct platform_driver scpsys_drv = {
486 .probe = scpsys_probe,