diff options
Diffstat (limited to 'arch/arm/mach-prima2')
-rw-r--r-- | arch/arm/mach-prima2/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/mach-prima2/clock.c | 4 | ||||
-rw-r--r-- | arch/arm/mach-prima2/include/mach/debug-macro.S | 2 | ||||
-rw-r--r-- | arch/arm/mach-prima2/include/mach/memory.h | 21 | ||||
-rw-r--r-- | arch/arm/mach-prima2/irq.c | 43 | ||||
-rw-r--r-- | arch/arm/mach-prima2/l2x0.c | 46 | ||||
-rw-r--r-- | arch/arm/mach-prima2/pm.c | 150 | ||||
-rw-r--r-- | arch/arm/mach-prima2/pm.h | 29 | ||||
-rw-r--r-- | arch/arm/mach-prima2/prima2.c | 5 | ||||
-rw-r--r-- | arch/arm/mach-prima2/rtciobrg.c | 139 | ||||
-rw-r--r-- | arch/arm/mach-prima2/sleep.S | 64 | ||||
-rw-r--r-- | arch/arm/mach-prima2/timer.c | 38 |
12 files changed, 478 insertions, 65 deletions
diff --git a/arch/arm/mach-prima2/Makefile b/arch/arm/mach-prima2/Makefile index 7af7fc05d56..13dd1604d95 100644 --- a/arch/arm/mach-prima2/Makefile +++ b/arch/arm/mach-prima2/Makefile @@ -3,5 +3,7 @@ obj-y += irq.o obj-y += clock.o obj-y += rstc.o obj-y += prima2.o +obj-y += rtciobrg.o obj-$(CONFIG_DEBUG_LL) += lluart.o obj-$(CONFIG_CACHE_L2X0) += l2x0.o +obj-$(CONFIG_SUSPEND) += pm.o sleep.o diff --git a/arch/arm/mach-prima2/clock.c b/arch/arm/mach-prima2/clock.c index 615a4e75cea..aebad7e565c 100644 --- a/arch/arm/mach-prima2/clock.c +++ b/arch/arm/mach-prima2/clock.c @@ -350,10 +350,10 @@ static struct clk_lookup onchip_clks[] = { .clk = &clk_mem, }, { .dev_id = "sys", - .clk = &clk_sys, + .clk = &clk_sys, }, { .dev_id = "io", - .clk = &clk_io, + .clk = &clk_io, }, }; diff --git a/arch/arm/mach-prima2/include/mach/debug-macro.S b/arch/arm/mach-prima2/include/mach/debug-macro.S index bf75106333f..cd97492bb07 100644 --- a/arch/arm/mach-prima2/include/mach/debug-macro.S +++ b/arch/arm/mach-prima2/include/mach/debug-macro.S @@ -9,7 +9,7 @@ #include <mach/hardware.h> #include <mach/uart.h> - .macro addruart, rp, rv + .macro addruart, rp, rv, tmp ldr \rp, =SIRFSOC_UART1_PA_BASE @ physical ldr \rv, =SIRFSOC_UART1_VA_BASE @ virtual .endm diff --git a/arch/arm/mach-prima2/include/mach/memory.h b/arch/arm/mach-prima2/include/mach/memory.h deleted file mode 100644 index 368cd5a0601..00000000000 --- a/arch/arm/mach-prima2/include/mach/memory.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * arch/arm/mach-prima2/include/mach/memory.h - * - * Copyright (c) 2010 – 2011 Cambridge Silicon Radio Limited, a CSR plc group company. - * - * Licensed under GPLv2 or later. - */ - -#ifndef __ASM_ARCH_MEMORY_H -#define __ASM_ARCH_MEMORY_H - -#define PLAT_PHYS_OFFSET UL(0x00000000) - -/* - * Restrict DMA-able region to workaround silicon limitation. - * The limitation restricts buffers available for DMA to SD/MMC - * hardware to be below 256MB - */ -#define ARM_DMA_ZONE_SIZE (SZ_256M) - -#endif diff --git a/arch/arm/mach-prima2/irq.c b/arch/arm/mach-prima2/irq.c index 7af254d046b..d93ceef4a50 100644 --- a/arch/arm/mach-prima2/irq.c +++ b/arch/arm/mach-prima2/irq.c @@ -13,6 +13,8 @@ #include <asm/mach/irq.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/irqdomain.h> +#include <linux/syscore_ops.h> #define SIRFSOC_INT_RISC_MASK0 0x0018 #define SIRFSOC_INT_RISC_MASK1 0x001C @@ -66,7 +68,48 @@ void __init sirfsoc_of_irq_init(void) if (!sirfsoc_intc_base) panic("unable to map intc cpu registers\n"); + irq_domain_add_simple(np, 0); + of_node_put(np); sirfsoc_irq_init(); } + +struct sirfsoc_irq_status { + u32 mask0; + u32 mask1; + u32 level0; + u32 level1; +}; + +static struct sirfsoc_irq_status sirfsoc_irq_st; + +static int sirfsoc_irq_suspend(void) +{ + sirfsoc_irq_st.mask0 = readl_relaxed(sirfsoc_intc_base + SIRFSOC_INT_RISC_MASK0); + sirfsoc_irq_st.mask1 = readl_relaxed(sirfsoc_intc_base + SIRFSOC_INT_RISC_MASK1); + sirfsoc_irq_st.level0 = readl_relaxed(sirfsoc_intc_base + SIRFSOC_INT_RISC_LEVEL0); + sirfsoc_irq_st.level1 = readl_relaxed(sirfsoc_intc_base + SIRFSOC_INT_RISC_LEVEL1); + + return 0; +} + +static void sirfsoc_irq_resume(void) +{ + writel_relaxed(sirfsoc_irq_st.mask0, sirfsoc_intc_base + SIRFSOC_INT_RISC_MASK0); + writel_relaxed(sirfsoc_irq_st.mask1, sirfsoc_intc_base + SIRFSOC_INT_RISC_MASK1); + writel_relaxed(sirfsoc_irq_st.level0, sirfsoc_intc_base + SIRFSOC_INT_RISC_LEVEL0); + writel_relaxed(sirfsoc_irq_st.level1, sirfsoc_intc_base + SIRFSOC_INT_RISC_LEVEL1); +} + +static struct syscore_ops sirfsoc_irq_syscore_ops = { + .suspend = sirfsoc_irq_suspend, + .resume = sirfsoc_irq_resume, +}; + +static int __init sirfsoc_irq_pm_init(void) +{ + register_syscore_ops(&sirfsoc_irq_syscore_ops); + return 0; +} +device_initcall(sirfsoc_irq_pm_init); diff --git a/arch/arm/mach-prima2/l2x0.c b/arch/arm/mach-prima2/l2x0.c index 9cda2057bcf..c99837797d7 100644 --- a/arch/arm/mach-prima2/l2x0.c +++ b/arch/arm/mach-prima2/l2x0.c @@ -8,52 +8,24 @@ #include <linux/init.h> #include <linux/kernel.h> -#include <linux/io.h> -#include <linux/errno.h> #include <linux/of.h> -#include <linux/of_address.h> #include <asm/hardware/cache-l2x0.h> -#include <mach/memory.h> -#define L2X0_ADDR_FILTERING_START 0xC00 -#define L2X0_ADDR_FILTERING_END 0xC04 - -static struct of_device_id l2x_ids[] = { - { .compatible = "arm,pl310-cache" }, +static struct of_device_id prima2_l2x0_ids[] = { + { .compatible = "sirf,prima2-pl310-cache" }, + {}, }; -static int __init sirfsoc_of_l2x_init(void) +static int __init sirfsoc_l2x0_init(void) { struct device_node *np; - void __iomem *sirfsoc_l2x_base; - - np = of_find_matching_node(NULL, l2x_ids); - if (!np) - panic("unable to find compatible l2x node in dtb\n"); - - sirfsoc_l2x_base = of_iomap(np, 0); - if (!sirfsoc_l2x_base) - panic("unable to map l2x cpu registers\n"); - - of_node_put(np); - - if (!(readl_relaxed(sirfsoc_l2x_base + L2X0_CTRL) & 1)) { - /* - * set the physical memory windows L2 cache will cover - */ - writel_relaxed(PLAT_PHYS_OFFSET + 1024 * 1024 * 1024, - sirfsoc_l2x_base + L2X0_ADDR_FILTERING_END); - writel_relaxed(PLAT_PHYS_OFFSET | 0x1, - sirfsoc_l2x_base + L2X0_ADDR_FILTERING_START); - writel_relaxed(0, - sirfsoc_l2x_base + L2X0_TAG_LATENCY_CTRL); - writel_relaxed(0, - sirfsoc_l2x_base + L2X0_DATA_LATENCY_CTRL); + np = of_find_matching_node(NULL, prima2_l2x0_ids); + if (np) { + pr_info("Initializing prima2 L2 cache\n"); + return l2x0_of_init(0x40000, 0); } - l2x0_init((void __iomem *)sirfsoc_l2x_base, 0x00040000, - 0x00000000); return 0; } -early_initcall(sirfsoc_of_l2x_init); +early_initcall(sirfsoc_l2x0_init); diff --git a/arch/arm/mach-prima2/pm.c b/arch/arm/mach-prima2/pm.c new file mode 100644 index 00000000000..cb53160f6c5 --- /dev/null +++ b/arch/arm/mach-prima2/pm.c @@ -0,0 +1,150 @@ +/* + * power management entry for CSR SiRFprimaII + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#include <linux/kernel.h> +#include <linux/suspend.h> +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/of_platform.h> +#include <linux/io.h> +#include <linux/rtc/sirfsoc_rtciobrg.h> +#include <asm/suspend.h> +#include <asm/hardware/cache-l2x0.h> + +#include "pm.h" + +/* + * suspend asm codes will access these to make DRAM become self-refresh and + * system sleep + */ +u32 sirfsoc_pwrc_base; +void __iomem *sirfsoc_memc_base; + +static void sirfsoc_set_wakeup_source(void) +{ + u32 pwr_trigger_en_reg; + pwr_trigger_en_reg = sirfsoc_rtc_iobrg_readl(sirfsoc_pwrc_base + + SIRFSOC_PWRC_TRIGGER_EN); +#define X_ON_KEY_B (1 << 0) + sirfsoc_rtc_iobrg_writel(pwr_trigger_en_reg | X_ON_KEY_B, + sirfsoc_pwrc_base + SIRFSOC_PWRC_TRIGGER_EN); +} + +static void sirfsoc_set_sleep_mode(u32 mode) +{ + u32 sleep_mode = sirfsoc_rtc_iobrg_readl(sirfsoc_pwrc_base + + SIRFSOC_PWRC_PDN_CTRL); + sleep_mode &= ~(SIRFSOC_SLEEP_MODE_MASK << 1); + sleep_mode |= mode << 1; + sirfsoc_rtc_iobrg_writel(sleep_mode, sirfsoc_pwrc_base + + SIRFSOC_PWRC_PDN_CTRL); +} + +static int sirfsoc_pre_suspend_power_off(void) +{ + u32 wakeup_entry = virt_to_phys(cpu_resume); + + sirfsoc_rtc_iobrg_writel(wakeup_entry, sirfsoc_pwrc_base + + SIRFSOC_PWRC_SCRATCH_PAD1); + + sirfsoc_set_wakeup_source(); + + sirfsoc_set_sleep_mode(SIRFSOC_DEEP_SLEEP_MODE); + + return 0; +} + +static int sirfsoc_pm_enter(suspend_state_t state) +{ + switch (state) { + case PM_SUSPEND_MEM: + sirfsoc_pre_suspend_power_off(); + + outer_flush_all(); + outer_disable(); + /* go zzz */ + cpu_suspend(0, sirfsoc_finish_suspend); + outer_resume(); + break; + default: + return -EINVAL; + } + return 0; +} + +static const struct platform_suspend_ops sirfsoc_pm_ops = { + .enter = sirfsoc_pm_enter, + .valid = suspend_valid_only_mem, +}; + +static int __init sirfsoc_pm_init(void) +{ + suspend_set_ops(&sirfsoc_pm_ops); + return 0; +} +late_initcall(sirfsoc_pm_init); + +static const struct of_device_id pwrc_ids[] = { + { .compatible = "sirf,prima2-pwrc" }, + {} +}; + +static int __init sirfsoc_of_pwrc_init(void) +{ + struct device_node *np; + + np = of_find_matching_node(NULL, pwrc_ids); + if (!np) + panic("unable to find compatible pwrc node in dtb\n"); + + /* + * pwrc behind rtciobrg is not located in memory space + * though the property is named reg. reg only means base + * offset for pwrc. then of_iomap is not suitable here. + */ + if (of_property_read_u32(np, "reg", &sirfsoc_pwrc_base)) + panic("unable to find base address of pwrc node in dtb\n"); + + of_node_put(np); + + return 0; +} +postcore_initcall(sirfsoc_of_pwrc_init); + +static const struct of_device_id memc_ids[] = { + { .compatible = "sirf,prima2-memc" }, + {} +}; + +static int __devinit sirfsoc_memc_probe(struct platform_device *op) +{ + struct device_node *np = op->dev.of_node; + + sirfsoc_memc_base = of_iomap(np, 0); + if (!sirfsoc_memc_base) + panic("unable to map memc registers\n"); + + return 0; +} + +static struct platform_driver sirfsoc_memc_driver = { + .probe = sirfsoc_memc_probe, + .driver = { + .name = "sirfsoc-memc", + .owner = THIS_MODULE, + .of_match_table = memc_ids, + }, +}; + +static int __init sirfsoc_memc_init(void) +{ + return platform_driver_register(&sirfsoc_memc_driver); +} +postcore_initcall(sirfsoc_memc_init); diff --git a/arch/arm/mach-prima2/pm.h b/arch/arm/mach-prima2/pm.h new file mode 100644 index 00000000000..bae6d77e01a --- /dev/null +++ b/arch/arm/mach-prima2/pm.h @@ -0,0 +1,29 @@ +/* + * arch/arm/mach-prima2/pm.h + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#ifndef _MACH_PRIMA2_PM_H_ +#define _MACH_PRIMA2_PM_H_ + +#define SIRFSOC_PWR_SLEEPFORCE 0x01 + +#define SIRFSOC_SLEEP_MODE_MASK 0x3 +#define SIRFSOC_DEEP_SLEEP_MODE 0x1 + +#define SIRFSOC_PWRC_PDN_CTRL 0x0 +#define SIRFSOC_PWRC_PON_OFF 0x4 +#define SIRFSOC_PWRC_TRIGGER_EN 0x8 +#define SIRFSOC_PWRC_PIN_STATUS 0x14 +#define SIRFSOC_PWRC_SCRATCH_PAD1 0x18 +#define SIRFSOC_PWRC_SCRATCH_PAD2 0x1C + +#ifndef __ASSEMBLY__ +extern int sirfsoc_finish_suspend(unsigned long); +#endif + +#endif + diff --git a/arch/arm/mach-prima2/prima2.c b/arch/arm/mach-prima2/prima2.c index f57124bdd14..ef555c04196 100644 --- a/arch/arm/mach-prima2/prima2.c +++ b/arch/arm/mach-prima2/prima2.c @@ -1,5 +1,5 @@ /* - * Defines machines for CSR SiRFprimaII + * Defines machines for CSR SiRFprimaII * * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. * @@ -31,11 +31,12 @@ static const char *prima2cb_dt_match[] __initdata = { MACHINE_START(PRIMA2_EVB, "prima2cb") /* Maintainer: Barry Song <baohua.song@csr.com> */ - .boot_params = 0x00000100, + .atag_offset = 0x100, .init_early = sirfsoc_of_clk_init, .map_io = sirfsoc_map_lluart, .init_irq = sirfsoc_of_irq_init, .timer = &sirfsoc_timer, + .dma_zone_size = SZ_256M, .init_machine = sirfsoc_mach_init, .dt_compat = prima2cb_dt_match, MACHINE_END diff --git a/arch/arm/mach-prima2/rtciobrg.c b/arch/arm/mach-prima2/rtciobrg.c new file mode 100644 index 00000000000..9d80f1e20a9 --- /dev/null +++ b/arch/arm/mach-prima2/rtciobrg.c @@ -0,0 +1,139 @@ +/* + * RTC I/O Bridge interfaces for CSR SiRFprimaII + * ARM access the registers of SYSRTC, GPSRTC and PWRC through this module + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/of_platform.h> + +#define SIRFSOC_CPUIOBRG_CTRL 0x00 +#define SIRFSOC_CPUIOBRG_WRBE 0x04 +#define SIRFSOC_CPUIOBRG_ADDR 0x08 +#define SIRFSOC_CPUIOBRG_DATA 0x0c + +/* + * suspend asm codes will access this address to make system deepsleep + * after DRAM becomes self-refresh + */ +void __iomem *sirfsoc_rtciobrg_base; +static DEFINE_SPINLOCK(rtciobrg_lock); + +/* + * symbols without lock are only used by suspend asm codes + * and these symbols are not exported too + */ +void sirfsoc_rtc_iobrg_wait_sync(void) +{ + while (readl_relaxed(sirfsoc_rtciobrg_base + SIRFSOC_CPUIOBRG_CTRL)) + cpu_relax(); +} + +void sirfsoc_rtc_iobrg_besyncing(void) +{ + unsigned long flags; + + spin_lock_irqsave(&rtciobrg_lock, flags); + + sirfsoc_rtc_iobrg_wait_sync(); + + spin_unlock_irqrestore(&rtciobrg_lock, flags); +} +EXPORT_SYMBOL_GPL(sirfsoc_rtc_iobrg_besyncing); + +u32 __sirfsoc_rtc_iobrg_readl(u32 addr) +{ + sirfsoc_rtc_iobrg_wait_sync(); + + writel_relaxed(0x00, sirfsoc_rtciobrg_base + SIRFSOC_CPUIOBRG_WRBE); + writel_relaxed(addr, sirfsoc_rtciobrg_base + SIRFSOC_CPUIOBRG_ADDR); + writel_relaxed(0x01, sirfsoc_rtciobrg_base + SIRFSOC_CPUIOBRG_CTRL); + + sirfsoc_rtc_iobrg_wait_sync(); + + return readl_relaxed(sirfsoc_rtciobrg_base + SIRFSOC_CPUIOBRG_DATA); +} + +u32 sirfsoc_rtc_iobrg_readl(u32 addr) +{ + unsigned long flags, val; + + spin_lock_irqsave(&rtciobrg_lock, flags); + + val = __sirfsoc_rtc_iobrg_readl(addr); + + spin_unlock_irqrestore(&rtciobrg_lock, flags); + + return val; +} +EXPORT_SYMBOL_GPL(sirfsoc_rtc_iobrg_readl); + +void sirfsoc_rtc_iobrg_pre_writel(u32 val, u32 addr) +{ + sirfsoc_rtc_iobrg_wait_sync(); + + writel_relaxed(0xf1, sirfsoc_rtciobrg_base + SIRFSOC_CPUIOBRG_WRBE); + writel_relaxed(addr, sirfsoc_rtciobrg_base + SIRFSOC_CPUIOBRG_ADDR); + + writel_relaxed(val, sirfsoc_rtciobrg_base + SIRFSOC_CPUIOBRG_DATA); +} + +void sirfsoc_rtc_iobrg_writel(u32 val, u32 addr) +{ + unsigned long flags; + + spin_lock_irqsave(&rtciobrg_lock, flags); + + sirfsoc_rtc_iobrg_pre_writel(val, addr); + + writel_relaxed(0x01, sirfsoc_rtciobrg_base + SIRFSOC_CPUIOBRG_CTRL); + + sirfsoc_rtc_iobrg_wait_sync(); + + spin_unlock_irqrestore(&rtciobrg_lock, flags); +} +EXPORT_SYMBOL_GPL(sirfsoc_rtc_iobrg_writel); + +static const struct of_device_id rtciobrg_ids[] = { + { .compatible = "sirf,prima2-rtciobg" }, + {} +}; + +static int __devinit sirfsoc_rtciobrg_probe(struct platform_device *op) +{ + struct device_node *np = op->dev.of_node; + + sirfsoc_rtciobrg_base = of_iomap(np, 0); + if (!sirfsoc_rtciobrg_base) + panic("unable to map rtc iobrg registers\n"); + + return 0; +} + +static struct platform_driver sirfsoc_rtciobrg_driver = { + .probe = sirfsoc_rtciobrg_probe, + .driver = { + .name = "sirfsoc-rtciobrg", + .owner = THIS_MODULE, + .of_match_table = rtciobrg_ids, + }, +}; + +static int __init sirfsoc_rtciobrg_init(void) +{ + return platform_driver_register(&sirfsoc_rtciobrg_driver); +} +postcore_initcall(sirfsoc_rtciobrg_init); + +MODULE_AUTHOR("Zhiwu Song <zhiwu.song@csr.com>, " + "Barry Song <baohua.song@csr.com>"); +MODULE_DESCRIPTION("CSR SiRFprimaII rtc io bridge"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-prima2/sleep.S b/arch/arm/mach-prima2/sleep.S new file mode 100644 index 00000000000..0745abc365f --- /dev/null +++ b/arch/arm/mach-prima2/sleep.S @@ -0,0 +1,64 @@ +/* + * sleep mode for CSR SiRFprimaII + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#include <linux/linkage.h> +#include <asm/ptrace.h> +#include <asm/assembler.h> + +#include "pm.h" + +#define DENALI_CTL_22_OFF 0x58 +#define DENALI_CTL_112_OFF 0x1c0 + + .text + +ENTRY(sirfsoc_finish_suspend) + @ r5: mem controller + ldr r0, =sirfsoc_memc_base + ldr r5, [r0] + @ r6: pwrc base offset + ldr r0, =sirfsoc_pwrc_base + ldr r6, [r0] + @ r7: rtc iobrg controller + ldr r0, =sirfsoc_rtciobrg_base + ldr r7, [r0] + + @ Read the power control register and set the + @ sleep force bit. + add r0, r6, #SIRFSOC_PWRC_PDN_CTRL + bl __sirfsoc_rtc_iobrg_readl + orr r0,r0,#SIRFSOC_PWR_SLEEPFORCE + add r1, r6, #SIRFSOC_PWRC_PDN_CTRL + bl sirfsoc_rtc_iobrg_pre_writel + mov r1, #0x1 + + @ read the MEM ctl register and set the self + @ refresh bit + + ldr r2, [r5, #DENALI_CTL_22_OFF] + orr r2, r2, #0x1 + + @ Following code has to run from cache since + @ the RAM is going to self refresh mode + .align 5 + str r2, [r5, #DENALI_CTL_22_OFF] + +1: + ldr r4, [r5, #DENALI_CTL_112_OFF] + tst r4, #0x1 + bne 1b + + @ write SLEEPFORCE through rtc iobridge + + str r1, [r7] + @ wait rtc io bridge sync +1: + ldr r3, [r7] + tst r3, #0x01 + bne 1b + b . diff --git a/arch/arm/mach-prima2/timer.c b/arch/arm/mach-prima2/timer.c index ed7ec48d11d..b7a6091ce79 100644 --- a/arch/arm/mach-prima2/timer.c +++ b/arch/arm/mach-prima2/timer.c @@ -40,6 +40,17 @@ #define SIRFSOC_TIMER_LATCH_BIT BIT(0) +#define SIRFSOC_TIMER_REG_CNT 11 + +static const u32 sirfsoc_timer_reg_list[SIRFSOC_TIMER_REG_CNT] = { + SIRFSOC_TIMER_MATCH_0, SIRFSOC_TIMER_MATCH_1, SIRFSOC_TIMER_MATCH_2, + SIRFSOC_TIMER_MATCH_3, SIRFSOC_TIMER_MATCH_4, SIRFSOC_TIMER_MATCH_5, + SIRFSOC_TIMER_INT_EN, SIRFSOC_TIMER_WATCHDOG_EN, SIRFSOC_TIMER_DIV, + SIRFSOC_TIMER_LATCHED_LO, SIRFSOC_TIMER_LATCHED_HI, +}; + +static u32 sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT]; + static void __iomem *sirfsoc_timer_base; static void __init sirfsoc_of_timer_map(void); @@ -106,6 +117,27 @@ static void sirfsoc_timer_set_mode(enum clock_event_mode mode, } } +static void sirfsoc_clocksource_suspend(struct clocksource *cs) +{ + int i; + + writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH); + + for (i = 0; i < SIRFSOC_TIMER_REG_CNT; i++) + sirfsoc_timer_reg_val[i] = readl_relaxed(sirfsoc_timer_base + sirfsoc_timer_reg_list[i]); +} + +static void sirfsoc_clocksource_resume(struct clocksource *cs) +{ + int i; + + for (i = 0; i < SIRFSOC_TIMER_REG_CNT; i++) + writel_relaxed(sirfsoc_timer_reg_val[i], sirfsoc_timer_base + sirfsoc_timer_reg_list[i]); + + writel_relaxed(sirfsoc_timer_reg_val[i - 2], sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_LO); + writel_relaxed(sirfsoc_timer_reg_val[i - 1], sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_HI); +} + static struct clock_event_device sirfsoc_clockevent = { .name = "sirfsoc_clockevent", .rating = 200, @@ -120,6 +152,8 @@ static struct clocksource sirfsoc_clocksource = { .mask = CLOCKSOURCE_MASK(64), .flags = CLOCK_SOURCE_IS_CONTINUOUS, .read = sirfsoc_timer_read, + .suspend = sirfsoc_clocksource_suspend, + .resume = sirfsoc_clocksource_resume, }; static struct irqaction sirfsoc_timer_irq = { @@ -133,14 +167,14 @@ static struct irqaction sirfsoc_timer_irq = { /* Overwrite weak default sched_clock with more precise one */ unsigned long long notrace sched_clock(void) { - static int is_mapped = 0; + static int is_mapped; /* * sched_clock is called earlier than .init of sys_timer * if we map timer memory in .init of sys_timer, system * will panic due to illegal memory access */ - if(!is_mapped) { + if (!is_mapped) { sirfsoc_of_timer_map(); is_mapped = 1; } |