Skip to content
This repository was archived by the owner on Sep 24, 2020. It is now read-only.

Commit 721cabf

Browse files
lynxeye-devShawn Guo
authored andcommitted
soc: imx: move PGC handling to a new GPC driver
This is an almost complete re-write of the previous GPC power gating control code found in the IMX architecture code. It supports both the old and the new DT binding, allowing more domains to be added later and generally makes the driver easier to extend, while keeping compatibility with existing DTBs. As the result, all functionality regarding the power gating controller gets removed from the IMX architecture GPC driver. It keeps only the IRQ controller code in the architecture, as this is closely coupled to the CPU idle implementation. Signed-off-by: Lucas Stach <[email protected]> Signed-off-by: Shawn Guo <[email protected]>
1 parent b7a24a7 commit 721cabf

File tree

5 files changed

+490
-217
lines changed

5 files changed

+490
-217
lines changed

MAINTAINERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1266,6 +1266,7 @@ F: arch/arm/mach-mxs/
12661266
F: arch/arm/boot/dts/imx*
12671267
F: arch/arm/configs/imx*_defconfig
12681268
F: drivers/clk/imx/
1269+
F: drivers/soc/imx/
12691270
F: include/soc/imx/
12701271

12711272
ARM/FREESCALE VYBRID ARM ARCHITECTURE

arch/arm/mach-imx/gpc.c

Lines changed: 0 additions & 217 deletions
Original file line numberDiff line numberDiff line change
@@ -10,26 +10,17 @@
1010
* http://www.gnu.org/copyleft/gpl.html
1111
*/
1212

13-
#include <linux/clk.h>
14-
#include <linux/delay.h>
1513
#include <linux/io.h>
1614
#include <linux/irq.h>
1715
#include <linux/irqchip.h>
1816
#include <linux/of.h>
1917
#include <linux/of_address.h>
2018
#include <linux/of_irq.h>
21-
#include <linux/platform_device.h>
22-
#include <linux/pm_domain.h>
23-
#include <linux/regulator/consumer.h>
2419
#include <linux/irqchip/arm-gic.h>
2520
#include "common.h"
2621
#include "hardware.h"
2722

28-
#define GPC_CNTR 0x000
2923
#define GPC_IMR1 0x008
30-
#define GPC_PGC_GPU_PDN 0x260
31-
#define GPC_PGC_GPU_PUPSCR 0x264
32-
#define GPC_PGC_GPU_PDNSCR 0x268
3324
#define GPC_PGC_CPU_PDN 0x2a0
3425
#define GPC_PGC_CPU_PUPSCR 0x2a4
3526
#define GPC_PGC_CPU_PDNSCR 0x2a8
@@ -39,18 +30,6 @@
3930
#define IMR_NUM 4
4031
#define GPC_MAX_IRQS (IMR_NUM * 32)
4132

42-
#define GPU_VPU_PUP_REQ BIT(1)
43-
#define GPU_VPU_PDN_REQ BIT(0)
44-
45-
#define GPC_CLK_MAX 6
46-
47-
struct pu_domain {
48-
struct generic_pm_domain base;
49-
struct regulator *reg;
50-
struct clk *clk[GPC_CLK_MAX];
51-
int num_clks;
52-
};
53-
5433
static void __iomem *gpc_base;
5534
static u32 gpc_wake_irqs[IMR_NUM];
5635
static u32 gpc_saved_imrs[IMR_NUM];
@@ -296,199 +275,3 @@ void __init imx_gpc_check_dt(void)
296275
gpc_base = of_iomap(np, 0);
297276
}
298277
}
299-
300-
static void _imx6q_pm_pu_power_off(struct generic_pm_domain *genpd)
301-
{
302-
int iso, iso2sw;
303-
u32 val;
304-
305-
/* Read ISO and ISO2SW power down delays */
306-
val = readl_relaxed(gpc_base + GPC_PGC_GPU_PDNSCR);
307-
iso = val & 0x3f;
308-
iso2sw = (val >> 8) & 0x3f;
309-
310-
/* Gate off PU domain when GPU/VPU when powered down */
311-
writel_relaxed(0x1, gpc_base + GPC_PGC_GPU_PDN);
312-
313-
/* Request GPC to power down GPU/VPU */
314-
val = readl_relaxed(gpc_base + GPC_CNTR);
315-
val |= GPU_VPU_PDN_REQ;
316-
writel_relaxed(val, gpc_base + GPC_CNTR);
317-
318-
/* Wait ISO + ISO2SW IPG clock cycles */
319-
ndelay((iso + iso2sw) * 1000 / 66);
320-
}
321-
322-
static int imx6q_pm_pu_power_off(struct generic_pm_domain *genpd)
323-
{
324-
struct pu_domain *pu = container_of(genpd, struct pu_domain, base);
325-
326-
_imx6q_pm_pu_power_off(genpd);
327-
328-
if (pu->reg)
329-
regulator_disable(pu->reg);
330-
331-
return 0;
332-
}
333-
334-
static int imx6q_pm_pu_power_on(struct generic_pm_domain *genpd)
335-
{
336-
struct pu_domain *pu = container_of(genpd, struct pu_domain, base);
337-
int i, ret, sw, sw2iso;
338-
u32 val;
339-
340-
if (pu->reg)
341-
ret = regulator_enable(pu->reg);
342-
if (pu->reg && ret) {
343-
pr_err("%s: failed to enable regulator: %d\n", __func__, ret);
344-
return ret;
345-
}
346-
347-
/* Enable reset clocks for all devices in the PU domain */
348-
for (i = 0; i < pu->num_clks; i++)
349-
clk_prepare_enable(pu->clk[i]);
350-
351-
/* Gate off PU domain when GPU/VPU when powered down */
352-
writel_relaxed(0x1, gpc_base + GPC_PGC_GPU_PDN);
353-
354-
/* Read ISO and ISO2SW power down delays */
355-
val = readl_relaxed(gpc_base + GPC_PGC_GPU_PUPSCR);
356-
sw = val & 0x3f;
357-
sw2iso = (val >> 8) & 0x3f;
358-
359-
/* Request GPC to power up GPU/VPU */
360-
val = readl_relaxed(gpc_base + GPC_CNTR);
361-
val |= GPU_VPU_PUP_REQ;
362-
writel_relaxed(val, gpc_base + GPC_CNTR);
363-
364-
/* Wait ISO + ISO2SW IPG clock cycles */
365-
ndelay((sw + sw2iso) * 1000 / 66);
366-
367-
/* Disable reset clocks for all devices in the PU domain */
368-
for (i = 0; i < pu->num_clks; i++)
369-
clk_disable_unprepare(pu->clk[i]);
370-
371-
return 0;
372-
}
373-
374-
static struct generic_pm_domain imx6q_arm_domain = {
375-
.name = "ARM",
376-
};
377-
378-
static struct pu_domain imx6q_pu_domain = {
379-
.base = {
380-
.name = "PU",
381-
.power_off = imx6q_pm_pu_power_off,
382-
.power_on = imx6q_pm_pu_power_on,
383-
},
384-
};
385-
386-
static struct generic_pm_domain imx6sl_display_domain = {
387-
.name = "DISPLAY",
388-
};
389-
390-
static struct generic_pm_domain *imx_gpc_domains[] = {
391-
&imx6q_arm_domain,
392-
&imx6q_pu_domain.base,
393-
&imx6sl_display_domain,
394-
};
395-
396-
static struct genpd_onecell_data imx_gpc_onecell_data = {
397-
.domains = imx_gpc_domains,
398-
.num_domains = ARRAY_SIZE(imx_gpc_domains),
399-
};
400-
401-
static int imx_gpc_genpd_init(struct device *dev, struct regulator *pu_reg)
402-
{
403-
struct clk *clk;
404-
int i, ret;
405-
406-
imx6q_pu_domain.reg = pu_reg;
407-
408-
for (i = 0; ; i++) {
409-
clk = of_clk_get(dev->of_node, i);
410-
if (IS_ERR(clk))
411-
break;
412-
if (i >= GPC_CLK_MAX) {
413-
dev_err(dev, "more than %d clocks\n", GPC_CLK_MAX);
414-
goto clk_err;
415-
}
416-
imx6q_pu_domain.clk[i] = clk;
417-
}
418-
imx6q_pu_domain.num_clks = i;
419-
420-
/* Enable power always in case bootloader disabled it. */
421-
imx6q_pm_pu_power_on(&imx6q_pu_domain.base);
422-
423-
if (!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS))
424-
return 0;
425-
426-
imx6q_pu_domain.base.states = devm_kzalloc(dev,
427-
sizeof(*imx6q_pu_domain.base.states),
428-
GFP_KERNEL);
429-
if (!imx6q_pu_domain.base.states)
430-
return -ENOMEM;
431-
432-
imx6q_pu_domain.base.states[0].power_off_latency_ns = 25000;
433-
imx6q_pu_domain.base.states[0].power_on_latency_ns = 2000000;
434-
imx6q_pu_domain.base.state_count = 1;
435-
436-
for (i = 0; i < ARRAY_SIZE(imx_gpc_domains); i++)
437-
pm_genpd_init(imx_gpc_domains[i], NULL, false);
438-
439-
ret = of_genpd_add_provider_onecell(dev->of_node,
440-
&imx_gpc_onecell_data);
441-
if (ret)
442-
goto power_off;
443-
444-
return 0;
445-
446-
power_off:
447-
imx6q_pm_pu_power_off(&imx6q_pu_domain.base);
448-
clk_err:
449-
while (i--)
450-
clk_put(imx6q_pu_domain.clk[i]);
451-
imx6q_pu_domain.reg = NULL;
452-
return -EINVAL;
453-
}
454-
455-
static int imx_gpc_probe(struct platform_device *pdev)
456-
{
457-
struct regulator *pu_reg;
458-
int ret;
459-
460-
/* bail out if DT too old and doesn't provide the necessary info */
461-
if (!of_property_read_bool(pdev->dev.of_node, "#power-domain-cells"))
462-
return 0;
463-
464-
pu_reg = devm_regulator_get_optional(&pdev->dev, "pu");
465-
if (PTR_ERR(pu_reg) == -ENODEV)
466-
pu_reg = NULL;
467-
if (IS_ERR(pu_reg)) {
468-
ret = PTR_ERR(pu_reg);
469-
dev_err(&pdev->dev, "failed to get pu regulator: %d\n", ret);
470-
return ret;
471-
}
472-
473-
return imx_gpc_genpd_init(&pdev->dev, pu_reg);
474-
}
475-
476-
static const struct of_device_id imx_gpc_dt_ids[] = {
477-
{ .compatible = "fsl,imx6q-gpc" },
478-
{ .compatible = "fsl,imx6sl-gpc" },
479-
{ }
480-
};
481-
482-
static struct platform_driver imx_gpc_driver = {
483-
.driver = {
484-
.name = "imx-gpc",
485-
.of_match_table = imx_gpc_dt_ids,
486-
},
487-
.probe = imx_gpc_probe,
488-
};
489-
490-
static int __init imx_pgc_init(void)
491-
{
492-
return platform_driver_register(&imx_gpc_driver);
493-
}
494-
subsys_initcall(imx_pgc_init);

drivers/soc/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ obj-y += bcm/
66
obj-$(CONFIG_ARCH_DOVE) += dove/
77
obj-$(CONFIG_MACH_DOVE) += dove/
88
obj-y += fsl/
9+
obj-$(CONFIG_ARCH_MXC) += imx/
910
obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/
1011
obj-$(CONFIG_ARCH_QCOM) += qcom/
1112
obj-$(CONFIG_ARCH_RENESAS) += renesas/

drivers/soc/imx/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
obj-y += gpc.o

0 commit comments

Comments
 (0)