From 2abf13c9ffdcde537fc54b83f1bcd50cc758beca Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 24 Dec 2011 11:38:27 +0900 Subject: [PATCH 01/20] ARM: S3C64XX: Add basic cpuidle driver Add a very basic cpuidle driver for S3C64xx which merely drives the CPU into IDLE mode. We could do this with pm_idle but the more modern idiom is to use cpuidle and the intention is to go further and support STOP and DEEP-STOP states in conjunction with the pm_domain framework. The actual state entry code was lifted from Tomasz Figa's work on spica. Signed-off-by: Mark Brown Signed-off-by: Kukjin Kim --- arch/arm/mach-s3c64xx/Makefile | 1 + arch/arm/mach-s3c64xx/cpuidle.c | 91 +++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 arch/arm/mach-s3c64xx/cpuidle.c diff --git a/arch/arm/mach-s3c64xx/Makefile b/arch/arm/mach-s3c64xx/Makefile index 1822ac2eba31..610fe2807ed7 100644 --- a/arch/arm/mach-s3c64xx/Makefile +++ b/arch/arm/mach-s3c64xx/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_CPU_S3C6410) += s3c6410.o # PM obj-$(CONFIG_PM) += pm.o irq-pm.o sleep.o +obj-$(CONFIG_CPU_IDLE) += cpuidle.o # DMA support diff --git a/arch/arm/mach-s3c64xx/cpuidle.c b/arch/arm/mach-s3c64xx/cpuidle.c new file mode 100644 index 000000000000..625d2c7b4540 --- /dev/null +++ b/arch/arm/mach-s3c64xx/cpuidle.c @@ -0,0 +1,91 @@ +/* linux/arch/arm/mach-s3c64xx/cpuidle.c + * + * Copyright (c) 2011 Wolfson Microelectronics, plc + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * 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 +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include + +static int s3c64xx_enter_idle(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) +{ + struct timeval before, after; + unsigned long tmp; + int idle_time; + + local_irq_disable(); + do_gettimeofday(&before); + + /* Setup PWRCFG to enter idle mode */ + tmp = __raw_readl(S3C64XX_PWR_CFG); + tmp &= ~S3C64XX_PWRCFG_CFG_WFI_MASK; + tmp |= S3C64XX_PWRCFG_CFG_WFI_IDLE; + __raw_writel(tmp, S3C64XX_PWR_CFG); + + cpu_do_idle(); + + 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 struct cpuidle_state s3c64xx_cpuidle_set[] = { + [0] = { + .enter = s3c64xx_enter_idle, + .exit_latency = 1, + .target_residency = 100000, + .flags = CPUIDLE_FLAG_TIME_VALID, + .name = "IDLE", + .desc = "System active, ARM gated", + }, +}; + +static struct cpuidle_driver s3c64xx_cpuidle_driver = { + .name = "s3c64xx_cpuidle", + .owner = THIS_MODULE, + .state_count = ARRAY_SIZE(s3c64xx_cpuidle_set), +}; + +static struct cpuidle_device s3c64xx_cpuidle_device = { + .state_count = ARRAY_SIZE(s3c64xx_cpuidle_set), +}; + +static int __init s3c64xx_init_cpuidle(void) +{ + int ret; + + memcpy(s3c64xx_cpuidle_driver.states, s3c64xx_cpuidle_set, + sizeof(s3c64xx_cpuidle_set)); + cpuidle_register_driver(&s3c64xx_cpuidle_driver); + + ret = cpuidle_register_device(&s3c64xx_cpuidle_device); + if (ret) { + pr_err("Failed to register cpuidle device: %d\n", ret); + return ret; + } + + return 0; +} +device_initcall(s3c64xx_init_cpuidle); From ed8d8aa1e674b5b03fceae56a81cccbcf60ec95e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 12 Jan 2012 10:41:35 +0900 Subject: [PATCH 02/20] ARM: S3C64XX: Gate some more clocks by default Gate the AC'97 and CF clocks by default. The drivers will enable them required. Signed-off-by: Mark Brown Signed-off-by: Kukjin Kim --- arch/arm/mach-s3c64xx/clock.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/arm/mach-s3c64xx/clock.c b/arch/arm/mach-s3c64xx/clock.c index 31bb27dc4aeb..b58274f80cf9 100644 --- a/arch/arm/mach-s3c64xx/clock.c +++ b/arch/arm/mach-s3c64xx/clock.c @@ -201,6 +201,15 @@ static struct clk init_clocks_off[] = { .parent = &clk_48m, .enable = s3c64xx_sclk_ctrl, .ctrlbit = S3C_CLKCON_SCLK_MMC2_48, + }, { + .name = "ac97", + .parent = &clk_p, + .ctrlbit = S3C_CLKCON_PCLK_AC97, + }, { + .name = "cfcon", + .parent = &clk_h, + .enable = s3c64xx_hclk_ctrl, + .ctrlbit = S3C_CLKCON_HCLK_IHOST, }, { .name = "dma0", .parent = &clk_h, @@ -284,16 +293,7 @@ static struct clk init_clocks[] = { .name = "watchdog", .parent = &clk_p, .ctrlbit = S3C_CLKCON_PCLK_WDT, - }, { - .name = "ac97", - .parent = &clk_p, - .ctrlbit = S3C_CLKCON_PCLK_AC97, - }, { - .name = "cfcon", - .parent = &clk_h, - .enable = s3c64xx_hclk_ctrl, - .ctrlbit = S3C_CLKCON_HCLK_IHOST, - } + }, }; static struct clk clk_hsmmc0 = { From 561ab530bf81c86df1c88d6c8b75718ef1d3b8a6 Mon Sep 17 00:00:00 2001 From: Kamil Debski Date: Tue, 27 Dec 2011 17:16:44 +0900 Subject: [PATCH 03/20] ARM: SAMSUNG: add G2D to plat-s5p and mach-exynos G2D is a 2D graphics accelerator engine present in the s5p family of Samsung SoCs. It is capable of bitblt and raster operations on images having dimensions of up to 8000x8000. Signed-off-by: Kamil Debski Signed-off-by: Kyungmin Park Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/include/mach/map.h | 3 +++ arch/arm/plat-s5p/Kconfig | 5 ++++ arch/arm/plat-samsung/devs.c | 28 +++++++++++++++++++++++ arch/arm/plat-samsung/include/plat/devs.h | 1 + 4 files changed, 37 insertions(+) diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h index c754a22a2bb3..7df9e7456814 100644 --- a/arch/arm/mach-exynos/include/mach/map.h +++ b/arch/arm/mach-exynos/include/mach/map.h @@ -31,6 +31,8 @@ #define EXYNOS4_PA_FIMC2 0x11820000 #define EXYNOS4_PA_FIMC3 0x11830000 +#define EXYNOS4_PA_G2D 0x12800000 + #define EXYNOS4_PA_I2S0 0x03830000 #define EXYNOS4_PA_I2S1 0xE3100000 #define EXYNOS4_PA_I2S2 0xE2A00000 @@ -162,6 +164,7 @@ #define S5P_PA_FIMC1 EXYNOS4_PA_FIMC1 #define S5P_PA_FIMC2 EXYNOS4_PA_FIMC2 #define S5P_PA_FIMC3 EXYNOS4_PA_FIMC3 +#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/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig index 8167ce66188c..e7fec7820a18 100644 --- a/arch/arm/plat-s5p/Kconfig +++ b/arch/arm/plat-s5p/Kconfig @@ -80,6 +80,11 @@ config S5P_DEV_FIMC3 help Compile in platform device definitions for FIMC controller 3 +config S5P_DEV_G2D + bool + help + Compile in platform device definitions for G2D device + config S5P_DEV_FIMD0 bool help diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c index 32a6e394db24..145580a4a62c 100644 --- a/arch/arm/plat-samsung/devs.c +++ b/arch/arm/plat-samsung/devs.c @@ -267,6 +267,34 @@ struct platform_device s5p_device_fimc3 = { }; #endif /* CONFIG_S5P_DEV_FIMC3 */ +/* G2D */ + +#ifdef CONFIG_S5P_DEV_G2D +static struct resource s5p_g2d_resource[] = { + [0] = { + .start = S5P_PA_G2D, + .end = S5P_PA_G2D + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_2D, + .end = IRQ_2D, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device s5p_device_g2d = { + .name = "s5p-g2d", + .id = 0, + .num_resources = ARRAY_SIZE(s5p_g2d_resource), + .resource = s5p_g2d_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; +#endif /* CONFIG_S5P_DEV_G2D */ + /* FIMD0 */ #ifdef CONFIG_S5P_DEV_FIMD0 diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h index 4214ea0ff8fe..bb4584815037 100644 --- a/arch/arm/plat-samsung/include/plat/devs.h +++ b/arch/arm/plat-samsung/include/plat/devs.h @@ -79,6 +79,7 @@ extern struct platform_device s5p_device_fimc1; extern struct platform_device s5p_device_fimc2; extern struct platform_device s5p_device_fimc3; extern struct platform_device s5p_device_fimc_md; +extern struct platform_device s5p_device_g2d; extern struct platform_device s5p_device_fimd0; extern struct platform_device s5p_device_hdmi; extern struct platform_device s5p_device_i2c_hdmiphy; From 23747145070779682ccdf948b786adaf88b2a89e Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Mon, 26 Dec 2011 20:29:31 +0900 Subject: [PATCH 04/20] ARM: SAMSUNG: Add a callback 'notify_after' for PWM backlight control The callback 'notify_after' was added to struct platform_pwm_backlight_data provided by PWM backlight driver. Therefore, this patch adds a callback 'notify_after' which can be called after pwm_enable, pwm_disable and pwm_config. Signed-off-by: Jingoo Han Signed-off-by: Kukjin Kim --- arch/arm/plat-samsung/dev-backlight.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/plat-samsung/dev-backlight.c b/arch/arm/plat-samsung/dev-backlight.c index a976c023b286..2254920a02cf 100644 --- a/arch/arm/plat-samsung/dev-backlight.c +++ b/arch/arm/plat-samsung/dev-backlight.c @@ -115,6 +115,8 @@ void samsung_bl_set(struct samsung_bl_gpio_info *gpio_info, samsung_bl_data->init = bl_data->init; if (bl_data->notify) samsung_bl_data->notify = bl_data->notify; + if (bl_data->notify_after) + samsung_bl_data->notify_after = bl_data->notify_after; if (bl_data->exit) samsung_bl_data->exit = bl_data->exit; if (bl_data->check_fb) From 90ca2979ed9d69d8b1b729cb2e9d8e9874fad5f5 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 30 Dec 2011 09:41:56 +0900 Subject: [PATCH 05/20] ARM: S3C64XX: Reduce residency requirement for cpuidle WFI mode Entering and leaving WFI is really cheap so there's no reason to have much of a residency requirement for the state. Lower it to 1ms. Signed-off-by: Mark Brown Signed-off-by: Kukjin Kim --- arch/arm/mach-s3c64xx/cpuidle.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-s3c64xx/cpuidle.c b/arch/arm/mach-s3c64xx/cpuidle.c index 625d2c7b4540..179460f38db7 100644 --- a/arch/arm/mach-s3c64xx/cpuidle.c +++ b/arch/arm/mach-s3c64xx/cpuidle.c @@ -55,7 +55,7 @@ static struct cpuidle_state s3c64xx_cpuidle_set[] = { [0] = { .enter = s3c64xx_enter_idle, .exit_latency = 1, - .target_residency = 100000, + .target_residency = 1, .flags = CPUIDLE_FLAG_TIME_VALID, .name = "IDLE", .desc = "System active, ARM gated", From 8942ad89a059f9854ddf7223ca6e32869d7d9059 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 27 Jan 2012 14:42:19 +0900 Subject: [PATCH 06/20] ARM: S3C64XX: Define some additional always off clocks Add entries to clocks_off for some additional clocks which are not currently used by any mainline drivers. They default on at power up but are never actually used so If these blocks are actually supported some of these bindings would need to be redone properly, for example hooking up to the muxes that use them, but that can be done incrementally. Signed-off-by: Mark Brown Signed-off-by: Kukjin Kim --- arch/arm/mach-s3c64xx/clock.c | 101 ++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/arch/arm/mach-s3c64xx/clock.c b/arch/arm/mach-s3c64xx/clock.c index b58274f80cf9..63f2c8aa119d 100644 --- a/arch/arm/mach-s3c64xx/clock.c +++ b/arch/arm/mach-s3c64xx/clock.c @@ -220,6 +220,107 @@ static struct clk init_clocks_off[] = { .parent = &clk_h, .enable = s3c64xx_hclk_ctrl, .ctrlbit = S3C_CLKCON_HCLK_DMA1, + }, { + .name = "3dse", + .parent = &clk_h, + .enable = s3c64xx_hclk_ctrl, + .ctrlbit = S3C_CLKCON_HCLK_3DSE, + }, { + .name = "hclk_secur", + .parent = &clk_h, + .enable = s3c64xx_hclk_ctrl, + .ctrlbit = S3C_CLKCON_HCLK_SECUR, + }, { + .name = "sdma1", + .parent = &clk_h, + .enable = s3c64xx_hclk_ctrl, + .ctrlbit = S3C_CLKCON_HCLK_SDMA1, + }, { + .name = "sdma0", + .parent = &clk_h, + .enable = s3c64xx_hclk_ctrl, + .ctrlbit = S3C_CLKCON_HCLK_SDMA0, + }, { + .name = "hclk_jpeg", + .parent = &clk_h, + .enable = s3c64xx_hclk_ctrl, + .ctrlbit = S3C_CLKCON_HCLK_JPEG, + }, { + .name = "camif", + .parent = &clk_h, + .enable = s3c64xx_hclk_ctrl, + .ctrlbit = S3C_CLKCON_HCLK_CAMIF, + }, { + .name = "hclk_scaler", + .parent = &clk_h, + .enable = s3c64xx_hclk_ctrl, + .ctrlbit = S3C_CLKCON_HCLK_SCALER, + }, { + .name = "2d", + .parent = &clk_h, + .enable = s3c64xx_hclk_ctrl, + .ctrlbit = S3C_CLKCON_HCLK_2D, + }, { + .name = "tv", + .parent = &clk_h, + .enable = s3c64xx_hclk_ctrl, + .ctrlbit = S3C_CLKCON_HCLK_TV, + }, { + .name = "post0", + .parent = &clk_h, + .enable = s3c64xx_hclk_ctrl, + .ctrlbit = S3C_CLKCON_HCLK_POST0, + }, { + .name = "rot", + .parent = &clk_h, + .enable = s3c64xx_hclk_ctrl, + .ctrlbit = S3C_CLKCON_HCLK_ROT, + }, { + .name = "hclk_mfc", + .parent = &clk_h, + .enable = s3c64xx_hclk_ctrl, + .ctrlbit = S3C_CLKCON_HCLK_MFC, + }, { + .name = "pclk_mfc", + .parent = &clk_p, + .enable = s3c64xx_pclk_ctrl, + .ctrlbit = S3C_CLKCON_PCLK_MFC, + }, { + .name = "dac27", + .enable = s3c64xx_sclk_ctrl, + .ctrlbit = S3C_CLKCON_SCLK_DAC27, + }, { + .name = "tv27", + .enable = s3c64xx_sclk_ctrl, + .ctrlbit = S3C_CLKCON_SCLK_TV27, + }, { + .name = "scaler27", + .enable = s3c64xx_sclk_ctrl, + .ctrlbit = S3C_CLKCON_SCLK_SCALER27, + }, { + .name = "sclk_scaler", + .enable = s3c64xx_sclk_ctrl, + .ctrlbit = S3C_CLKCON_SCLK_SCALER, + }, { + .name = "post0_27", + .enable = s3c64xx_sclk_ctrl, + .ctrlbit = S3C_CLKCON_SCLK_POST0_27, + }, { + .name = "secur", + .enable = s3c64xx_sclk_ctrl, + .ctrlbit = S3C_CLKCON_SCLK_SECUR, + }, { + .name = "sclk_mfc", + .enable = s3c64xx_sclk_ctrl, + .ctrlbit = S3C_CLKCON_SCLK_MFC, + }, { + .name = "cam", + .enable = s3c64xx_sclk_ctrl, + .ctrlbit = S3C_CLKCON_SCLK_CAM, + }, { + .name = "sclk_jpeg", + .enable = s3c64xx_sclk_ctrl, + .ctrlbit = S3C_CLKCON_SCLK_JPEG, }, }; From 0cdf3affd3ddf4ff1a88e32b89bc629d569793f3 Mon Sep 17 00:00:00 2001 From: Minho Ban Date: Fri, 20 Jan 2012 11:03:07 +0900 Subject: [PATCH 07/20] ARM: SAMSUNG: use spin_lock_irqsave() in clk_{enable,disable} The clk_enable()and clk_disable() can be used process and ISR either. And actually it is used for real product and other platforms use it now. So spin_lock_irqsave() should be used instead. Signed-off-by: Minho Ban Signed-off-by: Jaecheol Lee Signed-off-by: Sunyoung Kang Signed-off-by: Kukjin Kim --- arch/arm/plat-samsung/clock.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/arch/arm/plat-samsung/clock.c b/arch/arm/plat-samsung/clock.c index 10f71179071f..65c5eca475e7 100644 --- a/arch/arm/plat-samsung/clock.c +++ b/arch/arm/plat-samsung/clock.c @@ -84,31 +84,35 @@ static int clk_null_enable(struct clk *clk, int enable) int clk_enable(struct clk *clk) { + unsigned long flags; + if (IS_ERR(clk) || clk == NULL) return -EINVAL; clk_enable(clk->parent); - spin_lock(&clocks_lock); + spin_lock_irqsave(&clocks_lock, flags); if ((clk->usage++) == 0) (clk->enable)(clk, 1); - spin_unlock(&clocks_lock); + spin_unlock_irqrestore(&clocks_lock, flags); return 0; } void clk_disable(struct clk *clk) { + unsigned long flags; + if (IS_ERR(clk) || clk == NULL) return; - spin_lock(&clocks_lock); + spin_lock_irqsave(&clocks_lock, flags); if ((--clk->usage) == 0) (clk->enable)(clk, 0); - spin_unlock(&clocks_lock); + spin_unlock_irqrestore(&clocks_lock, flags); clk_disable(clk->parent); } From 67173ca492ab6f3a6ee6c1283961008635f6322e Mon Sep 17 00:00:00 2001 From: Amit Daniel Kachhap Date: Thu, 8 Mar 2012 02:07:27 -0800 Subject: [PATCH 08/20] ARM: EXYNOS: Add support AFTR mode on EXYNOS4210 This patch adds support AFTR(ARM OFF TOP RUNNING) mode in cpuidle driver. L2 cache keeps their data in this mode. This patch ports the code to the latest interfaces to save/restore CPU state inclusive of CPU PM notifiers, l2 resume and cpu_suspend/resume. Signed-off-by: Jaecheol Lee Signed-off-by: Lorenzo Pieralisi Signed-off-by: Amit Daniel Kachhap [kgene.kim@samsung.com: fixed for non-smp as per Tushar's pointing out] Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/cpuidle.c | 151 +++++++++++++++++++++++- arch/arm/mach-exynos/include/mach/pmu.h | 2 + 2 files changed, 149 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c index 4ebb382c5979..33ab4e7558af 100644 --- a/arch/arm/mach-exynos/cpuidle.c +++ b/arch/arm/mach-exynos/cpuidle.c @@ -11,25 +11,53 @@ #include #include #include +#include #include #include #include #include +#include +#include +#include +#include +#include + +#include + +#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/include/mach/pmu.h b/arch/arm/mach-exynos/include/mach/pmu.h index 632dd5630138..e76b7faba66b 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 */ From 7c6035b63b023d241516c540ee581cd2d75b9f6a Mon Sep 17 00:00:00 2001 From: Amit Daniel Kachhap Date: Thu, 8 Mar 2012 02:07:34 -0800 Subject: [PATCH 09/20] ARM: S5P: add L2 early resume code This patch adds code to resume L2 before MMU is enabled in suspend and cpuidle resume paths. s3c_cpu_resume is moved to the data section with appropriate comments. Signed-off-by: Lorenzo Pieralisi Signed-off-by: Amit Daniel Kachhap Signed-off-by: Kukjin Kim --- arch/arm/plat-s5p/sleep.S | 44 +++++++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/arch/arm/plat-s5p/sleep.S b/arch/arm/plat-s5p/sleep.S index 0fd591bfc9fd..006bd01eda02 100644 --- a/arch/arm/plat-s5p/sleep.S +++ b/arch/arm/plat-s5p/sleep.S @@ -23,9 +23,18 @@ */ #include -#include +#include +#include - .text +/* + * The following code is located into the .data section. This is to + * allow l2x0_regs_phys to be accessed with a relative load while we + * can't rely on any MMU translation. We could have put l2x0_regs_phys + * in the .text section as well, but some setups might insist on it to + * be truly read-only. (Reference from: arch/arm/kernel/sleep.S) + */ + .data + .align /* * sleep magic, to allow the bootloader to check for an valid @@ -39,11 +48,34 @@ * s3c_cpu_resume * * resume code entry for bootloader to call - * - * we must put this code here in the data segment as we have no - * other way of restoring the stack pointer after sleep, and we - * must not write to the code segment (code is read-only) */ ENTRY(s3c_cpu_resume) +#ifdef CONFIG_CACHE_L2X0 + adr r0, l2x0_regs_phys + ldr r0, [r0] + ldr r1, [r0, #L2X0_R_PHY_BASE] + ldr r2, [r1, #L2X0_CTRL] + tst r2, #0x1 + bne resume_l2on + ldr r2, [r0, #L2X0_R_AUX_CTRL] + str r2, [r1, #L2X0_AUX_CTRL] + ldr r2, [r0, #L2X0_R_TAG_LATENCY] + str r2, [r1, #L2X0_TAG_LATENCY_CTRL] + ldr r2, [r0, #L2X0_R_DATA_LATENCY] + str r2, [r1, #L2X0_DATA_LATENCY_CTRL] + ldr r2, [r0, #L2X0_R_PREFETCH_CTRL] + str r2, [r1, #L2X0_PREFETCH_CTRL] + ldr r2, [r0, #L2X0_R_PWR_CTRL] + str r2, [r1, #L2X0_POWER_CTRL] + mov r2, #1 + str r2, [r1, #L2X0_CTRL] +resume_l2on: +#endif b cpu_resume +ENDPROC(s3c_cpu_resume) +#ifdef CONFIG_CACHE_L2X0 + .globl l2x0_regs_phys +l2x0_regs_phys: + .long 0 +#endif From b756a50f7f47e1dee70921399dcb338e4d3bc183 Mon Sep 17 00:00:00 2001 From: Amit Daniel Kachhap Date: Thu, 8 Mar 2012 02:07:41 -0800 Subject: [PATCH 10/20] ARM: EXYNOS: save L2 settings during bootup This patch adds code to save L2 register configuration at boot, and later used to resume L2 before MMU is enabled in suspend and cpuidle resume paths. Signed-off-by: Lorenzo Pieralisi Signed-off-by: Amit Daniel Kachhap Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/common.c | 42 ++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c index c59e18871006..9ff38aa08fd0 100644 --- a/arch/arm/mach-exynos/common.c +++ b/arch/arm/mach-exynos/common.c @@ -26,10 +26,12 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -441,20 +443,38 @@ 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); + 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_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 (soc_is_exynos4212() || soc_is_exynos4412()) + l2x0_saved_regs.data_latency = 0x120; + else + l2x0_saved_regs.data_latency = 0x110; - /* L2X0 Prefetch Control */ - __raw_writel(0x30000007, S5P_VA_L2CC + L2X0_PREFETCH_CTRL); + l2x0_saved_regs.prefetch_ctrl = 0x30000007; + l2x0_saved_regs.pwr_ctrl = + (L2X0_DYNAMIC_CLK_GATING_EN | L2X0_STNDBY_MODE_EN); - /* L2X0 Power Control */ - __raw_writel(L2X0_DYNAMIC_CLK_GATING_EN | L2X0_STNDBY_MODE_EN, - S5P_VA_L2CC + L2X0_POWER_CTRL); + l2x0_regs_phys = virt_to_phys(&l2x0_saved_regs); + + __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 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, 0x7C470001, 0xC200ffff); From d0341c61a2f641c4f90f4ed4b0d538c9bcb63d18 Mon Sep 17 00:00:00 2001 From: Amit Daniel Kachhap Date: Thu, 8 Mar 2012 02:09:06 -0800 Subject: [PATCH 11/20] ARM: EXYNOS: remove useless code to save/restore L2 Following the merge of CPU PM notifiers and L2 resume code, this patch removes useless code to save and restore L2 registers. This is now automatically covered by suspend calls which integrated CPU PM notifiers and new sleep code that allows to resume L2 before MMU is turned on. Signed-off-by: Lorenzo Pieralisi Signed-off-by: Amit Daniel Kachhap Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/pm.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index a4f61a43c7ba..2dd55a191abd 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)); @@ -386,13 +378,6 @@ static void exynos4_pm_resume(void) scu_enable(S5P_VA_SCU); -#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; } From 6cdeddcc8149672d4b888709d063825a80304d09 Mon Sep 17 00:00:00 2001 From: Amit Daniel Kachhap Date: Thu, 8 Mar 2012 02:09:12 -0800 Subject: [PATCH 12/20] ARM: EXYNOS: Enable l2 configuration through device tree This patch enables calling generic l2 setup functions if device tree is used. Signed-off-by: Amit Daniel Kachhap Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/common.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c index 9ff38aa08fd0..cb5ad8c1fea8 100644 --- a/arch/arm/mach-exynos/common.c +++ b/arch/arm/mach-exynos/common.c @@ -47,6 +47,8 @@ #include #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"; @@ -443,6 +445,14 @@ core_initcall(exynos4_core_init); #ifdef CONFIG_CACHE_L2X0 static int __init exynos4_l2x0_cache_init(void) { + 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 (!(__raw_readl(S5P_VA_L2CC + L2X0_CTRL) & 0x1)) { l2x0_saved_regs.phy_base = EXYNOS4_PA_L2CC; /* TAG, Data Latency Control: 2 cycles */ @@ -476,8 +486,7 @@ static int __init exynos4_l2x0_cache_init(void) clean_dcache_area(&l2x0_saved_regs, sizeof(struct l2x0_regs)); } - l2x0_init(S5P_VA_L2CC, 0x7C470001, 0xC200ffff); - + l2x0_init(S5P_VA_L2CC, L2_AUX_VAL, L2_AUX_MASK); return 0; } From 99f6e1f50cbb048325c966f2d0e7fe3e47010905 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Wed, 7 Mar 2012 04:23:47 -0800 Subject: [PATCH 13/20] ARM: S3C64XX: Add usb otg phy control This patch supports to control usb otg phy of S3C64XX. Currently, the driver for usb otg controls usb otg phy but it can be removed by this patch. Signed-off-by: Joonyoung Shim Signed-off-by: Kyungmin Park [Rebased on the newest git/kgene/linux-samsung #for-next] Signed-off-by: Lukasz Majewski Acked-by: Mark Brown Signed-off-by: Kukjin Kim --- arch/arm/mach-s3c64xx/Kconfig | 8 ++ arch/arm/mach-s3c64xx/Makefile | 1 + arch/arm/mach-s3c64xx/mach-crag6410.c | 4 + arch/arm/mach-s3c64xx/mach-smartq.c | 3 + arch/arm/mach-s3c64xx/mach-smdk6410.c | 4 + arch/arm/mach-s3c64xx/setup-usb-phy.c | 90 +++++++++++++++++++ arch/arm/plat-samsung/devs.c | 14 +++ .../include/plat/regs-usb-hsotg-phy.h | 7 +- arch/arm/plat-samsung/include/plat/udc-hs.h | 5 ++ 9 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 arch/arm/mach-s3c64xx/setup-usb-phy.c diff --git a/arch/arm/mach-s3c64xx/Kconfig b/arch/arm/mach-s3c64xx/Kconfig index dd20c66cd700..326ea3a98725 100644 --- a/arch/arm/mach-s3c64xx/Kconfig +++ b/arch/arm/mach-s3c64xx/Kconfig @@ -83,6 +83,11 @@ config S3C64XX_SETUP_SPI help Common setup code for SPI GPIO configurations +config S3C64XX_SETUP_USB_PHY + bool + help + Common setup code for USB PHY controller + # S36400 Macchine support config MACH_SMDK6400 @@ -157,6 +162,7 @@ config MACH_SMDK6410 select S3C64XX_SETUP_IDE select S3C64XX_SETUP_FB_24BPP select S3C64XX_SETUP_KEYPAD + select S3C64XX_SETUP_USB_PHY help Machine support for the Samsung SMDK6410 @@ -256,6 +262,7 @@ config MACH_SMARTQ select S3C_DEV_USB_HOST select S3C64XX_SETUP_SDHCI select S3C64XX_SETUP_FB_24BPP + select S3C64XX_SETUP_USB_PHY select SAMSUNG_DEV_ADC select SAMSUNG_DEV_PWM select SAMSUNG_DEV_TS @@ -283,6 +290,7 @@ config MACH_WLF_CRAGG_6410 select S3C64XX_SETUP_FB_24BPP select S3C64XX_SETUP_KEYPAD select S3C64XX_SETUP_SPI + select S3C64XX_SETUP_USB_PHY select SAMSUNG_DEV_ADC select SAMSUNG_DEV_KEYPAD select S3C_DEV_USB_HOST diff --git a/arch/arm/mach-s3c64xx/Makefile b/arch/arm/mach-s3c64xx/Makefile index 610fe2807ed7..f9ce1dc28ce4 100644 --- a/arch/arm/mach-s3c64xx/Makefile +++ b/arch/arm/mach-s3c64xx/Makefile @@ -43,6 +43,7 @@ obj-$(CONFIG_S3C64XX_SETUP_IDE) += setup-ide.o obj-$(CONFIG_S3C64XX_SETUP_KEYPAD) += setup-keypad.o obj-$(CONFIG_S3C64XX_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o obj-$(CONFIG_S3C64XX_SETUP_SPI) += setup-spi.o +obj-$(CONFIG_S3C64XX_SETUP_USB_PHY) += setup-usb-phy.o # Machine support diff --git a/arch/arm/mach-s3c64xx/mach-crag6410.c b/arch/arm/mach-s3c64xx/mach-crag6410.c index 8077f650eb0e..3b56bd9cb880 100644 --- a/arch/arm/mach-s3c64xx/mach-crag6410.c +++ b/arch/arm/mach-s3c64xx/mach-crag6410.c @@ -59,6 +59,7 @@ #include #include #include +#include #include #include @@ -698,6 +699,8 @@ static struct s3c_sdhci_platdata crag6410_hsmmc0_pdata = { .cfg_gpio = crag6410_cfg_sdhci0, }; +static struct s3c_hsotg_plat crag6410_hsotg_pdata; + static void __init crag6410_machine_init(void) { /* Open drain IRQs need pullups */ @@ -722,6 +725,7 @@ static void __init crag6410_machine_init(void) s3c_i2c0_set_platdata(&i2c0_pdata); s3c_i2c1_set_platdata(&i2c1_pdata); s3c_fb_set_platdata(&crag6410_lcd_pdata); + s3c_hsotg_set_platdata(&crag6410_hsotg_pdata); i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0)); i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1)); diff --git a/arch/arm/mach-s3c64xx/mach-smartq.c b/arch/arm/mach-s3c64xx/mach-smartq.c index ce31db136231..ce745e19aa27 100644 --- a/arch/arm/mach-s3c64xx/mach-smartq.c +++ b/arch/arm/mach-s3c64xx/mach-smartq.c @@ -187,6 +187,8 @@ static struct s3c_hwmon_pdata smartq_hwmon_pdata __initdata = { }, }; +static struct s3c_hsotg_plat smartq_hsotg_pdata; + static int __init smartq_lcd_setup_gpio(void) { int ret; @@ -383,6 +385,7 @@ void __init smartq_map_io(void) void __init smartq_machine_init(void) { s3c_i2c0_set_platdata(NULL); + s3c_hsotg_set_platdata(&smartq_hsotg_pdata); s3c_hwmon_set_platdata(&smartq_hwmon_pdata); s3c_sdhci1_set_platdata(&smartq_internal_hsmmc_pdata); s3c_sdhci2_set_platdata(&smartq_internal_hsmmc_pdata); diff --git a/arch/arm/mach-s3c64xx/mach-smdk6410.c b/arch/arm/mach-s3c64xx/mach-smdk6410.c index ca6fc204f0ea..d55bc96d9582 100644 --- a/arch/arm/mach-s3c64xx/mach-smdk6410.c +++ b/arch/arm/mach-s3c64xx/mach-smdk6410.c @@ -72,6 +72,7 @@ #include #include #include +#include #include "common.h" @@ -631,6 +632,8 @@ static struct platform_pwm_backlight_data smdk6410_bl_data = { .pwm_id = 1, }; +static struct s3c_hsotg_plat smdk6410_hsotg_pdata; + static void __init smdk6410_map_io(void) { u32 tmp; @@ -659,6 +662,7 @@ static void __init smdk6410_machine_init(void) s3c_i2c0_set_platdata(NULL); s3c_i2c1_set_platdata(NULL); s3c_fb_set_platdata(&smdk6410_lcd_pdata); + s3c_hsotg_set_platdata(&smdk6410_hsotg_pdata); samsung_keypad_set_platdata(&smdk6410_keypad_data); diff --git a/arch/arm/mach-s3c64xx/setup-usb-phy.c b/arch/arm/mach-s3c64xx/setup-usb-phy.c new file mode 100644 index 000000000000..f6757e02d7db --- /dev/null +++ b/arch/arm/mach-s3c64xx/setup-usb-phy.c @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2011 Samsung Electronics Co.Ltd + * Author: Joonyoung Shim + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int s3c_usb_otgphy_init(struct platform_device *pdev) +{ + struct clk *xusbxti; + u32 phyclk; + + writel(readl(S3C64XX_OTHERS) | S3C64XX_OTHERS_USBMASK, S3C64XX_OTHERS); + + /* set clock frequency for PLL */ + phyclk = readl(S3C_PHYCLK) & ~S3C_PHYCLK_CLKSEL_MASK; + + xusbxti = clk_get(&pdev->dev, "xusbxti"); + if (xusbxti && !IS_ERR(xusbxti)) { + switch (clk_get_rate(xusbxti)) { + case 12 * MHZ: + phyclk |= S3C_PHYCLK_CLKSEL_12M; + break; + case 24 * MHZ: + phyclk |= S3C_PHYCLK_CLKSEL_24M; + break; + default: + case 48 * MHZ: + /* default reference clock */ + break; + } + clk_put(xusbxti); + } + + /* TODO: select external clock/oscillator */ + writel(phyclk | S3C_PHYCLK_CLK_FORCE, S3C_PHYCLK); + + /* set to normal OTG PHY */ + writel((readl(S3C_PHYPWR) & ~S3C_PHYPWR_NORMAL_MASK), S3C_PHYPWR); + mdelay(1); + + /* reset OTG PHY and Link */ + writel(S3C_RSTCON_PHY | S3C_RSTCON_HCLK | S3C_RSTCON_PHYCLK, + S3C_RSTCON); + udelay(20); /* at-least 10uS */ + writel(0, S3C_RSTCON); + + return 0; +} + +static int s3c_usb_otgphy_exit(struct platform_device *pdev) +{ + writel((readl(S3C_PHYPWR) | S3C_PHYPWR_ANALOG_POWERDOWN | + S3C_PHYPWR_OTG_DISABLE), S3C_PHYPWR); + + writel(readl(S3C64XX_OTHERS) & ~S3C64XX_OTHERS_USBMASK, S3C64XX_OTHERS); + + return 0; +} + +int s5p_usb_phy_init(struct platform_device *pdev, int type) +{ + if (type == S5P_USB_PHY_DEVICE) + return s3c_usb_otgphy_init(pdev); + + return -EINVAL; +} + +int s5p_usb_phy_exit(struct platform_device *pdev, int type) +{ + if (type == S5P_USB_PHY_DEVICE) + return s3c_usb_otgphy_exit(pdev); + + return -EINVAL; +} diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c index 145580a4a62c..21168eaad356 100644 --- a/arch/arm/plat-samsung/devs.c +++ b/arch/arm/plat-samsung/devs.c @@ -57,6 +57,7 @@ #include #include #include +#include #include #include #include @@ -1449,6 +1450,19 @@ struct platform_device s3c_device_usb_hsotg = { .coherent_dma_mask = DMA_BIT_MASK(32), }, }; + +void __init s3c_hsotg_set_platdata(struct s3c_hsotg_plat *pd) +{ + struct s3c_hsotg_plat *npd; + + npd = s3c_set_platdata(pd, sizeof(struct s3c_hsotg_plat), + &s3c_device_usb_hsotg); + + if (!npd->phy_init) + npd->phy_init = s5p_usb_phy_init; + if (!npd->phy_exit) + npd->phy_exit = s5p_usb_phy_exit; +} #endif /* CONFIG_S3C_DEV_USB_HSOTG */ /* USB High Spped 2.0 Device (Gadget) */ diff --git a/arch/arm/plat-samsung/include/plat/regs-usb-hsotg-phy.h b/arch/arm/plat-samsung/include/plat/regs-usb-hsotg-phy.h index a111ad871833..fcf279662067 100644 --- a/arch/arm/plat-samsung/include/plat/regs-usb-hsotg-phy.h +++ b/arch/arm/plat-samsung/include/plat/regs-usb-hsotg-phy.h @@ -25,8 +25,9 @@ #define S3C_HSOTG_PHYREG(x) ((x) + S3C_VA_USB_HSPHY) #define S3C_PHYPWR S3C_HSOTG_PHYREG(0x00) -#define SRC_PHYPWR_OTG_DISABLE (1 << 4) -#define SRC_PHYPWR_ANALOG_POWERDOWN (1 << 3) +#define S3C_PHYPWR_NORMAL_MASK (0x19 << 0) +#define S3C_PHYPWR_OTG_DISABLE (1 << 4) +#define S3C_PHYPWR_ANALOG_POWERDOWN (1 << 3) #define SRC_PHYPWR_FORCE_SUSPEND (1 << 1) #define S3C_PHYCLK S3C_HSOTG_PHYREG(0x04) @@ -42,7 +43,7 @@ #define S3C_RSTCON S3C_HSOTG_PHYREG(0x08) #define S3C_RSTCON_PHYCLK (1 << 2) -#define S3C_RSTCON_HCLK (1 << 2) +#define S3C_RSTCON_HCLK (1 << 1) #define S3C_RSTCON_PHY (1 << 0) #define S3C_PHYTUNE S3C_HSOTG_PHYREG(0x20) diff --git a/arch/arm/plat-samsung/include/plat/udc-hs.h b/arch/arm/plat-samsung/include/plat/udc-hs.h index a22a4f2eea94..c9e3667cb2b1 100644 --- a/arch/arm/plat-samsung/include/plat/udc-hs.h +++ b/arch/arm/plat-samsung/include/plat/udc-hs.h @@ -26,4 +26,9 @@ enum s3c_hsotg_dmamode { struct s3c_hsotg_plat { enum s3c_hsotg_dmamode dma; unsigned int is_osc : 1; + + int (*phy_init)(struct platform_device *pdev, int type); + int (*phy_exit)(struct platform_device *pdev, int type); }; + +extern void s3c_hsotg_set_platdata(struct s3c_hsotg_plat *pd); From 7f471ee8bed570c0f8ea48f17a957c3b31f54a61 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Thu, 8 Mar 2012 19:52:25 +0900 Subject: [PATCH 14/20] ARM: S5PV210: Add usb otg phy control This patch supports to control usb otg phy of S5PV210. Based on setup-usb-phy.c of S3C64XX. Signed-off-by: Joonyoung Shim Signed-off-by: Kyungmin Park [Test HW: GONI S5PC110] Tested-by: Lukasz Majewski Signed-off-by: Kukjin Kim --- arch/arm/mach-s5pv210/Kconfig | 6 ++ arch/arm/mach-s5pv210/Makefile | 1 + arch/arm/mach-s5pv210/include/mach/regs-sys.h | 4 - arch/arm/mach-s5pv210/setup-usb-phy.c | 90 +++++++++++++++++++ 4 files changed, 97 insertions(+), 4 deletions(-) create mode 100644 arch/arm/mach-s5pv210/setup-usb-phy.c diff --git a/arch/arm/mach-s5pv210/Kconfig b/arch/arm/mach-s5pv210/Kconfig index 2cdc42e838b8..82525e3831e9 100644 --- a/arch/arm/mach-s5pv210/Kconfig +++ b/arch/arm/mach-s5pv210/Kconfig @@ -65,6 +65,11 @@ config S5PV210_SETUP_SPI help Common setup code for SPI GPIO configurations. +config S5PV210_SETUP_USB_PHY + bool + help + Common setup code for USB PHY controller + menu "S5PC110 Machines" config MACH_AQUILA @@ -107,6 +112,7 @@ config MACH_GONI select S5PV210_SETUP_KEYPAD select S5PV210_SETUP_SDHCI select S5PV210_SETUP_FIMC + select S5PV210_SETUP_USB_PHY help Machine support for Samsung GONI board S5PC110(MCP) is one of package option of S5PV210 diff --git a/arch/arm/mach-s5pv210/Makefile b/arch/arm/mach-s5pv210/Makefile index 76a121dd52b4..1c4e41998a10 100644 --- a/arch/arm/mach-s5pv210/Makefile +++ b/arch/arm/mach-s5pv210/Makefile @@ -39,3 +39,4 @@ obj-$(CONFIG_S5PV210_SETUP_IDE) += setup-ide.o obj-$(CONFIG_S5PV210_SETUP_KEYPAD) += setup-keypad.o obj-$(CONFIG_S5PV210_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o obj-$(CONFIG_S5PV210_SETUP_SPI) += setup-spi.o +obj-$(CONFIG_S5PV210_SETUP_USB_PHY) += setup-usb-phy.o diff --git a/arch/arm/mach-s5pv210/include/mach/regs-sys.h b/arch/arm/mach-s5pv210/include/mach/regs-sys.h index 26691d39d0f4..cccb1eddaa38 100644 --- a/arch/arm/mach-s5pv210/include/mach/regs-sys.h +++ b/arch/arm/mach-s5pv210/include/mach/regs-sys.h @@ -13,7 +13,3 @@ #define S5PV210_USB_PHY_CON (S3C_VA_SYS + 0xE80C) #define S5PV210_USB_PHY0_EN (1 << 0) #define S5PV210_USB_PHY1_EN (1 << 1) - -/* compatibility defines for s3c-hsotg driver */ -#define S3C64XX_OTHERS S5PV210_USB_PHY_CON -#define S3C64XX_OTHERS_USBMASK S5PV210_USB_PHY0_EN diff --git a/arch/arm/mach-s5pv210/setup-usb-phy.c b/arch/arm/mach-s5pv210/setup-usb-phy.c new file mode 100644 index 000000000000..be39cf4aa91b --- /dev/null +++ b/arch/arm/mach-s5pv210/setup-usb-phy.c @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2012 Samsung Electronics Co.Ltd + * Author: Joonyoung Shim + * + * 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 Foundationr + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int s5pv210_usb_otgphy_init(struct platform_device *pdev) +{ + struct clk *xusbxti; + u32 phyclk; + + writel(readl(S5PV210_USB_PHY_CON) | S5PV210_USB_PHY0_EN, + S5PV210_USB_PHY_CON); + + /* set clock frequency for PLL */ + phyclk = readl(S3C_PHYCLK) & ~S3C_PHYCLK_CLKSEL_MASK; + + xusbxti = clk_get(&pdev->dev, "xusbxti"); + if (xusbxti && !IS_ERR(xusbxti)) { + switch (clk_get_rate(xusbxti)) { + case 12 * MHZ: + phyclk |= S3C_PHYCLK_CLKSEL_12M; + break; + case 24 * MHZ: + phyclk |= S3C_PHYCLK_CLKSEL_24M; + break; + default: + case 48 * MHZ: + /* default reference clock */ + break; + } + clk_put(xusbxti); + } + + /* TODO: select external clock/oscillator */ + writel(phyclk | S3C_PHYCLK_CLK_FORCE, S3C_PHYCLK); + + /* set to normal OTG PHY */ + writel((readl(S3C_PHYPWR) & ~S3C_PHYPWR_NORMAL_MASK), S3C_PHYPWR); + mdelay(1); + + /* reset OTG PHY and Link */ + writel(S3C_RSTCON_PHY | S3C_RSTCON_HCLK | S3C_RSTCON_PHYCLK, + S3C_RSTCON); + udelay(20); /* at-least 10uS */ + writel(0, S3C_RSTCON); + + return 0; +} + +static int s5pv210_usb_otgphy_exit(struct platform_device *pdev) +{ + writel((readl(S3C_PHYPWR) | S3C_PHYPWR_ANALOG_POWERDOWN | + S3C_PHYPWR_OTG_DISABLE), S3C_PHYPWR); + + writel(readl(S5PV210_USB_PHY_CON) & ~S5PV210_USB_PHY0_EN, + S5PV210_USB_PHY_CON); + + return 0; +} + +int s5p_usb_phy_init(struct platform_device *pdev, int type) +{ + if (type == S5P_USB_PHY_DEVICE) + return s5pv210_usb_otgphy_init(pdev); + + return -EINVAL; +} + +int s5p_usb_phy_exit(struct platform_device *pdev, int type) +{ + if (type == S5P_USB_PHY_DEVICE) + return s5pv210_usb_otgphy_exit(pdev); + + return -EINVAL; +} From 4db17215da33940e4c594c1152ce765c5506a621 Mon Sep 17 00:00:00 2001 From: Tushar Behera Date: Fri, 9 Mar 2012 08:03:13 -0800 Subject: [PATCH 15/20] ARM: SAMSUNG: Add __init attribute to samsung_bl_set() s3c_set_platdata() is defined with __init attribute, hence all functions referencing this function should also be defined with __init attribute. samsung_bl_set() is referenced only in '__init xxx_machine_init()' functions, thus this change won't put any additional constraint on the usage of samsung_bl_set(). Signed-off-by: Tushar Behera Signed-off-by: Kukjin Kim --- arch/arm/plat-samsung/dev-backlight.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/plat-samsung/dev-backlight.c b/arch/arm/plat-samsung/dev-backlight.c index 2254920a02cf..5f197dcaf10c 100644 --- a/arch/arm/plat-samsung/dev-backlight.c +++ b/arch/arm/plat-samsung/dev-backlight.c @@ -77,7 +77,7 @@ static struct platform_device samsung_dfl_bl_device __initdata = { * @gpio_info: structure containing GPIO info for PWM timer * @bl_data: structure containing Backlight control data */ -void samsung_bl_set(struct samsung_bl_gpio_info *gpio_info, +void __init samsung_bl_set(struct samsung_bl_gpio_info *gpio_info, struct platform_pwm_backlight_data *bl_data) { int ret = 0; From eff4c58dac1c7d90377ba5c060bab3966a3879ae Mon Sep 17 00:00:00 2001 From: Tushar Behera Date: Fri, 9 Mar 2012 08:03:17 -0800 Subject: [PATCH 16/20] ARM: SAMSUNG: fix __init attribute on regarding s3c_set_platdata() s3c_set_platdata() is defined with __init attribute, hence all functions referencing this function should also be defined with __init attribute. Signed-off-by: Tushar Behera Signed-off-by: Kukjin Kim --- arch/arm/plat-samsung/devs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c index 21168eaad356..663f837a101f 100644 --- a/arch/arm/plat-samsung/devs.c +++ b/arch/arm/plat-samsung/devs.c @@ -796,7 +796,7 @@ struct platform_device s3c_device_cfcon = { .resource = s3c_cfcon_resource, }; -void s3c_ide_set_platdata(struct s3c_ide_platdata *pdata) +void __init s3c_ide_set_platdata(struct s3c_ide_platdata *pdata) { s3c_set_platdata(pdata, sizeof(struct s3c_ide_platdata), &s3c_device_cfcon); @@ -1076,7 +1076,7 @@ struct platform_device s3c64xx_device_onenand1 = { .resource = s3c64xx_onenand1_resources, }; -void s3c64xx_onenand1_set_platdata(struct onenand_platform_data *pdata) +void __init s3c64xx_onenand1_set_platdata(struct onenand_platform_data *pdata) { s3c_set_platdata(pdata, sizeof(struct onenand_platform_data), &s3c64xx_device_onenand1); From 75ac7284c980ccb3f0e2ab21fe8acf3818317bc3 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 9 Mar 2012 08:38:41 -0800 Subject: [PATCH 17/20] ARM: SAMSUNG: Correct MIPI-CSIS io memory resource definition The resources size is increased to 16KB to also include the non-image packet data buffers (CSIS_PKTDATAn). The 4KiB region is only sufficient when the driver is not using the packet data buffers. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Kukjin Kim --- arch/arm/plat-samsung/devs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c index 663f837a101f..996567ee94cd 100644 --- a/arch/arm/plat-samsung/devs.c +++ b/arch/arm/plat-samsung/devs.c @@ -914,7 +914,7 @@ struct platform_device s5p_device_mfc_r = { #ifdef CONFIG_S5P_DEV_CSIS0 static struct resource s5p_mipi_csis0_resource[] = { - [0] = DEFINE_RES_MEM(S5P_PA_MIPI_CSIS0, SZ_4K), + [0] = DEFINE_RES_MEM(S5P_PA_MIPI_CSIS0, SZ_16K), [1] = DEFINE_RES_IRQ(IRQ_MIPI_CSIS0), }; @@ -928,7 +928,7 @@ struct platform_device s5p_device_mipi_csis0 = { #ifdef CONFIG_S5P_DEV_CSIS1 static struct resource s5p_mipi_csis1_resource[] = { - [0] = DEFINE_RES_MEM(S5P_PA_MIPI_CSIS1, SZ_4K), + [0] = DEFINE_RES_MEM(S5P_PA_MIPI_CSIS1, SZ_16K), [1] = DEFINE_RES_IRQ(IRQ_MIPI_CSIS1), }; From 2bde0b08cae739056d1c136839b67eec0ac0c3a4 Mon Sep 17 00:00:00 2001 From: MyungJoo Ham Date: Thu, 1 Dec 2011 15:12:30 +0900 Subject: [PATCH 18/20] ARM: EXYNOS: Add DMC1, allow PPMU access for DMC - Add DMC1 - Enlarge address space for DMC from 4k to 64k so that PPMU registers may be accessed. Signed-off-by: MyungJoo Ham Signed-off-by: Kyungmin Park Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/common.c | 7 ++++++- arch/arm/mach-exynos/include/mach/map.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c index cb5ad8c1fea8..02696ac143bd 100644 --- a/arch/arm/mach-exynos/common.c +++ b/arch/arm/mach-exynos/common.c @@ -177,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, diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h index 7df9e7456814..535f55f76920 100644 --- a/arch/arm/mach-exynos/include/mach/map.h +++ b/arch/arm/mach-exynos/include/mach/map.h @@ -59,6 +59,7 @@ #define EXYNOS4_PA_KEYPAD 0x100A0000 #define EXYNOS4_PA_DMC0 0x10400000 +#define EXYNOS4_PA_DMC1 0x10410000 #define EXYNOS4_PA_COMBINER 0x10440000 From 3dbe6d4cacc76100f3166cd824d3ce7a8cef7cef Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Sat, 10 Mar 2012 02:45:42 -0800 Subject: [PATCH 19/20] ARM: EXYNOS: add support JPEG This patch adds platform_device, clock, map for JPEG Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/clock.c | 5 +++++ arch/arm/mach-exynos/include/mach/map.h | 3 +++ arch/arm/plat-s5p/Kconfig | 5 +++++ arch/arm/plat-samsung/devs.c | 18 ++++++++++++++++++ arch/arm/plat-samsung/include/plat/devs.h | 1 + 5 files changed, 32 insertions(+) diff --git a/arch/arm/mach-exynos/clock.c b/arch/arm/mach-exynos/clock.c index 5a8c42e90005..e532bc2960a4 100644 --- a/arch/arm/mach-exynos/clock.c +++ b/arch/arm/mach-exynos/clock.c @@ -469,6 +469,11 @@ static struct clk init_clocks_off[] = { .devname = "s5p-mipi-csis.1", .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", diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h index 535f55f76920..a8cd65fcc685 100644 --- a/arch/arm/mach-exynos/include/mach/map.h +++ b/arch/arm/mach-exynos/include/mach/map.h @@ -31,6 +31,8 @@ #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 @@ -165,6 +167,7 @@ #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 diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig index e7fec7820a18..7a308699f816 100644 --- a/arch/arm/plat-s5p/Kconfig +++ b/arch/arm/plat-s5p/Kconfig @@ -80,6 +80,11 @@ config S5P_DEV_FIMC3 help Compile in platform device definitions for FIMC controller 3 +config S5P_DEV_JPEG + bool + help + Compile in platform device definitions for JPEG codec + config S5P_DEV_G2D bool help diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c index 996567ee94cd..cd0b9da9bbc4 100644 --- a/arch/arm/plat-samsung/devs.c +++ b/arch/arm/plat-samsung/devs.c @@ -296,6 +296,24 @@ struct platform_device s5p_device_g2d = { }; #endif /* CONFIG_S5P_DEV_G2D */ +#ifdef CONFIG_S5P_DEV_JPEG +static struct resource s5p_jpeg_resource[] = { + [0] = DEFINE_RES_MEM(S5P_PA_JPEG, SZ_4K), + [1] = DEFINE_RES_IRQ(IRQ_JPEG), +}; + +struct platform_device s5p_device_jpeg = { + .name = "s5p-jpeg", + .id = 0, + .num_resources = ARRAY_SIZE(s5p_jpeg_resource), + .resource = s5p_jpeg_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; +#endif /* CONFIG_S5P_DEV_JPEG */ + /* FIMD0 */ #ifdef CONFIG_S5P_DEV_FIMD0 diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h index bb4584815037..5e7972de3ed5 100644 --- a/arch/arm/plat-samsung/include/plat/devs.h +++ b/arch/arm/plat-samsung/include/plat/devs.h @@ -79,6 +79,7 @@ extern struct platform_device s5p_device_fimc1; extern struct platform_device s5p_device_fimc2; extern struct platform_device s5p_device_fimc3; extern struct platform_device s5p_device_fimc_md; +extern struct platform_device s5p_device_jpeg; extern struct platform_device s5p_device_g2d; extern struct platform_device s5p_device_fimd0; extern struct platform_device s5p_device_hdmi; From 4d2e4d7f2c2b1a4382286821a59fa2f4012cb748 Mon Sep 17 00:00:00 2001 From: Changhwan Youn Date: Fri, 9 Mar 2012 15:09:21 -0800 Subject: [PATCH 20/20] ARM: EXYNOS: fix cycle count for periodic mode of clock event timers EXYNOS SOC series use MCT for kernel timer and MCT has two types of clock event timers, which are mct-comp and mct-tick. Because the clock rate of each event timer is diffent from the other, this patch fixes cycles_per_jiffy for each timer's periodic mode. Signed-off-by: Changhwan Youn Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/mct.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-exynos/mct.c b/arch/arm/mach-exynos/mct.c index 85b5527d0918..3e894ba25b01 100644 --- a/arch/arm/mach-exynos/mct.c +++ b/arch/arm/mach-exynos/mct.c @@ -29,12 +29,13 @@ #include #include +#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 +206,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 +252,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 +316,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: @@ -393,7 +398,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 +406,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) {