diff options
Diffstat (limited to 'arch/arm/mach-integrator/core.c')
| -rw-r--r-- | arch/arm/mach-integrator/core.c | 401 |
1 files changed, 133 insertions, 268 deletions
diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c index a0f60e55da6..e3f3aca43ef 100644 --- a/arch/arm/mach-integrator/core.c +++ b/arch/arm/mach-integrator/core.c @@ -11,327 +11,192 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/device.h> +#include <linux/export.h> #include <linux/spinlock.h> #include <linux/interrupt.h> #include <linux/irq.h> +#include <linux/memblock.h> #include <linux/sched.h> #include <linux/smp.h> -#include <linux/termios.h> #include <linux/amba/bus.h> #include <linux/amba/serial.h> #include <linux/io.h> +#include <linux/stat.h> +#include <linux/of.h> +#include <linux/of_address.h> -#include <asm/clkdev.h> -#include <mach/clkdev.h> -#include <mach/hardware.h> -#include <asm/irq.h> -#include <asm/hardware/arm_timer.h> -#include <mach/cm.h> -#include <asm/system.h> -#include <asm/leds.h> +#include <asm/mach-types.h> #include <asm/mach/time.h> +#include <asm/pgtable.h> +#include "hardware.h" +#include "cm.h" #include "common.h" -static struct amba_pl010_data integrator_uart_data; +static DEFINE_RAW_SPINLOCK(cm_lock); +static void __iomem *cm_base; -static struct amba_device rtc_device = { - .dev = { - .init_name = "mb:15", - }, - .res = { - .start = INTEGRATOR_RTC_BASE, - .end = INTEGRATOR_RTC_BASE + SZ_4K - 1, - .flags = IORESOURCE_MEM, - }, - .irq = { IRQ_RTCINT, NO_IRQ }, - .periphid = 0x00041030, -}; - -static struct amba_device uart0_device = { - .dev = { - .init_name = "mb:16", - .platform_data = &integrator_uart_data, - }, - .res = { - .start = INTEGRATOR_UART0_BASE, - .end = INTEGRATOR_UART0_BASE + SZ_4K - 1, - .flags = IORESOURCE_MEM, - }, - .irq = { IRQ_UARTINT0, NO_IRQ }, - .periphid = 0x0041010, -}; - -static struct amba_device uart1_device = { - .dev = { - .init_name = "mb:17", - .platform_data = &integrator_uart_data, - }, - .res = { - .start = INTEGRATOR_UART1_BASE, - .end = INTEGRATOR_UART1_BASE + SZ_4K - 1, - .flags = IORESOURCE_MEM, - }, - .irq = { IRQ_UARTINT1, NO_IRQ }, - .periphid = 0x0041010, -}; - -static struct amba_device kmi0_device = { - .dev = { - .init_name = "mb:18", - }, - .res = { - .start = KMI0_BASE, - .end = KMI0_BASE + SZ_4K - 1, - .flags = IORESOURCE_MEM, - }, - .irq = { IRQ_KMIINT0, NO_IRQ }, - .periphid = 0x00041050, -}; - -static struct amba_device kmi1_device = { - .dev = { - .init_name = "mb:19", - }, - .res = { - .start = KMI1_BASE, - .end = KMI1_BASE + SZ_4K - 1, - .flags = IORESOURCE_MEM, - }, - .irq = { IRQ_KMIINT1, NO_IRQ }, - .periphid = 0x00041050, -}; - -static struct amba_device *amba_devs[] __initdata = { - &rtc_device, - &uart0_device, - &uart1_device, - &kmi0_device, - &kmi1_device, -}; - -/* - * These are fixed clocks. +/** + * cm_get - get the value from the CM_CTRL register */ -static struct clk clk24mhz = { - .rate = 24000000, -}; - -static struct clk uartclk = { - .rate = 14745600, -}; - -static struct clk_lookup lookups[] = { - { /* UART0 */ - .dev_id = "mb:16", - .clk = &uartclk, - }, { /* UART1 */ - .dev_id = "mb:17", - .clk = &uartclk, - }, { /* KMI0 */ - .dev_id = "mb:18", - .clk = &clk24mhz, - }, { /* KMI1 */ - .dev_id = "mb:19", - .clk = &clk24mhz, - }, { /* MMCI - IntegratorCP */ - .dev_id = "mb:1c", - .clk = &uartclk, - } -}; +u32 cm_get(void) +{ + return readl(cm_base + INTEGRATOR_HDR_CTRL_OFFSET); +} -static int __init integrator_init(void) +/** + * cm_control - update the CM_CTRL register. + * @mask: bits to change + * @set: bits to set + */ +void cm_control(u32 mask, u32 set) { - int i; + unsigned long flags; + u32 val; - for (i = 0; i < ARRAY_SIZE(lookups); i++) - clkdev_add(&lookups[i]); + raw_spin_lock_irqsave(&cm_lock, flags); + val = readl(cm_base + INTEGRATOR_HDR_CTRL_OFFSET) & ~mask; + writel(val | set, cm_base + INTEGRATOR_HDR_CTRL_OFFSET); + raw_spin_unlock_irqrestore(&cm_lock, flags); +} - for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { - struct amba_device *d = amba_devs[i]; - amba_device_register(d, &iomem_resource); +static const char *integrator_arch_str(u32 id) +{ + switch ((id >> 16) & 0xff) { + case 0x00: + return "ASB little-endian"; + case 0x01: + return "AHB little-endian"; + case 0x03: + return "AHB-Lite system bus, bi-endian"; + case 0x04: + return "AHB"; + case 0x08: + return "AHB system bus, ASB processor bus"; + default: + return "Unknown"; } - - return 0; } -arch_initcall(integrator_init); - -/* - * On the Integrator platform, the port RTS and DTR are provided by - * bits in the following SC_CTRLS register bits: - * RTS DTR - * UART0 7 6 - * UART1 5 4 - */ -#define SC_CTRLC (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLC_OFFSET) -#define SC_CTRLS (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLS_OFFSET) - -static void integrator_uart_set_mctrl(struct amba_device *dev, void __iomem *base, unsigned int mctrl) +static const char *integrator_fpga_str(u32 id) { - unsigned int ctrls = 0, ctrlc = 0, rts_mask, dtr_mask; - - if (dev == &uart0_device) { - rts_mask = 1 << 4; - dtr_mask = 1 << 5; - } else { - rts_mask = 1 << 6; - dtr_mask = 1 << 7; + switch ((id >> 12) & 0xf) { + case 0x01: + return "XC4062"; + case 0x02: + return "XC4085"; + case 0x03: + return "XVC600"; + case 0x04: + return "EPM7256AE (Altera PLD)"; + default: + return "Unknown"; } +} - if (mctrl & TIOCM_RTS) - ctrlc |= rts_mask; - else - ctrls |= rts_mask; - - if (mctrl & TIOCM_DTR) - ctrlc |= dtr_mask; - else - ctrls |= dtr_mask; - - __raw_writel(ctrls, SC_CTRLS); - __raw_writel(ctrlc, SC_CTRLC); +void cm_clear_irqs(void) +{ + /* disable core module IRQs */ + writel(0xffffffffU, cm_base + INTEGRATOR_HDR_IC_OFFSET + + IRQ_ENABLE_CLEAR); } -static struct amba_pl010_data integrator_uart_data = { - .set_mctrl = integrator_uart_set_mctrl, +static const struct of_device_id cm_match[] = { + { .compatible = "arm,core-module-integrator"}, + { }, }; -#define CM_CTRL IO_ADDRESS(INTEGRATOR_HDR_BASE) + INTEGRATOR_HDR_CTRL_OFFSET - -static DEFINE_SPINLOCK(cm_lock); - -/** - * cm_control - update the CM_CTRL register. - * @mask: bits to change - * @set: bits to set - */ -void cm_control(u32 mask, u32 set) +void cm_init(void) { - unsigned long flags; + struct device_node *cm = of_find_matching_node(NULL, cm_match); u32 val; - spin_lock_irqsave(&cm_lock, flags); - val = readl(CM_CTRL) & ~mask; - writel(val | set, CM_CTRL); - spin_unlock_irqrestore(&cm_lock, flags); + if (!cm) { + pr_crit("no core module node found in device tree\n"); + return; + } + cm_base = of_iomap(cm, 0); + if (!cm_base) { + pr_crit("could not remap core module\n"); + return; + } + cm_clear_irqs(); + val = readl(cm_base + INTEGRATOR_HDR_ID_OFFSET); + pr_info("Detected ARM core module:\n"); + pr_info(" Manufacturer: %02x\n", (val >> 24)); + pr_info(" Architecture: %s\n", integrator_arch_str(val)); + pr_info(" FPGA: %s\n", integrator_fpga_str(val)); + pr_info(" Build: %02x\n", (val >> 4) & 0xFF); + pr_info(" Rev: %c\n", ('A' + (val & 0x03))); } -EXPORT_SYMBOL(cm_control); - -/* - * Where is the timer (VA)? - */ -#define TIMER0_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000000) -#define TIMER1_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000100) -#define TIMER2_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000200) -#define VA_IC_BASE IO_ADDRESS(INTEGRATOR_IC_BASE) - /* - * How long is the timer interval? + * We need to stop things allocating the low memory; ideally we need a + * better implementation of GFP_DMA which does not assume that DMA-able + * memory starts at zero. */ -#define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10) -#if TIMER_INTERVAL >= 0x100000 -#define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC) -#elif TIMER_INTERVAL >= 0x10000 -#define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC) -#else -#define TICKS2USECS(x) ((x) / TICKS_PER_uSEC) -#endif - -static unsigned long timer_reload; +void __init integrator_reserve(void) +{ + memblock_reserve(PHYS_OFFSET, __pa(swapper_pg_dir) - PHYS_OFFSET); +} /* - * Returns number of ms since last clock interrupt. Note that interrupts - * will have been disabled by do_gettimeoffset() + * To reset, we hit the on-board reset register in the system FPGA */ -unsigned long integrator_gettimeoffset(void) +void integrator_restart(enum reboot_mode mode, const char *cmd) { - unsigned long ticks1, ticks2, status; - - /* - * Get the current number of ticks. Note that there is a race - * condition between us reading the timer and checking for - * an interrupt. We get around this by ensuring that the - * counter has not reloaded between our two reads. - */ - ticks2 = readl(TIMER1_VA_BASE + TIMER_VALUE) & 0xffff; - do { - ticks1 = ticks2; - status = __raw_readl(VA_IC_BASE + IRQ_RAW_STATUS); - ticks2 = readl(TIMER1_VA_BASE + TIMER_VALUE) & 0xffff; - } while (ticks2 > ticks1); - - /* - * Number of ticks since last interrupt. - */ - ticks1 = timer_reload - ticks2; + cm_control(CM_CTRL_RESET, CM_CTRL_RESET); +} - /* - * Interrupt pending? If so, we've reloaded once already. - */ - if (status & (1 << IRQ_TIMERINT1)) - ticks1 += timer_reload; +static u32 integrator_id; - /* - * Convert the ticks to usecs - */ - return TICKS2USECS(ticks1); +static ssize_t intcp_get_manf(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%02x\n", integrator_id >> 24); } -/* - * IRQ handler for the timer - */ -static irqreturn_t -integrator_timer_interrupt(int irq, void *dev_id) +static struct device_attribute intcp_manf_attr = + __ATTR(manufacturer, S_IRUGO, intcp_get_manf, NULL); + +static ssize_t intcp_get_arch(struct device *dev, + struct device_attribute *attr, + char *buf) { - /* - * clear the interrupt - */ - writel(1, TIMER1_VA_BASE + TIMER_INTCLR); + return sprintf(buf, "%s\n", integrator_arch_str(integrator_id)); +} - timer_tick(); +static struct device_attribute intcp_arch_attr = + __ATTR(architecture, S_IRUGO, intcp_get_arch, NULL); - return IRQ_HANDLED; +static ssize_t intcp_get_fpga(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%s\n", integrator_fpga_str(integrator_id)); } -static struct irqaction integrator_timer_irq = { - .name = "Integrator Timer Tick", - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, - .handler = integrator_timer_interrupt, -}; +static struct device_attribute intcp_fpga_attr = + __ATTR(fpga, S_IRUGO, intcp_get_fpga, NULL); -/* - * Set up timer interrupt, and return the current time in seconds. - */ -void __init integrator_time_init(unsigned long reload, unsigned int ctrl) +static ssize_t intcp_get_build(struct device *dev, + struct device_attribute *attr, + char *buf) { - unsigned int timer_ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC; - - timer_reload = reload; - timer_ctrl |= ctrl; + return sprintf(buf, "%02x\n", (integrator_id >> 4) & 0xFF); +} - if (timer_reload > 0x100000) { - timer_reload >>= 8; - timer_ctrl |= TIMER_CTRL_DIV256; - } else if (timer_reload > 0x010000) { - timer_reload >>= 4; - timer_ctrl |= TIMER_CTRL_DIV16; - } +static struct device_attribute intcp_build_attr = + __ATTR(build, S_IRUGO, intcp_get_build, NULL); - /* - * Initialise to a known state (all timers off) - */ - writel(0, TIMER0_VA_BASE + TIMER_CTRL); - writel(0, TIMER1_VA_BASE + TIMER_CTRL); - writel(0, TIMER2_VA_BASE + TIMER_CTRL); - writel(timer_reload, TIMER1_VA_BASE + TIMER_LOAD); - writel(timer_reload, TIMER1_VA_BASE + TIMER_VALUE); - writel(timer_ctrl, TIMER1_VA_BASE + TIMER_CTRL); - /* - * Make irqs happen for the system timer - */ - setup_irq(IRQ_TIMERINT1, &integrator_timer_irq); +void integrator_init_sysfs(struct device *parent, u32 id) +{ + integrator_id = id; + device_create_file(parent, &intcp_manf_attr); + device_create_file(parent, &intcp_arch_attr); + device_create_file(parent, &intcp_fpga_attr); + device_create_file(parent, &intcp_build_attr); } |
