aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/arm/exynos/power_domain.txt21
-rw-r--r--arch/arm/mach-exynos/Kconfig10
-rw-r--r--arch/arm/mach-exynos/Makefile2
-rw-r--r--arch/arm/mach-exynos/dev-pd.c139
-rw-r--r--arch/arm/mach-exynos/mach-nuri.c11
-rw-r--r--arch/arm/mach-exynos/mach-origen.c14
-rw-r--r--arch/arm/mach-exynos/mach-smdkv310.c12
-rw-r--r--arch/arm/mach-exynos/mach-universal_c210.c17
-rw-r--r--arch/arm/mach-exynos/pm_domains.c195
9 files changed, 218 insertions, 203 deletions
diff --git a/Documentation/devicetree/bindings/arm/exynos/power_domain.txt b/Documentation/devicetree/bindings/arm/exynos/power_domain.txt
new file mode 100644
index 000000000000..6528e215c5fe
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/exynos/power_domain.txt
@@ -0,0 +1,21 @@
1* Samsung Exynos Power Domains
2
3Exynos processors include support for multiple power domains which are used
4to gate power to one or more peripherals on the processor.
5
6Required Properties:
7- compatiable: should be one of the following.
8 * samsung,exynos4210-pd - for exynos4210 type power domain.
9- reg: physical base address of the controller and length of memory mapped
10 region.
11
12Optional Properties:
13- samsung,exynos4210-pd-off: Specifies that the power domain is in turned-off
14 state during boot and remains to be turned-off until explicitly turned-on.
15
16Example:
17
18 lcd0: power-domain-lcd0 {
19 compatible = "samsung,exynos4210-pd";
20 reg = <0x10023C00 0x10>;
21 };
diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index 5d602f68a0e8..dfad6538b273 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -34,6 +34,7 @@ config CPU_EXYNOS4210
34 select ARM_CPU_SUSPEND if PM 34 select ARM_CPU_SUSPEND if PM
35 select S5P_PM if PM 35 select S5P_PM if PM
36 select S5P_SLEEP if PM 36 select S5P_SLEEP if PM
37 select PM_GENERIC_DOMAINS
37 help 38 help
38 Enable EXYNOS4210 CPU support 39 Enable EXYNOS4210 CPU support
39 40
@@ -74,11 +75,6 @@ config EXYNOS4_SETUP_FIMD0
74 help 75 help
75 Common setup code for FIMD0. 76 Common setup code for FIMD0.
76 77
77config EXYNOS4_DEV_PD
78 bool
79 help
80 Compile in platform device definitions for Power Domain
81
82config EXYNOS4_DEV_SYSMMU 78config EXYNOS4_DEV_SYSMMU
83 bool 79 bool
84 help 80 help
@@ -195,7 +191,6 @@ config MACH_SMDKV310
195 select EXYNOS4_DEV_AHCI 191 select EXYNOS4_DEV_AHCI
196 select SAMSUNG_DEV_KEYPAD 192 select SAMSUNG_DEV_KEYPAD
197 select EXYNOS4_DEV_DMA 193 select EXYNOS4_DEV_DMA
198 select EXYNOS4_DEV_PD
199 select SAMSUNG_DEV_PWM 194 select SAMSUNG_DEV_PWM
200 select EXYNOS4_DEV_USB_OHCI 195 select EXYNOS4_DEV_USB_OHCI
201 select EXYNOS4_DEV_SYSMMU 196 select EXYNOS4_DEV_SYSMMU
@@ -243,7 +238,6 @@ config MACH_UNIVERSAL_C210
243 select S5P_DEV_ONENAND 238 select S5P_DEV_ONENAND
244 select S5P_DEV_TV 239 select S5P_DEV_TV
245 select EXYNOS4_DEV_DMA 240 select EXYNOS4_DEV_DMA
246 select EXYNOS4_DEV_PD
247 select EXYNOS4_SETUP_FIMD0 241 select EXYNOS4_SETUP_FIMD0
248 select EXYNOS4_SETUP_I2C1 242 select EXYNOS4_SETUP_I2C1
249 select EXYNOS4_SETUP_I2C3 243 select EXYNOS4_SETUP_I2C3
@@ -277,7 +271,6 @@ config MACH_NURI
277 select S5P_DEV_USB_EHCI 271 select S5P_DEV_USB_EHCI
278 select S5P_SETUP_MIPIPHY 272 select S5P_SETUP_MIPIPHY
279 select EXYNOS4_DEV_DMA 273 select EXYNOS4_DEV_DMA
280 select EXYNOS4_DEV_PD
281 select EXYNOS4_SETUP_FIMC 274 select EXYNOS4_SETUP_FIMC
282 select EXYNOS4_SETUP_FIMD0 275 select EXYNOS4_SETUP_FIMD0
283 select EXYNOS4_SETUP_I2C1 276 select EXYNOS4_SETUP_I2C1
@@ -310,7 +303,6 @@ config MACH_ORIGEN
310 select SAMSUNG_DEV_BACKLIGHT 303 select SAMSUNG_DEV_BACKLIGHT
311 select SAMSUNG_DEV_PWM 304 select SAMSUNG_DEV_PWM
312 select EXYNOS4_DEV_DMA 305 select EXYNOS4_DEV_DMA
313 select EXYNOS4_DEV_PD
314 select EXYNOS4_DEV_USB_OHCI 306 select EXYNOS4_DEV_USB_OHCI
315 select EXYNOS4_SETUP_FIMD0 307 select EXYNOS4_SETUP_FIMD0
316 select EXYNOS4_SETUP_SDHCI 308 select EXYNOS4_SETUP_SDHCI
diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile
index 5fc202cdfdb6..d9191f9a7af8 100644
--- a/arch/arm/mach-exynos/Makefile
+++ b/arch/arm/mach-exynos/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_CPU_EXYNOS4210) += clock-exynos4210.o
17obj-$(CONFIG_SOC_EXYNOS4212) += clock-exynos4212.o 17obj-$(CONFIG_SOC_EXYNOS4212) += clock-exynos4212.o
18 18
19obj-$(CONFIG_PM) += pm.o 19obj-$(CONFIG_PM) += pm.o
20obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o
20obj-$(CONFIG_CPU_IDLE) += cpuidle.o 21obj-$(CONFIG_CPU_IDLE) += cpuidle.o
21 22
22obj-$(CONFIG_ARCH_EXYNOS4) += pmu.o 23obj-$(CONFIG_ARCH_EXYNOS4) += pmu.o
@@ -45,7 +46,6 @@ obj-$(CONFIG_MACH_EXYNOS4_DT) += mach-exynos4-dt.o
45 46
46obj-$(CONFIG_ARCH_EXYNOS4) += dev-audio.o 47obj-$(CONFIG_ARCH_EXYNOS4) += dev-audio.o
47obj-$(CONFIG_EXYNOS4_DEV_AHCI) += dev-ahci.o 48obj-$(CONFIG_EXYNOS4_DEV_AHCI) += dev-ahci.o
48obj-$(CONFIG_EXYNOS4_DEV_PD) += dev-pd.o
49obj-$(CONFIG_EXYNOS4_DEV_SYSMMU) += dev-sysmmu.o 49obj-$(CONFIG_EXYNOS4_DEV_SYSMMU) += dev-sysmmu.o
50obj-$(CONFIG_EXYNOS4_DEV_DWMCI) += dev-dwmci.o 50obj-$(CONFIG_EXYNOS4_DEV_DWMCI) += dev-dwmci.o
51obj-$(CONFIG_EXYNOS4_DEV_DMA) += dma.o 51obj-$(CONFIG_EXYNOS4_DEV_DMA) += dma.o
diff --git a/arch/arm/mach-exynos/dev-pd.c b/arch/arm/mach-exynos/dev-pd.c
deleted file mode 100644
index 3273f25d6a75..000000000000
--- a/arch/arm/mach-exynos/dev-pd.c
+++ /dev/null
@@ -1,139 +0,0 @@
1/* linux/arch/arm/mach-exynos4/dev-pd.c
2 *
3 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
5 *
6 * EXYNOS4 - Power Domain support
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11*/
12
13#include <linux/io.h>
14#include <linux/kernel.h>
15#include <linux/platform_device.h>
16#include <linux/delay.h>
17
18#include <mach/regs-pmu.h>
19
20#include <plat/pd.h>
21
22static int exynos4_pd_enable(struct device *dev)
23{
24 struct samsung_pd_info *pdata = dev->platform_data;
25 u32 timeout;
26
27 __raw_writel(S5P_INT_LOCAL_PWR_EN, pdata->base);
28
29 /* Wait max 1ms */
30 timeout = 10;
31 while ((__raw_readl(pdata->base + 0x4) & S5P_INT_LOCAL_PWR_EN)
32 != S5P_INT_LOCAL_PWR_EN) {
33 if (timeout == 0) {
34 printk(KERN_ERR "Power domain %s enable failed.\n",
35 dev_name(dev));
36 return -ETIMEDOUT;
37 }
38 timeout--;
39 udelay(100);
40 }
41
42 return 0;
43}
44
45static int exynos4_pd_disable(struct device *dev)
46{
47 struct samsung_pd_info *pdata = dev->platform_data;
48 u32 timeout;
49
50 __raw_writel(0, pdata->base);
51
52 /* Wait max 1ms */
53 timeout = 10;
54 while (__raw_readl(pdata->base + 0x4) & S5P_INT_LOCAL_PWR_EN) {
55 if (timeout == 0) {
56 printk(KERN_ERR "Power domain %s disable failed.\n",
57 dev_name(dev));
58 return -ETIMEDOUT;
59 }
60 timeout--;
61 udelay(100);
62 }
63
64 return 0;
65}
66
67struct platform_device exynos4_device_pd[] = {
68 {
69 .name = "samsung-pd",
70 .id = 0,
71 .dev = {
72 .platform_data = &(struct samsung_pd_info) {
73 .enable = exynos4_pd_enable,
74 .disable = exynos4_pd_disable,
75 .base = S5P_PMU_MFC_CONF,
76 },
77 },
78 }, {
79 .name = "samsung-pd",
80 .id = 1,
81 .dev = {
82 .platform_data = &(struct samsung_pd_info) {
83 .enable = exynos4_pd_enable,
84 .disable = exynos4_pd_disable,
85 .base = S5P_PMU_G3D_CONF,
86 },
87 },
88 }, {
89 .name = "samsung-pd",
90 .id = 2,
91 .dev = {
92 .platform_data = &(struct samsung_pd_info) {
93 .enable = exynos4_pd_enable,
94 .disable = exynos4_pd_disable,
95 .base = S5P_PMU_LCD0_CONF,
96 },
97 },
98 }, {
99 .name = "samsung-pd",
100 .id = 3,
101 .dev = {
102 .platform_data = &(struct samsung_pd_info) {
103 .enable = exynos4_pd_enable,
104 .disable = exynos4_pd_disable,
105 .base = S5P_PMU_LCD1_CONF,
106 },
107 },
108 }, {
109 .name = "samsung-pd",
110 .id = 4,
111 .dev = {
112 .platform_data = &(struct samsung_pd_info) {
113 .enable = exynos4_pd_enable,
114 .disable = exynos4_pd_disable,
115 .base = S5P_PMU_TV_CONF,
116 },
117 },
118 }, {
119 .name = "samsung-pd",
120 .id = 5,
121 .dev = {
122 .platform_data = &(struct samsung_pd_info) {
123 .enable = exynos4_pd_enable,
124 .disable = exynos4_pd_disable,
125 .base = S5P_PMU_CAM_CONF,
126 },
127 },
128 }, {
129 .name = "samsung-pd",
130 .id = 6,
131 .dev = {
132 .platform_data = &(struct samsung_pd_info) {
133 .enable = exynos4_pd_enable,
134 .disable = exynos4_pd_disable,
135 .base = S5P_PMU_GPS_CONF,
136 },
137 },
138 },
139};
diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c
index b895ec031105..df705db08b06 100644
--- a/arch/arm/mach-exynos/mach-nuri.c
+++ b/arch/arm/mach-exynos/mach-nuri.c
@@ -1263,9 +1263,6 @@ static struct platform_device *nuri_devices[] __initdata = {
1263 &s5p_device_mfc, 1263 &s5p_device_mfc,
1264 &s5p_device_mfc_l, 1264 &s5p_device_mfc_l,
1265 &s5p_device_mfc_r, 1265 &s5p_device_mfc_r,
1266 &exynos4_device_pd[PD_MFC],
1267 &exynos4_device_pd[PD_LCD0],
1268 &exynos4_device_pd[PD_CAM],
1269 &s5p_device_fimc_md, 1266 &s5p_device_fimc_md,
1270 1267
1271 /* NURI Devices */ 1268 /* NURI Devices */
@@ -1315,14 +1312,6 @@ static void __init nuri_machine_init(void)
1315 1312
1316 /* Last */ 1313 /* Last */
1317 platform_add_devices(nuri_devices, ARRAY_SIZE(nuri_devices)); 1314 platform_add_devices(nuri_devices, ARRAY_SIZE(nuri_devices));
1318 s5p_device_mfc.dev.parent = &exynos4_device_pd[PD_MFC].dev;
1319 s5p_device_fimd0.dev.parent = &exynos4_device_pd[PD_LCD0].dev;
1320
1321 s5p_device_fimc0.dev.parent = &exynos4_device_pd[PD_CAM].dev;
1322 s5p_device_fimc1.dev.parent = &exynos4_device_pd[PD_CAM].dev;
1323 s5p_device_fimc2.dev.parent = &exynos4_device_pd[PD_CAM].dev;
1324 s5p_device_fimc3.dev.parent = &exynos4_device_pd[PD_CAM].dev;
1325 s5p_device_mipi_csis0.dev.parent = &exynos4_device_pd[PD_CAM].dev;
1326} 1315}
1327 1316
1328MACHINE_START(NURI, "NURI") 1317MACHINE_START(NURI, "NURI")
diff --git a/arch/arm/mach-exynos/mach-origen.c b/arch/arm/mach-exynos/mach-origen.c
index 0679b8ad2d1e..fa5c4a59b0aa 100644
--- a/arch/arm/mach-exynos/mach-origen.c
+++ b/arch/arm/mach-exynos/mach-origen.c
@@ -621,13 +621,6 @@ static struct platform_device *origen_devices[] __initdata = {
621 &s5p_device_mfc_r, 621 &s5p_device_mfc_r,
622 &s5p_device_mixer, 622 &s5p_device_mixer,
623 &exynos4_device_ohci, 623 &exynos4_device_ohci,
624 &exynos4_device_pd[PD_LCD0],
625 &exynos4_device_pd[PD_TV],
626 &exynos4_device_pd[PD_G3D],
627 &exynos4_device_pd[PD_LCD1],
628 &exynos4_device_pd[PD_CAM],
629 &exynos4_device_pd[PD_GPS],
630 &exynos4_device_pd[PD_MFC],
631 &origen_device_gpiokeys, 624 &origen_device_gpiokeys,
632 &origen_lcd_hv070wsa, 625 &origen_lcd_hv070wsa,
633}; 626};
@@ -695,13 +688,6 @@ static void __init origen_machine_init(void)
695 688
696 platform_add_devices(origen_devices, ARRAY_SIZE(origen_devices)); 689 platform_add_devices(origen_devices, ARRAY_SIZE(origen_devices));
697 690
698 s5p_device_fimd0.dev.parent = &exynos4_device_pd[PD_LCD0].dev;
699
700 s5p_device_hdmi.dev.parent = &exynos4_device_pd[PD_TV].dev;
701 s5p_device_mixer.dev.parent = &exynos4_device_pd[PD_TV].dev;
702
703 s5p_device_mfc.dev.parent = &exynos4_device_pd[PD_MFC].dev;
704
705 samsung_bl_set(&origen_bl_gpio_info, &origen_bl_data); 691 samsung_bl_set(&origen_bl_gpio_info, &origen_bl_data);
706} 692}
707 693
diff --git a/arch/arm/mach-exynos/mach-smdkv310.c b/arch/arm/mach-exynos/mach-smdkv310.c
index b2c5557f50e4..5258b8563676 100644
--- a/arch/arm/mach-exynos/mach-smdkv310.c
+++ b/arch/arm/mach-exynos/mach-smdkv310.c
@@ -277,13 +277,6 @@ static struct platform_device *smdkv310_devices[] __initdata = {
277 &s5p_device_mfc, 277 &s5p_device_mfc,
278 &s5p_device_mfc_l, 278 &s5p_device_mfc_l,
279 &s5p_device_mfc_r, 279 &s5p_device_mfc_r,
280 &exynos4_device_pd[PD_MFC],
281 &exynos4_device_pd[PD_G3D],
282 &exynos4_device_pd[PD_LCD0],
283 &exynos4_device_pd[PD_LCD1],
284 &exynos4_device_pd[PD_CAM],
285 &exynos4_device_pd[PD_TV],
286 &exynos4_device_pd[PD_GPS],
287 &exynos4_device_spdif, 280 &exynos4_device_spdif,
288 &exynos4_device_sysmmu, 281 &exynos4_device_sysmmu,
289 &samsung_asoc_dma, 282 &samsung_asoc_dma,
@@ -336,10 +329,6 @@ static void s5p_tv_setup(void)
336 WARN_ON(gpio_request_one(EXYNOS4_GPX3(7), GPIOF_IN, "hpd-plug")); 329 WARN_ON(gpio_request_one(EXYNOS4_GPX3(7), GPIOF_IN, "hpd-plug"));
337 s3c_gpio_cfgpin(EXYNOS4_GPX3(7), S3C_GPIO_SFN(0x3)); 330 s3c_gpio_cfgpin(EXYNOS4_GPX3(7), S3C_GPIO_SFN(0x3));
338 s3c_gpio_setpull(EXYNOS4_GPX3(7), S3C_GPIO_PULL_NONE); 331 s3c_gpio_setpull(EXYNOS4_GPX3(7), S3C_GPIO_PULL_NONE);
339
340 /* setup dependencies between TV devices */
341 s5p_device_hdmi.dev.parent = &exynos4_device_pd[PD_TV].dev;
342 s5p_device_mixer.dev.parent = &exynos4_device_pd[PD_TV].dev;
343} 332}
344 333
345static void __init smdkv310_map_io(void) 334static void __init smdkv310_map_io(void)
@@ -379,7 +368,6 @@ static void __init smdkv310_machine_init(void)
379 clk_xusbxti.rate = 24000000; 368 clk_xusbxti.rate = 24000000;
380 369
381 platform_add_devices(smdkv310_devices, ARRAY_SIZE(smdkv310_devices)); 370 platform_add_devices(smdkv310_devices, ARRAY_SIZE(smdkv310_devices));
382 s5p_device_mfc.dev.parent = &exynos4_device_pd[PD_MFC].dev;
383} 371}
384 372
385MACHINE_START(SMDKV310, "SMDKV310") 373MACHINE_START(SMDKV310, "SMDKV310")
diff --git a/arch/arm/mach-exynos/mach-universal_c210.c b/arch/arm/mach-exynos/mach-universal_c210.c
index 37ac93e8d6d9..026241737919 100644
--- a/arch/arm/mach-exynos/mach-universal_c210.c
+++ b/arch/arm/mach-exynos/mach-universal_c210.c
@@ -969,7 +969,6 @@ static struct platform_device *universal_devices[] __initdata = {
969 &s3c_device_i2c5, 969 &s3c_device_i2c5,
970 &s5p_device_i2c_hdmiphy, 970 &s5p_device_i2c_hdmiphy,
971 &hdmi_fixed_voltage, 971 &hdmi_fixed_voltage,
972 &exynos4_device_pd[PD_TV],
973 &s5p_device_hdmi, 972 &s5p_device_hdmi,
974 &s5p_device_sdo, 973 &s5p_device_sdo,
975 &s5p_device_mixer, 974 &s5p_device_mixer,
@@ -982,9 +981,6 @@ static struct platform_device *universal_devices[] __initdata = {
982 &s5p_device_mfc, 981 &s5p_device_mfc,
983 &s5p_device_mfc_l, 982 &s5p_device_mfc_l,
984 &s5p_device_mfc_r, 983 &s5p_device_mfc_r,
985 &exynos4_device_pd[PD_MFC],
986 &exynos4_device_pd[PD_LCD0],
987 &exynos4_device_pd[PD_CAM],
988 &cam_i_core_fixed_reg_dev, 984 &cam_i_core_fixed_reg_dev,
989 &cam_s_if_fixed_reg_dev, 985 &cam_s_if_fixed_reg_dev,
990 &s5p_device_fimc_md, 986 &s5p_device_fimc_md,
@@ -1003,10 +999,6 @@ void s5p_tv_setup(void)
1003 gpio_request_one(EXYNOS4_GPX3(7), GPIOF_IN, "hpd-plug"); 999 gpio_request_one(EXYNOS4_GPX3(7), GPIOF_IN, "hpd-plug");
1004 s3c_gpio_cfgpin(EXYNOS4_GPX3(7), S3C_GPIO_SFN(0x3)); 1000 s3c_gpio_cfgpin(EXYNOS4_GPX3(7), S3C_GPIO_SFN(0x3));
1005 s3c_gpio_setpull(EXYNOS4_GPX3(7), S3C_GPIO_PULL_NONE); 1001 s3c_gpio_setpull(EXYNOS4_GPX3(7), S3C_GPIO_PULL_NONE);
1006
1007 /* setup dependencies between TV devices */
1008 s5p_device_hdmi.dev.parent = &exynos4_device_pd[PD_TV].dev;
1009 s5p_device_mixer.dev.parent = &exynos4_device_pd[PD_TV].dev;
1010} 1002}
1011 1003
1012static void __init universal_reserve(void) 1004static void __init universal_reserve(void)
@@ -1040,15 +1032,6 @@ static void __init universal_machine_init(void)
1040 1032
1041 /* Last */ 1033 /* Last */
1042 platform_add_devices(universal_devices, ARRAY_SIZE(universal_devices)); 1034 platform_add_devices(universal_devices, ARRAY_SIZE(universal_devices));
1043
1044 s5p_device_mfc.dev.parent = &exynos4_device_pd[PD_MFC].dev;
1045 s5p_device_fimd0.dev.parent = &exynos4_device_pd[PD_LCD0].dev;
1046
1047 s5p_device_fimc0.dev.parent = &exynos4_device_pd[PD_CAM].dev;
1048 s5p_device_fimc1.dev.parent = &exynos4_device_pd[PD_CAM].dev;
1049 s5p_device_fimc2.dev.parent = &exynos4_device_pd[PD_CAM].dev;
1050 s5p_device_fimc3.dev.parent = &exynos4_device_pd[PD_CAM].dev;
1051 s5p_device_mipi_csis0.dev.parent = &exynos4_device_pd[PD_CAM].dev;
1052} 1035}
1053 1036
1054MACHINE_START(UNIVERSAL_C210, "UNIVERSAL_C210") 1037MACHINE_START(UNIVERSAL_C210, "UNIVERSAL_C210")
diff --git a/arch/arm/mach-exynos/pm_domains.c b/arch/arm/mach-exynos/pm_domains.c
new file mode 100644
index 000000000000..0b04af2b13cc
--- /dev/null
+++ b/arch/arm/mach-exynos/pm_domains.c
@@ -0,0 +1,195 @@
1/*
2 * Exynos Generic power domain support.
3 *
4 * Copyright (c) 2012 Samsung Electronics Co., Ltd.
5 * http://www.samsung.com
6 *
7 * Implementation of Exynos specific power domain control which is used in
8 * conjunction with runtime-pm. Support for both device-tree and non-device-tree
9 * based power domain support is included.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
14*/
15
16#include <linux/io.h>
17#include <linux/err.h>
18#include <linux/slab.h>
19#include <linux/pm_domain.h>
20#include <linux/delay.h>
21#include <linux/of_address.h>
22
23#include <mach/regs-pmu.h>
24#include <plat/devs.h>
25
26/*
27 * Exynos specific wrapper around the generic power domain
28 */
29struct exynos_pm_domain {
30 void __iomem *base;
31 char const *name;
32 bool is_off;
33 struct generic_pm_domain pd;
34};
35
36static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on)
37{
38 struct exynos_pm_domain *pd;
39 void __iomem *base;
40 u32 timeout, pwr;
41 char *op;
42
43 pd = container_of(domain, struct exynos_pm_domain, pd);
44 base = pd->base;
45
46 pwr = power_on ? S5P_INT_LOCAL_PWR_EN : 0;
47 __raw_writel(pwr, base);
48
49 /* Wait max 1ms */
50 timeout = 10;
51
52 while ((__raw_readl(base + 0x4) & S5P_INT_LOCAL_PWR_EN) != pwr) {
53 if (!timeout) {
54 op = (power_on) ? "enable" : "disable";
55 pr_err("Power domain %s %s failed\n", domain->name, op);
56 return -ETIMEDOUT;
57 }
58 timeout--;
59 cpu_relax();
60 usleep_range(80, 100);
61 }
62 return 0;
63}
64
65static int exynos_pd_power_on(struct generic_pm_domain *domain)
66{
67 return exynos_pd_power(domain, true);
68}
69
70static int exynos_pd_power_off(struct generic_pm_domain *domain)
71{
72 return exynos_pd_power(domain, false);
73}
74
75#define EXYNOS_GPD(PD, BASE, NAME) \
76static struct exynos_pm_domain PD = { \
77 .base = (void __iomem *)BASE, \
78 .name = NAME, \
79 .pd = { \
80 .power_off = exynos_pd_power_off, \
81 .power_on = exynos_pd_power_on, \
82 }, \
83}
84
85#ifdef CONFIG_OF
86static __init int exynos_pm_dt_parse_domains(void)
87{
88 struct device_node *np;
89
90 for_each_compatible_node(np, NULL, "samsung,exynos4210-pd") {
91 struct exynos_pm_domain *pd;
92
93 pd = kzalloc(sizeof(*pd), GFP_KERNEL);
94 if (!pd) {
95 pr_err("%s: failed to allocate memory for domain\n",
96 __func__);
97 return -ENOMEM;
98 }
99
100 if (of_get_property(np, "samsung,exynos4210-pd-off", NULL))
101 pd->is_off = true;
102 pd->name = np->name;
103 pd->base = of_iomap(np, 0);
104 pd->pd.power_off = exynos_pd_power_off;
105 pd->pd.power_on = exynos_pd_power_on;
106 pd->pd.of_node = np;
107 pm_genpd_init(&pd->pd, NULL, false);
108 }
109 return 0;
110}
111#else
112static __init int exynos_pm_dt_parse_domains(void)
113{
114 return 0;
115}
116#endif /* CONFIG_OF */
117
118static __init void exynos_pm_add_dev_to_genpd(struct platform_device *pdev,
119 struct exynos_pm_domain *pd)
120{
121 if (pdev->dev.bus) {
122 if (pm_genpd_add_device(&pd->pd, &pdev->dev))
123 pr_info("%s: error in adding %s device to %s power"
124 "domain\n", __func__, dev_name(&pdev->dev),
125 pd->name);
126 }
127}
128
129EXYNOS_GPD(exynos4_pd_mfc, S5P_PMU_MFC_CONF, "pd-mfc");
130EXYNOS_GPD(exynos4_pd_g3d, S5P_PMU_G3D_CONF, "pd-g3d");
131EXYNOS_GPD(exynos4_pd_lcd0, S5P_PMU_LCD0_CONF, "pd-lcd0");
132EXYNOS_GPD(exynos4_pd_lcd1, S5P_PMU_LCD1_CONF, "pd-lcd1");
133EXYNOS_GPD(exynos4_pd_tv, S5P_PMU_TV_CONF, "pd-tv");
134EXYNOS_GPD(exynos4_pd_cam, S5P_PMU_CAM_CONF, "pd-cam");
135EXYNOS_GPD(exynos4_pd_gps, S5P_PMU_GPS_CONF, "pd-gps");
136
137static struct exynos_pm_domain *exynos4_pm_domains[] = {
138 &exynos4_pd_mfc,
139 &exynos4_pd_g3d,
140 &exynos4_pd_lcd0,
141 &exynos4_pd_lcd1,
142 &exynos4_pd_tv,
143 &exynos4_pd_cam,
144 &exynos4_pd_gps,
145};
146
147static __init int exynos4_pm_init_power_domain(void)
148{
149 int idx;
150
151 if (of_have_populated_dt())
152 return exynos_pm_dt_parse_domains();
153
154 for (idx = 0; idx < ARRAY_SIZE(exynos4_pm_domains); idx++)
155 pm_genpd_init(&exynos4_pm_domains[idx]->pd, NULL,
156 exynos4_pm_domains[idx]->is_off);
157
158#ifdef CONFIG_S5P_DEV_FIMD0
159 exynos_pm_add_dev_to_genpd(&s5p_device_fimd0, &exynos4_pd_lcd0);
160#endif
161#ifdef CONFIG_S5P_DEV_TV
162 exynos_pm_add_dev_to_genpd(&s5p_device_hdmi, &exynos4_pd_tv);
163 exynos_pm_add_dev_to_genpd(&s5p_device_mixer, &exynos4_pd_tv);
164#endif
165#ifdef CONFIG_S5P_DEV_MFC
166 exynos_pm_add_dev_to_genpd(&s5p_device_mfc, &exynos4_pd_mfc);
167#endif
168#ifdef CONFIG_S5P_DEV_FIMC0
169 exynos_pm_add_dev_to_genpd(&s5p_device_fimc0, &exynos4_pd_cam);
170#endif
171#ifdef CONFIG_S5P_DEV_FIMC1
172 exynos_pm_add_dev_to_genpd(&s5p_device_fimc1, &exynos4_pd_cam);
173#endif
174#ifdef CONFIG_S5P_DEV_FIMC2
175 exynos_pm_add_dev_to_genpd(&s5p_device_fimc2, &exynos4_pd_cam);
176#endif
177#ifdef CONFIG_S5P_DEV_FIMC3
178 exynos_pm_add_dev_to_genpd(&s5p_device_fimc3, &exynos4_pd_cam);
179#endif
180#ifdef CONFIG_S5P_DEV_CSIS0
181 exynos_pm_add_dev_to_genpd(&s5p_device_mipi_csis0, &exynos4_pd_cam);
182#endif
183#ifdef CONFIG_S5P_DEV_CSIS1
184 exynos_pm_add_dev_to_genpd(&s5p_device_mipi_csis1, &exynos4_pd_cam);
185#endif
186 return 0;
187}
188arch_initcall(exynos4_pm_init_power_domain);
189
190static __init int exynos_pm_late_initcall(void)
191{
192 pm_genpd_poweroff_unused();
193 return 0;
194}
195late_initcall(exynos_pm_late_initcall);