Initial commit; kernel source import

This commit is contained in:
Nathan
2025-04-06 23:50:55 -05:00
commit 25c6d769f4
45093 changed files with 18199410 additions and 0 deletions

View File

@@ -0,0 +1,50 @@
config ARCH_SIRF
bool "CSR SiRF" if ARCH_MULTI_V7
select ARCH_REQUIRE_GPIOLIB
select GENERIC_CLOCKEVENTS
select GENERIC_IRQ_CHIP
select MIGHT_HAVE_CACHE_L2X0
select NO_IOPORT
select PINCTRL
select PINCTRL_SIRF
help
Support for CSR SiRFprimaII/Marco/Polo platforms
if ARCH_SIRF
menu "CSR SiRF atlas6/primaII/Marco/Polo Specific Features"
config ARCH_ATLAS6
bool "CSR SiRFSoC ATLAS6 ARM Cortex A9 Platform"
default y
select CPU_V7
select SIRF_IRQ
help
Support for CSR SiRFSoC ARM Cortex A9 Platform
config ARCH_PRIMA2
bool "CSR SiRFSoC PRIMA2 ARM Cortex A9 Platform"
default y
select CPU_V7
select SIRF_IRQ
select ZONE_DMA
help
Support for CSR SiRFSoC ARM Cortex A9 Platform
config ARCH_MARCO
bool "CSR SiRFSoC MARCO ARM Cortex A9 Platform"
default y
select ARM_GIC
select CPU_V7
select HAVE_ARM_SCU if SMP
select HAVE_SMP
select SMP_ON_UP if SMP
help
Support for CSR SiRFSoC ARM Cortex A9 Platform
endmenu
config SIRF_IRQ
bool
endif

View File

@@ -0,0 +1,10 @@
obj-y += rstc.o
obj-y += common.o
obj-y += rtciobrg.o
obj-$(CONFIG_DEBUG_LL) += lluart.o
obj-$(CONFIG_CACHE_L2X0) += l2x0.o
obj-$(CONFIG_SUSPEND) += pm.o sleep.o
obj-$(CONFIG_SMP) += platsmp.o headsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
CFLAGS_hotplug.o += -march=armv7-a

View File

@@ -0,0 +1,3 @@
zreladdr-y += 0x00008000
params_phys-y := 0x00000100
initrd_phys-y := 0x00800000

View File

@@ -0,0 +1,104 @@
/*
* Defines machines for CSR SiRFprimaII
*
* Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
*
* Licensed under GPLv2 or later.
*/
#include <linux/clocksource.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/irqchip.h>
#include <asm/sizes.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include "common.h"
static struct of_device_id sirfsoc_of_bus_ids[] __initdata = {
{ .compatible = "simple-bus", },
{},
};
void __init sirfsoc_mach_init(void)
{
of_platform_bus_probe(NULL, sirfsoc_of_bus_ids, NULL);
}
void __init sirfsoc_init_late(void)
{
sirfsoc_pm_init();
}
static __init void sirfsoc_init_time(void)
{
/* initialize clocking early, we want to set the OS timer */
sirfsoc_of_clk_init();
clocksource_of_init();
}
static __init void sirfsoc_map_io(void)
{
sirfsoc_map_lluart();
sirfsoc_map_scu();
}
#ifdef CONFIG_ARCH_ATLAS6
static const char *atlas6_dt_match[] __initdata = {
"sirf,atlas6",
NULL
};
DT_MACHINE_START(ATLAS6_DT, "Generic ATLAS6 (Flattened Device Tree)")
/* Maintainer: Barry Song <baohua.song@csr.com> */
.nr_irqs = 128,
.map_io = sirfsoc_map_io,
.init_irq = irqchip_init,
.init_time = sirfsoc_init_time,
.init_machine = sirfsoc_mach_init,
.init_late = sirfsoc_init_late,
.dt_compat = atlas6_dt_match,
.restart = sirfsoc_restart,
MACHINE_END
#endif
#ifdef CONFIG_ARCH_PRIMA2
static const char *prima2_dt_match[] __initdata = {
"sirf,prima2",
NULL
};
DT_MACHINE_START(PRIMA2_DT, "Generic PRIMA2 (Flattened Device Tree)")
/* Maintainer: Barry Song <baohua.song@csr.com> */
.nr_irqs = 128,
.map_io = sirfsoc_map_io,
.init_irq = irqchip_init,
.init_time = sirfsoc_init_time,
.dma_zone_size = SZ_256M,
.init_machine = sirfsoc_mach_init,
.init_late = sirfsoc_init_late,
.dt_compat = prima2_dt_match,
.restart = sirfsoc_restart,
MACHINE_END
#endif
#ifdef CONFIG_ARCH_MARCO
static const char *marco_dt_match[] __initdata = {
"sirf,marco",
NULL
};
DT_MACHINE_START(MARCO_DT, "Generic MARCO (Flattened Device Tree)")
/* Maintainer: Barry Song <baohua.song@csr.com> */
.smp = smp_ops(sirfsoc_smp_ops),
.map_io = sirfsoc_map_io,
.init_irq = irqchip_init,
.init_time = sirfsoc_init_time,
.init_machine = sirfsoc_mach_init,
.init_late = sirfsoc_init_late,
.dt_compat = marco_dt_match,
.restart = sirfsoc_restart,
MACHINE_END
#endif

View File

@@ -0,0 +1,46 @@
/*
* This file contains common function prototypes to avoid externs in the c files.
*
* Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
*
* Licensed under GPLv2 or later.
*/
#ifndef __MACH_PRIMA2_COMMON_H__
#define __MACH_PRIMA2_COMMON_H__
#include <linux/init.h>
#include <asm/mach/time.h>
#include <asm/exception.h>
#define SIRFSOC_VA_BASE _AC(0xFEC00000, UL)
#define SIRFSOC_VA(x) (SIRFSOC_VA_BASE + ((x) & 0x00FFF000))
extern struct smp_operations sirfsoc_smp_ops;
extern void sirfsoc_secondary_startup(void);
extern void sirfsoc_cpu_die(unsigned int cpu);
extern void __init sirfsoc_of_irq_init(void);
extern void __init sirfsoc_of_clk_init(void);
extern void sirfsoc_restart(char, const char *);
extern asmlinkage void __exception_irq_entry sirfsoc_handle_irq(struct pt_regs *regs);
#ifndef CONFIG_DEBUG_LL
static inline void sirfsoc_map_lluart(void) {}
#else
extern void __init sirfsoc_map_lluart(void);
#endif
#ifndef CONFIG_SMP
static inline void sirfsoc_map_scu(void) {}
#else
extern void sirfsoc_map_scu(void);
#endif
#ifdef CONFIG_SUSPEND
extern int sirfsoc_pm_init(void);
#else
static inline int sirfsoc_pm_init(void) { return 0; }
#endif
#endif

View File

@@ -0,0 +1,40 @@
/*
* Entry of the second core for CSR Marco dual-core SMP SoCs
*
* Copyright (c) 2012 Cambridge Silicon Radio Limited, a CSR plc group company.
*
* Licensed under GPLv2 or later.
*/
#include <linux/linkage.h>
#include <linux/init.h>
__CPUINIT
/*
* SIRFSOC specific entry point for secondary CPUs. This provides
* a "holding pen" into which all secondary cores are held until we're
* ready for them to initialise.
*/
ENTRY(sirfsoc_secondary_startup)
bl v7_invalidate_l1
mrc p15, 0, r0, c0, c0, 5
and r0, r0, #15
adr r4, 1f
ldmia r4, {r5, r6}
sub r4, r4, r5
add r6, r6, r4
pen: ldr r7, [r6]
cmp r7, r0
bne pen
/*
* we've been released from the holding pen: secondary_stack
* should now contain the SVC stack for this core
*/
b secondary_startup
ENDPROC(sirfsoc_secondary_startup)
.align
1: .long .
.long pen_release

View File

@@ -0,0 +1,38 @@
/*
* CPU hotplug support for CSR Marco dual-core SMP SoCs
*
* Copyright (c) 2012 Cambridge Silicon Radio Limited, a CSR plc group company.
*
* Licensed under GPLv2 or later.
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/smp.h>
#include <asm/smp_plat.h>
static inline void platform_do_lowpower(unsigned int cpu)
{
/* we put the platform to just WFI */
for (;;) {
__asm__ __volatile__("dsb\n\t" "wfi\n\t"
: : : "memory");
if (pen_release == cpu_logical_map(cpu)) {
/*
* OK, proper wakeup, we're done
*/
break;
}
}
}
/*
* platform-specific code to shutdown a CPU
*
* Called with IRQs disabled
*/
void __ref sirfsoc_cpu_die(unsigned int cpu)
{
platform_do_lowpower(cpu);
}

View File

@@ -0,0 +1,50 @@
/*
* l2 cache initialization for CSR SiRFprimaII
*
* Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
*
* Licensed under GPLv2 or later.
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <asm/hardware/cache-l2x0.h>
struct l2x0_aux
{
u32 val;
u32 mask;
};
static struct l2x0_aux prima2_l2x0_aux __initconst = {
.val = 2 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT,
.mask = 0,
};
static struct l2x0_aux marco_l2x0_aux __initconst = {
.val = (2 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT) |
(1 << L2X0_AUX_CTRL_ASSOCIATIVITY_SHIFT),
.mask = L2X0_AUX_CTRL_MASK,
};
static struct of_device_id sirf_l2x0_ids[] __initconst = {
{ .compatible = "sirf,prima2-pl310-cache", .data = &prima2_l2x0_aux, },
{ .compatible = "sirf,marco-pl310-cache", .data = &marco_l2x0_aux, },
{},
};
static int __init sirfsoc_l2x0_init(void)
{
struct device_node *np;
const struct l2x0_aux *aux;
np = of_find_matching_node(NULL, sirf_l2x0_ids);
if (np) {
aux = of_match_node(sirf_l2x0_ids, np)->data;
return l2x0_of_init(aux->val, aux->mask);
}
return 0;
}
early_initcall(sirfsoc_l2x0_init);

View File

@@ -0,0 +1,35 @@
/*
* Static memory mapping for DEBUG_LL
*
* Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
*
* Licensed under GPLv2 or later.
*/
#include <linux/kernel.h>
#include <asm/page.h>
#include <asm/mach/map.h>
#include "common.h"
#if defined(CONFIG_DEBUG_SIRFPRIMA2_UART1)
#define SIRFSOC_UART1_PA_BASE 0xb0060000
#elif defined(CONFIG_DEBUG_SIRFMARCO_UART1)
#define SIRFSOC_UART1_PA_BASE 0xcc060000
#else
#define SIRFSOC_UART1_PA_BASE 0
#endif
#define SIRFSOC_UART1_VA_BASE SIRFSOC_VA(0x060000)
#define SIRFSOC_UART1_SIZE SZ_4K
void __init sirfsoc_map_lluart(void)
{
struct map_desc sirfsoc_lluart_map = {
.virtual = SIRFSOC_UART1_VA_BASE,
.pfn = __phys_to_pfn(SIRFSOC_UART1_PA_BASE),
.length = SIRFSOC_UART1_SIZE,
.type = MT_DEVICE,
};
iotable_init(&sirfsoc_lluart_map, 1);
}

View File

@@ -0,0 +1,148 @@
/*
* plat smp support for CSR Marco dual-core SMP SoCs
*
* Copyright (c) 2012 Cambridge Silicon Radio Limited, a CSR plc group company.
*
* Licensed under GPLv2 or later.
*/
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <asm/page.h>
#include <asm/mach/map.h>
#include <asm/smp_plat.h>
#include <asm/smp_scu.h>
#include <asm/cacheflush.h>
#include <asm/cputype.h>
#include "common.h"
static void __iomem *scu_base;
static void __iomem *rsc_base;
static DEFINE_SPINLOCK(boot_lock);
static struct map_desc scu_io_desc __initdata = {
.length = SZ_4K,
.type = MT_DEVICE,
};
void __init sirfsoc_map_scu(void)
{
unsigned long base;
/* Get SCU base */
asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (base));
scu_io_desc.virtual = SIRFSOC_VA(base);
scu_io_desc.pfn = __phys_to_pfn(base);
iotable_init(&scu_io_desc, 1);
scu_base = (void __iomem *)SIRFSOC_VA(base);
}
static void __cpuinit sirfsoc_secondary_init(unsigned int cpu)
{
/*
* let the primary processor know we're out of the
* pen, then head off into the C entry point
*/
pen_release = -1;
smp_wmb();
/*
* Synchronise with the boot thread.
*/
spin_lock(&boot_lock);
spin_unlock(&boot_lock);
}
static struct of_device_id rsc_ids[] = {
{ .compatible = "sirf,marco-rsc" },
{},
};
static int __cpuinit sirfsoc_boot_secondary(unsigned int cpu, struct task_struct *idle)
{
unsigned long timeout;
struct device_node *np;
np = of_find_matching_node(NULL, rsc_ids);
if (!np)
return -ENODEV;
rsc_base = of_iomap(np, 0);
if (!rsc_base)
return -ENOMEM;
/*
* write the address of secondary startup into the sram register
* at offset 0x2C, then write the magic number 0x3CAF5D62 to the
* RSC register at offset 0x28, which is what boot rom code is
* waiting for. This would wake up the secondary core from WFE
*/
#define SIRFSOC_CPU1_JUMPADDR_OFFSET 0x2C
__raw_writel(virt_to_phys(sirfsoc_secondary_startup),
rsc_base + SIRFSOC_CPU1_JUMPADDR_OFFSET);
#define SIRFSOC_CPU1_WAKEMAGIC_OFFSET 0x28
__raw_writel(0x3CAF5D62,
rsc_base + SIRFSOC_CPU1_WAKEMAGIC_OFFSET);
/* make sure write buffer is drained */
mb();
spin_lock(&boot_lock);
/*
* The secondary processor is waiting to be released from
* the holding pen - release it, then wait for it to flag
* that it has been released by resetting pen_release.
*
* Note that "pen_release" is the hardware CPU ID, whereas
* "cpu" is Linux's internal ID.
*/
pen_release = cpu_logical_map(cpu);
__cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
/*
* Send the secondary CPU SEV, thereby causing the boot monitor to read
* the JUMPADDR and WAKEMAGIC, and branch to the address found there.
*/
dsb_sev();
timeout = jiffies + (1 * HZ);
while (time_before(jiffies, timeout)) {
smp_rmb();
if (pen_release == -1)
break;
udelay(10);
}
/*
* now the secondary core is starting up let it run its
* calibrations, then wait for it to finish
*/
spin_unlock(&boot_lock);
return pen_release != -1 ? -ENOSYS : 0;
}
static void __init sirfsoc_smp_prepare_cpus(unsigned int max_cpus)
{
scu_enable(scu_base);
}
struct smp_operations sirfsoc_smp_ops __initdata = {
.smp_prepare_cpus = sirfsoc_smp_prepare_cpus,
.smp_secondary_init = sirfsoc_secondary_init,
.smp_boot_secondary = sirfsoc_boot_secondary,
#ifdef CONFIG_HOTPLUG_CPU
.cpu_die = sirfsoc_cpu_die,
#endif
};

152
arch/arm/mach-prima2/pm.c Normal file
View File

@@ -0,0 +1,152 @@
/*
* 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/module.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,
};
int __init sirfsoc_pm_init(void)
{
suspend_set_ops(&sirfsoc_pm_ops);
return 0;
}
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) {
pr_err("unable to find compatible sirf pwrc node in dtb\n");
return -ENOENT;
}
/*
* 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 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);

29
arch/arm/mach-prima2/pm.h Normal file
View File

@@ -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

View File

@@ -0,0 +1,90 @@
/*
* reset controller 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/mutex.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
void __iomem *sirfsoc_rstc_base;
static DEFINE_MUTEX(rstc_lock);
static struct of_device_id rstc_ids[] = {
{ .compatible = "sirf,prima2-rstc" },
{ .compatible = "sirf,marco-rstc" },
{},
};
static int __init sirfsoc_of_rstc_init(void)
{
struct device_node *np;
np = of_find_matching_node(NULL, rstc_ids);
if (!np) {
pr_err("unable to find compatible sirf rstc node in dtb\n");
return -ENOENT;
}
sirfsoc_rstc_base = of_iomap(np, 0);
if (!sirfsoc_rstc_base)
panic("unable to map rstc cpu registers\n");
of_node_put(np);
return 0;
}
early_initcall(sirfsoc_of_rstc_init);
int sirfsoc_reset_device(struct device *dev)
{
u32 reset_bit;
if (of_property_read_u32(dev->of_node, "reset-bit", &reset_bit))
return -EINVAL;
mutex_lock(&rstc_lock);
if (of_device_is_compatible(dev->of_node, "sirf,prima2-rstc")) {
/*
* Writing 1 to this bit resets corresponding block. Writing 0 to this
* bit de-asserts reset signal of the corresponding block.
* datasheet doesn't require explicit delay between the set and clear
* of reset bit. it could be shorter if tests pass.
*/
writel(readl(sirfsoc_rstc_base + (reset_bit / 32) * 4) | reset_bit,
sirfsoc_rstc_base + (reset_bit / 32) * 4);
msleep(10);
writel(readl(sirfsoc_rstc_base + (reset_bit / 32) * 4) & ~reset_bit,
sirfsoc_rstc_base + (reset_bit / 32) * 4);
} else {
/*
* For MARCO and POLO
* Writing 1 to SET register resets corresponding block. Writing 1 to CLEAR
* register de-asserts reset signal of the corresponding block.
* datasheet doesn't require explicit delay between the set and clear
* of reset bit. it could be shorter if tests pass.
*/
writel(reset_bit, sirfsoc_rstc_base + (reset_bit / 32) * 8);
msleep(10);
writel(reset_bit, sirfsoc_rstc_base + (reset_bit / 32) * 8 + 4);
}
mutex_unlock(&rstc_lock);
return 0;
}
#define SIRFSOC_SYS_RST_BIT BIT(31)
void sirfsoc_restart(char mode, const char *cmd)
{
writel(SIRFSOC_SYS_RST_BIT, sirfsoc_rstc_base);
}

View File

@@ -0,0 +1,140 @@
/*
* 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" },
{ .compatible = "sirf,marco-rtciobg" },
{}
};
static int 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");

View File

@@ -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 .