Skip to content

Commit

Permalink
Merge branch 'samsung/soc' into next/soc2
Browse files Browse the repository at this point in the history
* samsung/soc:
  ARM: EXYNOS: fix cycle count for periodic mode of clock event timers
  ARM: EXYNOS: add support JPEG
  ARM: EXYNOS: Add DMC1, allow PPMU access for DMC
  ARM: SAMSUNG: Correct MIPI-CSIS io memory resource definition
  ARM: SAMSUNG: fix __init attribute on regarding s3c_set_platdata()
  ARM: SAMSUNG: Add __init attribute to samsung_bl_set()
  ARM: S5PV210: Add usb otg phy control
  ARM: S3C64XX: Add usb otg phy control
  ARM: EXYNOS: Enable l2 configuration through device tree
  ARM: EXYNOS: remove useless code to save/restore L2
  ARM: EXYNOS: save L2 settings during bootup
  ARM: S5P: add L2 early resume code
  ARM: EXYNOS: Add support AFTR mode on EXYNOS4210
  ARM: SAMSUNG: use spin_lock_irqsave() in clk_{enable,disable}
  ARM: S3C64XX: Define some additional always off clocks
  ARM: S3C64XX: Reduce residency requirement for cpuidle WFI mode
  ARM: SAMSUNG: Add a callback 'notify_after' for PWM backlight control
  ARM: SAMSUNG: add G2D to plat-s5p and mach-exynos
  ARM: S3C64XX: Gate some more clocks by default
  ARM: S3C64XX: Add basic cpuidle driver

Conflicts:
	arch/arm/mach-exynos/clock.c
	arch/arm/mach-exynos/common.c

This merges the earlier samsung support into the next/soc2 branch to
resolve conflicts between commits in the earlier work and the exynos5
branch.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
  • Loading branch information
Arnd Bergmann committed Mar 15, 2012
2 parents e7051e9 + 4d2e4d7 commit 853a023
Show file tree
Hide file tree
Showing 27 changed files with 765 additions and 72 deletions.
5 changes: 5 additions & 0 deletions arch/arm/mach-exynos/clock-exynos4.c
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,11 @@ static struct clk exynos4_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",
Expand Down
60 changes: 47 additions & 13 deletions arch/arm/mach-exynos/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -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";
Expand Down Expand Up @@ -189,7 +193,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,
Expand Down Expand Up @@ -592,23 +601,48 @@ static int __init exynos4_l2x0_cache_init(void)
if (soc_is_exynos5250())
return 0;

/* 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 (!(__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_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;
}
early_initcall(exynos4_l2x0_cache_init);
Expand Down
151 changes: 147 additions & 4 deletions arch/arm/mach-exynos/cpuidle.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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);
7 changes: 7 additions & 0 deletions arch/arm/mach-exynos/include/mach/map.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,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
Expand Down Expand Up @@ -67,6 +71,7 @@
#define EXYNOS4_PA_KEYPAD 0x100A0000

#define EXYNOS4_PA_DMC0 0x10400000
#define EXYNOS4_PA_DMC1 0x10410000

#define EXYNOS4_PA_COMBINER 0x10440000
#define EXYNOS5_PA_COMBINER 0x10440000
Expand Down Expand Up @@ -179,6 +184,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
Expand Down
2 changes: 2 additions & 0 deletions arch/arm/mach-exynos/include/mach/pmu.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Loading

0 comments on commit 853a023

Please sign in to comment.