1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright 2015-2017 Pengutronix, Lucas Stach <kernel@pengutronix.de>
4 * Copyright 2011-2013 Freescale Semiconductor, Inc.
8 #include <linux/delay.h>
10 #include <linux/of_device.h>
11 #include <linux/platform_device.h>
12 #include <linux/pm_domain.h>
13 #include <linux/regmap.h>
14 #include <linux/regulator/consumer.h>
16 #define GPC_CNTR 0x000
18 #define GPC_PGC_CTRL_OFFS 0x0
19 #define GPC_PGC_PUPSCR_OFFS 0x4
20 #define GPC_PGC_PDNSCR_OFFS 0x8
21 #define GPC_PGC_SW2ISO_SHIFT 0x8
22 #define GPC_PGC_SW_SHIFT 0x0
24 #define GPC_PGC_PCI_PDN 0x200
25 #define GPC_PGC_PCI_SR 0x20c
27 #define GPC_PGC_GPU_PDN 0x260
28 #define GPC_PGC_GPU_PUPSCR 0x264
29 #define GPC_PGC_GPU_PDNSCR 0x268
30 #define GPC_PGC_GPU_SR 0x26c
32 #define GPC_PGC_DISP_PDN 0x240
33 #define GPC_PGC_DISP_SR 0x24c
35 #define GPU_VPU_PUP_REQ BIT(1)
36 #define GPU_VPU_PDN_REQ BIT(0)
40 #define PGC_DOMAIN_FLAG_NO_PD BIT(0)
42 struct imx_pm_domain
{
43 struct generic_pm_domain base
;
44 struct regmap
*regmap
;
45 struct regulator
*supply
;
46 struct clk
*clk
[GPC_CLK_MAX
];
48 unsigned int reg_offs
;
49 signed char cntr_pdn_bit
;
50 unsigned int ipg_rate_mhz
;
53 static inline struct imx_pm_domain
*
54 to_imx_pm_domain(struct generic_pm_domain
*genpd
)
56 return container_of(genpd
, struct imx_pm_domain
, base
);
59 static int imx6_pm_domain_power_off(struct generic_pm_domain
*genpd
)
61 struct imx_pm_domain
*pd
= to_imx_pm_domain(genpd
);
65 /* Read ISO and ISO2SW power down delays */
66 regmap_read(pd
->regmap
, pd
->reg_offs
+ GPC_PGC_PDNSCR_OFFS
, &val
);
68 iso2sw
= (val
>> 8) & 0x3f;
70 /* Gate off domain when powered down */
71 regmap_update_bits(pd
->regmap
, pd
->reg_offs
+ GPC_PGC_CTRL_OFFS
,
74 /* Request GPC to power down domain */
75 val
= BIT(pd
->cntr_pdn_bit
);
76 regmap_update_bits(pd
->regmap
, GPC_CNTR
, val
, val
);
78 /* Wait ISO + ISO2SW IPG clock cycles */
79 udelay(DIV_ROUND_UP(iso
+ iso2sw
, pd
->ipg_rate_mhz
));
82 regulator_disable(pd
->supply
);
87 static int imx6_pm_domain_power_on(struct generic_pm_domain
*genpd
)
89 struct imx_pm_domain
*pd
= to_imx_pm_domain(genpd
);
90 int i
, ret
, sw
, sw2iso
;
94 ret
= regulator_enable(pd
->supply
);
96 pr_err("%s: failed to enable regulator: %d\n",
102 /* Enable reset clocks for all devices in the domain */
103 for (i
= 0; i
< pd
->num_clks
; i
++)
104 clk_prepare_enable(pd
->clk
[i
]);
106 /* Gate off domain when powered down */
107 regmap_update_bits(pd
->regmap
, pd
->reg_offs
+ GPC_PGC_CTRL_OFFS
,
110 /* Read ISO and ISO2SW power up delays */
111 regmap_read(pd
->regmap
, pd
->reg_offs
+ GPC_PGC_PUPSCR_OFFS
, &val
);
113 sw2iso
= (val
>> 8) & 0x3f;
115 /* Request GPC to power up domain */
116 val
= BIT(pd
->cntr_pdn_bit
+ 1);
117 regmap_update_bits(pd
->regmap
, GPC_CNTR
, val
, val
);
119 /* Wait ISO + ISO2SW IPG clock cycles */
120 udelay(DIV_ROUND_UP(sw
+ sw2iso
, pd
->ipg_rate_mhz
));
122 /* Disable reset clocks for all devices in the domain */
123 for (i
= 0; i
< pd
->num_clks
; i
++)
124 clk_disable_unprepare(pd
->clk
[i
]);
129 static int imx_pgc_get_clocks(struct device
*dev
, struct imx_pm_domain
*domain
)
134 struct clk
*clk
= of_clk_get(dev
->of_node
, i
);
137 if (i
>= GPC_CLK_MAX
) {
138 dev_err(dev
, "more than %d clocks\n", GPC_CLK_MAX
);
142 domain
->clk
[i
] = clk
;
144 domain
->num_clks
= i
;
150 clk_put(domain
->clk
[i
]);
155 static void imx_pgc_put_clocks(struct imx_pm_domain
*domain
)
159 for (i
= domain
->num_clks
- 1; i
>= 0; i
--)
160 clk_put(domain
->clk
[i
]);
163 static int imx_pgc_parse_dt(struct device
*dev
, struct imx_pm_domain
*domain
)
165 /* try to get the domain supply regulator */
166 domain
->supply
= devm_regulator_get_optional(dev
, "power");
167 if (IS_ERR(domain
->supply
)) {
168 if (PTR_ERR(domain
->supply
) == -ENODEV
)
169 domain
->supply
= NULL
;
171 return PTR_ERR(domain
->supply
);
174 /* try to get all clocks needed for reset propagation */
175 return imx_pgc_get_clocks(dev
, domain
);
178 static int imx_pgc_power_domain_probe(struct platform_device
*pdev
)
180 struct imx_pm_domain
*domain
= pdev
->dev
.platform_data
;
181 struct device
*dev
= &pdev
->dev
;
184 /* if this PD is associated with a DT node try to parse it */
186 ret
= imx_pgc_parse_dt(dev
, domain
);
191 /* initially power on the domain */
192 if (domain
->base
.power_on
)
193 domain
->base
.power_on(&domain
->base
);
195 if (IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS
)) {
196 pm_genpd_init(&domain
->base
, NULL
, false);
197 ret
= of_genpd_add_provider_simple(dev
->of_node
, &domain
->base
);
202 device_link_add(dev
, dev
->parent
, DL_FLAG_AUTOREMOVE_CONSUMER
);
207 pm_genpd_remove(&domain
->base
);
208 imx_pgc_put_clocks(domain
);
213 static int imx_pgc_power_domain_remove(struct platform_device
*pdev
)
215 struct imx_pm_domain
*domain
= pdev
->dev
.platform_data
;
217 if (IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS
)) {
218 of_genpd_del_provider(pdev
->dev
.of_node
);
219 pm_genpd_remove(&domain
->base
);
220 imx_pgc_put_clocks(domain
);
226 static const struct platform_device_id imx_pgc_power_domain_id
[] = {
227 { "imx-pgc-power-domain"},
231 static struct platform_driver imx_pgc_power_domain_driver
= {
233 .name
= "imx-pgc-pd",
235 .probe
= imx_pgc_power_domain_probe
,
236 .remove
= imx_pgc_power_domain_remove
,
237 .id_table
= imx_pgc_power_domain_id
,
239 builtin_platform_driver(imx_pgc_power_domain_driver
)
241 #define GPC_PGC_DOMAIN_ARM 0
242 #define GPC_PGC_DOMAIN_PU 1
243 #define GPC_PGC_DOMAIN_DISPLAY 2
244 #define GPC_PGC_DOMAIN_PCI 3
246 static struct genpd_power_state imx6_pm_domain_pu_state
= {
247 .power_off_latency_ns
= 25000,
248 .power_on_latency_ns
= 2000000,
251 static struct imx_pm_domain imx_gpc_domains
[] = {
252 [GPC_PGC_DOMAIN_ARM
] {
255 .flags
= GENPD_FLAG_ALWAYS_ON
,
258 [GPC_PGC_DOMAIN_PU
] {
261 .power_off
= imx6_pm_domain_power_off
,
262 .power_on
= imx6_pm_domain_power_on
,
263 .states
= &imx6_pm_domain_pu_state
,
269 [GPC_PGC_DOMAIN_DISPLAY
] {
272 .power_off
= imx6_pm_domain_power_off
,
273 .power_on
= imx6_pm_domain_power_on
,
278 [GPC_PGC_DOMAIN_PCI
] {
281 .power_off
= imx6_pm_domain_power_off
,
282 .power_on
= imx6_pm_domain_power_on
,
289 struct imx_gpc_dt_data
{
291 bool err009619_present
;
292 bool err006287_present
;
295 static const struct imx_gpc_dt_data imx6q_dt_data
= {
297 .err009619_present
= false,
298 .err006287_present
= false,
301 static const struct imx_gpc_dt_data imx6qp_dt_data
= {
303 .err009619_present
= true,
304 .err006287_present
= false,
307 static const struct imx_gpc_dt_data imx6sl_dt_data
= {
309 .err009619_present
= false,
310 .err006287_present
= true,
313 static const struct imx_gpc_dt_data imx6sx_dt_data
= {
315 .err009619_present
= false,
316 .err006287_present
= false,
319 static const struct of_device_id imx_gpc_dt_ids
[] = {
320 { .compatible
= "fsl,imx6q-gpc", .data
= &imx6q_dt_data
},
321 { .compatible
= "fsl,imx6qp-gpc", .data
= &imx6qp_dt_data
},
322 { .compatible
= "fsl,imx6sl-gpc", .data
= &imx6sl_dt_data
},
323 { .compatible
= "fsl,imx6sx-gpc", .data
= &imx6sx_dt_data
},
327 static const struct regmap_range yes_ranges
[] = {
328 regmap_reg_range(GPC_CNTR
, GPC_CNTR
),
329 regmap_reg_range(GPC_PGC_PCI_PDN
, GPC_PGC_PCI_SR
),
330 regmap_reg_range(GPC_PGC_GPU_PDN
, GPC_PGC_GPU_SR
),
331 regmap_reg_range(GPC_PGC_DISP_PDN
, GPC_PGC_DISP_SR
),
334 static const struct regmap_access_table access_table
= {
335 .yes_ranges
= yes_ranges
,
336 .n_yes_ranges
= ARRAY_SIZE(yes_ranges
),
339 static const struct regmap_config imx_gpc_regmap_config
= {
343 .rd_table
= &access_table
,
344 .wr_table
= &access_table
,
345 .max_register
= 0x2ac,
348 static struct generic_pm_domain
*imx_gpc_onecell_domains
[] = {
349 &imx_gpc_domains
[GPC_PGC_DOMAIN_ARM
].base
,
350 &imx_gpc_domains
[GPC_PGC_DOMAIN_PU
].base
,
353 static struct genpd_onecell_data imx_gpc_onecell_data
= {
354 .domains
= imx_gpc_onecell_domains
,
358 static int imx_gpc_old_dt_init(struct device
*dev
, struct regmap
*regmap
,
359 unsigned int num_domains
)
361 struct imx_pm_domain
*domain
;
364 for (i
= 0; i
< num_domains
; i
++) {
365 domain
= &imx_gpc_domains
[i
];
366 domain
->regmap
= regmap
;
367 domain
->ipg_rate_mhz
= 66;
370 domain
->supply
= devm_regulator_get(dev
, "pu");
371 if (IS_ERR(domain
->supply
))
372 return PTR_ERR(domain
->supply
);
374 ret
= imx_pgc_get_clocks(dev
, domain
);
378 domain
->base
.power_on(&domain
->base
);
382 for (i
= 0; i
< num_domains
; i
++)
383 pm_genpd_init(&imx_gpc_domains
[i
].base
, NULL
, false);
385 if (IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS
)) {
386 ret
= of_genpd_add_provider_onecell(dev
->of_node
,
387 &imx_gpc_onecell_data
);
395 for (i
= 0; i
< num_domains
; i
++)
396 pm_genpd_remove(&imx_gpc_domains
[i
].base
);
397 imx_pgc_put_clocks(&imx_gpc_domains
[GPC_PGC_DOMAIN_PU
]);
402 static int imx_gpc_probe(struct platform_device
*pdev
)
404 const struct of_device_id
*of_id
=
405 of_match_device(imx_gpc_dt_ids
, &pdev
->dev
);
406 const struct imx_gpc_dt_data
*of_id_data
= of_id
->data
;
407 struct device_node
*pgc_node
;
408 struct regmap
*regmap
;
409 struct resource
*res
;
413 pgc_node
= of_get_child_by_name(pdev
->dev
.of_node
, "pgc");
415 /* bail out if DT too old and doesn't provide the necessary info */
416 if (!of_property_read_bool(pdev
->dev
.of_node
, "#power-domain-cells") &&
420 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
421 base
= devm_ioremap_resource(&pdev
->dev
, res
);
423 return PTR_ERR(base
);
425 regmap
= devm_regmap_init_mmio_clk(&pdev
->dev
, NULL
, base
,
426 &imx_gpc_regmap_config
);
427 if (IS_ERR(regmap
)) {
428 ret
= PTR_ERR(regmap
);
429 dev_err(&pdev
->dev
, "failed to init regmap: %d\n",
434 /* Disable PU power down in normal operation if ERR009619 is present */
435 if (of_id_data
->err009619_present
)
436 imx_gpc_domains
[GPC_PGC_DOMAIN_PU
].base
.flags
|=
437 GENPD_FLAG_ALWAYS_ON
;
439 /* Keep DISP always on if ERR006287 is present */
440 if (of_id_data
->err006287_present
)
441 imx_gpc_domains
[GPC_PGC_DOMAIN_DISPLAY
].base
.flags
|=
442 GENPD_FLAG_ALWAYS_ON
;
445 ret
= imx_gpc_old_dt_init(&pdev
->dev
, regmap
,
446 of_id_data
->num_domains
);
450 struct imx_pm_domain
*domain
;
451 struct platform_device
*pd_pdev
;
452 struct device_node
*np
;
454 unsigned int ipg_rate_mhz
;
457 ipg_clk
= devm_clk_get(&pdev
->dev
, "ipg");
459 return PTR_ERR(ipg_clk
);
460 ipg_rate_mhz
= clk_get_rate(ipg_clk
) / 1000000;
462 for_each_child_of_node(pgc_node
, np
) {
463 ret
= of_property_read_u32(np
, "reg", &domain_index
);
468 if (domain_index
>= of_id_data
->num_domains
)
471 pd_pdev
= platform_device_alloc("imx-pgc-power-domain",
478 ret
= platform_device_add_data(pd_pdev
,
479 &imx_gpc_domains
[domain_index
],
480 sizeof(imx_gpc_domains
[domain_index
]));
482 platform_device_put(pd_pdev
);
486 domain
= pd_pdev
->dev
.platform_data
;
487 domain
->regmap
= regmap
;
488 domain
->ipg_rate_mhz
= ipg_rate_mhz
;
490 pd_pdev
->dev
.parent
= &pdev
->dev
;
491 pd_pdev
->dev
.of_node
= np
;
493 ret
= platform_device_add(pd_pdev
);
495 platform_device_put(pd_pdev
);
505 static int imx_gpc_remove(struct platform_device
*pdev
)
507 struct device_node
*pgc_node
;
510 pgc_node
= of_get_child_by_name(pdev
->dev
.of_node
, "pgc");
512 /* bail out if DT too old and doesn't provide the necessary info */
513 if (!of_property_read_bool(pdev
->dev
.of_node
, "#power-domain-cells") &&
518 * If the old DT binding is used the toplevel driver needs to
519 * de-register the power domains
522 of_genpd_del_provider(pdev
->dev
.of_node
);
524 ret
= pm_genpd_remove(&imx_gpc_domains
[GPC_PGC_DOMAIN_PU
].base
);
527 imx_pgc_put_clocks(&imx_gpc_domains
[GPC_PGC_DOMAIN_PU
]);
529 ret
= pm_genpd_remove(&imx_gpc_domains
[GPC_PGC_DOMAIN_ARM
].base
);
537 static struct platform_driver imx_gpc_driver
= {
540 .of_match_table
= imx_gpc_dt_ids
,
542 .probe
= imx_gpc_probe
,
543 .remove
= imx_gpc_remove
,
545 builtin_platform_driver(imx_gpc_driver
)