aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-exynos
diff options
context:
space:
mode:
authorThomas Abraham <thomas.abraham@linaro.org>2012-01-27 01:25:00 -0500
committerKukjin Kim <kgene.kim@samsung.com>2012-01-27 01:25:49 -0500
commit91cfbd4ee0875f8a826731983378670012ba6e01 (patch)
tree9beff0dd0cad6cb929fa4c6f1228881255999594 /arch/arm/mach-exynos
parentc8aa130b74cc5b112cb2b119d3b477abaaf6e5b2 (diff)
ARM: EXYNOS: Hook up power domains to generic power domain infrastructure
Add support for generic power domain for Exynos4 platforms and remove the Samsung specific power domain control for Exynos4. The generic power domain infrastructure is used to control the power domains available on Exynos4. For non-dt platforms, the power domains are statically instantiated. For dt platforms, the power domain nodes found in the device tree are instantiated. Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Rob Herring <rob.herring@calxeda.com> Cc: Grant Likely <grant.likely@secretlab.ca> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org> Acked-by: Rafael J. Wysocki <rjw@sisk.pl> Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
Diffstat (limited to 'arch/arm/mach-exynos')
-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
8 files changed, 197 insertions, 203 deletions
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);