Skip to content

Commit ee4df23

Browse files
lkundrakbebarino
authored andcommitted
clk: mmp2: Add support for power islands
Apart from the clocks and resets, the PMU hardware also controls power to peripherals that are on separate power islands. On MMP2, that's the GC860 GPU and the SSPA audio interface, while on MMP3 also the camera interface is on a separate island, along with the pair of GC2000 and GC300 GPUs and the SSPA. Signed-off-by: Lubomir Rintel <[email protected]> Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Stephen Boyd <[email protected]>
1 parent 17d4304 commit ee4df23

File tree

5 files changed

+170
-1
lines changed

5 files changed

+170
-1
lines changed

arch/arm/mach-mmp/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ config MACH_MMP2_DT
125125
select PINCTRL_SINGLE
126126
select ARCH_HAS_RESET_CONTROLLER
127127
select CPU_PJ4
128+
select PM_GENERIC_DOMAINS if PM
129+
select PM_GENERIC_DOMAINS_OF if PM && OF
128130
help
129131
Include support for Marvell MMP2 based platforms using
130132
the device tree.

drivers/clk/mmp/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ obj-y += clk-apbc.o clk-apmu.o clk-frac.o clk-mix.o clk-gate.o clk.o
88
obj-$(CONFIG_RESET_CONTROLLER) += reset.o
99

1010
obj-$(CONFIG_MACH_MMP_DT) += clk-of-pxa168.o clk-of-pxa910.o
11-
obj-$(CONFIG_COMMON_CLK_MMP2) += clk-of-mmp2.o clk-pll.o
11+
obj-$(CONFIG_COMMON_CLK_MMP2) += clk-of-mmp2.o clk-pll.o pwr-island.o
1212

1313
obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o
1414
obj-$(CONFIG_CPU_PXA910) += clk-pxa910.o

drivers/clk/mmp/clk-of-mmp2.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717
#include <linux/delay.h>
1818
#include <linux/err.h>
1919
#include <linux/of_address.h>
20+
#include <linux/clk.h>
2021

2122
#include <dt-bindings/clock/marvell,mmp2.h>
23+
#include <dt-bindings/power/marvell,mmp2.h>
2224

2325
#include "clk.h"
2426
#include "reset.h"
@@ -63,6 +65,7 @@
6365
#define APMU_USBHSIC1 0xfc
6466
#define APMU_GPU 0xcc
6567
#define APMU_AUDIO 0x10c
68+
#define APMU_CAMERA 0x1fc
6669

6770
#define MPMU_FCCR 0x8
6871
#define MPMU_POSR 0x10
@@ -86,6 +89,8 @@ enum mmp2_clk_model {
8689
struct mmp2_clk_unit {
8790
struct mmp_clk_unit unit;
8891
enum mmp2_clk_model model;
92+
struct genpd_onecell_data pd_data;
93+
struct generic_pm_domain *pm_domains[MMP2_NR_POWER_DOMAINS];
8994
void __iomem *mpmu_base;
9095
void __iomem *apmu_base;
9196
void __iomem *apbc_base;
@@ -473,6 +478,41 @@ static void mmp2_clk_reset_init(struct device_node *np,
473478
mmp_clk_reset_register(np, cells, nr_resets);
474479
}
475480

481+
static void mmp2_pm_domain_init(struct device_node *np,
482+
struct mmp2_clk_unit *pxa_unit)
483+
{
484+
if (pxa_unit->model == CLK_MODEL_MMP3) {
485+
pxa_unit->pm_domains[MMP2_POWER_DOMAIN_GPU]
486+
= mmp_pm_domain_register("gpu",
487+
pxa_unit->apmu_base + APMU_GPU,
488+
0x0600, 0x40003, 0x18000c, 0, &gpu_lock);
489+
} else {
490+
pxa_unit->pm_domains[MMP2_POWER_DOMAIN_GPU]
491+
= mmp_pm_domain_register("gpu",
492+
pxa_unit->apmu_base + APMU_GPU,
493+
0x8600, 0x00003, 0x00000c,
494+
MMP_PM_DOMAIN_NO_DISABLE, &gpu_lock);
495+
}
496+
pxa_unit->pd_data.num_domains++;
497+
498+
pxa_unit->pm_domains[MMP2_POWER_DOMAIN_AUDIO]
499+
= mmp_pm_domain_register("audio",
500+
pxa_unit->apmu_base + APMU_AUDIO,
501+
0x600, 0x2, 0, 0, &audio_lock);
502+
pxa_unit->pd_data.num_domains++;
503+
504+
if (pxa_unit->model == CLK_MODEL_MMP3) {
505+
pxa_unit->pm_domains[MMP3_POWER_DOMAIN_CAMERA]
506+
= mmp_pm_domain_register("camera",
507+
pxa_unit->apmu_base + APMU_CAMERA,
508+
0x600, 0, 0, 0, NULL);
509+
pxa_unit->pd_data.num_domains++;
510+
}
511+
512+
pxa_unit->pd_data.domains = pxa_unit->pm_domains;
513+
of_genpd_add_provider_onecell(np, &pxa_unit->pd_data);
514+
}
515+
476516
static void __init mmp2_clk_init(struct device_node *np)
477517
{
478518
struct mmp2_clk_unit *pxa_unit;
@@ -504,6 +544,8 @@ static void __init mmp2_clk_init(struct device_node *np)
504544
goto unmap_apmu_region;
505545
}
506546

547+
mmp2_pm_domain_init(np, pxa_unit);
548+
507549
mmp_clk_init(np, &pxa_unit->unit, MMP2_NR_CLKS);
508550

509551
mmp2_main_clk_init(pxa_unit);

drivers/clk/mmp/clk.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#define __MACH_MMP_CLK_H
44

55
#include <linux/clk-provider.h>
6+
#include <linux/pm_domain.h>
67
#include <linux/clkdev.h>
78

89
#define APBC_NO_BUS_CTRL BIT(0)
@@ -259,4 +260,13 @@ void mmp_clk_init(struct device_node *np, struct mmp_clk_unit *unit,
259260
int nr_clks);
260261
void mmp_clk_add(struct mmp_clk_unit *unit, unsigned int id,
261262
struct clk *clk);
263+
264+
/* Power islands */
265+
#define MMP_PM_DOMAIN_NO_DISABLE BIT(0)
266+
267+
struct generic_pm_domain *mmp_pm_domain_register(const char *name,
268+
void __iomem *reg,
269+
u32 power_on, u32 reset, u32 clock_enable,
270+
unsigned int flags, spinlock_t *lock);
271+
262272
#endif

drivers/clk/mmp/pwr-island.c

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
/*
3+
* MMP PMU power island support
4+
*
5+
* Copyright (C) 2020 Lubomir Rintel <[email protected]>
6+
*/
7+
8+
#include <linux/pm_domain.h>
9+
#include <linux/slab.h>
10+
#include <linux/io.h>
11+
12+
#include "clk.h"
13+
14+
#define to_mmp_pm_domain(genpd) container_of(genpd, struct mmp_pm_domain, genpd)
15+
16+
struct mmp_pm_domain {
17+
struct generic_pm_domain genpd;
18+
void __iomem *reg;
19+
spinlock_t *lock;
20+
u32 power_on;
21+
u32 reset;
22+
u32 clock_enable;
23+
unsigned int flags;
24+
};
25+
26+
static int mmp_pm_domain_power_on(struct generic_pm_domain *genpd)
27+
{
28+
struct mmp_pm_domain *pm_domain = to_mmp_pm_domain(genpd);
29+
unsigned long flags = 0;
30+
u32 val;
31+
32+
if (pm_domain->lock)
33+
spin_lock_irqsave(pm_domain->lock, flags);
34+
35+
val = readl(pm_domain->reg);
36+
37+
/* Turn on the power island */
38+
val |= pm_domain->power_on;
39+
writel(val, pm_domain->reg);
40+
41+
/* Disable isolation */
42+
val |= 0x100;
43+
writel(val, pm_domain->reg);
44+
45+
/* Some blocks need to be reset after a power up */
46+
if (pm_domain->reset || pm_domain->clock_enable) {
47+
u32 after_power_on = val;
48+
49+
val &= ~pm_domain->reset;
50+
writel(val, pm_domain->reg);
51+
52+
val |= pm_domain->clock_enable;
53+
writel(val, pm_domain->reg);
54+
55+
val |= pm_domain->reset;
56+
writel(val, pm_domain->reg);
57+
58+
writel(after_power_on, pm_domain->reg);
59+
}
60+
61+
if (pm_domain->lock)
62+
spin_unlock_irqrestore(pm_domain->lock, flags);
63+
64+
return 0;
65+
}
66+
67+
static int mmp_pm_domain_power_off(struct generic_pm_domain *genpd)
68+
{
69+
struct mmp_pm_domain *pm_domain = to_mmp_pm_domain(genpd);
70+
unsigned long flags = 0;
71+
u32 val;
72+
73+
if (pm_domain->flags & MMP_PM_DOMAIN_NO_DISABLE)
74+
return 0;
75+
76+
if (pm_domain->lock)
77+
spin_lock_irqsave(pm_domain->lock, flags);
78+
79+
/* Turn off and isolate the the power island. */
80+
val = readl(pm_domain->reg);
81+
val &= ~pm_domain->power_on;
82+
val &= ~0x100;
83+
writel(val, pm_domain->reg);
84+
85+
if (pm_domain->lock)
86+
spin_unlock_irqrestore(pm_domain->lock, flags);
87+
88+
return 0;
89+
}
90+
91+
struct generic_pm_domain *mmp_pm_domain_register(const char *name,
92+
void __iomem *reg,
93+
u32 power_on, u32 reset, u32 clock_enable,
94+
unsigned int flags, spinlock_t *lock)
95+
{
96+
struct mmp_pm_domain *pm_domain;
97+
98+
pm_domain = kzalloc(sizeof(*pm_domain), GFP_KERNEL);
99+
if (!pm_domain)
100+
return ERR_PTR(-ENOMEM);
101+
102+
pm_domain->reg = reg;
103+
pm_domain->power_on = power_on;
104+
pm_domain->reset = reset;
105+
pm_domain->clock_enable = clock_enable;
106+
pm_domain->flags = flags;
107+
pm_domain->lock = lock;
108+
109+
pm_genpd_init(&pm_domain->genpd, NULL, true);
110+
pm_domain->genpd.name = name;
111+
pm_domain->genpd.power_on = mmp_pm_domain_power_on;
112+
pm_domain->genpd.power_off = mmp_pm_domain_power_off;
113+
114+
return &pm_domain->genpd;
115+
}

0 commit comments

Comments
 (0)