diff options
Diffstat (limited to 'arch/arm/mach-exynos')
-rw-r--r-- | arch/arm/mach-exynos/Kconfig | 20 | ||||
-rw-r--r-- | arch/arm/mach-exynos/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/mach-exynos/clock-exynos4.c | 5 | ||||
-rw-r--r-- | arch/arm/mach-exynos/common.c | 60 | ||||
-rw-r--r-- | arch/arm/mach-exynos/cpuidle.c | 151 | ||||
-rw-r--r-- | arch/arm/mach-exynos/dev-pd.c | 139 | ||||
-rw-r--r-- | arch/arm/mach-exynos/include/mach/cpufreq.h | 2 | ||||
-rw-r--r-- | arch/arm/mach-exynos/include/mach/entry-macro.S | 16 | ||||
-rw-r--r-- | arch/arm/mach-exynos/include/mach/map.h | 7 | ||||
-rw-r--r-- | arch/arm/mach-exynos/include/mach/pmu.h | 2 | ||||
-rw-r--r-- | arch/arm/mach-exynos/mach-nuri.c | 91 | ||||
-rw-r--r-- | arch/arm/mach-exynos/mach-origen.c | 51 | ||||
-rw-r--r-- | arch/arm/mach-exynos/mach-smdkv310.c | 15 | ||||
-rw-r--r-- | arch/arm/mach-exynos/mach-universal_c210.c | 97 | ||||
-rw-r--r-- | arch/arm/mach-exynos/mct.c | 39 | ||||
-rw-r--r-- | arch/arm/mach-exynos/pm.c | 15 | ||||
-rw-r--r-- | arch/arm/mach-exynos/pm_domains.c | 195 |
17 files changed, 631 insertions, 276 deletions
diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index 5e0a456..2bf7d6e 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -34,6 +34,7 @@ config CPU_EXYNOS4210 select ARM_CPU_SUSPEND if PM select S5P_PM if PM select S5P_SLEEP if PM + select PM_GENERIC_DOMAINS help Enable EXYNOS4210 CPU support @@ -76,11 +77,6 @@ config EXYNOS4_SETUP_FIMD0 help Common setup code for FIMD0. -config EXYNOS4_DEV_PD - bool - help - Compile in platform device definitions for Power Domain - config EXYNOS4_DEV_SYSMMU bool help @@ -185,7 +181,9 @@ config MACH_SMDKV310 select S5P_DEV_FIMC1 select S5P_DEV_FIMC2 select S5P_DEV_FIMC3 + select S5P_DEV_G2D select S5P_DEV_I2C_HDMIPHY + select S5P_DEV_JPEG select S5P_DEV_MFC select S5P_DEV_TV select S5P_DEV_USB_EHCI @@ -197,7 +195,6 @@ config MACH_SMDKV310 select EXYNOS4_DEV_AHCI select SAMSUNG_DEV_KEYPAD select EXYNOS4_DEV_DMA - select EXYNOS4_DEV_PD select SAMSUNG_DEV_PWM select EXYNOS4_DEV_USB_OHCI select EXYNOS4_DEV_SYSMMU @@ -232,7 +229,9 @@ config MACH_UNIVERSAL_C210 select S5P_DEV_FIMC1 select S5P_DEV_FIMC2 select S5P_DEV_FIMC3 + select S5P_DEV_G2D select S5P_DEV_CSIS0 + select S5P_DEV_JPEG select S5P_DEV_FIMD0 select S3C_DEV_HSMMC select S3C_DEV_HSMMC2 @@ -245,7 +244,6 @@ config MACH_UNIVERSAL_C210 select S5P_DEV_ONENAND select S5P_DEV_TV select EXYNOS4_DEV_DMA - select EXYNOS4_DEV_PD select EXYNOS4_SETUP_FIMD0 select EXYNOS4_SETUP_I2C1 select EXYNOS4_SETUP_I2C3 @@ -270,21 +268,24 @@ config MACH_NURI select S3C_DEV_I2C1 select S3C_DEV_I2C3 select S3C_DEV_I2C5 + select S3C_DEV_I2C6 select S5P_DEV_CSIS0 + select S5P_DEV_JPEG select S5P_DEV_FIMC0 select S5P_DEV_FIMC1 select S5P_DEV_FIMC2 select S5P_DEV_FIMC3 + select S5P_DEV_G2D select S5P_DEV_MFC select S5P_DEV_USB_EHCI select S5P_SETUP_MIPIPHY select EXYNOS4_DEV_DMA - select EXYNOS4_DEV_PD select EXYNOS4_SETUP_FIMC select EXYNOS4_SETUP_FIMD0 select EXYNOS4_SETUP_I2C1 select EXYNOS4_SETUP_I2C3 select EXYNOS4_SETUP_I2C5 + select EXYNOS4_SETUP_I2C6 select EXYNOS4_SETUP_SDHCI select EXYNOS4_SETUP_USB_PHY select S5P_SETUP_MIPIPHY @@ -305,14 +306,15 @@ config MACH_ORIGEN select S5P_DEV_FIMC2 select S5P_DEV_FIMC3 select S5P_DEV_FIMD0 + select S5P_DEV_G2D select S5P_DEV_I2C_HDMIPHY + select S5P_DEV_JPEG select S5P_DEV_MFC select S5P_DEV_TV select S5P_DEV_USB_EHCI select SAMSUNG_DEV_BACKLIGHT select SAMSUNG_DEV_PWM select EXYNOS4_DEV_DMA - select EXYNOS4_DEV_PD select EXYNOS4_DEV_USB_OHCI select EXYNOS4_SETUP_FIMD0 select EXYNOS4_SETUP_SDHCI diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile index 995e7cc..9a4c098 100644 --- a/arch/arm/mach-exynos/Makefile +++ b/arch/arm/mach-exynos/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_CPU_EXYNOS4210) += clock-exynos4210.o obj-$(CONFIG_SOC_EXYNOS4212) += clock-exynos4212.o obj-$(CONFIG_PM) += pm.o +obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o obj-$(CONFIG_CPU_IDLE) += cpuidle.o obj-$(CONFIG_ARCH_EXYNOS4) += pmu.o @@ -46,7 +47,6 @@ obj-$(CONFIG_MACH_EXYNOS4_DT) += mach-exynos4-dt.o obj-$(CONFIG_ARCH_EXYNOS4) += dev-audio.o obj-$(CONFIG_EXYNOS4_DEV_AHCI) += dev-ahci.o -obj-$(CONFIG_EXYNOS4_DEV_PD) += dev-pd.o obj-$(CONFIG_EXYNOS4_DEV_SYSMMU) += dev-sysmmu.o obj-$(CONFIG_EXYNOS4_DEV_DWMCI) += dev-dwmci.o obj-$(CONFIG_EXYNOS4_DEV_DMA) += dma.o diff --git a/arch/arm/mach-exynos/clock-exynos4.c b/arch/arm/mach-exynos/clock-exynos4.c index 1bc0b75..200159d 100644 --- a/arch/arm/mach-exynos/clock-exynos4.c +++ b/arch/arm/mach-exynos/clock-exynos4.c @@ -471,6 +471,11 @@ static struct clk exynos4_init_clocks_off[] = { .enable = exynos4_clk_ip_cam_ctrl, .ctrlbit = (1 << 5), }, { + .name = "jpeg", + .id = 0, + .enable = exynos4_clk_ip_cam_ctrl, + .ctrlbit = (1 << 6), + }, { .name = "fimc", .devname = "exynos4-fimc.0", .enable = exynos4_clk_ip_cam_ctrl, diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c index f494db8..97ca259 100644 --- a/arch/arm/mach-exynos/common.c +++ b/arch/arm/mach-exynos/common.c @@ -26,10 +26,12 @@ #include <asm/hardware/gic.h> #include <asm/mach/map.h> #include <asm/mach/irq.h> +#include <asm/cacheflush.h> #include <mach/regs-irq.h> #include <mach/regs-pmu.h> #include <mach/regs-gpio.h> +#include <mach/pmu.h> #include <plat/cpu.h> #include <plat/clock.h> @@ -45,6 +47,8 @@ #include <plat/regs-serial.h> #include "common.h" +#define L2_AUX_VAL 0x7C470001 +#define L2_AUX_MASK 0xC200ffff static const char name_exynos4210[] = "EXYNOS4210"; static const char name_exynos4212[] = "EXYNOS4212"; @@ -173,7 +177,12 @@ static struct map_desc exynos4_iodesc[] __initdata = { }, { .virtual = (unsigned long)S5P_VA_DMC0, .pfn = __phys_to_pfn(EXYNOS4_PA_DMC0), - .length = SZ_4K, + .length = SZ_64K, + .type = MT_DEVICE, + }, { + .virtual = (unsigned long)S5P_VA_DMC1, + .pfn = __phys_to_pfn(EXYNOS4_PA_DMC1), + .length = SZ_64K, .type = MT_DEVICE, }, { .virtual = (unsigned long)S3C_VA_USB_HSPHY, @@ -433,23 +442,48 @@ core_initcall(exynos4_core_init); #ifdef CONFIG_CACHE_L2X0 static int __init exynos4_l2x0_cache_init(void) { - /* TAG, Data Latency Control: 2cycle */ - __raw_writel(0x110, S5P_VA_L2CC + L2X0_TAG_LATENCY_CTRL); + int ret; + ret = l2x0_of_init(L2_AUX_VAL, L2_AUX_MASK); + if (!ret) { + l2x0_regs_phys = virt_to_phys(&l2x0_saved_regs); + clean_dcache_area(&l2x0_regs_phys, sizeof(unsigned long)); + return 0; + } - if (soc_is_exynos4210()) - __raw_writel(0x110, S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL); - else if (soc_is_exynos4212() || soc_is_exynos4412()) - __raw_writel(0x120, S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL); + if (!(__raw_readl(S5P_VA_L2CC + L2X0_CTRL) & 0x1)) { + l2x0_saved_regs.phy_base = EXYNOS4_PA_L2CC; + /* TAG, Data Latency Control: 2 cycles */ + l2x0_saved_regs.tag_latency = 0x110; + + if (soc_is_exynos4212() || soc_is_exynos4412()) + l2x0_saved_regs.data_latency = 0x120; + else + l2x0_saved_regs.data_latency = 0x110; + + l2x0_saved_regs.prefetch_ctrl = 0x30000007; + l2x0_saved_regs.pwr_ctrl = + (L2X0_DYNAMIC_CLK_GATING_EN | L2X0_STNDBY_MODE_EN); - /* L2X0 Prefetch Control */ - __raw_writel(0x30000007, S5P_VA_L2CC + L2X0_PREFETCH_CTRL); + l2x0_regs_phys = virt_to_phys(&l2x0_saved_regs); - /* L2X0 Power Control */ - __raw_writel(L2X0_DYNAMIC_CLK_GATING_EN | L2X0_STNDBY_MODE_EN, - S5P_VA_L2CC + L2X0_POWER_CTRL); + __raw_writel(l2x0_saved_regs.tag_latency, + S5P_VA_L2CC + L2X0_TAG_LATENCY_CTRL); + __raw_writel(l2x0_saved_regs.data_latency, + S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL); - l2x0_init(S5P_VA_L2CC, 0x7C470001, 0xC200ffff); + /* L2X0 Prefetch Control */ + __raw_writel(l2x0_saved_regs.prefetch_ctrl, + S5P_VA_L2CC + L2X0_PREFETCH_CTRL); + + /* L2X0 Power Control */ + __raw_writel(l2x0_saved_regs.pwr_ctrl, + S5P_VA_L2CC + L2X0_POWER_CTRL); + + clean_dcache_area(&l2x0_regs_phys, sizeof(unsigned long)); + clean_dcache_area(&l2x0_saved_regs, sizeof(struct l2x0_regs)); + } + l2x0_init(S5P_VA_L2CC, L2_AUX_VAL, L2_AUX_MASK); return 0; } diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c index 4ebb382..33ab4e7 100644 --- a/arch/arm/mach-exynos/cpuidle.c +++ b/arch/arm/mach-exynos/cpuidle.c @@ -11,25 +11,53 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/cpuidle.h> +#include <linux/cpu_pm.h> #include <linux/io.h> #include <linux/export.h> #include <linux/time.h> #include <asm/proc-fns.h> +#include <asm/smp_scu.h> +#include <asm/suspend.h> +#include <asm/unified.h> +#include <mach/regs-pmu.h> +#include <mach/pmu.h> + +#include <plat/cpu.h> + +#define REG_DIRECTGO_ADDR (samsung_rev() == EXYNOS4210_REV_1_1 ? \ + S5P_INFORM7 : (samsung_rev() == EXYNOS4210_REV_1_0 ? \ + (S5P_VA_SYSRAM + 0x24) : S5P_INFORM0)) +#define REG_DIRECTGO_FLAG (samsung_rev() == EXYNOS4210_REV_1_1 ? \ + S5P_INFORM6 : (samsung_rev() == EXYNOS4210_REV_1_0 ? \ + (S5P_VA_SYSRAM + 0x20) : S5P_INFORM1)) + +#define S5P_CHECK_AFTR 0xFCBA0D10 static int exynos4_enter_idle(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index); +static int exynos4_enter_lowpower(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index); -static struct cpuidle_state exynos4_cpuidle_set[] = { +static struct cpuidle_state exynos4_cpuidle_set[] __initdata = { [0] = { .enter = exynos4_enter_idle, .exit_latency = 1, .target_residency = 100000, .flags = CPUIDLE_FLAG_TIME_VALID, - .name = "IDLE", + .name = "C0", .desc = "ARM clock gating(WFI)", }, + [1] = { + .enter = exynos4_enter_lowpower, + .exit_latency = 300, + .target_residency = 100000, + .flags = CPUIDLE_FLAG_TIME_VALID, + .name = "C1", + .desc = "ARM power down", + }, }; static DEFINE_PER_CPU(struct cpuidle_device, exynos4_cpuidle_device); @@ -39,9 +67,102 @@ static struct cpuidle_driver exynos4_idle_driver = { .owner = THIS_MODULE, }; +/* Ext-GIC nIRQ/nFIQ is the only wakeup source in AFTR */ +static void exynos4_set_wakeupmask(void) +{ + __raw_writel(0x0000ff3e, S5P_WAKEUP_MASK); +} + +static unsigned int g_pwr_ctrl, g_diag_reg; + +static void save_cpu_arch_register(void) +{ + /*read power control register*/ + asm("mrc p15, 0, %0, c15, c0, 0" : "=r"(g_pwr_ctrl) : : "cc"); + /*read diagnostic register*/ + asm("mrc p15, 0, %0, c15, c0, 1" : "=r"(g_diag_reg) : : "cc"); + return; +} + +static void restore_cpu_arch_register(void) +{ + /*write power control register*/ + asm("mcr p15, 0, %0, c15, c0, 0" : : "r"(g_pwr_ctrl) : "cc"); + /*write diagnostic register*/ + asm("mcr p15, 0, %0, c15, c0, 1" : : "r"(g_diag_reg) : "cc"); + return; +} + +static int idle_finisher(unsigned long flags) +{ + cpu_do_idle(); + return 1; +} + +static int exynos4_enter_core0_aftr(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) +{ + struct timeval before, after; + int idle_time; + unsigned long tmp; + + local_irq_disable(); + do_gettimeofday(&before); + + exynos4_set_wakeupmask(); + + /* Set value of power down register for aftr mode */ + exynos4_sys_powerdown_conf(SYS_AFTR); + + __raw_writel(virt_to_phys(s3c_cpu_resume), REG_DIRECTGO_ADDR); + __raw_writel(S5P_CHECK_AFTR, REG_DIRECTGO_FLAG); + + save_cpu_arch_register(); + + /* Setting Central Sequence Register for power down mode */ + tmp = __raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION); + tmp &= ~S5P_CENTRAL_LOWPWR_CFG; + __raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION); + + cpu_pm_enter(); + cpu_suspend(0, idle_finisher); + +#ifdef CONFIG_SMP + scu_enable(S5P_VA_SCU); +#endif + cpu_pm_exit(); + + restore_cpu_arch_register(); + + /* + * If PMU failed while entering sleep mode, WFI will be + * ignored by PMU and then exiting cpu_do_idle(). + * S5P_CENTRAL_LOWPWR_CFG bit will not be set automatically + * in this situation. + */ + tmp = __raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION); + if (!(tmp & S5P_CENTRAL_LOWPWR_CFG)) { + tmp |= S5P_CENTRAL_LOWPWR_CFG; + __raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION); + } + + /* Clear wakeup state register */ + __raw_writel(0x0, S5P_WAKEUP_STAT); + + do_gettimeofday(&after); + + local_irq_enable(); + idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC + + (after.tv_usec - before.tv_usec); + + dev->last_residency = idle_time; + return index; +} + static int exynos4_enter_idle(struct cpuidle_device *dev, struct cpuidle_driver *drv, - int index) + int index) { struct timeval before, after; int idle_time; @@ -60,6 +181,22 @@ static int exynos4_enter_idle(struct cpuidle_device *dev, return index; } +static int exynos4_enter_lowpower(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) +{ + int new_index = index; + + /* This mode only can be entered when other core's are offline */ + if (num_online_cpus() > 1) + new_index = drv->safe_state_index; + + if (new_index == 0) + return exynos4_enter_idle(dev, drv, new_index); + else + return exynos4_enter_core0_aftr(dev, drv, new_index); +} + static int __init exynos4_init_cpuidle(void) { int i, max_cpuidle_state, cpu_id; @@ -74,19 +211,25 @@ static int __init exynos4_init_cpuidle(void) memcpy(&drv->states[i], &exynos4_cpuidle_set[i], sizeof(struct cpuidle_state)); } + drv->safe_state_index = 0; cpuidle_register_driver(&exynos4_idle_driver); for_each_cpu(cpu_id, cpu_online_mask) { device = &per_cpu(exynos4_cpuidle_device, cpu_id); device->cpu = cpu_id; - device->state_count = drv->state_count; + if (cpu_id == 0) + device->state_count = (sizeof(exynos4_cpuidle_set) / + sizeof(struct cpuidle_state)); + else + device->state_count = 1; /* Support IDLE only */ if (cpuidle_register_device(device)) { printk(KERN_ERR "CPUidle register device failed\n,"); return -EIO; } } + return 0; } device_initcall(exynos4_init_cpuidle); diff --git a/arch/arm/mach-exynos/dev-pd.c b/arch/arm/mach-exynos/dev-pd.c deleted file mode 100644 index 3273f25..0000000 --- a/arch/arm/mach-exynos/dev-pd.c +++ /dev/null @@ -1,139 +0,0 @@ -/* linux/arch/arm/mach-exynos4/dev-pd.c - * - * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * EXYNOS4 - Power Domain support - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#include <linux/io.h> -#include <linux/kernel.h> -#include <linux/platform_device.h> -#include <linux/delay.h> - -#include <mach/regs-pmu.h> - -#include <plat/pd.h> - -static int exynos4_pd_enable(struct device *dev) -{ - struct samsung_pd_info *pdata = dev->platform_data; - u32 timeout; - - __raw_writel(S5P_INT_LOCAL_PWR_EN, pdata->base); - - /* Wait max 1ms */ - timeout = 10; - while ((__raw_readl(pdata->base + 0x4) & S5P_INT_LOCAL_PWR_EN) - != S5P_INT_LOCAL_PWR_EN) { - if (timeout == 0) { - printk(KERN_ERR "Power domain %s enable failed.\n", - dev_name(dev)); - return -ETIMEDOUT; - } - timeout--; - udelay(100); - } - - return 0; -} - -static int exynos4_pd_disable(struct device *dev) -{ - struct samsung_pd_info *pdata = dev->platform_data; - u32 timeout; - - __raw_writel(0, pdata->base); - - /* Wait max 1ms */ - timeout = 10; - while (__raw_readl(pdata->base + 0x4) & S5P_INT_LOCAL_PWR_EN) { - if (timeout == 0) { - printk(KERN_ERR "Power domain %s disable failed.\n", - dev_name(dev)); - return -ETIMEDOUT; - } - timeout--; - udelay(100); - } - - return 0; -} - -struct platform_device exynos4_device_pd[] = { - { - .name = "samsung-pd", - .id = 0, - .dev = { - .platform_data = &(struct samsung_pd_info) { - .enable = exynos4_pd_enable, - .disable = exynos4_pd_disable, - .base = S5P_PMU_MFC_CONF, - }, - }, - }, { - .name = "samsung-pd", - .id = 1, - .dev = { - .platform_data = &(struct samsung_pd_info) { - .enable = exynos4_pd_enable, - .disable = exynos4_pd_disable, - .base = S5P_PMU_G3D_CONF, - }, - }, - }, { - .name = "samsung-pd", - .id = 2, - .dev = { - .platform_data = &(struct samsung_pd_info) { - .enable = exynos4_pd_enable, - .disable = exynos4_pd_disable, - .base = S5P_PMU_LCD0_CONF, - }, - }, - }, { - .name = "samsung-pd", - .id = 3, - .dev = { - .platform_data = &(struct samsung_pd_info) { - .enable = exynos4_pd_enable, - .disable = exynos4_pd_disable, - .base = S5P_PMU_LCD1_CONF, - }, - }, - }, { - .name = "samsung-pd", - .id = 4, - .dev = { - .platform_data = &(struct samsung_pd_info) { - .enable = exynos4_pd_enable, - .disable = exynos4_pd_disable, - .base = S5P_PMU_TV_CONF, - }, - }, - }, { - .name = "samsung-pd", - .id = 5, - .dev = { - .platform_data = &(struct samsung_pd_info) { - .enable = exynos4_pd_enable, - .disable = exynos4_pd_disable, - .base = S5P_PMU_CAM_CONF, - }, - }, - }, { - .name = "samsung-pd", - .id = 6, - .dev = { - .platform_data = &(struct samsung_pd_info) { - .enable = exynos4_pd_enable, - .disable = exynos4_pd_disable, - .base = S5P_PMU_GPS_CONF, - }, - }, - }, -}; diff --git a/arch/arm/mach-exynos/include/mach/cpufreq.h b/arch/arm/mach-exynos/include/mach/cpufreq.h index 3df27f2..7517c3f 100644 --- a/arch/arm/mach-exynos/include/mach/cpufreq.h +++ b/arch/arm/mach-exynos/include/mach/cpufreq.h @@ -32,3 +32,5 @@ struct exynos_dvfs_info { }; extern int exynos4210_cpufreq_init(struct exynos_dvfs_info *); +extern int exynos4x12_cpufreq_init(struct exynos_dvfs_info *); +extern int exynos5250_cpufreq_init(struct exynos_dvfs_info *); diff --git a/arch/arm/mach-exynos/include/mach/entry-macro.S b/arch/arm/mach-exynos/include/mach/entry-macro.S deleted file mode 100644 index 3ba4f54..0000000 --- a/arch/arm/mach-exynos/include/mach/entry-macro.S +++ /dev/null @@ -1,16 +0,0 @@ -/* arch/arm/mach-exynos4/include/mach/entry-macro.S - * - * Cloned from arch/arm/mach-realview/include/mach/entry-macro.S - * - * Low-level IRQ helper macros for EXYNOS4 platforms - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. -*/ - - .macro disable_fiq - .endm - - .macro arch_ret_to_user, tmp1, tmp2 - .endm diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h index 2ad4e9c..609127d 100644 --- a/arch/arm/mach-exynos/include/mach/map.h +++ b/arch/arm/mach-exynos/include/mach/map.h @@ -31,6 +31,10 @@ #define EXYNOS4_PA_FIMC2 0x11820000 #define EXYNOS4_PA_FIMC3 0x11830000 +#define EXYNOS4_PA_JPEG 0x11840000 + +#define EXYNOS4_PA_G2D 0x12800000 + #define EXYNOS4_PA_I2S0 0x03830000 #define EXYNOS4_PA_I2S1 0xE3100000 #define EXYNOS4_PA_I2S2 0xE2A00000 @@ -57,6 +61,7 @@ #define EXYNOS4_PA_KEYPAD 0x100A0000 #define EXYNOS4_PA_DMC0 0x10400000 +#define EXYNOS4_PA_DMC1 0x10410000 #define EXYNOS4_PA_COMBINER 0x10440000 @@ -163,6 +168,8 @@ #define S5P_PA_FIMC1 EXYNOS4_PA_FIMC1 #define S5P_PA_FIMC2 EXYNOS4_PA_FIMC2 #define S5P_PA_FIMC3 EXYNOS4_PA_FIMC3 +#define S5P_PA_JPEG EXYNOS4_PA_JPEG +#define S5P_PA_G2D EXYNOS4_PA_G2D #define S5P_PA_FIMD0 EXYNOS4_PA_FIMD0 #define S5P_PA_HDMI EXYNOS4_PA_HDMI #define S5P_PA_IIC_HDMIPHY EXYNOS4_PA_IIC_HDMIPHY diff --git a/arch/arm/mach-exynos/include/mach/pmu.h b/arch/arm/mach-exynos/include/mach/pmu.h index 632dd56..e76b7fa 100644 --- a/arch/arm/mach-exynos/include/mach/pmu.h +++ b/arch/arm/mach-exynos/include/mach/pmu.h @@ -22,11 +22,13 @@ enum sys_powerdown { NUM_SYS_POWERDOWN, }; +extern unsigned long l2x0_regs_phys; struct exynos4_pmu_conf { void __iomem *reg; unsigned int val[NUM_SYS_POWERDOWN]; }; extern void exynos4_sys_powerdown_conf(enum sys_powerdown mode); +extern void s3c_cpu_resume(void); #endif /* __ASM_ARCH_PMU_H */ diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c index 685372f..82ea6fc 100644 --- a/arch/arm/mach-exynos/mach-nuri.c +++ b/arch/arm/mach-exynos/mach-nuri.c @@ -28,6 +28,7 @@ #include <video/platform_lcd.h> #include <media/m5mols.h> +#include <media/s5k6aa.h> #include <media/s5p_fimc.h> #include <media/v4l2-mediabus.h> @@ -75,6 +76,7 @@ enum fixed_regulator_id { FIXED_REG_ID_MAX8903, FIXED_REG_ID_CAM_A28V, FIXED_REG_ID_CAM_12V, + FIXED_REG_ID_CAM_VT_15V, }; static struct s3c2410_uartcfg nuri_uartcfgs[] __initdata = { @@ -399,6 +401,9 @@ static struct regulator_consumer_supply __initdata max8997_ldo4_[] = { static struct regulator_consumer_supply __initdata max8997_ldo5_[] = { REGULATOR_SUPPLY("vhsic", "modemctl"), /* MODEM */ }; +static struct regulator_consumer_supply nuri_max8997_ldo6_consumer[] = { + REGULATOR_SUPPLY("vdd_reg", "6-003c"), /* S5K6AA camera */ +}; static struct regulator_consumer_supply __initdata max8997_ldo7_[] = { REGULATOR_SUPPLY("dig_18", "0-001f"), /* HCD803 */ }; @@ -431,7 +436,7 @@ static struct regulator_consumer_supply __initdata max8997_buck1_[] = { REGULATOR_SUPPLY("vdd_arm", NULL), /* CPUFREQ */ }; static struct regulator_consumer_supply __initdata max8997_buck2_[] = { - REGULATOR_SUPPLY("vdd_int", NULL), /* CPUFREQ */ + REGULATOR_SUPPLY("vdd_int", "exynos4210-busfreq.0"), /* CPUFREQ */ }; static struct regulator_consumer_supply __initdata max8997_buck3_[] = { REGULATOR_SUPPLY("vdd", "mali_dev.0"), /* G3D of Exynos 4 */ @@ -546,6 +551,8 @@ static struct regulator_init_data __initdata max8997_ldo6_data = { .enabled = 1, }, }, + .num_consumer_supplies = ARRAY_SIZE(nuri_max8997_ldo6_consumer), + .consumer_supplies = nuri_max8997_ldo6_consumer, }; static struct regulator_init_data __initdata max8997_ldo7_data = { @@ -742,7 +749,7 @@ static struct regulator_init_data __initdata max8997_buck2_data = { .constraints = { .name = "VINT_1.1V_C210", .min_uV = 900000, - .max_uV = 1100000, + .max_uV = 1200000, .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, .always_on = 1, .state_mem = { @@ -957,7 +964,6 @@ static struct max8997_platform_data __initdata nuri_max8997_pdata = { .regulators = nuri_max8997_regulators, .buck125_gpios = { EXYNOS4_GPX0(5), EXYNOS4_GPX0(6), EXYNOS4_GPL0(0) }, - .buck2_gpiodvs = true, .buck1_voltage[0] = 1350000, /* 1.35V */ .buck1_voltage[1] = 1300000, /* 1.3V */ @@ -1116,7 +1122,30 @@ static void __init nuri_ehci_init(void) } /* CAMERA */ +static struct regulator_consumer_supply cam_vt_cam15_supply = + REGULATOR_SUPPLY("vdd_core", "6-003c"); + +static struct regulator_init_data cam_vt_cam15_reg_init_data = { + .constraints = { .valid_ops_mask = REGULATOR_CHANGE_STATUS }, + .num_consumer_supplies = 1, + .consumer_supplies = &cam_vt_cam15_supply, +}; + +static struct fixed_voltage_config cam_vt_cam15_fixed_voltage_cfg = { + .supply_name = "VT_CAM_1.5V", + .microvolts = 1500000, + .gpio = EXYNOS4_GPE2(2), /* VT_CAM_1.5V_EN */ + .enable_high = 1, + .init_data = &cam_vt_cam15_reg_init_data, +}; + +static struct platform_device cam_vt_cam15_fixed_rdev = { + .name = "reg-fixed-voltage", .id = FIXED_REG_ID_CAM_VT_15V, + .dev = { .platform_data = &cam_vt_cam15_fixed_voltage_cfg }, +}; + static struct regulator_consumer_supply cam_vdda_supply[] = { + REGULATOR_SUPPLY("vdda", "6-003c"), REGULATOR_SUPPLY("a_sensor", "0-001f"), }; @@ -1173,6 +1202,21 @@ static struct s5p_platform_mipi_csis mipi_csis_platdata = { #define GPIO_CAM_MEGA_RST EXYNOS4_GPY3(7) /* ISP_RESET */ #define GPIO_CAM_8M_ISP_INT EXYNOS4_GPL2(5) +#define GPIO_CAM_VT_NSTBY EXYNOS4_GPL2(0) +#define GPIO_CAM_VT_NRST EXYNOS4_GPL2(1) + +static struct s5k6aa_platform_data s5k6aa_pldata = { + .mclk_frequency = 24000000UL, + .gpio_reset = { GPIO_CAM_VT_NRST, 0 }, + .gpio_stby = { GPIO_CAM_VT_NSTBY, 0 }, + .bus_type = V4L2_MBUS_PARALLEL, + .horiz_flip = 1, +}; + +static struct i2c_board_info s5k6aa_board_info = { + I2C_BOARD_INFO("S5K6AA", 0x3c), + .platform_data = &s5k6aa_pldata, +}; static struct m5mols_platform_data m5mols_platdata = { .gpio_reset = GPIO_CAM_MEGA_RST, @@ -1185,6 +1229,13 @@ static struct i2c_board_info m5mols_board_info = { static struct s5p_fimc_isp_info nuri_camera_sensors[] = { { + .flags = V4L2_MBUS_PCLK_SAMPLE_RISING | + V4L2_MBUS_VSYNC_ACTIVE_LOW, + .bus_type = FIMC_ITU_601, + .board_info = &s5k6aa_board_info, + .clk_frequency = 24000000UL, + .i2c_bus_num = 6, + }, { .flags = V4L2_MBUS_PCLK_SAMPLE_FALLING | V4L2_MBUS_VSYNC_ACTIVE_LOW, .bus_type = FIMC_MIPI_CSI2, @@ -1200,11 +1251,13 @@ static struct s5p_platform_fimc fimc_md_platdata = { }; static struct gpio nuri_camera_gpios[] = { + { GPIO_CAM_VT_NSTBY, GPIOF_OUT_INIT_LOW, "CAM_VGA_NSTBY" }, + { GPIO_CAM_VT_NRST, GPIOF_OUT_INIT_LOW, "CAM_VGA_NRST" }, { GPIO_CAM_8M_ISP_INT, GPIOF_IN, "8M_ISP_INT" }, { GPIO_CAM_MEGA_RST, GPIOF_OUT_INIT_LOW, "CAM_8M_NRST" }, }; -static void nuri_camera_init(void) +static void __init nuri_camera_init(void) { s3c_set_platdata(&mipi_csis_platdata, sizeof(mipi_csis_platdata), &s5p_device_mipi_csis0); @@ -1224,6 +1277,8 @@ static void nuri_camera_init(void) pr_err("%s: Failed to configure 8M_ISP_INT GPIO\n", __func__); /* Free GPIOs controlled directly by the sensor drivers. */ + gpio_free(GPIO_CAM_VT_NRST); + gpio_free(GPIO_CAM_VT_NSTBY); gpio_free(GPIO_CAM_MEGA_RST); if (exynos4_fimc_setup_gpio(S5P_CAMPORT_A)) { @@ -1234,15 +1289,27 @@ static void nuri_camera_init(void) s5p_gpio_set_drvstr(EXYNOS4_GPJ1(3), S5P_GPIO_DRVSTR_LV4); } +static struct s3c2410_platform_i2c nuri_i2c6_platdata __initdata = { + .frequency = 400000U, + .sda_delay = 200, + .bus_num = 6, +}; + static struct s3c2410_platform_i2c nuri_i2c0_platdata __initdata = { .frequency = 400000U, .sda_delay = 200, }; +/* DEVFREQ controlling memory/bus */ +static struct platform_device exynos4_bus_devfreq = { + .name = "exynos4210-busfreq", +}; + static struct platform_device *nuri_devices[] __initdata = { /* Samsung Platform Devices */ &s3c_device_i2c5, /* PMIC should initialize first */ &s3c_device_i2c0, + &s3c_device_i2c6, &emmc_fixed_voltage, &s5p_device_mipi_csis0, &s5p_device_fimc0, @@ -1259,13 +1326,12 @@ static struct platform_device *nuri_devices[] __initdata = { &s3c_device_i2c3, &i2c9_gpio, &s3c_device_adc, + &s5p_device_g2d, + &s5p_device_jpeg, &s3c_device_rtc, &s5p_device_mfc, &s5p_device_mfc_l, &s5p_device_mfc_r, - &exynos4_device_pd[PD_MFC], - &exynos4_device_pd[PD_LCD0], - &exynos4_device_pd[PD_CAM], &s5p_device_fimc_md, /* NURI Devices */ @@ -1274,8 +1340,10 @@ static struct platform_device *nuri_devices[] __initdata = { &nuri_backlight_device, &max8903_fixed_reg_dev, &nuri_max8903_device, + &cam_vt_cam15_fixed_rdev, &cam_vdda_fixed_rdev, &cam_8m_12v_fixed_rdev, + &exynos4_bus_devfreq, }; static void __init nuri_map_io(void) @@ -1305,6 +1373,7 @@ static void __init nuri_machine_init(void) i2c_register_board_info(5, i2c5_devs, ARRAY_SIZE(i2c5_devs)); i2c9_devs[I2C9_MAX17042].irq = gpio_to_irq(EXYNOS4_GPX2(3)); i2c_register_board_info(9, i2c9_devs, ARRAY_SIZE(i2c9_devs)); + s3c_i2c6_set_platdata(&nuri_i2c6_platdata); s5p_fimd0_set_platdata(&nuri_fb_pdata); @@ -1315,14 +1384,6 @@ static void __init nuri_machine_init(void) /* Last */ platform_add_devices(nuri_devices, ARRAY_SIZE(nuri_devices)); - s5p_device_mfc.dev.parent = &exynos4_device_pd[PD_MFC].dev; - s5p_device_fimd0.dev.parent = &exynos4_device_pd[PD_LCD0].dev; - - s5p_device_fimc0.dev.parent = &exynos4_device_pd[PD_CAM].dev; - s5p_device_fimc1.dev.parent = &exynos4_device_pd[PD_CAM].dev; - s5p_device_fimc2.dev.parent = &exynos4_device_pd[PD_CAM].dev; - s5p_device_fimc3.dev.parent = &exynos4_device_pd[PD_CAM].dev; - s5p_device_mipi_csis0.dev.parent = &exynos4_device_pd[PD_CAM].dev; } MACHINE_START(NURI, "NURI") diff --git a/arch/arm/mach-exynos/mach-origen.c b/arch/arm/mach-exynos/mach-origen.c index 3ec3ccf..878d4c9 100644 --- a/arch/arm/mach-exynos/mach-origen.c +++ b/arch/arm/mach-exynos/mach-origen.c @@ -20,6 +20,7 @@ #include <linux/regulator/machine.h> #include <linux/mfd/max8997.h> #include <linux/lcd.h> +#include <linux/rfkill-gpio.h> #include <asm/mach/arch.h> #include <asm/hardware/gic.h> @@ -235,6 +236,7 @@ static struct regulator_init_data __initdata max8997_ldo9_data = { .min_uV = 2800000, .max_uV = 2800000, .apply_uV = 1, + .always_on = 1, .valid_ops_mask = REGULATOR_CHANGE_STATUS, .state_mem = { .disabled = 1, @@ -278,6 +280,7 @@ static struct regulator_init_data __initdata max8997_ldo14_data = { .min_uV = 1800000, .max_uV = 1800000, .apply_uV = 1, + .always_on = 1, .valid_ops_mask = REGULATOR_CHANGE_STATUS, .state_mem = { .disabled = 1, @@ -293,6 +296,7 @@ static struct regulator_init_data __initdata max8997_ldo17_data = { .min_uV = 3300000, .max_uV = 3300000, .apply_uV = 1, + .always_on = 1, .valid_ops_mask = REGULATOR_CHANGE_STATUS, .state_mem = { .disabled = 1, @@ -602,6 +606,23 @@ static struct s3c_fb_platdata origen_lcd_pdata __initdata = { .setup_gpio = exynos4_fimd0_gpio_setup_24bpp, }; +/* Bluetooth rfkill gpio platform data */ +struct rfkill_gpio_platform_data origen_bt_pdata = { + .reset_gpio = EXYNOS4_GPX2(2), + .shutdown_gpio = -1, + .type = RFKILL_TYPE_BLUETOOTH, + .name = "origen-bt", +}; + +/* Bluetooth Platform device */ +static struct platform_device origen_device_bluetooth = { + .name = "rfkill_gpio", + .id = -1, + .dev = { + .platform_data = &origen_bt_pdata, + }, +}; + static struct platform_device *origen_devices[] __initdata = { &s3c_device_hsmmc2, &s3c_device_hsmmc0, @@ -613,23 +634,20 @@ static struct platform_device *origen_devices[] __initdata = { &s5p_device_fimc1, &s5p_device_fimc2, &s5p_device_fimc3, + &s5p_device_fimc_md, &s5p_device_fimd0, + &s5p_device_g2d, &s5p_device_hdmi, &s5p_device_i2c_hdmiphy, + &s5p_device_jpeg, &s5p_device_mfc, &s5p_device_mfc_l, &s5p_device_mfc_r, &s5p_device_mixer, &exynos4_device_ohci, - &exynos4_device_pd[PD_LCD0], - &exynos4_device_pd[PD_TV], - &exynos4_device_pd[PD_G3D], - &exynos4_device_pd[PD_LCD1], - &exynos4_device_pd[PD_CAM], - &exynos4_device_pd[PD_GPS], - &exynos4_device_pd[PD_MFC], &origen_device_gpiokeys, &origen_lcd_hv070wsa, + &origen_device_bluetooth, }; /* LCD Backlight data */ @@ -643,6 +661,16 @@ static struct platform_pwm_backlight_data origen_bl_data = { .pwm_period_ns = 1000, }; +static void __init origen_bt_setup(void) +{ + gpio_request(EXYNOS4_GPA0(0), "GPIO BT_UART"); + /* 4 UART Pins configuration */ + s3c_gpio_cfgrange_nopull(EXYNOS4_GPA0(0), 4, S3C_GPIO_SFN(2)); + /* Setup BT Reset, this gpio will be requesed by rfkill-gpio */ + s3c_gpio_cfgpin(EXYNOS4_GPX2(2), S3C_GPIO_OUTPUT); + s3c_gpio_setpull(EXYNOS4_GPX2(2), S3C_GPIO_PULL_NONE); +} + static void s5p_tv_setup(void) { /* Direct HPD to HDMI chip */ @@ -695,14 +723,9 @@ static void __init origen_machine_init(void) platform_add_devices(origen_devices, ARRAY_SIZE(origen_devices)); - s5p_device_fimd0.dev.parent = &exynos4_device_pd[PD_LCD0].dev; - - s5p_device_hdmi.dev.parent = &exynos4_device_pd[PD_TV].dev; - s5p_device_mixer.dev.parent = &exynos4_device_pd[PD_TV].dev; - - s5p_device_mfc.dev.parent = &exynos4_device_pd[PD_MFC].dev; - samsung_bl_set(&origen_bl_gpio_info, &origen_bl_data); + + origen_bt_setup(); } MACHINE_START(ORIGEN, "ORIGEN") diff --git a/arch/arm/mach-exynos/mach-smdkv310.c b/arch/arm/mach-exynos/mach-smdkv310.c index b2c5557..83b91fa 100644 --- a/arch/arm/mach-exynos/mach-smdkv310.c +++ b/arch/arm/mach-exynos/mach-smdkv310.c @@ -270,6 +270,9 @@ static struct platform_device *smdkv310_devices[] __initdata = { &s5p_device_fimc1, &s5p_device_fimc2, &s5p_device_fimc3, + &s5p_device_fimc_md, + &s5p_device_g2d, + &s5p_device_jpeg, &exynos4_device_ac97, &exynos4_device_i2s0, &exynos4_device_ohci, @@ -277,13 +280,6 @@ static struct platform_device *smdkv310_devices[] __initdata = { &s5p_device_mfc, &s5p_device_mfc_l, &s5p_device_mfc_r, - &exynos4_device_pd[PD_MFC], - &exynos4_device_pd[PD_G3D], - &exynos4_device_pd[PD_LCD0], - &exynos4_device_pd[PD_LCD1], - &exynos4_device_pd[PD_CAM], - &exynos4_device_pd[PD_TV], - &exynos4_device_pd[PD_GPS], &exynos4_device_spdif, &exynos4_device_sysmmu, &samsung_asoc_dma, @@ -336,10 +332,6 @@ static void s5p_tv_setup(void) WARN_ON(gpio_request_one(EXYNOS4_GPX3(7), GPIOF_IN, "hpd-plug")); s3c_gpio_cfgpin(EXYNOS4_GPX3(7), S3C_GPIO_SFN(0x3)); s3c_gpio_setpull(EXYNOS4_GPX3(7), S3C_GPIO_PULL_NONE); - - /* setup dependencies between TV devices */ - s5p_device_hdmi.dev.parent = &exynos4_device_pd[PD_TV].dev; - s5p_device_mixer.dev.parent = &exynos4_device_pd[PD_TV].dev; } static void __init smdkv310_map_io(void) @@ -379,7 +371,6 @@ static void __init smdkv310_machine_init(void) clk_xusbxti.rate = 24000000; platform_add_devices(smdkv310_devices, ARRAY_SIZE(smdkv310_devices)); - s5p_device_mfc.dev.parent = &exynos4_device_pd[PD_MFC].dev; } MACHINE_START(SMDKV310, "SMDKV310") diff --git a/arch/arm/mach-exynos/mach-universal_c210.c b/arch/arm/mach-exynos/mach-universal_c210.c index 02f086d..28658da 100644 --- a/arch/arm/mach-exynos/mach-universal_c210.c +++ b/arch/arm/mach-exynos/mach-universal_c210.c @@ -47,6 +47,7 @@ #include <media/v4l2-mediabus.h> #include <media/s5p_fimc.h> #include <media/m5mols.h> +#include <media/s5k6aa.h> #include "common.h" @@ -123,8 +124,10 @@ static struct regulator_consumer_supply lp3974_buck1_consumer = static struct regulator_consumer_supply lp3974_buck2_consumer = REGULATOR_SUPPLY("vddg3d", NULL); -static struct regulator_consumer_supply lp3974_buck3_consumer = - REGULATOR_SUPPLY("vdet", "s5p-sdo"); +static struct regulator_consumer_supply lp3974_buck3_consumer[] = { + REGULATOR_SUPPLY("vdet", "s5p-sdo"), + REGULATOR_SUPPLY("vdd_reg", "0-003c"), +}; static struct regulator_init_data lp3974_buck1_data = { .constraints = { @@ -169,8 +172,8 @@ static struct regulator_init_data lp3974_buck3_data = { .enabled = 1, }, }, - .num_consumer_supplies = 1, - .consumer_supplies = &lp3974_buck3_consumer, + .num_consumer_supplies = ARRAY_SIZE(lp3974_buck3_consumer), + .consumer_supplies = lp3974_buck3_consumer, }; static struct regulator_init_data lp3974_buck4_data = { @@ -303,6 +306,9 @@ static struct regulator_init_data lp3974_ldo8_data = { .consumer_supplies = lp3974_ldo8_consumer, }; +static struct regulator_consumer_supply lp3974_ldo9_consumer = + REGULATOR_SUPPLY("vddio", "0-003c"); + static struct regulator_init_data lp3974_ldo9_data = { .constraints = { .name = "VCC_2.8V", @@ -314,6 +320,8 @@ static struct regulator_init_data lp3974_ldo9_data = { .enabled = 1, }, }, + .num_consumer_supplies = 1, + .consumer_supplies = &lp3974_ldo9_consumer, }; static struct regulator_init_data lp3974_ldo10_data = { @@ -412,6 +420,7 @@ static struct regulator_init_data lp3974_ldo15_data = { }; static struct regulator_consumer_supply lp3974_ldo16_consumer[] = { + REGULATOR_SUPPLY("vdda", "0-003c"), REGULATOR_SUPPLY("a_sensor", "0-001f"), }; @@ -819,6 +828,8 @@ static struct s3c_fb_pd_win universal_fb_win0 = { }, .max_bpp = 32, .default_bpp = 16, + .virtual_x = 480, + .virtual_y = 2 * 800, }; static struct s3c_fb_platdata universal_lcd_pdata __initdata = { @@ -830,6 +841,28 @@ static struct s3c_fb_platdata universal_lcd_pdata __initdata = { .setup_gpio = exynos4_fimd0_gpio_setup_24bpp, }; +static struct regulator_consumer_supply cam_vt_dio_supply = + REGULATOR_SUPPLY("vdd_core", "0-003c"); + +static struct regulator_init_data cam_vt_dio_reg_init_data = { + .constraints = { .valid_ops_mask = REGULATOR_CHANGE_STATUS }, + .num_consumer_supplies = 1, + .consumer_supplies = &cam_vt_dio_supply, +}; + +static struct fixed_voltage_config cam_vt_dio_fixed_voltage_cfg = { + .supply_name = "CAM_VT_D_IO", + .microvolts = 2800000, + .gpio = EXYNOS4_GPE2(1), /* CAM_PWR_EN2 */ + .enable_high = 1, + .init_data = &cam_vt_dio_reg_init_data, +}; + +static struct platform_device cam_vt_dio_fixed_reg_dev = { + .name = "reg-fixed-voltage", .id = FIXED_REG_ID_CAM_VT_DIO, + .dev = { .platform_data = &cam_vt_dio_fixed_voltage_cfg }, +}; + static struct regulator_consumer_supply cam_i_core_supply = REGULATOR_SUPPLY("core", "0-001f"); @@ -885,6 +918,28 @@ static struct s5p_platform_mipi_csis mipi_csis_platdata = { #define GPIO_CAM_LEVEL_EN(n) EXYNOS4_GPE4(n + 3) #define GPIO_CAM_8M_ISP_INT EXYNOS4_GPX1(5) /* XEINT_13 */ #define GPIO_CAM_MEGA_nRST EXYNOS4_GPE2(5) +#define GPIO_CAM_VGA_NRST EXYNOS4_GPE4(7) +#define GPIO_CAM_VGA_NSTBY EXYNOS4_GPE4(6) + +static int s5k6aa_set_power(int on) +{ + gpio_set_value(GPIO_CAM_LEVEL_EN(2), !!on); + return 0; +} + +static struct s5k6aa_platform_data s5k6aa_platdata = { + .mclk_frequency = 21600000UL, + .gpio_reset = { GPIO_CAM_VGA_NRST, 0 }, + .gpio_stby = { GPIO_CAM_VGA_NSTBY, 0 }, + .bus_type = V4L2_MBUS_PARALLEL, + .horiz_flip = 1, + .set_power = s5k6aa_set_power, +}; + +static struct i2c_board_info s5k6aa_board_info = { + I2C_BOARD_INFO("S5K6AA", 0x3C), + .platform_data = &s5k6aa_platdata, +}; static int m5mols_set_power(struct device *dev, int on) { @@ -909,6 +964,14 @@ static struct s5p_fimc_isp_info universal_camera_sensors[] = { .mux_id = 0, .flags = V4L2_MBUS_PCLK_SAMPLE_FALLING | V4L2_MBUS_VSYNC_ACTIVE_LOW, + .bus_type = FIMC_ITU_601, + .board_info = &s5k6aa_board_info, + .i2c_bus_num = 0, + .clk_frequency = 24000000UL, + }, { + .mux_id = 0, + .flags = V4L2_MBUS_PCLK_SAMPLE_FALLING | + V4L2_MBUS_VSYNC_ACTIVE_LOW, .bus_type = FIMC_MIPI_CSI2, .board_info = &m5mols_board_info, .i2c_bus_num = 0, @@ -927,9 +990,11 @@ static struct gpio universal_camera_gpios[] = { { GPIO_CAM_LEVEL_EN(2), GPIOF_OUT_INIT_LOW, "CAM_LVL_EN2" }, { GPIO_CAM_8M_ISP_INT, GPIOF_IN, "8M_ISP_INT" }, { GPIO_CAM_MEGA_nRST, GPIOF_OUT_INIT_LOW, "CAM_8M_NRST" }, + { GPIO_CAM_VGA_NRST, GPIOF_OUT_INIT_LOW, "CAM_VGA_NRST" }, + { GPIO_CAM_VGA_NSTBY, GPIOF_OUT_INIT_LOW, "CAM_VGA_NSTBY" }, }; -static void universal_camera_init(void) +static void __init universal_camera_init(void) { s3c_set_platdata(&mipi_csis_platdata, sizeof(mipi_csis_platdata), &s5p_device_mipi_csis0); @@ -950,6 +1015,8 @@ static void universal_camera_init(void) /* Free GPIOs controlled directly by the sensor drivers. */ gpio_free(GPIO_CAM_MEGA_nRST); gpio_free(GPIO_CAM_8M_ISP_INT); + gpio_free(GPIO_CAM_VGA_NRST); + gpio_free(GPIO_CAM_VGA_NSTBY); if (exynos4_fimc_setup_gpio(S5P_CAMPORT_A)) pr_err("Camera port A setup failed\n"); @@ -962,6 +1029,7 @@ static struct platform_device *universal_devices[] __initdata = { &s5p_device_fimc1, &s5p_device_fimc2, &s5p_device_fimc3, + &s5p_device_g2d, &mmc0_fixed_voltage, &s3c_device_hsmmc0, &s3c_device_hsmmc2, @@ -971,7 +1039,6 @@ static struct platform_device *universal_devices[] __initdata = { &s3c_device_i2c5, &s5p_device_i2c_hdmiphy, &hdmi_fixed_voltage, - &exynos4_device_pd[PD_TV], &s5p_device_hdmi, &s5p_device_sdo, &s5p_device_mixer, @@ -981,12 +1048,11 @@ static struct platform_device *universal_devices[] __initdata = { &universal_gpio_keys, &s5p_device_onenand, &s5p_device_fimd0, + &s5p_device_jpeg, &s5p_device_mfc, &s5p_device_mfc_l, &s5p_device_mfc_r, - &exynos4_device_pd[PD_MFC], - &exynos4_device_pd[PD_LCD0], - &exynos4_device_pd[PD_CAM], + &cam_vt_dio_fixed_reg_dev, &cam_i_core_fixed_reg_dev, &cam_s_if_fixed_reg_dev, &s5p_device_fimc_md, @@ -1005,10 +1071,6 @@ static void s5p_tv_setup(void) gpio_request_one(EXYNOS4_GPX3(7), GPIOF_IN, "hpd-plug"); s3c_gpio_cfgpin(EXYNOS4_GPX3(7), S3C_GPIO_SFN(0x3)); s3c_gpio_setpull(EXYNOS4_GPX3(7), S3C_GPIO_PULL_NONE); - - /* setup dependencies between TV devices */ - s5p_device_hdmi.dev.parent = &exynos4_device_pd[PD_TV].dev; - s5p_device_mixer.dev.parent = &exynos4_device_pd[PD_TV].dev; } static void __init universal_reserve(void) @@ -1042,15 +1104,6 @@ static void __init universal_machine_init(void) /* Last */ platform_add_devices(universal_devices, ARRAY_SIZE(universal_devices)); - - s5p_device_mfc.dev.parent = &exynos4_device_pd[PD_MFC].dev; - s5p_device_fimd0.dev.parent = &exynos4_device_pd[PD_LCD0].dev; - - s5p_device_fimc0.dev.parent = &exynos4_device_pd[PD_CAM].dev; - s5p_device_fimc1.dev.parent = &exynos4_device_pd[PD_CAM].dev; - s5p_device_fimc2.dev.parent = &exynos4_device_pd[PD_CAM].dev; - s5p_device_fimc3.dev.parent = &exynos4_device_pd[PD_CAM].dev; - s5p_device_mipi_csis0.dev.parent = &exynos4_device_pd[PD_CAM].dev; } MACHINE_START(UNIVERSAL_C210, "UNIVERSAL_C210") diff --git a/arch/arm/mach-exynos/mct.c b/arch/arm/mach-exynos/mct.c index 85b5527..e8a1caa 100644 --- a/arch/arm/mach-exynos/mct.c +++ b/arch/arm/mach-exynos/mct.c @@ -21,6 +21,7 @@ #include <linux/percpu.h> #include <asm/hardware/gic.h> +#include <asm/localtimer.h> #include <plat/cpu.h> @@ -29,12 +30,13 @@ #include <mach/regs-mct.h> #include <asm/mach/time.h> +#define TICK_BASE_CNT 1 + enum { MCT_INT_SPI, MCT_INT_PPI }; -static unsigned long clk_cnt_per_tick; static unsigned long clk_rate; static unsigned int mct_int_type; @@ -205,11 +207,14 @@ static int exynos4_comp_set_next_event(unsigned long cycles, static void exynos4_comp_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) { + unsigned long cycles_per_jiffy; exynos4_mct_comp0_stop(); switch (mode) { case CLOCK_EVT_MODE_PERIODIC: - exynos4_mct_comp0_start(mode, clk_cnt_per_tick); + cycles_per_jiffy = + (((unsigned long long) NSEC_PER_SEC / HZ * evt->mult) >> evt->shift); + exynos4_mct_comp0_start(mode, cycles_per_jiffy); break; case CLOCK_EVT_MODE_ONESHOT: @@ -248,9 +253,7 @@ static struct irqaction mct_comp_event_irq = { static void exynos4_clockevent_init(void) { - clk_cnt_per_tick = clk_rate / 2 / HZ; - - clockevents_calc_mult_shift(&mct_comp_device, clk_rate / 2, 5); + clockevents_calc_mult_shift(&mct_comp_device, clk_rate, 5); mct_comp_device.max_delta_ns = clockevent_delta2ns(0xffffffff, &mct_comp_device); mct_comp_device.min_delta_ns = @@ -314,12 +317,15 @@ static inline void exynos4_tick_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) { struct mct_clock_event_device *mevt = this_cpu_ptr(&percpu_mct_tick); + unsigned long cycles_per_jiffy; exynos4_mct_tick_stop(mevt); switch (mode) { case CLOCK_EVT_MODE_PERIODIC: - exynos4_mct_tick_start(clk_cnt_per_tick, mevt); + cycles_per_jiffy = + (((unsigned long long) NSEC_PER_SEC / HZ * evt->mult) >> evt->shift); + exynos4_mct_tick_start(cycles_per_jiffy, mevt); break; case CLOCK_EVT_MODE_ONESHOT: @@ -375,7 +381,7 @@ static struct irqaction mct_tick1_event_irq = { .handler = exynos4_mct_tick_isr, }; -static void exynos4_mct_tick_init(struct clock_event_device *evt) +static int __cpuinit exynos4_local_timer_setup(struct clock_event_device *evt) { struct mct_clock_event_device *mevt; unsigned int cpu = smp_processor_id(); @@ -393,7 +399,7 @@ static void exynos4_mct_tick_init(struct clock_event_device *evt) evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; evt->rating = 450; - clockevents_calc_mult_shift(evt, clk_rate / 2, 5); + clockevents_calc_mult_shift(evt, clk_rate / (TICK_BASE_CNT + 1), 5); evt->max_delta_ns = clockevent_delta2ns(0x7fffffff, evt); evt->min_delta_ns = @@ -401,7 +407,7 @@ static void exynos4_mct_tick_init(struct clock_event_device *evt) clockevents_register_device(evt); - exynos4_mct_write(0x1, mevt->base + MCT_L_TCNTB_OFFSET); + exynos4_mct_write(TICK_BASE_CNT, mevt->base + MCT_L_TCNTB_OFFSET); if (mct_int_type == MCT_INT_SPI) { if (cpu == 0) { @@ -417,17 +423,11 @@ static void exynos4_mct_tick_init(struct clock_event_device *evt) } else { enable_percpu_irq(IRQ_MCT_LOCALTIMER, 0); } -} - -/* Setup the local clock events for a CPU */ -int __cpuinit local_timer_setup(struct clock_event_device *evt) -{ - exynos4_mct_tick_init(evt); return 0; } -void local_timer_stop(struct clock_event_device *evt) +static void exynos4_local_timer_stop(struct clock_event_device *evt) { unsigned int cpu = smp_processor_id(); evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); @@ -439,6 +439,11 @@ void local_timer_stop(struct clock_event_device *evt) else disable_percpu_irq(IRQ_MCT_LOCALTIMER); } + +static struct local_timer_ops exynos4_mct_tick_ops __cpuinitdata = { + .setup = exynos4_local_timer_setup, + .stop = exynos4_local_timer_stop, +}; #endif /* CONFIG_LOCAL_TIMERS */ static void __init exynos4_timer_resources(void) @@ -458,6 +463,8 @@ static void __init exynos4_timer_resources(void) WARN(err, "MCT: can't request IRQ %d (%d)\n", IRQ_MCT_LOCALTIMER, err); } + + local_timer_register(&exynos4_mct_tick_ops); #endif /* CONFIG_LOCAL_TIMERS */ } diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index f105bd2..428cfeb 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -155,13 +155,6 @@ static struct sleep_save exynos4_core_save[] = { SAVE_ITEM(S5P_SROM_BC3), }; -static struct sleep_save exynos4_l2cc_save[] = { - SAVE_ITEM(S5P_VA_L2CC + L2X0_TAG_LATENCY_CTRL), - SAVE_ITEM(S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL), - SAVE_ITEM(S5P_VA_L2CC + L2X0_PREFETCH_CTRL), - SAVE_ITEM(S5P_VA_L2CC + L2X0_POWER_CTRL), - SAVE_ITEM(S5P_VA_L2CC + L2X0_AUX_CTRL), -}; /* For Cortex-A9 Diagnostic and Power control register */ static unsigned int save_arm_register[2]; @@ -182,7 +175,6 @@ static void exynos4_pm_prepare(void) u32 tmp; s3c_pm_do_save(exynos4_core_save, ARRAY_SIZE(exynos4_core_save)); - s3c_pm_do_save(exynos4_l2cc_save, ARRAY_SIZE(exynos4_l2cc_save)); s3c_pm_do_save(exynos4_epll_save, ARRAY_SIZE(exynos4_epll_save)); s3c_pm_do_save(exynos4_vpll_save, ARRAY_SIZE(exynos4_vpll_save)); @@ -388,13 +380,6 @@ static void exynos4_pm_resume(void) scu_enable(S5P_VA_SCU); #endif -#ifdef CONFIG_CACHE_L2X0 - s3c_pm_do_restore_core(exynos4_l2cc_save, ARRAY_SIZE(exynos4_l2cc_save)); - outer_inv_all(); - /* enable L2X0*/ - writel_relaxed(1, S5P_VA_L2CC + L2X0_CTRL); -#endif - early_wakeup: return; } diff --git a/arch/arm/mach-exynos/pm_domains.c b/arch/arm/mach-exynos/pm_domains.c new file mode 100644 index 0000000..0b04af2 --- /dev/null +++ b/arch/arm/mach-exynos/pm_domains.c @@ -0,0 +1,195 @@ +/* + * Exynos Generic power domain support. + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Implementation of Exynos specific power domain control which is used in + * conjunction with runtime-pm. Support for both device-tree and non-device-tree + * based power domain support is included. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/io.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/pm_domain.h> +#include <linux/delay.h> +#include <linux/of_address.h> + +#include <mach/regs-pmu.h> +#include <plat/devs.h> + +/* + * Exynos specific wrapper around the generic power domain + */ +struct exynos_pm_domain { + void __iomem *base; + char const *name; + bool is_off; + struct generic_pm_domain pd; +}; + +static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on) +{ + struct exynos_pm_domain *pd; + void __iomem *base; + u32 timeout, pwr; + char *op; + + pd = container_of(domain, struct exynos_pm_domain, pd); + base = pd->base; + + pwr = power_on ? S5P_INT_LOCAL_PWR_EN : 0; + __raw_writel(pwr, base); + + /* Wait max 1ms */ + timeout = 10; + + while ((__raw_readl(base + 0x4) & S5P_INT_LOCAL_PWR_EN) != pwr) { + if (!timeout) { + op = (power_on) ? "enable" : "disable"; + pr_err("Power domain %s %s failed\n", domain->name, op); + return -ETIMEDOUT; + } + timeout--; + cpu_relax(); + usleep_range(80, 100); + } + return 0; +} + +static int exynos_pd_power_on(struct generic_pm_domain *domain) +{ + return exynos_pd_power(domain, true); +} + +static int exynos_pd_power_off(struct generic_pm_domain *domain) +{ + return exynos_pd_power(domain, false); +} + +#define EXYNOS_GPD(PD, BASE, NAME) \ +static struct exynos_pm_domain PD = { \ + .base = (void __iomem *)BASE, \ + .name = NAME, \ + .pd = { \ + .power_off = exynos_pd_power_off, \ + .power_on = exynos_pd_power_on, \ + }, \ +} + +#ifdef CONFIG_OF +static __init int exynos_pm_dt_parse_domains(void) +{ + struct device_node *np; + + for_each_compatible_node(np, NULL, "samsung,exynos4210-pd") { + struct exynos_pm_domain *pd; + + pd = kzalloc(sizeof(*pd), GFP_KERNEL); + if (!pd) { + pr_err("%s: failed to allocate memory for domain\n", + __func__); + return -ENOMEM; + } + + if (of_get_property(np, "samsung,exynos4210-pd-off", NULL)) + pd->is_off = true; + pd->name = np->name; + pd->base = of_iomap(np, 0); + pd->pd.power_off = exynos_pd_power_off; + pd->pd.power_on = exynos_pd_power_on; + pd->pd.of_node = np; + pm_genpd_init(&pd->pd, NULL, false); + } + return 0; +} +#else +static __init int exynos_pm_dt_parse_domains(void) +{ + return 0; +} +#endif /* CONFIG_OF */ + +static __init void exynos_pm_add_dev_to_genpd(struct platform_device *pdev, + struct exynos_pm_domain *pd) +{ + if (pdev->dev.bus) { + if (pm_genpd_add_device(&pd->pd, &pdev->dev)) + pr_info("%s: error in adding %s device to %s power" + "domain\n", __func__, dev_name(&pdev->dev), + pd->name); + } +} + +EXYNOS_GPD(exynos4_pd_mfc, S5P_PMU_MFC_CONF, "pd-mfc"); +EXYNOS_GPD(exynos4_pd_g3d, S5P_PMU_G3D_CONF, "pd-g3d"); +EXYNOS_GPD(exynos4_pd_lcd0, S5P_PMU_LCD0_CONF, "pd-lcd0"); +EXYNOS_GPD(exynos4_pd_lcd1, S5P_PMU_LCD1_CONF, "pd-lcd1"); +EXYNOS_GPD(exynos4_pd_tv, S5P_PMU_TV_CONF, "pd-tv"); +EXYNOS_GPD(exynos4_pd_cam, S5P_PMU_CAM_CONF, "pd-cam"); +EXYNOS_GPD(exynos4_pd_gps, S5P_PMU_GPS_CONF, "pd-gps"); + +static struct exynos_pm_domain *exynos4_pm_domains[] = { + &exynos4_pd_mfc, + &exynos4_pd_g3d, + &exynos4_pd_lcd0, + &exynos4_pd_lcd1, + &exynos4_pd_tv, + &exynos4_pd_cam, + &exynos4_pd_gps, +}; + +static __init int exynos4_pm_init_power_domain(void) +{ + int idx; + + if (of_have_populated_dt()) + return exynos_pm_dt_parse_domains(); + + for (idx = 0; idx < ARRAY_SIZE(exynos4_pm_domains); idx++) + pm_genpd_init(&exynos4_pm_domains[idx]->pd, NULL, + exynos4_pm_domains[idx]->is_off); + +#ifdef CONFIG_S5P_DEV_FIMD0 + exynos_pm_add_dev_to_genpd(&s5p_device_fimd0, &exynos4_pd_lcd0); +#endif +#ifdef CONFIG_S5P_DEV_TV + exynos_pm_add_dev_to_genpd(&s5p_device_hdmi, &exynos4_pd_tv); + exynos_pm_add_dev_to_genpd(&s5p_device_mixer, &exynos4_pd_tv); +#endif +#ifdef CONFIG_S5P_DEV_MFC + exynos_pm_add_dev_to_genpd(&s5p_device_mfc, &exynos4_pd_mfc); +#endif +#ifdef CONFIG_S5P_DEV_FIMC0 + exynos_pm_add_dev_to_genpd(&s5p_device_fimc0, &exynos4_pd_cam); +#endif +#ifdef CONFIG_S5P_DEV_FIMC1 + exynos_pm_add_dev_to_genpd(&s5p_device_fimc1, &exynos4_pd_cam); +#endif +#ifdef CONFIG_S5P_DEV_FIMC2 + exynos_pm_add_dev_to_genpd(&s5p_device_fimc2, &exynos4_pd_cam); +#endif +#ifdef CONFIG_S5P_DEV_FIMC3 + exynos_pm_add_dev_to_genpd(&s5p_device_fimc3, &exynos4_pd_cam); +#endif +#ifdef CONFIG_S5P_DEV_CSIS0 + exynos_pm_add_dev_to_genpd(&s5p_device_mipi_csis0, &exynos4_pd_cam); +#endif +#ifdef CONFIG_S5P_DEV_CSIS1 + exynos_pm_add_dev_to_genpd(&s5p_device_mipi_csis1, &exynos4_pd_cam); +#endif + return 0; +} +arch_initcall(exynos4_pm_init_power_domain); + +static __init int exynos_pm_late_initcall(void) +{ + pm_genpd_poweroff_unused(); + return 0; +} +late_initcall(exynos_pm_late_initcall); |