diff options
Diffstat (limited to 'arch/arm/mach-integrator')
23 files changed, 1873 insertions, 1869 deletions
diff --git a/arch/arm/mach-integrator/Kconfig b/arch/arm/mach-integrator/Kconfig index df97d16390e..64f8e2564a3 100644 --- a/arch/arm/mach-integrator/Kconfig +++ b/arch/arm/mach-integrator/Kconfig @@ -4,6 +4,11 @@ menu "Integrator Options" config ARCH_INTEGRATOR_AP bool "Support Integrator/AP and Integrator/PP2 platforms" + select CLKSRC_MMIO + select MIGHT_HAVE_PCI + select SERIAL_AMBA_PL010 if TTY + select SERIAL_AMBA_PL010_CONSOLE if TTY + select SOC_BUS help Include support for the ARM(R) Integrator/AP and Integrator/PP2 platforms. @@ -11,6 +16,11 @@ config ARCH_INTEGRATOR_AP config ARCH_INTEGRATOR_CP bool "Support Integrator/CP platform" select ARCH_CINTEGRATOR + select ARM_TIMER_SP804 + select PLAT_VERSATILE_CLCD + select SERIAL_AMBA_PL011 if TTY + select SERIAL_AMBA_PL011_CONSOLE if TTY + select SOC_BUS help Include support for the ARM(R) Integrator CP platform. @@ -18,8 +28,11 @@ config ARCH_CINTEGRATOR bool config INTEGRATOR_IMPD1 - tristate "Include support for Integrator/IM-PD1" + bool "Include support for Integrator/IM-PD1" depends on ARCH_INTEGRATOR_AP + select ARCH_REQUIRE_GPIOLIB + select ARM_VIC + select GPIO_PL061 if GPIOLIB help The IM-PD1 is an add-on logic module for the Integrator which allows ARM(R) Ltd PrimeCells to be developed and evaluated. diff --git a/arch/arm/mach-integrator/Makefile b/arch/arm/mach-integrator/Makefile index 158daaf9e3b..ec759ded7b6 100644 --- a/arch/arm/mach-integrator/Makefile +++ b/arch/arm/mach-integrator/Makefile @@ -4,11 +4,9 @@ # Object file lists. -obj-y := clock.o core.o lm.o time.o +obj-y := core.o lm.o leds.o obj-$(CONFIG_ARCH_INTEGRATOR_AP) += integrator_ap.o obj-$(CONFIG_ARCH_INTEGRATOR_CP) += integrator_cp.o -obj-$(CONFIG_LEDS) += leds.o -obj-$(CONFIG_PCI) += pci_v3.o pci.o -obj-$(CONFIG_CPU_FREQ_INTEGRATOR) += cpu.o +obj-$(CONFIG_PCI) += pci_v3.o obj-$(CONFIG_INTEGRATOR_IMPD1) += impd1.o diff --git a/arch/arm/mach-integrator/Makefile.boot b/arch/arm/mach-integrator/Makefile.boot index c7e75acfe6c..ff0a4b5b0a8 100644 --- a/arch/arm/mach-integrator/Makefile.boot +++ b/arch/arm/mach-integrator/Makefile.boot @@ -1,4 +1,4 @@ - zreladdr-y := 0x00008000 + zreladdr-y += 0x00008000 params_phys-y := 0x00000100 initrd_phys-y := 0x00800000 diff --git a/arch/arm/mach-integrator/clock.c b/arch/arm/mach-integrator/clock.c deleted file mode 100644 index 95a1e263f7f..00000000000 --- a/arch/arm/mach-integrator/clock.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * linux/arch/arm/mach-integrator/clock.c - * - * Copyright (C) 2004 ARM Limited. - * Written by Deep Blue Solutions Limited. - * - * 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 <linux/module.h> -#include <linux/kernel.h> -#include <linux/list.h> -#include <linux/errno.h> -#include <linux/err.h> -#include <linux/string.h> -#include <linux/clk.h> -#include <linux/mutex.h> - -#include <asm/semaphore.h> -#include <asm/hardware/icst525.h> - -#include "clock.h" - -static LIST_HEAD(clocks); -static DEFINE_MUTEX(clocks_mutex); - -struct clk *clk_get(struct device *dev, const char *id) -{ - struct clk *p, *clk = ERR_PTR(-ENOENT); - - mutex_lock(&clocks_mutex); - list_for_each_entry(p, &clocks, node) { - if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) { - clk = p; - break; - } - } - mutex_unlock(&clocks_mutex); - - return clk; -} -EXPORT_SYMBOL(clk_get); - -void clk_put(struct clk *clk) -{ - module_put(clk->owner); -} -EXPORT_SYMBOL(clk_put); - -int clk_enable(struct clk *clk) -{ - return 0; -} -EXPORT_SYMBOL(clk_enable); - -void clk_disable(struct clk *clk) -{ -} -EXPORT_SYMBOL(clk_disable); - -unsigned long clk_get_rate(struct clk *clk) -{ - return clk->rate; -} -EXPORT_SYMBOL(clk_get_rate); - -long clk_round_rate(struct clk *clk, unsigned long rate) -{ - struct icst525_vco vco; - - vco = icst525_khz_to_vco(clk->params, rate / 1000); - return icst525_khz(clk->params, vco) * 1000; -} -EXPORT_SYMBOL(clk_round_rate); - -int clk_set_rate(struct clk *clk, unsigned long rate) -{ - int ret = -EIO; - if (clk->setvco) { - struct icst525_vco vco; - - vco = icst525_khz_to_vco(clk->params, rate / 1000); - clk->rate = icst525_khz(clk->params, vco) * 1000; - - printk("Clock %s: setting VCO reg params: S=%d R=%d V=%d\n", - clk->name, vco.s, vco.r, vco.v); - - clk->setvco(clk, vco); - ret = 0; - } - return 0; -} -EXPORT_SYMBOL(clk_set_rate); - -/* - * These are fixed clocks. - */ -static struct clk kmi_clk = { - .name = "KMIREFCLK", - .rate = 24000000, -}; - -static struct clk uart_clk = { - .name = "UARTCLK", - .rate = 14745600, -}; - -int clk_register(struct clk *clk) -{ - mutex_lock(&clocks_mutex); - list_add(&clk->node, &clocks); - mutex_unlock(&clocks_mutex); - return 0; -} -EXPORT_SYMBOL(clk_register); - -void clk_unregister(struct clk *clk) -{ - mutex_lock(&clocks_mutex); - list_del(&clk->node); - mutex_unlock(&clocks_mutex); -} -EXPORT_SYMBOL(clk_unregister); - -static int __init clk_init(void) -{ - clk_register(&kmi_clk); - clk_register(&uart_clk); - return 0; -} -arch_initcall(clk_init); diff --git a/arch/arm/mach-integrator/clock.h b/arch/arm/mach-integrator/clock.h deleted file mode 100644 index 09e6328ceba..00000000000 --- a/arch/arm/mach-integrator/clock.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * linux/arch/arm/mach-integrator/clock.h - * - * Copyright (C) 2004 ARM Limited. - * Written by Deep Blue Solutions Limited. - * - * 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. - */ -struct module; -struct icst525_params; - -struct clk { - struct list_head node; - unsigned long rate; - struct module *owner; - const char *name; - const struct icst525_params *params; - void *data; - void (*setvco)(struct clk *, struct icst525_vco vco); -}; - -int clk_register(struct clk *clk); -void clk_unregister(struct clk *clk); diff --git a/arch/arm/mach-integrator/cm.h b/arch/arm/mach-integrator/cm.h new file mode 100644 index 00000000000..4ecff7bff48 --- /dev/null +++ b/arch/arm/mach-integrator/cm.h @@ -0,0 +1,41 @@ +/* + * access the core module control register. + */ +u32 cm_get(void); +void cm_control(u32, u32); + +struct device_node; +void cm_init(void); +void cm_clear_irqs(void); + +#define CM_CTRL_LED (1 << 0) +#define CM_CTRL_nMBDET (1 << 1) +#define CM_CTRL_REMAP (1 << 2) +#define CM_CTRL_RESET (1 << 3) + +/* + * Integrator/AP,PP2 specific + */ +#define CM_CTRL_HIGHVECTORS (1 << 4) +#define CM_CTRL_BIGENDIAN (1 << 5) +#define CM_CTRL_FASTBUS (1 << 6) +#define CM_CTRL_SYNC (1 << 7) + +/* + * ARM926/946/966 Integrator/CP specific + */ +#define CM_CTRL_LCDBIASEN (1 << 8) +#define CM_CTRL_LCDBIASUP (1 << 9) +#define CM_CTRL_LCDBIASDN (1 << 10) +#define CM_CTRL_LCDMUXSEL_MASK (7 << 11) +#define CM_CTRL_LCDMUXSEL_GENLCD (1 << 11) +#define CM_CTRL_LCDMUXSEL_VGA565_TFT555 (2 << 11) +#define CM_CTRL_LCDMUXSEL_SHARPLCD (3 << 11) +#define CM_CTRL_LCDMUXSEL_VGA555_TFT555 (4 << 11) +#define CM_CTRL_LCDEN0 (1 << 14) +#define CM_CTRL_LCDEN1 (1 << 15) +#define CM_CTRL_STATIC1 (1 << 16) +#define CM_CTRL_STATIC2 (1 << 17) +#define CM_CTRL_STATIC (1 << 18) +#define CM_CTRL_n24BITEN (1 << 19) +#define CM_CTRL_EBIWP (1 << 20) diff --git a/arch/arm/mach-integrator/common.h b/arch/arm/mach-integrator/common.h index 609c49de3d4..ad0ac5547b2 100644 --- a/arch/arm/mach-integrator/common.h +++ b/arch/arm/mach-integrator/common.h @@ -1,2 +1,8 @@ -extern void integrator_time_init(unsigned long, unsigned int); -extern unsigned long integrator_gettimeoffset(void); +#include <linux/reboot.h> +#include <linux/amba/serial.h> +extern struct amba_pl010_data ap_uart_data; +void integrator_init_early(void); +int integrator_init(bool is_cp); +void integrator_reserve(void); +void integrator_restart(enum reboot_mode, const char *); +void integrator_init_sysfs(struct device *parent, u32 id); diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c index 7fbbc17f8e8..e3f3aca43ef 100644 --- a/arch/arm/mach-integrator/core.c +++ b/arch/arm/mach-integrator/core.c @@ -11,292 +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/hardware.h> -#include <asm/irq.h> -#include <asm/io.h> -#include <asm/hardware/arm_timer.h> -#include <asm/arch/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 = { - .bus_id = "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 = { - .bus_id = "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 = { - .bus_id = "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 = { - .bus_id = "mb:18", - }, - .res = { - .start = KMI0_BASE, - .end = KMI0_BASE + SZ_4K - 1, - .flags = IORESOURCE_MEM, - }, - .irq = { IRQ_KMIINT0, NO_IRQ }, - .periphid = 0x00041050, -}; +/** + * cm_get - get the value from the CM_CTRL register + */ +u32 cm_get(void) +{ + return readl(cm_base + INTEGRATOR_HDR_CTRL_OFFSET); +} -static struct amba_device kmi1_device = { - .dev = { - .bus_id = "mb:19", - }, - .res = { - .start = KMI1_BASE, - .end = KMI1_BASE + SZ_4K - 1, - .flags = IORESOURCE_MEM, - }, - .irq = { IRQ_KMIINT1, NO_IRQ }, - .periphid = 0x00041050, -}; +/** + * cm_control - update the CM_CTRL register. + * @mask: bits to change + * @set: bits to set + */ +void cm_control(u32 mask, u32 set) +{ + unsigned long flags; + u32 val; -static struct amba_device *amba_devs[] __initdata = { - &rtc_device, - &uart0_device, - &uart1_device, - &kmi0_device, - &kmi1_device, -}; + 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); +} -static int __init integrator_init(void) +static const char *integrator_arch_str(u32 id) { - int i; - - for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { - struct amba_device *d = amba_devs[i]; - amba_device_register(d, &iomem_resource); + 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); } diff --git a/arch/arm/mach-integrator/cpu.c b/arch/arm/mach-integrator/cpu.c deleted file mode 100644 index 71c58bff304..00000000000 --- a/arch/arm/mach-integrator/cpu.c +++ /dev/null @@ -1,221 +0,0 @@ -/* - * linux/arch/arm/mach-integrator/cpu.c - * - * Copyright (C) 2001-2002 Deep Blue Solutions Ltd. - * - * $Id: cpu.c,v 1.6 2002/07/18 13:58:51 rmk Exp $ - * - * 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. - * - * CPU support functions - */ -#include <linux/module.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/cpufreq.h> -#include <linux/slab.h> -#include <linux/sched.h> -#include <linux/smp.h> -#include <linux/init.h> - -#include <asm/hardware.h> -#include <asm/io.h> -#include <asm/mach-types.h> -#include <asm/hardware/icst525.h> - -static struct cpufreq_driver integrator_driver; - -#define CM_ID (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_ID_OFFSET) -#define CM_OSC (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_OSC_OFFSET) -#define CM_STAT (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_STAT_OFFSET) -#define CM_LOCK (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_LOCK_OFFSET) - -static const struct icst525_params lclk_params = { - .ref = 24000, - .vco_max = 320000, - .vd_min = 8, - .vd_max = 132, - .rd_min = 24, - .rd_max = 24, -}; - -static const struct icst525_params cclk_params = { - .ref = 24000, - .vco_max = 320000, - .vd_min = 12, - .vd_max = 160, - .rd_min = 24, - .rd_max = 24, -}; - -/* - * Validate the speed policy. - */ -static int integrator_verify_policy(struct cpufreq_policy *policy) -{ - struct icst525_vco vco; - - cpufreq_verify_within_limits(policy, - policy->cpuinfo.min_freq, - policy->cpuinfo.max_freq); - - vco = icst525_khz_to_vco(&cclk_params, policy->max); - policy->max = icst525_khz(&cclk_params, vco); - - vco = icst525_khz_to_vco(&cclk_params, policy->min); - policy->min = icst525_khz(&cclk_params, vco); - - cpufreq_verify_within_limits(policy, - policy->cpuinfo.min_freq, - policy->cpuinfo.max_freq); - - return 0; -} - - -static int integrator_set_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) -{ - cpumask_t cpus_allowed; - int cpu = policy->cpu; - struct icst525_vco vco; - struct cpufreq_freqs freqs; - u_int cm_osc; - - /* - * Save this threads cpus_allowed mask. - */ - cpus_allowed = current->cpus_allowed; - - /* - * Bind to the specified CPU. When this call returns, - * we should be running on the right CPU. - */ - set_cpus_allowed(current, cpumask_of_cpu(cpu)); - BUG_ON(cpu != smp_processor_id()); - - /* get current setting */ - cm_osc = __raw_readl(CM_OSC); - - if (machine_is_integrator()) { - vco.s = (cm_osc >> 8) & 7; - } else if (machine_is_cintegrator()) { - vco.s = 1; - } - vco.v = cm_osc & 255; - vco.r = 22; - freqs.old = icst525_khz(&cclk_params, vco); - - /* icst525_khz_to_vco rounds down -- so we need the next - * larger freq in case of CPUFREQ_RELATION_L. - */ - if (relation == CPUFREQ_RELATION_L) - target_freq += 999; - if (target_freq > policy->max) - target_freq = policy->max; - vco = icst525_khz_to_vco(&cclk_params, target_freq); - freqs.new = icst525_khz(&cclk_params, vco); - - freqs.cpu = policy->cpu; - - if (freqs.old == freqs.new) { - set_cpus_allowed(current, cpus_allowed); - return 0; - } - - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - - cm_osc = __raw_readl(CM_OSC); - - if (machine_is_integrator()) { - cm_osc &= 0xfffff800; - cm_osc |= vco.s << 8; - } else if (machine_is_cintegrator()) { - cm_osc &= 0xffffff00; - } - cm_osc |= vco.v; - - __raw_writel(0xa05f, CM_LOCK); - __raw_writel(cm_osc, CM_OSC); - __raw_writel(0, CM_LOCK); - - /* - * Restore the CPUs allowed mask. - */ - set_cpus_allowed(current, cpus_allowed); - - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - - return 0; -} - -static unsigned int integrator_get(unsigned int cpu) -{ - cpumask_t cpus_allowed; - unsigned int current_freq; - u_int cm_osc; - struct icst525_vco vco; - - cpus_allowed = current->cpus_allowed; - - set_cpus_allowed(current, cpumask_of_cpu(cpu)); - BUG_ON(cpu != smp_processor_id()); - - /* detect memory etc. */ - cm_osc = __raw_readl(CM_OSC); - - if (machine_is_integrator()) { - vco.s = (cm_osc >> 8) & 7; - } else if (machine_is_cintegrator()) { - vco.s = 1; - } - vco.v = cm_osc & 255; - vco.r = 22; - - current_freq = icst525_khz(&cclk_params, vco); /* current freq */ - - set_cpus_allowed(current, cpus_allowed); - - return current_freq; -} - -static int integrator_cpufreq_init(struct cpufreq_policy *policy) -{ - - /* set default policy and cpuinfo */ - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; - policy->cpuinfo.max_freq = 160000; - policy->cpuinfo.min_freq = 12000; - policy->cpuinfo.transition_latency = 1000000; /* 1 ms, assumed */ - policy->cur = policy->min = policy->max = integrator_get(policy->cpu); - - return 0; -} - -static struct cpufreq_driver integrator_driver = { - .verify = integrator_verify_policy, - .target = integrator_set_target, - .get = integrator_get, - .init = integrator_cpufreq_init, - .name = "integrator", -}; - -static int __init integrator_cpu_init(void) -{ - return cpufreq_register_driver(&integrator_driver); -} - -static void __exit integrator_cpu_exit(void) -{ - cpufreq_unregister_driver(&integrator_driver); -} - -MODULE_AUTHOR ("Russell M. King"); -MODULE_DESCRIPTION ("cpufreq driver for ARM Integrator CPUs"); -MODULE_LICENSE ("GPL"); - -module_init(integrator_cpu_init); -module_exit(integrator_cpu_exit); diff --git a/arch/arm/mach-integrator/hardware.h b/arch/arm/mach-integrator/hardware.h new file mode 100644 index 00000000000..857ca5f8b9a --- /dev/null +++ b/arch/arm/mach-integrator/hardware.h @@ -0,0 +1,354 @@ +/* + * This file contains the hardware definitions of the Integrator. + * + * Copyright (C) 1998-1999 ARM Limited. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef INTEGRATOR_HARDWARE_H +#define INTEGRATOR_HARDWARE_H + +/* + * Where in virtual memory the IO devices (timers, system controllers + * and so on) + */ +#define IO_BASE 0xF0000000 // VA of IO +#define IO_SIZE 0x0B000000 // How much? +#define IO_START INTEGRATOR_HDR_BASE // PA of IO + +/* macro to get at IO space when running virtually */ +#ifdef CONFIG_MMU +#define IO_ADDRESS(x) (((x) & 0x000fffff) | (((x) >> 4) & 0x0ff00000) | IO_BASE) +#else +#define IO_ADDRESS(x) (x) +#endif + +#define __io_address(n) ((void __iomem *)IO_ADDRESS(n)) + +/* + * Integrator memory map + */ +#define INTEGRATOR_BOOT_ROM_LO 0x00000000 +#define INTEGRATOR_BOOT_ROM_HI 0x20000000 +#define INTEGRATOR_BOOT_ROM_BASE INTEGRATOR_BOOT_ROM_HI /* Normal position */ +#define INTEGRATOR_BOOT_ROM_SIZE SZ_512K + +/* + * New Core Modules have different amounts of SSRAM, the amount of SSRAM + * fitted can be found in HDR_STAT. + * + * The symbol INTEGRATOR_SSRAM_SIZE is kept, however this now refers to + * the minimum amount of SSRAM fitted on any core module. + * + * New Core Modules also alias the SSRAM. + * + */ +#define INTEGRATOR_SSRAM_BASE 0x00000000 +#define INTEGRATOR_SSRAM_ALIAS_BASE 0x10800000 +#define INTEGRATOR_SSRAM_SIZE SZ_256K + +#define INTEGRATOR_FLASH_BASE 0x24000000 +#define INTEGRATOR_FLASH_SIZE SZ_32M + +#define INTEGRATOR_MBRD_SSRAM_BASE 0x28000000 +#define INTEGRATOR_MBRD_SSRAM_SIZE SZ_512K + +/* + * SDRAM is a SIMM therefore the size is not known. + */ +#define INTEGRATOR_SDRAM_BASE 0x00040000 + +#define INTEGRATOR_SDRAM_ALIAS_BASE 0x80000000 +#define INTEGRATOR_HDR0_SDRAM_BASE 0x80000000 +#define INTEGRATOR_HDR1_SDRAM_BASE 0x90000000 +#define INTEGRATOR_HDR2_SDRAM_BASE 0xA0000000 +#define INTEGRATOR_HDR3_SDRAM_BASE 0xB0000000 + +/* + * Logic expansion modules + * + */ +#define INTEGRATOR_LOGIC_MODULES_BASE 0xC0000000 +#define INTEGRATOR_LOGIC_MODULE0_BASE 0xC0000000 +#define INTEGRATOR_LOGIC_MODULE1_BASE 0xD0000000 +#define INTEGRATOR_LOGIC_MODULE2_BASE 0xE0000000 +#define INTEGRATOR_LOGIC_MODULE3_BASE 0xF0000000 + +/* + * Integrator header card registers + */ +#define INTEGRATOR_HDR_ID_OFFSET 0x00 +#define INTEGRATOR_HDR_PROC_OFFSET 0x04 +#define INTEGRATOR_HDR_OSC_OFFSET 0x08 +#define INTEGRATOR_HDR_CTRL_OFFSET 0x0C +#define INTEGRATOR_HDR_STAT_OFFSET 0x10 +#define INTEGRATOR_HDR_LOCK_OFFSET 0x14 +#define INTEGRATOR_HDR_SDRAM_OFFSET 0x20 +#define INTEGRATOR_HDR_INIT_OFFSET 0x24 /* CM9x6 */ +#define INTEGRATOR_HDR_IC_OFFSET 0x40 +#define INTEGRATOR_HDR_SPDBASE_OFFSET 0x100 +#define INTEGRATOR_HDR_SPDTOP_OFFSET 0x200 + +#define INTEGRATOR_HDR_BASE 0x10000000 +#define INTEGRATOR_HDR_ID (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_ID_OFFSET) +#define INTEGRATOR_HDR_PROC (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_PROC_OFFSET) +#define INTEGRATOR_HDR_OSC (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_OSC_OFFSET) +#define INTEGRATOR_HDR_CTRL (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_CTRL_OFFSET) +#define INTEGRATOR_HDR_STAT (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_STAT_OFFSET) +#define INTEGRATOR_HDR_LOCK (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_LOCK_OFFSET) +#define INTEGRATOR_HDR_SDRAM (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_SDRAM_OFFSET) +#define INTEGRATOR_HDR_INIT (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_INIT_OFFSET) +#define INTEGRATOR_HDR_IC (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_IC_OFFSET) +#define INTEGRATOR_HDR_SPDBASE (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_SPDBASE_OFFSET) +#define INTEGRATOR_HDR_SPDTOP (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_SPDTOP_OFFSET) + +#define INTEGRATOR_HDR_CTRL_LED 0x01 +#define INTEGRATOR_HDR_CTRL_MBRD_DETECH 0x02 +#define INTEGRATOR_HDR_CTRL_REMAP 0x04 +#define INTEGRATOR_HDR_CTRL_RESET 0x08 +#define INTEGRATOR_HDR_CTRL_HIGHVECTORS 0x10 +#define INTEGRATOR_HDR_CTRL_BIG_ENDIAN 0x20 +#define INTEGRATOR_HDR_CTRL_FASTBUS 0x40 +#define INTEGRATOR_HDR_CTRL_SYNC 0x80 + +#define INTEGRATOR_HDR_OSC_CORE_10MHz 0x102 +#define INTEGRATOR_HDR_OSC_CORE_15MHz 0x107 +#define INTEGRATOR_HDR_OSC_CORE_20MHz 0x10C +#define INTEGRATOR_HDR_OSC_CORE_25MHz 0x111 +#define INTEGRATOR_HDR_OSC_CORE_30MHz 0x116 +#define INTEGRATOR_HDR_OSC_CORE_35MHz 0x11B +#define INTEGRATOR_HDR_OSC_CORE_40MHz 0x120 +#define INTEGRATOR_HDR_OSC_CORE_45MHz 0x125 +#define INTEGRATOR_HDR_OSC_CORE_50MHz 0x12A +#define INTEGRATOR_HDR_OSC_CORE_55MHz 0x12F +#define INTEGRATOR_HDR_OSC_CORE_60MHz 0x134 +#define INTEGRATOR_HDR_OSC_CORE_65MHz 0x139 +#define INTEGRATOR_HDR_OSC_CORE_70MHz 0x13E +#define INTEGRATOR_HDR_OSC_CORE_75MHz 0x143 +#define INTEGRATOR_HDR_OSC_CORE_80MHz 0x148 +#define INTEGRATOR_HDR_OSC_CORE_85MHz 0x14D +#define INTEGRATOR_HDR_OSC_CORE_90MHz 0x152 +#define INTEGRATOR_HDR_OSC_CORE_95MHz 0x157 +#define INTEGRATOR_HDR_OSC_CORE_100MHz 0x15C +#define INTEGRATOR_HDR_OSC_CORE_105MHz 0x161 +#define INTEGRATOR_HDR_OSC_CORE_110MHz 0x166 +#define INTEGRATOR_HDR_OSC_CORE_115MHz 0x16B +#define INTEGRATOR_HDR_OSC_CORE_120MHz 0x170 +#define INTEGRATOR_HDR_OSC_CORE_125MHz 0x175 +#define INTEGRATOR_HDR_OSC_CORE_130MHz 0x17A +#define INTEGRATOR_HDR_OSC_CORE_135MHz 0x17F +#define INTEGRATOR_HDR_OSC_CORE_140MHz 0x184 +#define INTEGRATOR_HDR_OSC_CORE_145MHz 0x189 +#define INTEGRATOR_HDR_OSC_CORE_150MHz 0x18E +#define INTEGRATOR_HDR_OSC_CORE_155MHz 0x193 +#define INTEGRATOR_HDR_OSC_CORE_160MHz 0x198 +#define INTEGRATOR_HDR_OSC_CORE_MASK 0x7FF + +#define INTEGRATOR_HDR_OSC_MEM_10MHz 0x10C000 +#define INTEGRATOR_HDR_OSC_MEM_15MHz 0x116000 +#define INTEGRATOR_HDR_OSC_MEM_20MHz 0x120000 +#define INTEGRATOR_HDR_OSC_MEM_25MHz 0x12A000 +#define INTEGRATOR_HDR_OSC_MEM_30MHz 0x134000 +#define INTEGRATOR_HDR_OSC_MEM_33MHz 0x13A000 +#define INTEGRATOR_HDR_OSC_MEM_40MHz 0x148000 +#define INTEGRATOR_HDR_OSC_MEM_50MHz 0x15C000 +#define INTEGRATOR_HDR_OSC_MEM_60MHz 0x170000 +#define INTEGRATOR_HDR_OSC_MEM_66MHz 0x17C000 +#define INTEGRATOR_HDR_OSC_MEM_MASK 0x7FF000 + +#define INTEGRATOR_HDR_OSC_BUS_MODE_CM7x0 0x0 +#define INTEGRATOR_HDR_OSC_BUS_MODE_CM9x0 0x0800000 +#define INTEGRATOR_HDR_OSC_BUS_MODE_CM9x6 0x1000000 +#define INTEGRATOR_HDR_OSC_BUS_MODE_CM10x00 0x1800000 +#define INTEGRATOR_HDR_OSC_BUS_MODE_MASK 0x1800000 + +#define INTEGRATOR_HDR_SDRAM_SPD_OK (1 << 5) + +/* + * Integrator system registers + */ + +/* + * System Controller + */ +#define INTEGRATOR_SC_ID_OFFSET 0x00 +#define INTEGRATOR_SC_OSC_OFFSET 0x04 +#define INTEGRATOR_SC_CTRLS_OFFSET 0x08 +#define INTEGRATOR_SC_CTRLC_OFFSET 0x0C +#define INTEGRATOR_SC_DEC_OFFSET 0x10 +#define INTEGRATOR_SC_ARB_OFFSET 0x14 +#define INTEGRATOR_SC_LOCK_OFFSET 0x1C + +#define INTEGRATOR_SC_BASE 0x11000000 +#define INTEGRATOR_SC_ID (INTEGRATOR_SC_BASE + INTEGRATOR_SC_ID_OFFSET) +#define INTEGRATOR_SC_OSC (INTEGRATOR_SC_BASE + INTEGRATOR_SC_OSC_OFFSET) +#define INTEGRATOR_SC_CTRLS (INTEGRATOR_SC_BASE + INTEGRATOR_SC_CTRLS_OFFSET) +#define INTEGRATOR_SC_CTRLC (INTEGRATOR_SC_BASE + INTEGRATOR_SC_CTRLC_OFFSET) +#define INTEGRATOR_SC_DEC (INTEGRATOR_SC_BASE + INTEGRATOR_SC_DEC_OFFSET) +#define INTEGRATOR_SC_ARB (INTEGRATOR_SC_BASE + INTEGRATOR_SC_ARB_OFFSET) +#define INTEGRATOR_SC_PCIENABLE (INTEGRATOR_SC_BASE + INTEGRATOR_SC_PCIENABLE_OFFSET) +#define INTEGRATOR_SC_LOCK (INTEGRATOR_SC_BASE + INTEGRATOR_SC_LOCK_OFFSET) + +#define INTEGRATOR_SC_OSC_SYS_10MHz 0x20 +#define INTEGRATOR_SC_OSC_SYS_15MHz 0x34 +#define INTEGRATOR_SC_OSC_SYS_20MHz 0x48 +#define INTEGRATOR_SC_OSC_SYS_25MHz 0x5C +#define INTEGRATOR_SC_OSC_SYS_33MHz 0x7C +#define INTEGRATOR_SC_OSC_SYS_MASK 0xFF + +#define INTEGRATOR_SC_OSC_PCI_25MHz 0x100 +#define INTEGRATOR_SC_OSC_PCI_33MHz 0x0 +#define INTEGRATOR_SC_OSC_PCI_MASK 0x100 + +#define INTEGRATOR_SC_CTRL_SOFTRST (1 << 0) +#define INTEGRATOR_SC_CTRL_nFLVPPEN (1 << 1) +#define INTEGRATOR_SC_CTRL_nFLWP (1 << 2) +#define INTEGRATOR_SC_CTRL_URTS0 (1 << 4) +#define INTEGRATOR_SC_CTRL_UDTR0 (1 << 5) +#define INTEGRATOR_SC_CTRL_URTS1 (1 << 6) +#define INTEGRATOR_SC_CTRL_UDTR1 (1 << 7) + +/* + * External Bus Interface + */ +#define INTEGRATOR_EBI_BASE 0x12000000 + +#define INTEGRATOR_EBI_CSR0_OFFSET 0x00 +#define INTEGRATOR_EBI_CSR1_OFFSET 0x04 +#define INTEGRATOR_EBI_CSR2_OFFSET 0x08 +#define INTEGRATOR_EBI_CSR3_OFFSET 0x0C +#define INTEGRATOR_EBI_LOCK_OFFSET 0x20 + +#define INTEGRATOR_EBI_CSR0 (INTEGRATOR_EBI_BASE + INTEGRATOR_EBI_CSR0_OFFSET) +#define INTEGRATOR_EBI_CSR1 (INTEGRATOR_EBI_BASE + INTEGRATOR_EBI_CSR1_OFFSET) +#define INTEGRATOR_EBI_CSR2 (INTEGRATOR_EBI_BASE + INTEGRATOR_EBI_CSR2_OFFSET) +#define INTEGRATOR_EBI_CSR3 (INTEGRATOR_EBI_BASE + INTEGRATOR_EBI_CSR3_OFFSET) +#define INTEGRATOR_EBI_LOCK (INTEGRATOR_EBI_BASE + INTEGRATOR_EBI_LOCK_OFFSET) + +#define INTEGRATOR_EBI_8_BIT 0x00 +#define INTEGRATOR_EBI_16_BIT 0x01 +#define INTEGRATOR_EBI_32_BIT 0x02 +#define INTEGRATOR_EBI_WRITE_ENABLE 0x04 +#define INTEGRATOR_EBI_SYNC 0x08 +#define INTEGRATOR_EBI_WS_2 0x00 +#define INTEGRATOR_EBI_WS_3 0x10 +#define INTEGRATOR_EBI_WS_4 0x20 +#define INTEGRATOR_EBI_WS_5 0x30 +#define INTEGRATOR_EBI_WS_6 0x40 +#define INTEGRATOR_EBI_WS_7 0x50 +#define INTEGRATOR_EBI_WS_8 0x60 +#define INTEGRATOR_EBI_WS_9 0x70 +#define INTEGRATOR_EBI_WS_10 0x80 +#define INTEGRATOR_EBI_WS_11 0x90 +#define INTEGRATOR_EBI_WS_12 0xA0 +#define INTEGRATOR_EBI_WS_13 0xB0 +#define INTEGRATOR_EBI_WS_14 0xC0 +#define INTEGRATOR_EBI_WS_15 0xD0 +#define INTEGRATOR_EBI_WS_16 0xE0 +#define INTEGRATOR_EBI_WS_17 0xF0 + + +#define INTEGRATOR_CT_BASE 0x13000000 /* Counter/Timers */ +#define INTEGRATOR_IC_BASE 0x14000000 /* Interrupt Controller */ +#define INTEGRATOR_RTC_BASE 0x15000000 /* Real Time Clock */ +#define INTEGRATOR_UART0_BASE 0x16000000 /* UART 0 */ +#define INTEGRATOR_UART1_BASE 0x17000000 /* UART 1 */ +#define INTEGRATOR_KBD_BASE 0x18000000 /* Keyboard */ +#define INTEGRATOR_MOUSE_BASE 0x19000000 /* Mouse */ + +/* + * LED's & Switches + */ +#define INTEGRATOR_DBG_ALPHA_OFFSET 0x00 +#define INTEGRATOR_DBG_LEDS_OFFSET 0x04 +#define INTEGRATOR_DBG_SWITCH_OFFSET 0x08 + +#define INTEGRATOR_DBG_BASE 0x1A000000 +#define INTEGRATOR_DBG_ALPHA (INTEGRATOR_DBG_BASE + INTEGRATOR_DBG_ALPHA_OFFSET) +#define INTEGRATOR_DBG_LEDS (INTEGRATOR_DBG_BASE + INTEGRATOR_DBG_LEDS_OFFSET) +#define INTEGRATOR_DBG_SWITCH (INTEGRATOR_DBG_BASE + INTEGRATOR_DBG_SWITCH_OFFSET) + +#define INTEGRATOR_AP_GPIO_BASE 0x1B000000 /* GPIO */ + +#define INTEGRATOR_CP_MMC_BASE 0x1C000000 /* MMC */ +#define INTEGRATOR_CP_AACI_BASE 0x1D000000 /* AACI */ +#define INTEGRATOR_CP_ETH_BASE 0xC8000000 /* Ethernet */ +#define INTEGRATOR_CP_GPIO_BASE 0xC9000000 /* GPIO */ +#define INTEGRATOR_CP_SIC_BASE 0xCA000000 /* SIC */ +#define INTEGRATOR_CP_CTL_BASE 0xCB000000 /* CP system control */ + +/* PS2 Keyboard interface */ +#define KMI0_BASE INTEGRATOR_KBD_BASE + +/* PS2 Mouse interface */ +#define KMI1_BASE INTEGRATOR_MOUSE_BASE + +/* + * Integrator Interrupt Controllers + * + * + * Offsets from interrupt controller base + * + * System Controller interrupt controller base is + * + * INTEGRATOR_IC_BASE + (header_number << 6) + * + * Core Module interrupt controller base is + * + * INTEGRATOR_HDR_IC + */ +#define IRQ_STATUS 0 +#define IRQ_RAW_STATUS 0x04 +#define IRQ_ENABLE 0x08 +#define IRQ_ENABLE_SET 0x08 +#define IRQ_ENABLE_CLEAR 0x0C + +#define INT_SOFT_SET 0x10 +#define INT_SOFT_CLEAR 0x14 + +#define FIQ_STATUS 0x20 +#define FIQ_RAW_STATUS 0x24 +#define FIQ_ENABLE 0x28 +#define FIQ_ENABLE_SET 0x28 +#define FIQ_ENABLE_CLEAR 0x2C + + +/* + * LED's + */ +#define GREEN_LED 0x01 +#define YELLOW_LED 0x02 +#define RED_LED 0x04 +#define GREEN_LED_2 0x08 +#define ALL_LEDS 0x0F + +#define LED_BANK INTEGRATOR_DBG_LEDS + +/* + * Timer definitions + * + * Only use timer 1 & 2 + * (both run at 24MHz and will need the clock divider set to 16). + * + * Timer 0 runs at bus frequency + */ +#define INTEGRATOR_TIMER0_BASE INTEGRATOR_CT_BASE +#define INTEGRATOR_TIMER1_BASE (INTEGRATOR_CT_BASE + 0x100) +#define INTEGRATOR_TIMER2_BASE (INTEGRATOR_CT_BASE + 0x200) + +#define INTEGRATOR_CSR_BASE 0x10000000 +#define INTEGRATOR_CSR_SIZE 0x10000000 + +#endif /* INTEGRATOR_HARDWARE_H */ diff --git a/arch/arm/mach-integrator/impd1.c b/arch/arm/mach-integrator/impd1.c index 92d79fb3931..3ce880729cf 100644 --- a/arch/arm/mach-integrator/impd1.c +++ b/arch/arm/mach-integrator/impd1.c @@ -20,14 +20,14 @@ #include <linux/mm.h> #include <linux/amba/bus.h> #include <linux/amba/clcd.h> +#include <linux/io.h> +#include <linux/platform_data/clk-integrator.h> +#include <linux/slab.h> +#include <linux/irqchip/arm-vic.h> -#include <asm/io.h> -#include <asm/hardware/icst525.h> -#include <asm/arch/lm.h> -#include <asm/arch/impd1.h> #include <asm/sizes.h> - -#include "clock.h" +#include "lm.h" +#include "impd1.h" static int module_id; @@ -36,47 +36,9 @@ MODULE_PARM_DESC(lmid, "logic module stack position"); struct impd1_module { void __iomem *base; - struct clk vcos[2]; -}; - -static const struct icst525_params impd1_vco_params = { - .ref = 24000, /* 24 MHz */ - .vco_max = 200000, /* 200 MHz */ - .vd_min = 12, - .vd_max = 519, - .rd_min = 3, - .rd_max = 120, + void __iomem *vic_base; }; -static void impd1_setvco(struct clk *clk, struct icst525_vco vco) -{ - struct impd1_module *impd1 = clk->data; - int vconr = clk - impd1->vcos; - u32 val; - - val = vco.v | (vco.r << 9) | (vco.s << 16); - - writel(0xa05f, impd1->base + IMPD1_LOCK); - switch (vconr) { - case 0: - writel(val, impd1->base + IMPD1_OSC1); - break; - case 1: - writel(val, impd1->base + IMPD1_OSC2); - break; - } - writel(0, impd1->base + IMPD1_LOCK); - -#ifdef DEBUG - vco.v = val & 0x1ff; - vco.r = (val >> 9) & 0x7f; - vco.s = (val >> 16) & 7; - - pr_debug("IM-PD1: VCO%d clock is %ld kHz\n", - vconr, icst525_khz(&impd1_vco_params, vco)); -#endif -} - void impd1_tweak_control(struct device *dev, u32 mask, u32 val) { struct impd1_module *impd1 = dev_get_drvdata(dev); @@ -121,6 +83,7 @@ static struct clcd_panel vga = { .height = -1, .tim2 = TIM2_BCD | TIM2_IPC, .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), + .caps = CLCD_CAP_5551, .connector = IMPD1_CTRL_DISP_VGA, .bpp = 16, .grayscale = 0, @@ -149,6 +112,7 @@ static struct clcd_panel svga = { .tim2 = TIM2_BCD, .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), .connector = IMPD1_CTRL_DISP_VGA, + .caps = CLCD_CAP_5551, .bpp = 16, .grayscale = 0, }; @@ -175,6 +139,7 @@ static struct clcd_panel prospector = { .height = -1, .tim2 = TIM2_BCD, .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), + .caps = CLCD_CAP_5551, .fixedtimings = 1, .connector = IMPD1_CTRL_DISP_LCD, .bpp = 16, @@ -206,6 +171,7 @@ static struct clcd_panel ltm10c209 = { .height = -1, .tim2 = TIM2_BCD, .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), + .caps = CLCD_CAP_5551, .fixedtimings = 1, .connector = IMPD1_CTRL_DISP_LCD, .bpp = 16, @@ -279,6 +245,7 @@ static void impd1fb_clcd_remove(struct clcd_fb *fb) static struct clcd_board impd1_clcd_data = { .name = "IM-PD/1", + .caps = CLCD_CAP_5551 | CLCD_CAP_888, .check = clcdfb_check, .decode = clcdfb_decode, .disable = impd1fb_clcd_disable, @@ -297,9 +264,6 @@ struct impd1_device { static struct impd1_device impd1_devs[] = { { - .offset = 0x03000000, - .id = 0x00041190, - }, { .offset = 0x00100000, .irq = { 1 }, .id = 0x00141011, @@ -339,88 +303,86 @@ static struct impd1_device impd1_devs[] = { } }; -static const char *impd1_vconames[2] = { - "CLCDCLK", - "AUXVCO2", -}; +/* + * Valid IRQs: 0 thru 9 and 11, 10 unused. + */ +#define IMPD1_VALID_IRQS 0x00000bffU -static int impd1_probe(struct lm_device *dev) +/* + * As this module is bool, it is OK to have this as __init_refok() - no + * probe calls will be done after the initial system bootup, as devices + * are discovered as part of the machine startup. + */ +static int __init_refok impd1_probe(struct lm_device *dev) { struct impd1_module *impd1; - int i, ret; + int irq_base; + int i; if (dev->id != module_id) return -EINVAL; - if (!request_mem_region(dev->resource.start, SZ_4K, "LM registers")) + if (!devm_request_mem_region(&dev->dev, dev->resource.start, + SZ_4K, "LM registers")) return -EBUSY; - impd1 = kzalloc(sizeof(struct impd1_module), GFP_KERNEL); - if (!impd1) { - ret = -ENOMEM; - goto release_lm; - } + impd1 = devm_kzalloc(&dev->dev, sizeof(struct impd1_module), + GFP_KERNEL); + if (!impd1) + return -ENOMEM; - impd1->base = ioremap(dev->resource.start, SZ_4K); - if (!impd1->base) { - ret = -ENOMEM; - goto free_impd1; - } + impd1->base = devm_ioremap(&dev->dev, dev->resource.start, SZ_4K); + if (!impd1->base) + return -ENOMEM; - lm_set_drvdata(dev, impd1); + integrator_impd1_clk_init(impd1->base, dev->id); - printk("IM-PD1 found at 0x%08lx\n", dev->resource.start); + if (!devm_request_mem_region(&dev->dev, + dev->resource.start + 0x03000000, + SZ_4K, "VIC")) + return -EBUSY; - for (i = 0; i < ARRAY_SIZE(impd1->vcos); i++) { - impd1->vcos[i].owner = THIS_MODULE, - impd1->vcos[i].name = impd1_vconames[i], - impd1->vcos[i].params = &impd1_vco_params, - impd1->vcos[i].data = impd1, - impd1->vcos[i].setvco = impd1_setvco; + impd1->vic_base = devm_ioremap(&dev->dev, + dev->resource.start + 0x03000000, + SZ_4K); + if (!impd1->vic_base) + return -ENOMEM; - clk_register(&impd1->vcos[i]); - } + irq_base = vic_init_cascaded(impd1->vic_base, dev->irq, + IMPD1_VALID_IRQS, 0); + + lm_set_drvdata(dev, impd1); + + dev_info(&dev->dev, "IM-PD1 found at 0x%08lx\n", + (unsigned long)dev->resource.start); for (i = 0; i < ARRAY_SIZE(impd1_devs); i++) { struct impd1_device *idev = impd1_devs + i; struct amba_device *d; unsigned long pc_base; + char devname[32]; + int irq1 = idev->irq[0]; + int irq2 = idev->irq[1]; - pc_base = dev->resource.start + idev->offset; + /* Translate IRQs to IM-PD1 local numberspace */ + if (irq1) + irq1 += irq_base; + if (irq2) + irq2 += irq_base; - d = kzalloc(sizeof(struct amba_device), GFP_KERNEL); - if (!d) + pc_base = dev->resource.start + idev->offset; + snprintf(devname, 32, "lm%x:%5.5lx", dev->id, idev->offset >> 12); + d = amba_ahb_device_add_res(&dev->dev, devname, pc_base, SZ_4K, + irq1, irq2, + idev->platform_data, idev->id, + &dev->resource); + if (IS_ERR(d)) { + dev_err(&dev->dev, "unable to register device: %ld\n", PTR_ERR(d)); continue; - - snprintf(d->dev.bus_id, sizeof(d->dev.bus_id), - "lm%x:%5.5lx", dev->id, idev->offset >> 12); - - d->dev.parent = &dev->dev; - d->res.start = dev->resource.start + idev->offset; - d->res.end = d->res.start + SZ_4K - 1; - d->res.flags = IORESOURCE_MEM; - d->irq[0] = dev->irq; - d->irq[1] = dev->irq; - d->periphid = idev->id; - d->dev.platform_data = idev->platform_data; - - ret = amba_device_register(d, &dev->resource); - if (ret) { - printk("unable to register device %s: %d\n", - d->dev.bus_id, ret); - kfree(d); } } return 0; - - free_impd1: - if (impd1 && impd1->base) - iounmap(impd1->base); - kfree(impd1); - release_lm: - release_mem_region(dev->resource.start, SZ_4K); - return ret; } static int impd1_remove_one(struct device *dev, void *data) @@ -431,24 +393,20 @@ static int impd1_remove_one(struct device *dev, void *data) static void impd1_remove(struct lm_device *dev) { - struct impd1_module *impd1 = lm_get_drvdata(dev); - int i; - device_for_each_child(&dev->dev, NULL, impd1_remove_one); - - for (i = 0; i < ARRAY_SIZE(impd1->vcos); i++) - clk_unregister(&impd1->vcos[i]); + integrator_impd1_clk_exit(dev->id); lm_set_drvdata(dev, NULL); - - iounmap(impd1->base); - kfree(impd1); - release_mem_region(dev->resource.start, SZ_4K); } static struct lm_driver impd1_driver = { .drv = { .name = "impd1", + /* + * As we're dropping the probe() function, suppress driver + * binding from sysfs. + */ + .suppress_bind_attrs = true, }, .probe = impd1_probe, .remove = impd1_remove, diff --git a/arch/arm/mach-integrator/impd1.h b/arch/arm/mach-integrator/impd1.h new file mode 100644 index 00000000000..76de4dc9bee --- /dev/null +++ b/arch/arm/mach-integrator/impd1.h @@ -0,0 +1,14 @@ +#define IMPD1_LEDS 0x0c +#define IMPD1_INT 0x10 +#define IMPD1_SW 0x14 +#define IMPD1_CTRL 0x18 + +#define IMPD1_CTRL_DISP_LCD (0 << 0) +#define IMPD1_CTRL_DISP_VGA (1 << 0) +#define IMPD1_CTRL_DISP_LCD1 (2 << 0) +#define IMPD1_CTRL_DISP_ENABLE (1 << 2) +#define IMPD1_CTRL_DISP_MASK (7 << 0) + +struct device; + +void impd1_tweak_control(struct device *dev, u32 mask, u32 val); diff --git a/arch/arm/mach-integrator/include/mach/memory.h b/arch/arm/mach-integrator/include/mach/memory.h new file mode 100644 index 00000000000..334d5e27188 --- /dev/null +++ b/arch/arm/mach-integrator/include/mach/memory.h @@ -0,0 +1,34 @@ +/* + * arch/arm/mach-integrator/include/mach/memory.h + * + * Copyright (C) 1999 ARM Limited + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __ASM_ARCH_MEMORY_H +#define __ASM_ARCH_MEMORY_H + +/* + * Physical DRAM offset. + */ +#define PLAT_PHYS_OFFSET UL(0x00000000) + +#define BUS_OFFSET UL(0x80000000) +#define __virt_to_bus(x) ((x) - PAGE_OFFSET + BUS_OFFSET) +#define __bus_to_virt(x) ((x) - BUS_OFFSET + PAGE_OFFSET) +#define __pfn_to_bus(x) (__pfn_to_phys(x) + (BUS_OFFSET - PHYS_OFFSET)) +#define __bus_to_pfn(x) __phys_to_pfn((x) - (BUS_OFFSET - PHYS_OFFSET)) + +#endif diff --git a/arch/arm/mach-integrator/include/mach/uncompress.h b/arch/arm/mach-integrator/include/mach/uncompress.h new file mode 100644 index 00000000000..8f3cc9954c1 --- /dev/null +++ b/arch/arm/mach-integrator/include/mach/uncompress.h @@ -0,0 +1,48 @@ +/* + * arch/arm/mach-integrator/include/mach/uncompress.h + * + * Copyright (C) 1999 ARM Limited + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define AMBA_UART_DR (*(volatile unsigned char *)0x16000000) +#define AMBA_UART_LCRH (*(volatile unsigned char *)0x16000008) +#define AMBA_UART_LCRM (*(volatile unsigned char *)0x1600000c) +#define AMBA_UART_LCRL (*(volatile unsigned char *)0x16000010) +#define AMBA_UART_CR (*(volatile unsigned char *)0x16000014) +#define AMBA_UART_FR (*(volatile unsigned char *)0x16000018) + +/* + * This does not append a newline + */ +static void putc(int c) +{ + while (AMBA_UART_FR & (1 << 5)) + barrier(); + + AMBA_UART_DR = c; +} + +static inline void flush(void) +{ + while (AMBA_UART_FR & (1 << 3)) + barrier(); +} + +/* + * nothing to do + */ +#define arch_decomp_setup() diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c index df37e93c6fc..660ca6feff4 100644 --- a/arch/arm/mach-integrator/integrator_ap.c +++ b/arch/arm/mach-integrator/integrator_ap.c @@ -24,49 +24,61 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/string.h> -#include <linux/sysdev.h> +#include <linux/syscore_ops.h> #include <linux/amba/bus.h> #include <linux/amba/kmi.h> - -#include <asm/hardware.h> -#include <asm/io.h> -#include <asm/irq.h> +#include <linux/clocksource.h> +#include <linux/clockchips.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/irqchip/versatile-fpga.h> +#include <linux/mtd/physmap.h> +#include <linux/clk.h> +#include <linux/platform_data/clk-integrator.h> +#include <linux/of_irq.h> +#include <linux/of_address.h> +#include <linux/of_platform.h> +#include <linux/stat.h> +#include <linux/sys_soc.h> +#include <linux/termios.h> +#include <linux/sched_clock.h> +#include <linux/clk-provider.h> + +#include <asm/hardware/arm_timer.h> #include <asm/setup.h> #include <asm/param.h> /* HZ */ #include <asm/mach-types.h> -#include <asm/arch/lm.h> - #include <asm/mach/arch.h> -#include <asm/mach/flash.h> #include <asm/mach/irq.h> #include <asm/mach/map.h> #include <asm/mach/time.h> +#include "hardware.h" +#include "cm.h" #include "common.h" +#include "pci_v3.h" +#include "lm.h" + +/* Base address to the AP system controller */ +void __iomem *ap_syscon_base; +/* Base address to the external bus interface */ +static void __iomem *ebi_base; + -/* +/* * All IO addresses are mapped onto VA 0xFFFx.xxxx, where x.xxxx * is the (PA >> 12). * * Setup a VA for the Integrator interrupt controller (for header #0, * just for now). */ -#define VA_IC_BASE IO_ADDRESS(INTEGRATOR_IC_BASE) -#define VA_SC_BASE IO_ADDRESS(INTEGRATOR_SC_BASE) -#define VA_EBI_BASE IO_ADDRESS(INTEGRATOR_EBI_BASE) -#define VA_CMIC_BASE IO_ADDRESS(INTEGRATOR_HDR_BASE) + INTEGRATOR_HDR_IC_OFFSET +#define VA_IC_BASE __io_address(INTEGRATOR_IC_BASE) /* * Logical Physical - * e8000000 40000000 PCI memory PHYS_PCI_MEM_BASE (max 512M) - * ec000000 61000000 PCI config space PHYS_PCI_CONFIG_BASE (max 16M) - * ed000000 62000000 PCI V3 regs PHYS_PCI_V3_BASE (max 64k) - * ee000000 60000000 PCI IO PHYS_PCI_IO_BASE (max 16M) * ef000000 Cache flush - * f1000000 10000000 Core module registers * f1100000 11000000 System controller registers - * f1200000 12000000 EBI registers * f1300000 13000000 Counter/Timer * f1400000 14000000 Interrupt controller * f1600000 16000000 UART 0 @@ -75,23 +87,8 @@ * f1b00000 1b000000 GPIO */ -static struct map_desc ap_io_desc[] __initdata = { +static struct map_desc ap_io_desc[] __initdata __maybe_unused = { { - .virtual = IO_ADDRESS(INTEGRATOR_HDR_BASE), - .pfn = __phys_to_pfn(INTEGRATOR_HDR_BASE), - .length = SZ_4K, - .type = MT_DEVICE - }, { - .virtual = IO_ADDRESS(INTEGRATOR_SC_BASE), - .pfn = __phys_to_pfn(INTEGRATOR_SC_BASE), - .length = SZ_4K, - .type = MT_DEVICE - }, { - .virtual = IO_ADDRESS(INTEGRATOR_EBI_BASE), - .pfn = __phys_to_pfn(INTEGRATOR_EBI_BASE), - .length = SZ_4K, - .type = MT_DEVICE - }, { .virtual = IO_ADDRESS(INTEGRATOR_CT_BASE), .pfn = __phys_to_pfn(INTEGRATOR_CT_BASE), .length = SZ_4K, @@ -107,213 +104,430 @@ static struct map_desc ap_io_desc[] __initdata = { .length = SZ_4K, .type = MT_DEVICE }, { - .virtual = IO_ADDRESS(INTEGRATOR_UART1_BASE), - .pfn = __phys_to_pfn(INTEGRATOR_UART1_BASE), - .length = SZ_4K, - .type = MT_DEVICE - }, { .virtual = IO_ADDRESS(INTEGRATOR_DBG_BASE), .pfn = __phys_to_pfn(INTEGRATOR_DBG_BASE), .length = SZ_4K, .type = MT_DEVICE }, { - .virtual = IO_ADDRESS(INTEGRATOR_GPIO_BASE), - .pfn = __phys_to_pfn(INTEGRATOR_GPIO_BASE), + .virtual = IO_ADDRESS(INTEGRATOR_AP_GPIO_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_AP_GPIO_BASE), .length = SZ_4K, .type = MT_DEVICE - }, { - .virtual = PCI_MEMORY_VADDR, - .pfn = __phys_to_pfn(PHYS_PCI_MEM_BASE), - .length = SZ_16M, - .type = MT_DEVICE - }, { - .virtual = PCI_CONFIG_VADDR, - .pfn = __phys_to_pfn(PHYS_PCI_CONFIG_BASE), - .length = SZ_16M, - .type = MT_DEVICE - }, { - .virtual = PCI_V3_VADDR, - .pfn = __phys_to_pfn(PHYS_PCI_V3_BASE), - .length = SZ_64K, - .type = MT_DEVICE - }, { - .virtual = PCI_IO_VADDR, - .pfn = __phys_to_pfn(PHYS_PCI_IO_BASE), - .length = SZ_64K, - .type = MT_DEVICE } }; static void __init ap_map_io(void) { iotable_init(ap_io_desc, ARRAY_SIZE(ap_io_desc)); -} - -#define INTEGRATOR_SC_VALID_INT 0x003fffff - -static void sc_mask_irq(unsigned int irq) -{ - writel(1 << irq, VA_IC_BASE + IRQ_ENABLE_CLEAR); -} - -static void sc_unmask_irq(unsigned int irq) -{ - writel(1 << irq, VA_IC_BASE + IRQ_ENABLE_SET); -} - -static struct irq_chip sc_chip = { - .name = "SC", - .ack = sc_mask_irq, - .mask = sc_mask_irq, - .unmask = sc_unmask_irq, -}; - -static void __init ap_init_irq(void) -{ - unsigned int i; - - /* Disable all interrupts initially. */ - /* Do the core module ones */ - writel(-1, VA_CMIC_BASE + IRQ_ENABLE_CLEAR); - - /* do the header card stuff next */ - writel(-1, VA_IC_BASE + IRQ_ENABLE_CLEAR); - writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR); - - for (i = 0; i < NR_IRQS; i++) { - if (((1 << i) & INTEGRATOR_SC_VALID_INT) != 0) { - set_irq_chip(i, &sc_chip); - set_irq_handler(i, handle_level_irq); - set_irq_flags(i, IRQF_VALID | IRQF_PROBE); - } - } + pci_v3_early_init(); } #ifdef CONFIG_PM static unsigned long ic_irq_enable; -static int irq_suspend(struct sys_device *dev, pm_message_t state) +static int irq_suspend(void) { ic_irq_enable = readl(VA_IC_BASE + IRQ_ENABLE); return 0; } -static int irq_resume(struct sys_device *dev) +static void irq_resume(void) { /* disable all irq sources */ - writel(-1, VA_CMIC_BASE + IRQ_ENABLE_CLEAR); + cm_clear_irqs(); writel(-1, VA_IC_BASE + IRQ_ENABLE_CLEAR); writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR); writel(ic_irq_enable, VA_IC_BASE + IRQ_ENABLE_SET); - return 0; } #else #define irq_suspend NULL #define irq_resume NULL #endif -static struct sysdev_class irq_class = { - .name = "irq", +static struct syscore_ops irq_syscore_ops = { .suspend = irq_suspend, .resume = irq_resume, }; -static struct sys_device irq_device = { - .id = 0, - .cls = &irq_class, -}; - -static int __init irq_init_sysfs(void) +static int __init irq_syscore_init(void) { - int ret = sysdev_class_register(&irq_class); - if (ret == 0) - ret = sysdev_register(&irq_device); - return ret; + register_syscore_ops(&irq_syscore_ops); + + return 0; } -device_initcall(irq_init_sysfs); +device_initcall(irq_syscore_init); /* * Flash handling. */ -#define SC_CTRLC (VA_SC_BASE + INTEGRATOR_SC_CTRLC_OFFSET) -#define SC_CTRLS (VA_SC_BASE + INTEGRATOR_SC_CTRLS_OFFSET) -#define EBI_CSR1 (VA_EBI_BASE + INTEGRATOR_EBI_CSR1_OFFSET) -#define EBI_LOCK (VA_EBI_BASE + INTEGRATOR_EBI_LOCK_OFFSET) - -static int ap_flash_init(void) +static int ap_flash_init(struct platform_device *dev) { u32 tmp; - writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, SC_CTRLC); + writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, + ap_syscon_base + INTEGRATOR_SC_CTRLC_OFFSET); - tmp = readl(EBI_CSR1) | INTEGRATOR_EBI_WRITE_ENABLE; - writel(tmp, EBI_CSR1); + tmp = readl(ebi_base + INTEGRATOR_EBI_CSR1_OFFSET) | + INTEGRATOR_EBI_WRITE_ENABLE; + writel(tmp, ebi_base + INTEGRATOR_EBI_CSR1_OFFSET); - if (!(readl(EBI_CSR1) & INTEGRATOR_EBI_WRITE_ENABLE)) { - writel(0xa05f, EBI_LOCK); - writel(tmp, EBI_CSR1); - writel(0, EBI_LOCK); + if (!(readl(ebi_base + INTEGRATOR_EBI_CSR1_OFFSET) + & INTEGRATOR_EBI_WRITE_ENABLE)) { + writel(0xa05f, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET); + writel(tmp, ebi_base + INTEGRATOR_EBI_CSR1_OFFSET); + writel(0, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET); } return 0; } -static void ap_flash_exit(void) +static void ap_flash_exit(struct platform_device *dev) { u32 tmp; - writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, SC_CTRLC); + writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, + ap_syscon_base + INTEGRATOR_SC_CTRLC_OFFSET); - tmp = readl(EBI_CSR1) & ~INTEGRATOR_EBI_WRITE_ENABLE; - writel(tmp, EBI_CSR1); + tmp = readl(ebi_base + INTEGRATOR_EBI_CSR1_OFFSET) & + ~INTEGRATOR_EBI_WRITE_ENABLE; + writel(tmp, ebi_base + INTEGRATOR_EBI_CSR1_OFFSET); - if (readl(EBI_CSR1) & INTEGRATOR_EBI_WRITE_ENABLE) { - writel(0xa05f, EBI_LOCK); - writel(tmp, EBI_CSR1); - writel(0, EBI_LOCK); + if (readl(ebi_base + INTEGRATOR_EBI_CSR1_OFFSET) & + INTEGRATOR_EBI_WRITE_ENABLE) { + writel(0xa05f, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET); + writel(tmp, ebi_base + INTEGRATOR_EBI_CSR1_OFFSET); + writel(0, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET); } } -static void ap_flash_set_vpp(int on) +static void ap_flash_set_vpp(struct platform_device *pdev, int on) { - unsigned long reg = on ? SC_CTRLS : SC_CTRLC; - - writel(INTEGRATOR_SC_CTRL_nFLVPPEN, reg); + if (on) + writel(INTEGRATOR_SC_CTRL_nFLVPPEN, + ap_syscon_base + INTEGRATOR_SC_CTRLS_OFFSET); + else + writel(INTEGRATOR_SC_CTRL_nFLVPPEN, + ap_syscon_base + INTEGRATOR_SC_CTRLC_OFFSET); } -static struct flash_platform_data ap_flash_data = { - .map_name = "cfi_probe", +static struct physmap_flash_data ap_flash_data = { .width = 4, .init = ap_flash_init, .exit = ap_flash_exit, .set_vpp = ap_flash_set_vpp, }; -static struct resource cfi_flash_resource = { - .start = INTEGRATOR_FLASH_BASE, - .end = INTEGRATOR_FLASH_BASE + INTEGRATOR_FLASH_SIZE - 1, - .flags = IORESOURCE_MEM, +/* + * For the PL010 found in the Integrator/AP some of the UART control is + * implemented in the system controller and accessed using a callback + * from the driver. + */ +static void integrator_uart_set_mctrl(struct amba_device *dev, + void __iomem *base, unsigned int mctrl) +{ + unsigned int ctrls = 0, ctrlc = 0, rts_mask, dtr_mask; + u32 phybase = dev->res.start; + + if (phybase == INTEGRATOR_UART0_BASE) { + /* UART0 */ + rts_mask = 1 << 4; + dtr_mask = 1 << 5; + } else { + /* UART1 */ + rts_mask = 1 << 6; + dtr_mask = 1 << 7; + } + + 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, ap_syscon_base + INTEGRATOR_SC_CTRLS_OFFSET); + __raw_writel(ctrlc, ap_syscon_base + INTEGRATOR_SC_CTRLC_OFFSET); +} + +struct amba_pl010_data ap_uart_data = { + .set_mctrl = integrator_uart_set_mctrl, }; -static struct platform_device cfi_flash_device = { - .name = "armflash", - .id = 0, - .dev = { - .platform_data = &ap_flash_data, - }, - .num_resources = 1, - .resource = &cfi_flash_resource, +/* + * Where is the timer (VA)? + */ +#define TIMER0_VA_BASE __io_address(INTEGRATOR_TIMER0_BASE) +#define TIMER1_VA_BASE __io_address(INTEGRATOR_TIMER1_BASE) +#define TIMER2_VA_BASE __io_address(INTEGRATOR_TIMER2_BASE) + +static unsigned long timer_reload; + +static u64 notrace integrator_read_sched_clock(void) +{ + return -readl((void __iomem *) TIMER2_VA_BASE + TIMER_VALUE); +} + +static void integrator_clocksource_init(unsigned long inrate, + void __iomem *base) +{ + u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC; + unsigned long rate = inrate; + + if (rate >= 1500000) { + rate /= 16; + ctrl |= TIMER_CTRL_DIV16; + } + + writel(0xffff, base + TIMER_LOAD); + writel(ctrl, base + TIMER_CTRL); + + clocksource_mmio_init(base + TIMER_VALUE, "timer2", + rate, 200, 16, clocksource_mmio_readl_down); + sched_clock_register(integrator_read_sched_clock, 16, rate); +} + +static void __iomem * clkevt_base; + +/* + * IRQ handler for the timer + */ +static irqreturn_t integrator_timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *evt = dev_id; + + /* clear the interrupt */ + writel(1, clkevt_base + TIMER_INTCLR); + + evt->event_handler(evt); + + return IRQ_HANDLED; +} + +static void clkevt_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) +{ + u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE; + + /* Disable timer */ + writel(ctrl, clkevt_base + TIMER_CTRL); + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + /* Enable the timer and start the periodic tick */ + writel(timer_reload, clkevt_base + TIMER_LOAD); + ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE; + writel(ctrl, clkevt_base + TIMER_CTRL); + break; + case CLOCK_EVT_MODE_ONESHOT: + /* Leave the timer disabled, .set_next_event will enable it */ + ctrl &= ~TIMER_CTRL_PERIODIC; + writel(ctrl, clkevt_base + TIMER_CTRL); + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + case CLOCK_EVT_MODE_RESUME: + default: + /* Just leave in disabled state */ + break; + } + +} + +static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt) +{ + unsigned long ctrl = readl(clkevt_base + TIMER_CTRL); + + writel(ctrl & ~TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL); + writel(next, clkevt_base + TIMER_LOAD); + writel(ctrl | TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL); + + return 0; +} + +static struct clock_event_device integrator_clockevent = { + .name = "timer1", + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .set_mode = clkevt_set_mode, + .set_next_event = clkevt_set_next_event, + .rating = 300, +}; + +static struct irqaction integrator_timer_irq = { + .name = "timer", + .flags = IRQF_TIMER | IRQF_IRQPOLL, + .handler = integrator_timer_interrupt, + .dev_id = &integrator_clockevent, +}; + +static void integrator_clockevent_init(unsigned long inrate, + void __iomem *base, int irq) +{ + unsigned long rate = inrate; + unsigned int ctrl = 0; + + clkevt_base = base; + /* Calculate and program a divisor */ + if (rate > 0x100000 * HZ) { + rate /= 256; + ctrl |= TIMER_CTRL_DIV256; + } else if (rate > 0x10000 * HZ) { + rate /= 16; + ctrl |= TIMER_CTRL_DIV16; + } + timer_reload = rate / HZ; + writel(ctrl, clkevt_base + TIMER_CTRL); + + setup_irq(irq, &integrator_timer_irq); + clockevents_config_and_register(&integrator_clockevent, + rate, + 1, + 0xffffU); +} + +void __init ap_init_early(void) +{ +} + +static void __init ap_of_timer_init(void) +{ + struct device_node *node; + const char *path; + void __iomem *base; + int err; + int irq; + struct clk *clk; + unsigned long rate; + + of_clk_init(NULL); + + err = of_property_read_string(of_aliases, + "arm,timer-primary", &path); + if (WARN_ON(err)) + return; + node = of_find_node_by_path(path); + base = of_iomap(node, 0); + if (WARN_ON(!base)) + return; + + clk = of_clk_get(node, 0); + BUG_ON(IS_ERR(clk)); + clk_prepare_enable(clk); + rate = clk_get_rate(clk); + + writel(0, base + TIMER_CTRL); + integrator_clocksource_init(rate, base); + + err = of_property_read_string(of_aliases, + "arm,timer-secondary", &path); + if (WARN_ON(err)) + return; + node = of_find_node_by_path(path); + base = of_iomap(node, 0); + if (WARN_ON(!base)) + return; + irq = irq_of_parse_and_map(node, 0); + + clk = of_clk_get(node, 0); + BUG_ON(IS_ERR(clk)); + clk_prepare_enable(clk); + rate = clk_get_rate(clk); + + writel(0, base + TIMER_CTRL); + integrator_clockevent_init(rate, base, irq); +} + +static const struct of_device_id fpga_irq_of_match[] __initconst = { + { .compatible = "arm,versatile-fpga-irq", .data = fpga_irq_of_init, }, + { /* Sentinel */ } }; -static void __init ap_init(void) +static void __init ap_init_irq_of(void) +{ + cm_init(); + of_irq_init(fpga_irq_of_match); +} + +/* For the Device Tree, add in the UART callbacks as AUXDATA */ +static struct of_dev_auxdata ap_auxdata_lookup[] __initdata = { + OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_RTC_BASE, + "rtc", NULL), + OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_UART0_BASE, + "uart0", &ap_uart_data), + OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_UART1_BASE, + "uart1", &ap_uart_data), + OF_DEV_AUXDATA("arm,primecell", KMI0_BASE, + "kmi0", NULL), + OF_DEV_AUXDATA("arm,primecell", KMI1_BASE, + "kmi1", NULL), + OF_DEV_AUXDATA("cfi-flash", INTEGRATOR_FLASH_BASE, + "physmap-flash", &ap_flash_data), + { /* sentinel */ }, +}; + +static const struct of_device_id ap_syscon_match[] = { + { .compatible = "arm,integrator-ap-syscon"}, + { }, +}; + +static const struct of_device_id ebi_match[] = { + { .compatible = "arm,external-bus-interface"}, + { }, +}; + +static void __init ap_init_of(void) { unsigned long sc_dec; + struct device_node *syscon; + struct device_node *ebi; + struct device *parent; + struct soc_device *soc_dev; + struct soc_device_attribute *soc_dev_attr; + u32 ap_sc_id; int i; - platform_device_register(&cfi_flash_device); + syscon = of_find_matching_node(NULL, ap_syscon_match); + if (!syscon) + return; + ebi = of_find_matching_node(NULL, ebi_match); + if (!ebi) + return; + + ap_syscon_base = of_iomap(syscon, 0); + if (!ap_syscon_base) + return; + ebi_base = of_iomap(ebi, 0); + if (!ebi_base) + return; + + of_platform_populate(NULL, of_default_bus_match_table, + ap_auxdata_lookup, NULL); + + ap_sc_id = readl(ap_syscon_base); + + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + if (!soc_dev_attr) + return; + + soc_dev_attr->soc_id = "XVC"; + soc_dev_attr->machine = "Integrator/AP"; + soc_dev_attr->family = "Integrator"; + soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%c", + 'A' + (ap_sc_id & 0x0f)); + + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR(soc_dev)) { + kfree(soc_dev_attr->revision); + kfree(soc_dev_attr); + return; + } + + parent = soc_device_to_device(soc_dev); + integrator_init_sysfs(parent, ap_sc_id); - sc_dec = readl(VA_SC_BASE + INTEGRATOR_SC_DEC_OFFSET); + sc_dec = readl(ap_syscon_base + INTEGRATOR_SC_DEC_OFFSET); for (i = 0; i < 4; i++) { struct lm_device *lmdev; @@ -327,30 +541,26 @@ static void __init ap_init(void) lmdev->resource.start = 0xc0000000 + 0x10000000 * i; lmdev->resource.end = lmdev->resource.start + 0x0fffffff; lmdev->resource.flags = IORESOURCE_MEM; - lmdev->irq = IRQ_AP_EXPINT0 + i; + lmdev->irq = irq_of_parse_and_map(syscon, i); lmdev->id = i; lm_device_register(lmdev); } } -static void __init ap_init_timer(void) -{ - integrator_time_init(1000000 * TICKS_PER_uSEC / HZ, 0); -} - -static struct sys_timer ap_timer = { - .init = ap_init_timer, - .offset = integrator_gettimeoffset, +static const char * ap_dt_board_compat[] = { + "arm,integrator-ap", + NULL, }; -MACHINE_START(INTEGRATOR, "ARM-Integrator") - /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */ - .phys_io = 0x16000000, - .io_pg_offst = ((0xf1600000) >> 18) & 0xfffc, - .boot_params = 0x00000100, +DT_MACHINE_START(INTEGRATOR_AP_DT, "ARM Integrator/AP (Device Tree)") + .reserve = integrator_reserve, .map_io = ap_map_io, - .init_irq = ap_init_irq, - .timer = &ap_timer, - .init_machine = ap_init, + .init_early = ap_init_early, + .init_irq = ap_init_irq_of, + .handle_irq = fpga_handle_irq, + .init_time = ap_of_timer_init, + .init_machine = ap_init_of, + .restart = integrator_restart, + .dt_compat = ap_dt_board_compat, MACHINE_END diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c index 913f64b2240..0e57f8f820a 100644 --- a/arch/arm/mach-integrator/integrator_cp.c +++ b/arch/arm/mach-integrator/integrator_cp.c @@ -13,49 +13,42 @@ #include <linux/list.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> -#include <linux/slab.h> #include <linux/string.h> -#include <linux/sysdev.h> +#include <linux/device.h> #include <linux/amba/bus.h> #include <linux/amba/kmi.h> #include <linux/amba/clcd.h> +#include <linux/amba/mmci.h> +#include <linux/io.h> +#include <linux/irqchip/versatile-fpga.h> +#include <linux/gfp.h> +#include <linux/mtd/physmap.h> +#include <linux/of_irq.h> +#include <linux/of_address.h> +#include <linux/of_platform.h> +#include <linux/sys_soc.h> +#include <linux/sched_clock.h> -#include <asm/hardware.h> -#include <asm/io.h> -#include <asm/irq.h> #include <asm/setup.h> #include <asm/mach-types.h> -#include <asm/hardware/icst525.h> - -#include <asm/arch/cm.h> -#include <asm/arch/lm.h> - #include <asm/mach/arch.h> -#include <asm/mach/flash.h> #include <asm/mach/irq.h> -#include <asm/mach/mmc.h> #include <asm/mach/map.h> #include <asm/mach/time.h> +#include <plat/clcd.h> + +#include "hardware.h" +#include "cm.h" #include "common.h" -#include "clock.h" -#define INTCP_PA_MMC_BASE 0x1c000000 -#define INTCP_PA_AACI_BASE 0x1d000000 +/* Base address to the CP controller */ +static void __iomem *intcp_con_base; #define INTCP_PA_FLASH_BASE 0x24000000 -#define INTCP_FLASH_SIZE SZ_32M #define INTCP_PA_CLCD_BASE 0xc0000000 -#define INTCP_VA_CIC_BASE 0xf1000040 -#define INTCP_VA_PIC_BASE 0xf1400000 -#define INTCP_VA_SIC_BASE 0xfca00000 - -#define INTCP_PA_ETH_BASE 0xc8000000 -#define INTCP_ETH_SIZE 0x10 - -#define INTCP_VA_CTRL_BASE 0xfcb00000 #define INTCP_FLASHPROG 0x04 #define CINTEGRATOR_FLASHPROG_FLVPPEN (1 << 0) #define CINTEGRATOR_FLASHPROG_FLWREN (1 << 1) @@ -63,33 +56,22 @@ /* * Logical Physical * f1000000 10000000 Core module registers - * f1100000 11000000 System controller registers - * f1200000 12000000 EBI registers * f1300000 13000000 Counter/Timer * f1400000 14000000 Interrupt controller * f1600000 16000000 UART 0 * f1700000 17000000 UART 1 * f1a00000 1a000000 Debug LEDs - * f1b00000 1b000000 GPIO + * fc900000 c9000000 GPIO + * fca00000 ca000000 SIC */ -static struct map_desc intcp_io_desc[] __initdata = { +static struct map_desc intcp_io_desc[] __initdata __maybe_unused = { { .virtual = IO_ADDRESS(INTEGRATOR_HDR_BASE), .pfn = __phys_to_pfn(INTEGRATOR_HDR_BASE), .length = SZ_4K, .type = MT_DEVICE }, { - .virtual = IO_ADDRESS(INTEGRATOR_SC_BASE), - .pfn = __phys_to_pfn(INTEGRATOR_SC_BASE), - .length = SZ_4K, - .type = MT_DEVICE - }, { - .virtual = IO_ADDRESS(INTEGRATOR_EBI_BASE), - .pfn = __phys_to_pfn(INTEGRATOR_EBI_BASE), - .length = SZ_4K, - .type = MT_DEVICE - }, { .virtual = IO_ADDRESS(INTEGRATOR_CT_BASE), .pfn = __phys_to_pfn(INTEGRATOR_CT_BASE), .length = SZ_4K, @@ -105,28 +87,18 @@ static struct map_desc intcp_io_desc[] __initdata = { .length = SZ_4K, .type = MT_DEVICE }, { - .virtual = IO_ADDRESS(INTEGRATOR_UART1_BASE), - .pfn = __phys_to_pfn(INTEGRATOR_UART1_BASE), - .length = SZ_4K, - .type = MT_DEVICE - }, { .virtual = IO_ADDRESS(INTEGRATOR_DBG_BASE), .pfn = __phys_to_pfn(INTEGRATOR_DBG_BASE), .length = SZ_4K, .type = MT_DEVICE }, { - .virtual = IO_ADDRESS(INTEGRATOR_GPIO_BASE), - .pfn = __phys_to_pfn(INTEGRATOR_GPIO_BASE), - .length = SZ_4K, - .type = MT_DEVICE - }, { - .virtual = 0xfca00000, - .pfn = __phys_to_pfn(0xca000000), + .virtual = IO_ADDRESS(INTEGRATOR_CP_GPIO_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_CP_GPIO_BASE), .length = SZ_4K, .type = MT_DEVICE }, { - .virtual = 0xfcb00000, - .pfn = __phys_to_pfn(0xcb000000), + .virtual = IO_ADDRESS(INTEGRATOR_CP_SIC_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_CP_SIC_BASE), .length = SZ_4K, .type = MT_DEVICE } @@ -137,254 +109,48 @@ static void __init intcp_map_io(void) iotable_init(intcp_io_desc, ARRAY_SIZE(intcp_io_desc)); } -#define cic_writel __raw_writel -#define cic_readl __raw_readl -#define pic_writel __raw_writel -#define pic_readl __raw_readl -#define sic_writel __raw_writel -#define sic_readl __raw_readl - -static void cic_mask_irq(unsigned int irq) -{ - irq -= IRQ_CIC_START; - cic_writel(1 << irq, INTCP_VA_CIC_BASE + IRQ_ENABLE_CLEAR); -} - -static void cic_unmask_irq(unsigned int irq) -{ - irq -= IRQ_CIC_START; - cic_writel(1 << irq, INTCP_VA_CIC_BASE + IRQ_ENABLE_SET); -} - -static struct irq_chip cic_chip = { - .name = "CIC", - .ack = cic_mask_irq, - .mask = cic_mask_irq, - .unmask = cic_unmask_irq, -}; - -static void pic_mask_irq(unsigned int irq) -{ - irq -= IRQ_PIC_START; - pic_writel(1 << irq, INTCP_VA_PIC_BASE + IRQ_ENABLE_CLEAR); -} - -static void pic_unmask_irq(unsigned int irq) -{ - irq -= IRQ_PIC_START; - pic_writel(1 << irq, INTCP_VA_PIC_BASE + IRQ_ENABLE_SET); -} - -static struct irq_chip pic_chip = { - .name = "PIC", - .ack = pic_mask_irq, - .mask = pic_mask_irq, - .unmask = pic_unmask_irq, -}; - -static void sic_mask_irq(unsigned int irq) -{ - irq -= IRQ_SIC_START; - sic_writel(1 << irq, INTCP_VA_SIC_BASE + IRQ_ENABLE_CLEAR); -} - -static void sic_unmask_irq(unsigned int irq) -{ - irq -= IRQ_SIC_START; - sic_writel(1 << irq, INTCP_VA_SIC_BASE + IRQ_ENABLE_SET); -} - -static struct irq_chip sic_chip = { - .name = "SIC", - .ack = sic_mask_irq, - .mask = sic_mask_irq, - .unmask = sic_unmask_irq, -}; - -static void -sic_handle_irq(unsigned int irq, struct irq_desc *desc) -{ - unsigned long status = sic_readl(INTCP_VA_SIC_BASE + IRQ_STATUS); - - if (status == 0) { - do_bad_IRQ(irq, desc); - return; - } - - do { - irq = ffs(status) - 1; - status &= ~(1 << irq); - - irq += IRQ_SIC_START; - - desc = irq_desc + irq; - desc_handle_irq(irq, desc); - } while (status); -} - -static void __init intcp_init_irq(void) -{ - unsigned int i; - - /* - * Disable all interrupt sources - */ - pic_writel(0xffffffff, INTCP_VA_PIC_BASE + IRQ_ENABLE_CLEAR); - pic_writel(0xffffffff, INTCP_VA_PIC_BASE + FIQ_ENABLE_CLEAR); - - for (i = IRQ_PIC_START; i <= IRQ_PIC_END; i++) { - if (i == 11) - i = 22; - if (i == 29) - break; - set_irq_chip(i, &pic_chip); - set_irq_handler(i, handle_level_irq); - set_irq_flags(i, IRQF_VALID | IRQF_PROBE); - } - - cic_writel(0xffffffff, INTCP_VA_CIC_BASE + IRQ_ENABLE_CLEAR); - cic_writel(0xffffffff, INTCP_VA_CIC_BASE + FIQ_ENABLE_CLEAR); - - for (i = IRQ_CIC_START; i <= IRQ_CIC_END; i++) { - set_irq_chip(i, &cic_chip); - set_irq_handler(i, handle_level_irq); - set_irq_flags(i, IRQF_VALID); - } - - sic_writel(0x00000fff, INTCP_VA_SIC_BASE + IRQ_ENABLE_CLEAR); - sic_writel(0x00000fff, INTCP_VA_SIC_BASE + FIQ_ENABLE_CLEAR); - - for (i = IRQ_SIC_START; i <= IRQ_SIC_END; i++) { - set_irq_chip(i, &sic_chip); - set_irq_handler(i, handle_level_irq); - set_irq_flags(i, IRQF_VALID | IRQF_PROBE); - } - - set_irq_chained_handler(IRQ_CP_CPPLDINT, sic_handle_irq); -} - -/* - * Clock handling - */ -#define CM_LOCK (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_LOCK_OFFSET) -#define CM_AUXOSC (IO_ADDRESS(INTEGRATOR_HDR_BASE)+0x1c) - -static const struct icst525_params cp_auxvco_params = { - .ref = 24000, - .vco_max = 320000, - .vd_min = 8, - .vd_max = 263, - .rd_min = 3, - .rd_max = 65, -}; - -static void cp_auxvco_set(struct clk *clk, struct icst525_vco vco) -{ - u32 val; - - val = readl(CM_AUXOSC) & ~0x7ffff; - val |= vco.v | (vco.r << 9) | (vco.s << 16); - - writel(0xa05f, CM_LOCK); - writel(val, CM_AUXOSC); - writel(0, CM_LOCK); -} - -static struct clk cp_clcd_clk = { - .name = "CLCDCLK", - .params = &cp_auxvco_params, - .setvco = cp_auxvco_set, -}; - -static struct clk cp_mmci_clk = { - .name = "MCLK", - .rate = 14745600, -}; - /* * Flash handling. */ -static int intcp_flash_init(void) +static int intcp_flash_init(struct platform_device *dev) { u32 val; - val = readl(INTCP_VA_CTRL_BASE + INTCP_FLASHPROG); + val = readl(intcp_con_base + INTCP_FLASHPROG); val |= CINTEGRATOR_FLASHPROG_FLWREN; - writel(val, INTCP_VA_CTRL_BASE + INTCP_FLASHPROG); + writel(val, intcp_con_base + INTCP_FLASHPROG); return 0; } -static void intcp_flash_exit(void) +static void intcp_flash_exit(struct platform_device *dev) { u32 val; - val = readl(INTCP_VA_CTRL_BASE + INTCP_FLASHPROG); + val = readl(intcp_con_base + INTCP_FLASHPROG); val &= ~(CINTEGRATOR_FLASHPROG_FLVPPEN|CINTEGRATOR_FLASHPROG_FLWREN); - writel(val, INTCP_VA_CTRL_BASE + INTCP_FLASHPROG); + writel(val, intcp_con_base + INTCP_FLASHPROG); } -static void intcp_flash_set_vpp(int on) +static void intcp_flash_set_vpp(struct platform_device *pdev, int on) { u32 val; - val = readl(INTCP_VA_CTRL_BASE + INTCP_FLASHPROG); + val = readl(intcp_con_base + INTCP_FLASHPROG); if (on) val |= CINTEGRATOR_FLASHPROG_FLVPPEN; else val &= ~CINTEGRATOR_FLASHPROG_FLVPPEN; - writel(val, INTCP_VA_CTRL_BASE + INTCP_FLASHPROG); + writel(val, intcp_con_base + INTCP_FLASHPROG); } -static struct flash_platform_data intcp_flash_data = { - .map_name = "cfi_probe", +static struct physmap_flash_data intcp_flash_data = { .width = 4, .init = intcp_flash_init, .exit = intcp_flash_exit, .set_vpp = intcp_flash_set_vpp, }; -static struct resource intcp_flash_resource = { - .start = INTCP_PA_FLASH_BASE, - .end = INTCP_PA_FLASH_BASE + INTCP_FLASH_SIZE - 1, - .flags = IORESOURCE_MEM, -}; - -static struct platform_device intcp_flash_device = { - .name = "armflash", - .id = 0, - .dev = { - .platform_data = &intcp_flash_data, - }, - .num_resources = 1, - .resource = &intcp_flash_resource, -}; - -static struct resource smc91x_resources[] = { - [0] = { - .start = INTCP_PA_ETH_BASE, - .end = INTCP_PA_ETH_BASE + INTCP_ETH_SIZE - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_CP_ETHINT, - .end = IRQ_CP_ETHINT, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device smc91x_device = { - .name = "smc91x", - .id = 0, - .num_resources = ARRAY_SIZE(smc91x_resources), - .resource = smc91x_resources, -}; - -static struct platform_device *intcp_devs[] __initdata = { - &intcp_flash_device, - &smc91x_device, -}; - /* * It seems that the card insertion interrupt remains active after * we've acknowledged it. We therefore ignore the interrupt, and @@ -393,85 +159,38 @@ static struct platform_device *intcp_devs[] __initdata = { */ static unsigned int mmc_status(struct device *dev) { - unsigned int status = readl(0xfca00004); - writel(8, 0xfcb00008); + unsigned int status = readl(__io_address(0xca000000 + 4)); + writel(8, intcp_con_base + 8); return status & 8; } -static struct mmc_platform_data mmc_data = { +static struct mmci_platform_data mmc_data = { .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, .status = mmc_status, + .gpio_wp = -1, + .gpio_cd = -1, }; -static struct amba_device mmc_device = { - .dev = { - .bus_id = "mb:1c", - .platform_data = &mmc_data, - }, - .res = { - .start = INTCP_PA_MMC_BASE, - .end = INTCP_PA_MMC_BASE + SZ_4K - 1, - .flags = IORESOURCE_MEM, - }, - .irq = { IRQ_CP_MMCIINT0, IRQ_CP_MMCIINT1 }, - .periphid = 0, -}; - -static struct amba_device aaci_device = { - .dev = { - .bus_id = "mb:1d", - }, - .res = { - .start = INTCP_PA_AACI_BASE, - .end = INTCP_PA_AACI_BASE + SZ_4K - 1, - .flags = IORESOURCE_MEM, - }, - .irq = { IRQ_CP_AACIINT, NO_IRQ }, - .periphid = 0, -}; - - /* * CLCD support */ -static struct clcd_panel vga = { - .mode = { - .name = "VGA", - .refresh = 60, - .xres = 640, - .yres = 480, - .pixclock = 39721, - .left_margin = 40, - .right_margin = 24, - .upper_margin = 32, - .lower_margin = 11, - .hsync_len = 96, - .vsync_len = 2, - .sync = 0, - .vmode = FB_VMODE_NONINTERLACED, - }, - .width = -1, - .height = -1, - .tim2 = TIM2_BCD | TIM2_IPC, - .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), - .bpp = 16, - .grayscale = 0, -}; - /* * Ensure VGA is selected. */ static void cp_clcd_enable(struct clcd_fb *fb) { - u32 val; - - if (fb->fb.var.bits_per_pixel <= 8) - val = CM_CTRL_LCDMUXSEL_VGA_8421BPP; + struct fb_var_screeninfo *var = &fb->fb.var; + u32 val = CM_CTRL_STATIC1 | CM_CTRL_STATIC2 + | CM_CTRL_LCDEN0 | CM_CTRL_LCDEN1; + + if (var->bits_per_pixel <= 8 || + (var->bits_per_pixel == 16 && var->green.length == 5)) + /* Pseudocolor, RGB555, BGR555 */ + val |= CM_CTRL_LCDMUXSEL_VGA555_TFT555; else if (fb->fb.var.bits_per_pixel <= 16) - val = CM_CTRL_LCDMUXSEL_VGA_16BPP - | CM_CTRL_LCDEN0 | CM_CTRL_LCDEN1 - | CM_CTRL_STATIC1 | CM_CTRL_STATIC2; + /* truecolor RGB565 */ + val |= CM_CTRL_LCDMUXSEL_VGA565_TFT555; else val = 0; /* no idea for this, don't trust the docs */ @@ -484,107 +203,134 @@ static void cp_clcd_enable(struct clcd_fb *fb) CM_CTRL_n24BITEN, val); } -static unsigned long framesize = SZ_1M; - static int cp_clcd_setup(struct clcd_fb *fb) { - dma_addr_t dma; - - fb->panel = &vga; + fb->panel = versatile_clcd_get_panel("VGA"); + if (!fb->panel) + return -EINVAL; - fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, framesize, - &dma, GFP_KERNEL); - if (!fb->fb.screen_base) { - printk(KERN_ERR "CLCD: unable to map framebuffer\n"); - return -ENOMEM; - } + return versatile_clcd_setup_dma(fb, SZ_1M); +} - fb->fb.fix.smem_start = dma; - fb->fb.fix.smem_len = framesize; +static struct clcd_board clcd_data = { + .name = "Integrator/CP", + .caps = CLCD_CAP_5551 | CLCD_CAP_RGB565 | CLCD_CAP_888, + .check = clcdfb_check, + .decode = clcdfb_decode, + .enable = cp_clcd_enable, + .setup = cp_clcd_setup, + .mmap = versatile_clcd_mmap_dma, + .remove = versatile_clcd_remove_dma, +}; - return 0; -} +#define REFCOUNTER (__io_address(INTEGRATOR_HDR_BASE) + 0x28) -static int cp_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma) +static u64 notrace intcp_read_sched_clock(void) { - return dma_mmap_writecombine(&fb->dev->dev, vma, - fb->fb.screen_base, - fb->fb.fix.smem_start, - fb->fb.fix.smem_len); + return readl(REFCOUNTER); } -static void cp_clcd_remove(struct clcd_fb *fb) +static void __init intcp_init_early(void) { - dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len, - fb->fb.screen_base, fb->fb.fix.smem_start); + sched_clock_register(intcp_read_sched_clock, 32, 24000000); } -static struct clcd_board clcd_data = { - .name = "Integrator/CP", - .check = clcdfb_check, - .decode = clcdfb_decode, - .enable = cp_clcd_enable, - .setup = cp_clcd_setup, - .mmap = cp_clcd_mmap, - .remove = cp_clcd_remove, +static const struct of_device_id fpga_irq_of_match[] __initconst = { + { .compatible = "arm,versatile-fpga-irq", .data = fpga_irq_of_init, }, + { /* Sentinel */ } }; -static struct amba_device clcd_device = { - .dev = { - .bus_id = "mb:c0", - .coherent_dma_mask = ~0, - .platform_data = &clcd_data, - }, - .res = { - .start = INTCP_PA_CLCD_BASE, - .end = INTCP_PA_CLCD_BASE + SZ_4K - 1, - .flags = IORESOURCE_MEM, - }, - .dma_mask = ~0, - .irq = { IRQ_CP_CLCDCINT, NO_IRQ }, - .periphid = 0, +static void __init intcp_init_irq_of(void) +{ + cm_init(); + of_irq_init(fpga_irq_of_match); +} + +/* + * For the Device Tree, add in the UART, MMC and CLCD specifics as AUXDATA + * and enforce the bus names since these are used for clock lookups. + */ +static struct of_dev_auxdata intcp_auxdata_lookup[] __initdata = { + OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_RTC_BASE, + "rtc", NULL), + OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_UART0_BASE, + "uart0", NULL), + OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_UART1_BASE, + "uart1", NULL), + OF_DEV_AUXDATA("arm,primecell", KMI0_BASE, + "kmi0", NULL), + OF_DEV_AUXDATA("arm,primecell", KMI1_BASE, + "kmi1", NULL), + OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_CP_MMC_BASE, + "mmci", &mmc_data), + OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_CP_AACI_BASE, + "aaci", &mmc_data), + OF_DEV_AUXDATA("arm,primecell", INTCP_PA_CLCD_BASE, + "clcd", &clcd_data), + OF_DEV_AUXDATA("cfi-flash", INTCP_PA_FLASH_BASE, + "physmap-flash", &intcp_flash_data), + { /* sentinel */ }, }; -static struct amba_device *amba_devs[] __initdata = { - &mmc_device, - &aaci_device, - &clcd_device, +static const struct of_device_id intcp_syscon_match[] = { + { .compatible = "arm,integrator-cp-syscon"}, + { }, }; -static void __init intcp_init(void) +static void __init intcp_init_of(void) { - int i; + struct device_node *cpcon; + struct device *parent; + struct soc_device *soc_dev; + struct soc_device_attribute *soc_dev_attr; + u32 intcp_sc_id; + + cpcon = of_find_matching_node(NULL, intcp_syscon_match); + if (!cpcon) + return; + + intcp_con_base = of_iomap(cpcon, 0); + if (!intcp_con_base) + return; - clk_register(&cp_clcd_clk); - clk_register(&cp_mmci_clk); + of_platform_populate(NULL, of_default_bus_match_table, + intcp_auxdata_lookup, NULL); - platform_add_devices(intcp_devs, ARRAY_SIZE(intcp_devs)); + intcp_sc_id = readl(intcp_con_base); - for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { - struct amba_device *d = amba_devs[i]; - amba_device_register(d, &iomem_resource); - } -} + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + if (!soc_dev_attr) + return; -#define TIMER_CTRL_IE (1 << 5) /* Interrupt Enable */ + soc_dev_attr->soc_id = "XCV"; + soc_dev_attr->machine = "Integrator/CP"; + soc_dev_attr->family = "Integrator"; + soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%c", + 'A' + (intcp_sc_id & 0x0f)); -static void __init intcp_timer_init(void) -{ - integrator_time_init(1000000 / HZ, TIMER_CTRL_IE); + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR(soc_dev)) { + kfree(soc_dev_attr->revision); + kfree(soc_dev_attr); + return; + } + + parent = soc_device_to_device(soc_dev); + integrator_init_sysfs(parent, intcp_sc_id); } -static struct sys_timer cp_timer = { - .init = intcp_timer_init, - .offset = integrator_gettimeoffset, +static const char * intcp_dt_board_compat[] = { + "arm,integrator-cp", + NULL, }; -MACHINE_START(CINTEGRATOR, "ARM-IntegratorCP") - /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */ - .phys_io = 0x16000000, - .io_pg_offst = ((0xf1600000) >> 18) & 0xfffc, - .boot_params = 0x00000100, +DT_MACHINE_START(INTEGRATOR_CP_DT, "ARM Integrator/CP (Device Tree)") + .reserve = integrator_reserve, .map_io = intcp_map_io, - .init_irq = intcp_init_irq, - .timer = &cp_timer, - .init_machine = intcp_init, + .init_early = intcp_init_early, + .init_irq = intcp_init_irq_of, + .handle_irq = fpga_handle_irq, + .init_machine = intcp_init_of, + .restart = integrator_restart, + .dt_compat = intcp_dt_board_compat, MACHINE_END diff --git a/arch/arm/mach-integrator/leds.c b/arch/arm/mach-integrator/leds.c index f1436e683b4..f1dcb57a59e 100644 --- a/arch/arm/mach-integrator/leds.c +++ b/arch/arm/mach-integrator/leds.c @@ -1,90 +1,124 @@ /* - * linux/arch/arm/mach-integrator/leds.c + * Driver for the 4 user LEDs found on the Integrator AP/CP baseboard + * Based on Versatile and RealView machine LED code * - * Integrator/AP and Integrator/CP LED control routines - * - * Copyright (C) 1999 ARM Limited - * Copyright (C) 2000 Deep Blue Solutions Ltd - * - * 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * License terms: GNU General Public License (GPL) version 2 + * Author: Bryan Wu <bryan.wu@canonical.com> */ #include <linux/kernel.h> #include <linux/init.h> -#include <linux/smp.h> -#include <linux/spinlock.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/leds.h> -#include <asm/hardware.h> -#include <asm/io.h> -#include <asm/leds.h> -#include <asm/system.h> -#include <asm/mach-types.h> -#include <asm/arch/cm.h> +#include "hardware.h" +#include "cm.h" -static int saved_leds; +#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS) + +#define ALPHA_REG __io_address(INTEGRATOR_DBG_BASE) +#define LEDREG (__io_address(INTEGRATOR_DBG_BASE) + INTEGRATOR_DBG_LEDS_OFFSET) + +struct integrator_led { + struct led_classdev cdev; + u8 mask; +}; + +/* + * The triggers lines up below will only be used if the + * LED triggers are compiled in. + */ +static const struct { + const char *name; + const char *trigger; +} integrator_leds[] = { + { "integrator:green0", "heartbeat", }, + { "integrator:yellow", }, + { "integrator:red", }, + { "integrator:green1", }, + { "integrator:core_module", "cpu0", }, +}; -static void integrator_leds_event(led_event_t ledevt) +static void integrator_led_set(struct led_classdev *cdev, + enum led_brightness b) { - unsigned long flags; - const unsigned int dbg_base = IO_ADDRESS(INTEGRATOR_DBG_BASE); - unsigned int update_alpha_leds; + struct integrator_led *led = container_of(cdev, + struct integrator_led, cdev); + u32 reg = __raw_readl(LEDREG); - // yup, change the LEDs - local_irq_save(flags); - update_alpha_leds = 0; + if (b != LED_OFF) + reg |= led->mask; + else + reg &= ~led->mask; - switch(ledevt) { - case led_idle_start: - cm_control(CM_CTRL_LED, 0); - break; + while (__raw_readl(ALPHA_REG) & 1) + cpu_relax(); - case led_idle_end: - cm_control(CM_CTRL_LED, CM_CTRL_LED); - break; + __raw_writel(reg, LEDREG); +} - case led_timer: - saved_leds ^= GREEN_LED; - update_alpha_leds = 1; - break; +static enum led_brightness integrator_led_get(struct led_classdev *cdev) +{ + struct integrator_led *led = container_of(cdev, + struct integrator_led, cdev); + u32 reg = __raw_readl(LEDREG); - case led_red_on: - saved_leds |= RED_LED; - update_alpha_leds = 1; - break; + return (reg & led->mask) ? LED_FULL : LED_OFF; +} - case led_red_off: - saved_leds &= ~RED_LED; - update_alpha_leds = 1; - break; +static void cm_led_set(struct led_classdev *cdev, + enum led_brightness b) +{ + if (b != LED_OFF) + cm_control(CM_CTRL_LED, CM_CTRL_LED); + else + cm_control(CM_CTRL_LED, 0); +} - default: - break; - } +static enum led_brightness cm_led_get(struct led_classdev *cdev) +{ + u32 reg = cm_get(); - if (update_alpha_leds) { - while (__raw_readl(dbg_base + INTEGRATOR_DBG_ALPHA_OFFSET) & 1); - __raw_writel(saved_leds, dbg_base + INTEGRATOR_DBG_LEDS_OFFSET); - } - local_irq_restore(flags); + return (reg & CM_CTRL_LED) ? LED_FULL : LED_OFF; } -static int __init leds_init(void) +static int __init integrator_leds_init(void) { - if (machine_is_integrator() || machine_is_cintegrator()) - leds_event = integrator_leds_event; + int i; + + for (i = 0; i < ARRAY_SIZE(integrator_leds); i++) { + struct integrator_led *led; + + led = kzalloc(sizeof(*led), GFP_KERNEL); + if (!led) + break; + + + led->cdev.name = integrator_leds[i].name; + + if (i == 4) { /* Setting for LED in core module */ + led->cdev.brightness_set = cm_led_set; + led->cdev.brightness_get = cm_led_get; + } else { + led->cdev.brightness_set = integrator_led_set; + led->cdev.brightness_get = integrator_led_get; + } + + led->cdev.default_trigger = integrator_leds[i].trigger; + led->mask = BIT(i); + + if (led_classdev_register(NULL, &led->cdev) < 0) { + kfree(led); + break; + } + } return 0; } -core_initcall(leds_init); +/* + * Since we may have triggers on any subsystem, defer registration + * until after subsystem_init. + */ +fs_initcall(integrator_leds_init); +#endif diff --git a/arch/arm/mach-integrator/lm.c b/arch/arm/mach-integrator/lm.c index 622cdc4212d..3f9e9f04316 100644 --- a/arch/arm/mach-integrator/lm.c +++ b/arch/arm/mach-integrator/lm.c @@ -12,7 +12,7 @@ #include <linux/device.h> #include <linux/slab.h> -#include <asm/arch/lm.h> +#include "lm.h" #define to_lm_device(d) container_of(d, struct lm_device, dev) #define to_lm_driver(d) container_of(d, struct lm_driver, drv) @@ -81,8 +81,10 @@ int lm_device_register(struct lm_device *dev) dev->dev.release = lm_device_release; dev->dev.bus = &lm_bustype; - snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id), "lm%d", dev->id); - dev->resource.name = dev->dev.bus_id; + ret = dev_set_name(&dev->dev, "lm%d", dev->id); + if (ret) + return ret; + dev->resource.name = dev_name(&dev->dev); ret = request_resource(&iomem_resource, &dev->resource); if (ret == 0) { diff --git a/arch/arm/mach-integrator/lm.h b/arch/arm/mach-integrator/lm.h new file mode 100644 index 00000000000..28186b6f2c0 --- /dev/null +++ b/arch/arm/mach-integrator/lm.h @@ -0,0 +1,23 @@ + +struct lm_device { + struct device dev; + struct resource resource; + unsigned int irq; + unsigned int id; +}; + +struct lm_driver { + struct device_driver drv; + int (*probe)(struct lm_device *); + void (*remove)(struct lm_device *); + int (*suspend)(struct lm_device *, pm_message_t); + int (*resume)(struct lm_device *); +}; + +int lm_driver_register(struct lm_driver *drv); +void lm_driver_unregister(struct lm_driver *drv); + +int lm_device_register(struct lm_device *dev); + +#define lm_get_drvdata(lm) dev_get_drvdata(&(lm)->dev) +#define lm_set_drvdata(lm,d) dev_set_drvdata(&(lm)->dev, d) diff --git a/arch/arm/mach-integrator/pci.c b/arch/arm/mach-integrator/pci.c deleted file mode 100644 index af7d3ff013e..00000000000 --- a/arch/arm/mach-integrator/pci.c +++ /dev/null @@ -1,131 +0,0 @@ -/* - * linux/arch/arm/mach-integrator/pci-integrator.c - * - * Copyright (C) 1999 ARM Limited - * Copyright (C) 2000 Deep Blue Solutions Ltd - * - * 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * - * PCI functions for Integrator - */ -#include <linux/kernel.h> -#include <linux/pci.h> -#include <linux/interrupt.h> -#include <linux/init.h> - -#include <asm/irq.h> -#include <asm/system.h> -#include <asm/mach/pci.h> -#include <asm/mach-types.h> - -/* - * A small note about bridges and interrupts. The DECchip 21050 (and - * later) adheres to the PCI-PCI bridge specification. This says that - * the interrupts on the other side of a bridge are swizzled in the - * following manner: - * - * Dev Interrupt Interrupt - * Pin on Pin on - * Device Connector - * - * 4 A A - * B B - * C C - * D D - * - * 5 A B - * B C - * C D - * D A - * - * 6 A C - * B D - * C A - * D B - * - * 7 A D - * B A - * C B - * D C - * - * Where A = pin 1, B = pin 2 and so on and pin=0 = default = A. - * Thus, each swizzle is ((pin-1) + (device#-4)) % 4 - * - * The following code swizzles for exactly one bridge. - */ -static inline int bridge_swizzle(int pin, unsigned int slot) -{ - return (pin + slot) & 3; -} - -/* - * This routine handles multiple bridges. - */ -static u8 __init integrator_swizzle(struct pci_dev *dev, u8 *pinp) -{ - int pin = *pinp; - - if (pin == 0) - pin = 1; - - pin -= 1; - while (dev->bus->self) { - pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); - /* - * move up the chain of bridges, swizzling as we go. - */ - dev = dev->bus->self; - } - *pinp = pin + 1; - - return PCI_SLOT(dev->devfn); -} - -static int irq_tab[4] __initdata = { - IRQ_AP_PCIINT0, IRQ_AP_PCIINT1, IRQ_AP_PCIINT2, IRQ_AP_PCIINT3 -}; - -/* - * map the specified device/slot/pin to an IRQ. This works out such - * that slot 9 pin 1 is INT0, pin 2 is INT1, and slot 10 pin 1 is INT1. - */ -static int __init integrator_map_irq(struct pci_dev *dev, u8 slot, u8 pin) -{ - int intnr = ((slot - 9) + (pin - 1)) & 3; - - return irq_tab[intnr]; -} - -extern void pci_v3_init(void *); - -static struct hw_pci integrator_pci __initdata = { - .swizzle = integrator_swizzle, - .map_irq = integrator_map_irq, - .setup = pci_v3_setup, - .nr_controllers = 1, - .scan = pci_v3_scan_bus, - .preinit = pci_v3_preinit, - .postinit = pci_v3_postinit, -}; - -static int __init integrator_pci_init(void) -{ - if (machine_is_integrator()) - pci_common_init(&integrator_pci); - return 0; -} - -subsys_initcall(integrator_pci_init); diff --git a/arch/arm/mach-integrator/pci_v3.c b/arch/arm/mach-integrator/pci_v3.c index d55fa4e9bb4..05e1f73a1e8 100644 --- a/arch/arm/mach-integrator/pci_v3.c +++ b/arch/arm/mach-integrator/pci_v3.c @@ -22,93 +22,287 @@ */ #include <linux/kernel.h> #include <linux/pci.h> -#include <linux/slab.h> #include <linux/ioport.h> #include <linux/interrupt.h> #include <linux/spinlock.h> #include <linux/init.h> - -#include <asm/hardware.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/system.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/of_pci.h> +#include <video/vga.h> + +#include <asm/mach/map.h> +#include <asm/signal.h> #include <asm/mach/pci.h> #include <asm/irq_regs.h> -#include <asm/hardware/pci_v3.h> +#include "pci_v3.h" +#include "hardware.h" + +/* + * Where in the memory map does PCI live? + * + * This represents a fairly liberal usage of address space. Even though + * the V3 only has two windows (therefore we need to map stuff on the fly), + * we maintain the same addresses, even if they're not mapped. + */ +#define PHYS_PCI_MEM_BASE 0x40000000 /* 256M */ +#define PHYS_PCI_PRE_BASE 0x50000000 /* 256M */ +#define PHYS_PCI_IO_BASE 0x60000000 /* 16M */ +#define PHYS_PCI_CONFIG_BASE 0x61000000 /* 16M */ +#define PHYS_PCI_V3_BASE 0x62000000 /* 64K */ + +#define PCI_MEMORY_VADDR IOMEM(0xe8000000) +#define PCI_CONFIG_VADDR IOMEM(0xec000000) + +/* + * V3 Local Bus to PCI Bridge definitions + * + * Registers (these are taken from page 129 of the EPC User's Manual Rev 1.04 + * All V3 register names are prefaced by V3_ to avoid clashing with any other + * PCI definitions. Their names match the user's manual. + * + * I'm assuming that I20 is disabled. + * + */ +#define V3_PCI_VENDOR 0x00000000 +#define V3_PCI_DEVICE 0x00000002 +#define V3_PCI_CMD 0x00000004 +#define V3_PCI_STAT 0x00000006 +#define V3_PCI_CC_REV 0x00000008 +#define V3_PCI_HDR_CFG 0x0000000C +#define V3_PCI_IO_BASE 0x00000010 +#define V3_PCI_BASE0 0x00000014 +#define V3_PCI_BASE1 0x00000018 +#define V3_PCI_SUB_VENDOR 0x0000002C +#define V3_PCI_SUB_ID 0x0000002E +#define V3_PCI_ROM 0x00000030 +#define V3_PCI_BPARAM 0x0000003C +#define V3_PCI_MAP0 0x00000040 +#define V3_PCI_MAP1 0x00000044 +#define V3_PCI_INT_STAT 0x00000048 +#define V3_PCI_INT_CFG 0x0000004C +#define V3_LB_BASE0 0x00000054 +#define V3_LB_BASE1 0x00000058 +#define V3_LB_MAP0 0x0000005E +#define V3_LB_MAP1 0x00000062 +#define V3_LB_BASE2 0x00000064 +#define V3_LB_MAP2 0x00000066 +#define V3_LB_SIZE 0x00000068 +#define V3_LB_IO_BASE 0x0000006E +#define V3_FIFO_CFG 0x00000070 +#define V3_FIFO_PRIORITY 0x00000072 +#define V3_FIFO_STAT 0x00000074 +#define V3_LB_ISTAT 0x00000076 +#define V3_LB_IMASK 0x00000077 +#define V3_SYSTEM 0x00000078 +#define V3_LB_CFG 0x0000007A +#define V3_PCI_CFG 0x0000007C +#define V3_DMA_PCI_ADR0 0x00000080 +#define V3_DMA_PCI_ADR1 0x00000090 +#define V3_DMA_LOCAL_ADR0 0x00000084 +#define V3_DMA_LOCAL_ADR1 0x00000094 +#define V3_DMA_LENGTH0 0x00000088 +#define V3_DMA_LENGTH1 0x00000098 +#define V3_DMA_CSR0 0x0000008B +#define V3_DMA_CSR1 0x0000009B +#define V3_DMA_CTLB_ADR0 0x0000008C +#define V3_DMA_CTLB_ADR1 0x0000009C +#define V3_DMA_DELAY 0x000000E0 +#define V3_MAIL_DATA 0x000000C0 +#define V3_PCI_MAIL_IEWR 0x000000D0 +#define V3_PCI_MAIL_IERD 0x000000D2 +#define V3_LB_MAIL_IEWR 0x000000D4 +#define V3_LB_MAIL_IERD 0x000000D6 +#define V3_MAIL_WR_STAT 0x000000D8 +#define V3_MAIL_RD_STAT 0x000000DA +#define V3_QBA_MAP 0x000000DC + +/* PCI COMMAND REGISTER bits + */ +#define V3_COMMAND_M_FBB_EN (1 << 9) +#define V3_COMMAND_M_SERR_EN (1 << 8) +#define V3_COMMAND_M_PAR_EN (1 << 6) +#define V3_COMMAND_M_MASTER_EN (1 << 2) +#define V3_COMMAND_M_MEM_EN (1 << 1) +#define V3_COMMAND_M_IO_EN (1 << 0) + +/* SYSTEM REGISTER bits + */ +#define V3_SYSTEM_M_RST_OUT (1 << 15) +#define V3_SYSTEM_M_LOCK (1 << 14) + +/* PCI_CFG bits + */ +#define V3_PCI_CFG_M_I2O_EN (1 << 15) +#define V3_PCI_CFG_M_IO_REG_DIS (1 << 14) +#define V3_PCI_CFG_M_IO_DIS (1 << 13) +#define V3_PCI_CFG_M_EN3V (1 << 12) +#define V3_PCI_CFG_M_RETRY_EN (1 << 10) +#define V3_PCI_CFG_M_AD_LOW1 (1 << 9) +#define V3_PCI_CFG_M_AD_LOW0 (1 << 8) + +/* PCI_BASE register bits (PCI -> Local Bus) + */ +#define V3_PCI_BASE_M_ADR_BASE 0xFFF00000 +#define V3_PCI_BASE_M_ADR_BASEL 0x000FFF00 +#define V3_PCI_BASE_M_PREFETCH (1 << 3) +#define V3_PCI_BASE_M_TYPE (3 << 1) +#define V3_PCI_BASE_M_IO (1 << 0) + +/* PCI MAP register bits (PCI -> Local bus) + */ +#define V3_PCI_MAP_M_MAP_ADR 0xFFF00000 +#define V3_PCI_MAP_M_RD_POST_INH (1 << 15) +#define V3_PCI_MAP_M_ROM_SIZE (3 << 10) +#define V3_PCI_MAP_M_SWAP (3 << 8) +#define V3_PCI_MAP_M_ADR_SIZE 0x000000F0 +#define V3_PCI_MAP_M_REG_EN (1 << 1) +#define V3_PCI_MAP_M_ENABLE (1 << 0) + +/* + * LB_BASE0,1 register bits (Local bus -> PCI) + */ +#define V3_LB_BASE_ADR_BASE 0xfff00000 +#define V3_LB_BASE_SWAP (3 << 8) +#define V3_LB_BASE_ADR_SIZE (15 << 4) +#define V3_LB_BASE_PREFETCH (1 << 3) +#define V3_LB_BASE_ENABLE (1 << 0) + +#define V3_LB_BASE_ADR_SIZE_1MB (0 << 4) +#define V3_LB_BASE_ADR_SIZE_2MB (1 << 4) +#define V3_LB_BASE_ADR_SIZE_4MB (2 << 4) +#define V3_LB_BASE_ADR_SIZE_8MB (3 << 4) +#define V3_LB_BASE_ADR_SIZE_16MB (4 << 4) +#define V3_LB_BASE_ADR_SIZE_32MB (5 << 4) +#define V3_LB_BASE_ADR_SIZE_64MB (6 << 4) +#define V3_LB_BASE_ADR_SIZE_128MB (7 << 4) +#define V3_LB_BASE_ADR_SIZE_256MB (8 << 4) +#define V3_LB_BASE_ADR_SIZE_512MB (9 << 4) +#define V3_LB_BASE_ADR_SIZE_1GB (10 << 4) +#define V3_LB_BASE_ADR_SIZE_2GB (11 << 4) + +#define v3_addr_to_lb_base(a) ((a) & V3_LB_BASE_ADR_BASE) + +/* + * LB_MAP0,1 register bits (Local bus -> PCI) + */ +#define V3_LB_MAP_MAP_ADR 0xfff0 +#define V3_LB_MAP_TYPE (7 << 1) +#define V3_LB_MAP_AD_LOW_EN (1 << 0) + +#define V3_LB_MAP_TYPE_IACK (0 << 1) +#define V3_LB_MAP_TYPE_IO (1 << 1) +#define V3_LB_MAP_TYPE_MEM (3 << 1) +#define V3_LB_MAP_TYPE_CONFIG (5 << 1) +#define V3_LB_MAP_TYPE_MEM_MULTIPLE (6 << 1) + +#define v3_addr_to_lb_map(a) (((a) >> 16) & V3_LB_MAP_MAP_ADR) + +/* + * LB_BASE2 register bits (Local bus -> PCI IO) + */ +#define V3_LB_BASE2_ADR_BASE 0xff00 +#define V3_LB_BASE2_SWAP (3 << 6) +#define V3_LB_BASE2_ENABLE (1 << 0) + +#define v3_addr_to_lb_base2(a) (((a) >> 16) & V3_LB_BASE2_ADR_BASE) + +/* + * LB_MAP2 register bits (Local bus -> PCI IO) + */ +#define V3_LB_MAP2_MAP_ADR 0xff00 + +#define v3_addr_to_lb_map2(a) (((a) >> 16) & V3_LB_MAP2_MAP_ADR) /* * The V3 PCI interface chip in Integrator provides several windows from * local bus memory into the PCI memory areas. Unfortunately, there - * are not really enough windows for our usage, therefore we reuse + * are not really enough windows for our usage, therefore we reuse * one of the windows for access to PCI configuration space. The * memory map is as follows: - * + * * Local Bus Memory Usage - * + * * 40000000 - 4FFFFFFF PCI memory. 256M non-prefetchable * 50000000 - 5FFFFFFF PCI memory. 256M prefetchable * 60000000 - 60FFFFFF PCI IO. 16M * 61000000 - 61FFFFFF PCI Configuration. 16M - * + * * There are three V3 windows, each described by a pair of V3 registers. * These are LB_BASE0/LB_MAP0, LB_BASE1/LB_MAP1 and LB_BASE2/LB_MAP2. * Base0 and Base1 can be used for any type of PCI memory access. Base2 * can be used either for PCI I/O or for I20 accesses. By default, uHAL * uses this only for PCI IO space. - * + * * Normally these spaces are mapped using the following base registers: - * + * * Usage Local Bus Memory Base/Map registers used - * + * * Mem 40000000 - 4FFFFFFF LB_BASE0/LB_MAP0 * Mem 50000000 - 5FFFFFFF LB_BASE1/LB_MAP1 * IO 60000000 - 60FFFFFF LB_BASE2/LB_MAP2 * Cfg 61000000 - 61FFFFFF - * + * * This means that I20 and PCI configuration space accesses will fail. - * When PCI configuration accesses are needed (via the uHAL PCI + * When PCI configuration accesses are needed (via the uHAL PCI * configuration space primitives) we must remap the spaces as follows: - * + * * Usage Local Bus Memory Base/Map registers used - * + * * Mem 40000000 - 4FFFFFFF LB_BASE0/LB_MAP0 * Mem 50000000 - 5FFFFFFF LB_BASE0/LB_MAP0 * IO 60000000 - 60FFFFFF LB_BASE2/LB_MAP2 * Cfg 61000000 - 61FFFFFF LB_BASE1/LB_MAP1 - * + * * To make this work, the code depends on overlapping windows working. - * The V3 chip translates an address by checking its range within + * The V3 chip translates an address by checking its range within * each of the BASE/MAP pairs in turn (in ascending register number * order). It will use the first matching pair. So, for example, * if the same address is mapped by both LB_BASE0/LB_MAP0 and - * LB_BASE1/LB_MAP1, the V3 will use the translation from + * LB_BASE1/LB_MAP1, the V3 will use the translation from * LB_BASE0/LB_MAP0. - * + * * To allow PCI Configuration space access, the code enlarges the * window mapped by LB_BASE0/LB_MAP0 from 256M to 512M. This occludes * the windows currently mapped by LB_BASE1/LB_MAP1 so that it can * be remapped for use by configuration cycles. - * - * At the end of the PCI Configuration space accesses, + * + * At the end of the PCI Configuration space accesses, * LB_BASE1/LB_MAP1 is reset to map PCI Memory. Finally the window * mapped by LB_BASE0/LB_MAP0 is reduced in size from 512M to 256M to * reveal the now restored LB_BASE1/LB_MAP1 window. - * + * * NOTE: We do not set up I2O mapping. I suspect that this is only * for an intelligent (target) device. Using I2O disables most of * the mappings into PCI memory. */ +/* Filled in by probe */ +static void __iomem *pci_v3_base; +/* CPU side memory ranges */ +static struct resource conf_mem; /* FIXME: remap this instead of static map */ +static struct resource io_mem; +static struct resource non_mem; +static struct resource pre_mem; +/* PCI side memory ranges */ +static u64 non_mem_pci; +static u64 non_mem_pci_sz; +static u64 pre_mem_pci; +static u64 pre_mem_pci_sz; + // V3 access routines -#define v3_writeb(o,v) __raw_writeb(v, PCI_V3_VADDR + (unsigned int)(o)) -#define v3_readb(o) (__raw_readb(PCI_V3_VADDR + (unsigned int)(o))) +#define v3_writeb(o,v) __raw_writeb(v, pci_v3_base + (unsigned int)(o)) +#define v3_readb(o) (__raw_readb(pci_v3_base + (unsigned int)(o))) -#define v3_writew(o,v) __raw_writew(v, PCI_V3_VADDR + (unsigned int)(o)) -#define v3_readw(o) (__raw_readw(PCI_V3_VADDR + (unsigned int)(o))) +#define v3_writew(o,v) __raw_writew(v, pci_v3_base + (unsigned int)(o)) +#define v3_readw(o) (__raw_readw(pci_v3_base + (unsigned int)(o))) -#define v3_writel(o,v) __raw_writel(v, PCI_V3_VADDR + (unsigned int)(o)) -#define v3_readl(o) (__raw_readl(PCI_V3_VADDR + (unsigned int)(o))) +#define v3_writel(o,v) __raw_writel(v, pci_v3_base + (unsigned int)(o)) +#define v3_readl(o) (__raw_readl(pci_v3_base + (unsigned int)(o))) /*============================================================================ * @@ -126,8 +320,8 @@ * * returns: configuration address to play on the PCI bus * - * To generate the appropriate PCI configuration cycles in the PCI - * configuration address space, you present the V3 with the following pattern + * To generate the appropriate PCI configuration cycles in the PCI + * configuration address space, you present the V3 with the following pattern * (which is very nearly a type 1 (except that the lower two bits are 00 and * not 01). In order for this mapping to work you need to set up one of * the local to PCI aperatures to 16Mbytes in length translating to @@ -137,7 +331,7 @@ * * Type 0: * - * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 + * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | | |D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|0| @@ -149,7 +343,7 @@ * * Type 1: * - * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 + * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1| @@ -160,27 +354,14 @@ * 15:11 Device number (5 bits) * 10:8 function number * 7:2 register number - * + * */ -static DEFINE_SPINLOCK(v3_lock); - -#define PCI_BUS_NONMEM_START 0x00000000 -#define PCI_BUS_NONMEM_SIZE SZ_256M - -#define PCI_BUS_PREMEM_START PCI_BUS_NONMEM_START + PCI_BUS_NONMEM_SIZE -#define PCI_BUS_PREMEM_SIZE SZ_256M - -#if PCI_BUS_NONMEM_START & 0x000fffff -#error PCI_BUS_NONMEM_START must be megabyte aligned -#endif -#if PCI_BUS_PREMEM_START & 0x000fffff -#error PCI_BUS_PREMEM_START must be megabyte aligned -#endif +static DEFINE_RAW_SPINLOCK(v3_lock); #undef V3_LB_BASE_PREFETCH #define V3_LB_BASE_PREFETCH 0 -static unsigned long v3_open_config_window(struct pci_bus *bus, +static void __iomem *v3_open_config_window(struct pci_bus *bus, unsigned int devfn, int offset) { unsigned int address, mapaddress, busnr; @@ -190,12 +371,9 @@ static unsigned long v3_open_config_window(struct pci_bus *bus, /* * Trap out illegal values */ - if (offset > 255) - BUG(); - if (busnr > 255) - BUG(); - if (devfn > 255) - BUG(); + BUG_ON(offset > 255); + BUG_ON(busnr > 255); + BUG_ON(devfn > 255); if (busnr == 0) { int slot = PCI_SLOT(devfn); @@ -245,13 +423,13 @@ static unsigned long v3_open_config_window(struct pci_bus *bus, * prefetchable), this frees up base1 for re-use by * configuration memory */ - v3_writel(V3_LB_BASE0, v3_addr_to_lb_base(PHYS_PCI_MEM_BASE) | + v3_writel(V3_LB_BASE0, v3_addr_to_lb_base(non_mem.start) | V3_LB_BASE_ADR_SIZE_512MB | V3_LB_BASE_ENABLE); /* * Set up base1/map1 to point into configuration space. */ - v3_writel(V3_LB_BASE1, v3_addr_to_lb_base(PHYS_PCI_CONFIG_BASE) | + v3_writel(V3_LB_BASE1, v3_addr_to_lb_base(conf_mem.start) | V3_LB_BASE_ADR_SIZE_16MB | V3_LB_BASE_ENABLE); v3_writew(V3_LB_MAP1, mapaddress); @@ -263,27 +441,27 @@ static void v3_close_config_window(void) /* * Reassign base1 for use by prefetchable PCI memory */ - v3_writel(V3_LB_BASE1, v3_addr_to_lb_base(PHYS_PCI_MEM_BASE + SZ_256M) | + v3_writel(V3_LB_BASE1, v3_addr_to_lb_base(pre_mem.start) | V3_LB_BASE_ADR_SIZE_256MB | V3_LB_BASE_PREFETCH | V3_LB_BASE_ENABLE); - v3_writew(V3_LB_MAP1, v3_addr_to_lb_map(PCI_BUS_PREMEM_START) | + v3_writew(V3_LB_MAP1, v3_addr_to_lb_map(pre_mem_pci) | V3_LB_MAP_TYPE_MEM_MULTIPLE); /* * And shrink base0 back to a 256M window (NOTE: MAP0 already correct) */ - v3_writel(V3_LB_BASE0, v3_addr_to_lb_base(PHYS_PCI_MEM_BASE) | + v3_writel(V3_LB_BASE0, v3_addr_to_lb_base(non_mem.start) | V3_LB_BASE_ADR_SIZE_256MB | V3_LB_BASE_ENABLE); } static int v3_read_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val) { - unsigned long addr; + void __iomem *addr; unsigned long flags; u32 v; - spin_lock_irqsave(&v3_lock, flags); + raw_spin_lock_irqsave(&v3_lock, flags); addr = v3_open_config_window(bus, devfn, where); switch (size) { @@ -301,7 +479,7 @@ static int v3_read_config(struct pci_bus *bus, unsigned int devfn, int where, } v3_close_config_window(); - spin_unlock_irqrestore(&v3_lock, flags); + raw_spin_unlock_irqrestore(&v3_lock, flags); *val = v; return PCIBIOS_SUCCESSFUL; @@ -310,10 +488,10 @@ static int v3_read_config(struct pci_bus *bus, unsigned int devfn, int where, static int v3_write_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val) { - unsigned long addr; + void __iomem *addr; unsigned long flags; - spin_lock_irqsave(&v3_lock, flags); + raw_spin_lock_irqsave(&v3_lock, flags); addr = v3_open_config_window(bus, devfn, where); switch (size) { @@ -334,7 +512,7 @@ static int v3_write_config(struct pci_bus *bus, unsigned int devfn, int where, } v3_close_config_window(); - spin_unlock_irqrestore(&v3_lock, flags); + raw_spin_unlock_irqrestore(&v3_lock, flags); return PCIBIOS_SUCCESSFUL; } @@ -344,21 +522,7 @@ static struct pci_ops pci_v3_ops = { .write = v3_write_config, }; -static struct resource non_mem = { - .name = "PCI non-prefetchable", - .start = PHYS_PCI_MEM_BASE + PCI_BUS_NONMEM_START, - .end = PHYS_PCI_MEM_BASE + PCI_BUS_NONMEM_START + PCI_BUS_NONMEM_SIZE - 1, - .flags = IORESOURCE_MEM, -}; - -static struct resource pre_mem = { - .name = "PCI prefetchable", - .start = PHYS_PCI_MEM_BASE + PCI_BUS_PREMEM_START, - .end = PHYS_PCI_MEM_BASE + PCI_BUS_PREMEM_START + PCI_BUS_PREMEM_SIZE - 1, - .flags = IORESOURCE_MEM | IORESOURCE_PREFETCH, -}; - -static int __init pci_v3_setup_resources(struct resource **resource) +static int __init pci_v3_setup_resources(struct pci_sys_data *sys) { if (request_resource(&iomem_resource, &non_mem)) { printk(KERN_ERR "PCI: unable to allocate non-prefetchable " @@ -373,13 +537,11 @@ static int __init pci_v3_setup_resources(struct resource **resource) } /* - * bus->resource[0] is the IO resource for this bus - * bus->resource[1] is the mem resource for this bus - * bus->resource[2] is the prefetch mem resource for this bus + * the mem resource for this bus + * the prefetch mem resource for this bus */ - resource[0] = &ioport_resource; - resource[1] = &non_mem; - resource[2] = &pre_mem; + pci_add_resource_offset(&sys->resources, &non_mem, sys->mem_offset); + pci_add_resource_offset(&sys->resources, &pre_mem, sys->mem_offset); return 1; } @@ -389,9 +551,10 @@ static int __init pci_v3_setup_resources(struct resource **resource) * means I can't get additional information on the reason for the pm2fb * problems. I suppose I'll just have to mind-meld with the machine. ;) */ -#define SC_PCI (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_PCIENABLE_OFFSET) -#define SC_LBFADDR (IO_ADDRESS(INTEGRATOR_SC_BASE) + 0x20) -#define SC_LBFCODE (IO_ADDRESS(INTEGRATOR_SC_BASE) + 0x24) +static void __iomem *ap_syscon_base; +#define INTEGRATOR_SC_PCIENABLE_OFFSET 0x18 +#define INTEGRATOR_SC_LBFADDR_OFFSET 0x20 +#define INTEGRATOR_SC_LBFCODE_OFFSET 0x24 static int v3_pci_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) @@ -402,14 +565,13 @@ v3_pci_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) char buf[128]; sprintf(buf, "V3 fault: addr 0x%08lx, FSR 0x%03x, PC 0x%08lx [%08lx] LBFADDR=%08x LBFCODE=%02x ISTAT=%02x\n", - addr, fsr, pc, instr, __raw_readl(SC_LBFADDR), __raw_readl(SC_LBFCODE) & 255, + addr, fsr, pc, instr, __raw_readl(ap_syscon_base + INTEGRATOR_SC_LBFADDR_OFFSET), __raw_readl(ap_syscon_base + INTEGRATOR_SC_LBFCODE_OFFSET) & 255, v3_readb(V3_LB_ISTAT)); printk(KERN_DEBUG "%s", buf); - printascii(buf); #endif v3_writeb(V3_LB_ISTAT, 0); - __raw_writel(3, SC_PCI); + __raw_writel(3, ap_syscon_base + INTEGRATOR_SC_PCIENABLE_OFFSET); /* * If the instruction being executed was a read, @@ -440,25 +602,26 @@ v3_pci_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) return 1; } -static irqreturn_t v3_irq(int dummy, void *devid) +static irqreturn_t v3_irq(int irq, void *devid) { #ifdef CONFIG_DEBUG_LL struct pt_regs *regs = get_irq_regs(); unsigned long pc = instruction_pointer(regs); unsigned long instr = *(unsigned long *)pc; char buf[128]; + extern void printascii(const char *); sprintf(buf, "V3 int %d: pc=0x%08lx [%08lx] LBFADDR=%08x LBFCODE=%02x " - "ISTAT=%02x\n", IRQ_AP_V3INT, pc, instr, - __raw_readl(SC_LBFADDR), - __raw_readl(SC_LBFCODE) & 255, + "ISTAT=%02x\n", irq, pc, instr, + __raw_readl(ap_syscon_base + INTEGRATOR_SC_LBFADDR_OFFSET), + __raw_readl(ap_syscon_base + INTEGRATOR_SC_LBFCODE_OFFSET) & 255, v3_readb(V3_LB_ISTAT)); printascii(buf); #endif v3_writew(V3_PCI_STAT, 0xf000); v3_writeb(V3_LB_ISTAT, 0); - __raw_writel(3, SC_PCI); + __raw_writel(3, ap_syscon_base + INTEGRATOR_SC_PCIENABLE_OFFSET); #ifdef CONFIG_DEBUG_LL /* @@ -474,42 +637,41 @@ static irqreturn_t v3_irq(int dummy, void *devid) return IRQ_HANDLED; } -int __init pci_v3_setup(int nr, struct pci_sys_data *sys) +static int __init pci_v3_setup(int nr, struct pci_sys_data *sys) { int ret = 0; + if (!ap_syscon_base) + return -EINVAL; + if (nr == 0) { - sys->mem_offset = PHYS_PCI_MEM_BASE; - ret = pci_v3_setup_resources(sys->resource); + sys->mem_offset = non_mem.start; + ret = pci_v3_setup_resources(sys); } return ret; } -struct pci_bus *pci_v3_scan_bus(int nr, struct pci_sys_data *sys) -{ - return pci_scan_bus(sys->busnr, &pci_v3_ops, sys); -} - /* * V3_LB_BASE? - local bus address * V3_LB_MAP? - pci bus address */ -void __init pci_v3_preinit(void) +static void __init pci_v3_preinit(void) { unsigned long flags; unsigned int temp; - int ret; + + pcibios_min_mem = 0x00100000; /* * Hook in our fault handler for PCI errors */ - hook_fault_code(4, v3_pci_fault, SIGBUS, "external abort on linefetch"); - hook_fault_code(6, v3_pci_fault, SIGBUS, "external abort on linefetch"); - hook_fault_code(8, v3_pci_fault, SIGBUS, "external abort on non-linefetch"); - hook_fault_code(10, v3_pci_fault, SIGBUS, "external abort on non-linefetch"); + hook_fault_code(4, v3_pci_fault, SIGBUS, 0, "external abort on linefetch"); + hook_fault_code(6, v3_pci_fault, SIGBUS, 0, "external abort on linefetch"); + hook_fault_code(8, v3_pci_fault, SIGBUS, 0, "external abort on non-linefetch"); + hook_fault_code(10, v3_pci_fault, SIGBUS, 0, "external abort on non-linefetch"); - spin_lock_irqsave(&v3_lock, flags); + raw_spin_lock_irqsave(&v3_lock, flags); /* * Unlock V3 registers, but only if they were previously locked. @@ -521,25 +683,25 @@ void __init pci_v3_preinit(void) * Setup window 0 - PCI non-prefetchable memory * Local: 0x40000000 Bus: 0x00000000 Size: 256MB */ - v3_writel(V3_LB_BASE0, v3_addr_to_lb_base(PHYS_PCI_MEM_BASE) | + v3_writel(V3_LB_BASE0, v3_addr_to_lb_base(non_mem.start) | V3_LB_BASE_ADR_SIZE_256MB | V3_LB_BASE_ENABLE); - v3_writew(V3_LB_MAP0, v3_addr_to_lb_map(PCI_BUS_NONMEM_START) | + v3_writew(V3_LB_MAP0, v3_addr_to_lb_map(non_mem_pci) | V3_LB_MAP_TYPE_MEM); /* * Setup window 1 - PCI prefetchable memory * Local: 0x50000000 Bus: 0x10000000 Size: 256MB */ - v3_writel(V3_LB_BASE1, v3_addr_to_lb_base(PHYS_PCI_MEM_BASE + SZ_256M) | + v3_writel(V3_LB_BASE1, v3_addr_to_lb_base(pre_mem.start) | V3_LB_BASE_ADR_SIZE_256MB | V3_LB_BASE_PREFETCH | V3_LB_BASE_ENABLE); - v3_writew(V3_LB_MAP1, v3_addr_to_lb_map(PCI_BUS_PREMEM_START) | + v3_writew(V3_LB_MAP1, v3_addr_to_lb_map(pre_mem_pci) | V3_LB_MAP_TYPE_MEM_MULTIPLE); /* * Setup window 2 - PCI IO */ - v3_writel(V3_LB_BASE2, v3_addr_to_lb_base2(PHYS_PCI_IO_BASE) | + v3_writel(V3_LB_BASE2, v3_addr_to_lb_base2(io_mem.start) | V3_LB_BASE_ENABLE); v3_writew(V3_LB_MAP2, v3_addr_to_lb_map2(0)); @@ -572,20 +734,12 @@ void __init pci_v3_preinit(void) v3_writeb(V3_LB_ISTAT, 0); v3_writew(V3_LB_CFG, v3_readw(V3_LB_CFG) | (1 << 10)); v3_writeb(V3_LB_IMASK, 0x28); - __raw_writel(3, SC_PCI); - - /* - * Grab the PCI error interrupt. - */ - ret = request_irq(IRQ_AP_V3INT, v3_irq, 0, "V3", NULL); - if (ret) - printk(KERN_ERR "PCI: unable to grab PCI error " - "interrupt: %d\n", ret); + __raw_writel(3, ap_syscon_base + INTEGRATOR_SC_PCIENABLE_OFFSET); - spin_unlock_irqrestore(&v3_lock, flags); + raw_spin_unlock_irqrestore(&v3_lock, flags); } -void __init pci_v3_postinit(void) +static void __init pci_v3_postinit(void) { unsigned int pci_cmd; @@ -604,5 +758,194 @@ void __init pci_v3_postinit(void) "interrupt: %d\n", ret); #endif - register_isa_ports(PHYS_PCI_MEM_BASE, PHYS_PCI_IO_BASE, 0); + register_isa_ports(non_mem.start, io_mem.start, 0); +} + +/* + * A small note about bridges and interrupts. The DECchip 21050 (and + * later) adheres to the PCI-PCI bridge specification. This says that + * the interrupts on the other side of a bridge are swizzled in the + * following manner: + * + * Dev Interrupt Interrupt + * Pin on Pin on + * Device Connector + * + * 4 A A + * B B + * C C + * D D + * + * 5 A B + * B C + * C D + * D A + * + * 6 A C + * B D + * C A + * D B + * + * 7 A D + * B A + * C B + * D C + * + * Where A = pin 1, B = pin 2 and so on and pin=0 = default = A. + * Thus, each swizzle is ((pin-1) + (device#-4)) % 4 + */ + +/* + * This routine handles multiple bridges. + */ +static u8 __init pci_v3_swizzle(struct pci_dev *dev, u8 *pinp) +{ + if (*pinp == 0) + *pinp = 1; + + return pci_common_swizzle(dev, pinp); +} + +static struct hw_pci pci_v3 __initdata = { + .swizzle = pci_v3_swizzle, + .setup = pci_v3_setup, + .nr_controllers = 1, + .ops = &pci_v3_ops, + .preinit = pci_v3_preinit, + .postinit = pci_v3_postinit, +}; + +static int __init pci_v3_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct of_pci_range_parser parser; + struct of_pci_range range; + struct resource *res; + int irq, ret; + + /* Remap the Integrator system controller */ + ap_syscon_base = devm_ioremap(&pdev->dev, INTEGRATOR_SC_BASE, 0x100); + if (!ap_syscon_base) { + dev_err(&pdev->dev, "unable to remap the AP syscon for PCIv3\n"); + return -ENODEV; + } + + /* Device tree probe path */ + if (!np) { + dev_err(&pdev->dev, "no device tree node for PCIv3\n"); + return -ENODEV; + } + + if (of_pci_range_parser_init(&parser, np)) + return -EINVAL; + + /* Get base for bridge registers */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "unable to obtain PCIv3 base\n"); + return -ENODEV; + } + pci_v3_base = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!pci_v3_base) { + dev_err(&pdev->dev, "unable to remap PCIv3 base\n"); + return -ENODEV; + } + + /* Get and request error IRQ resource */ + irq = platform_get_irq(pdev, 0); + if (irq <= 0) { + dev_err(&pdev->dev, "unable to obtain PCIv3 error IRQ\n"); + return -ENODEV; + } + ret = devm_request_irq(&pdev->dev, irq, v3_irq, 0, + "PCIv3 error", NULL); + if (ret < 0) { + dev_err(&pdev->dev, "unable to request PCIv3 error IRQ %d (%d)\n", irq, ret); + return ret; + } + + for_each_of_pci_range(&parser, &range) { + if (!range.flags) { + of_pci_range_to_resource(&range, np, &conf_mem); + conf_mem.name = "PCIv3 config"; + } + if (range.flags & IORESOURCE_IO) { + of_pci_range_to_resource(&range, np, &io_mem); + io_mem.name = "PCIv3 I/O"; + } + if ((range.flags & IORESOURCE_MEM) && + !(range.flags & IORESOURCE_PREFETCH)) { + non_mem_pci = range.pci_addr; + non_mem_pci_sz = range.size; + of_pci_range_to_resource(&range, np, &non_mem); + non_mem.name = "PCIv3 non-prefetched mem"; + } + if ((range.flags & IORESOURCE_MEM) && + (range.flags & IORESOURCE_PREFETCH)) { + pre_mem_pci = range.pci_addr; + pre_mem_pci_sz = range.size; + of_pci_range_to_resource(&range, np, &pre_mem); + pre_mem.name = "PCIv3 prefetched mem"; + } + } + + if (!conf_mem.start || !io_mem.start || + !non_mem.start || !pre_mem.start) { + dev_err(&pdev->dev, "missing ranges in device node\n"); + return -EINVAL; + } + + pci_v3.map_irq = of_irq_parse_and_map_pci; + pci_common_init_dev(&pdev->dev, &pci_v3); + + return 0; +} + +static const struct of_device_id pci_ids[] = { + { .compatible = "v3,v360epc-pci", }, + {}, +}; + +static struct platform_driver pci_v3_driver = { + .driver = { + .name = "pci-v3", + .of_match_table = pci_ids, + }, +}; + +static int __init pci_v3_init(void) +{ + return platform_driver_probe(&pci_v3_driver, pci_v3_probe); +} + +subsys_initcall(pci_v3_init); + +/* + * Static mappings for the PCIv3 bridge + * + * e8000000 40000000 PCI memory PHYS_PCI_MEM_BASE (max 512M) + * ec000000 61000000 PCI config space PHYS_PCI_CONFIG_BASE (max 16M) + * fee00000 60000000 PCI IO PHYS_PCI_IO_BASE (max 16M) + */ +static struct map_desc pci_v3_io_desc[] __initdata __maybe_unused = { + { + .virtual = (unsigned long)PCI_MEMORY_VADDR, + .pfn = __phys_to_pfn(PHYS_PCI_MEM_BASE), + .length = SZ_16M, + .type = MT_DEVICE + }, { + .virtual = (unsigned long)PCI_CONFIG_VADDR, + .pfn = __phys_to_pfn(PHYS_PCI_CONFIG_BASE), + .length = SZ_16M, + .type = MT_DEVICE + } +}; + +int __init pci_v3_early_init(void) +{ + iotable_init(pci_v3_io_desc, ARRAY_SIZE(pci_v3_io_desc)); + vga_base = (unsigned long)PCI_MEMORY_VADDR; + pci_map_io_early(__phys_to_pfn(PHYS_PCI_IO_BASE)); + return 0; } diff --git a/arch/arm/mach-integrator/pci_v3.h b/arch/arm/mach-integrator/pci_v3.h new file mode 100644 index 00000000000..06a9e2e7d00 --- /dev/null +++ b/arch/arm/mach-integrator/pci_v3.h @@ -0,0 +1,9 @@ +/* Simple oneliner include to the PCIv3 early init */ +#ifdef CONFIG_PCI +extern int pci_v3_early_init(void); +#else +static inline int pci_v3_early_init(void) +{ + return 0; +} +#endif diff --git a/arch/arm/mach-integrator/time.c b/arch/arm/mach-integrator/time.c deleted file mode 100644 index 5278f589fce..00000000000 --- a/arch/arm/mach-integrator/time.c +++ /dev/null @@ -1,220 +0,0 @@ -/* - * linux/arch/arm/mach-integrator/time.c - * - * Copyright (C) 2000-2001 Deep Blue Solutions Ltd. - * - * 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 <linux/module.h> -#include <linux/kernel.h> -#include <linux/time.h> -#include <linux/mc146818rtc.h> -#include <linux/interrupt.h> -#include <linux/init.h> -#include <linux/device.h> -#include <linux/amba/bus.h> - -#include <asm/hardware.h> -#include <asm/io.h> -#include <asm/uaccess.h> -#include <asm/rtc.h> - -#include <asm/mach/time.h> - -#define RTC_DR (0) -#define RTC_MR (4) -#define RTC_STAT (8) -#define RTC_EOI (8) -#define RTC_LR (12) -#define RTC_CR (16) -#define RTC_CR_MIE (1 << 0) - -extern int (*set_rtc)(void); -static void __iomem *rtc_base; - -static int integrator_set_rtc(void) -{ - __raw_writel(xtime.tv_sec, rtc_base + RTC_LR); - return 1; -} - -static int integrator_rtc_read_alarm(struct rtc_wkalrm *alrm) -{ - rtc_time_to_tm(readl(rtc_base + RTC_MR), &alrm->time); - return 0; -} - -static inline int integrator_rtc_set_alarm(struct rtc_wkalrm *alrm) -{ - unsigned long time; - int ret; - - /* - * At the moment, we can only deal with non-wildcarded alarm times. - */ - ret = rtc_valid_tm(&alrm->time); - if (ret == 0) - ret = rtc_tm_to_time(&alrm->time, &time); - if (ret == 0) - writel(time, rtc_base + RTC_MR); - return ret; -} - -static int integrator_rtc_read_time(struct rtc_time *tm) -{ - rtc_time_to_tm(readl(rtc_base + RTC_DR), tm); - return 0; -} - -/* - * Set the RTC time. Unfortunately, we can't accurately set - * the point at which the counter updates. - * - * Also, since RTC_LR is transferred to RTC_CR on next rising - * edge of the 1Hz clock, we must write the time one second - * in advance. - */ -static inline int integrator_rtc_set_time(struct rtc_time *tm) -{ - unsigned long time; - int ret; - - ret = rtc_tm_to_time(tm, &time); - if (ret == 0) - writel(time + 1, rtc_base + RTC_LR); - - return ret; -} - -static struct rtc_ops rtc_ops = { - .owner = THIS_MODULE, - .read_time = integrator_rtc_read_time, - .set_time = integrator_rtc_set_time, - .read_alarm = integrator_rtc_read_alarm, - .set_alarm = integrator_rtc_set_alarm, -}; - -static irqreturn_t arm_rtc_interrupt(int irq, void *dev_id) -{ - writel(0, rtc_base + RTC_EOI); - return IRQ_HANDLED; -} - -static int rtc_probe(struct amba_device *dev, void *id) -{ - int ret; - - if (rtc_base) - return -EBUSY; - - ret = amba_request_regions(dev, NULL); - if (ret) - goto out; - - rtc_base = ioremap(dev->res.start, SZ_4K); - if (!rtc_base) { - ret = -ENOMEM; - goto res_out; - } - - __raw_writel(0, rtc_base + RTC_CR); - __raw_writel(0, rtc_base + RTC_EOI); - - xtime.tv_sec = __raw_readl(rtc_base + RTC_DR); - - ret = request_irq(dev->irq[0], arm_rtc_interrupt, IRQF_DISABLED, - "rtc-pl030", dev); - if (ret) - goto map_out; - - ret = register_rtc(&rtc_ops); - if (ret) - goto irq_out; - - set_rtc = integrator_set_rtc; - return 0; - - irq_out: - free_irq(dev->irq[0], dev); - map_out: - iounmap(rtc_base); - rtc_base = NULL; - res_out: - amba_release_regions(dev); - out: - return ret; -} - -static int rtc_remove(struct amba_device *dev) -{ - set_rtc = NULL; - - writel(0, rtc_base + RTC_CR); - - free_irq(dev->irq[0], dev); - unregister_rtc(&rtc_ops); - - iounmap(rtc_base); - rtc_base = NULL; - amba_release_regions(dev); - - return 0; -} - -static struct timespec rtc_delta; - -static int rtc_suspend(struct amba_device *dev, pm_message_t state) -{ - struct timespec rtc; - - rtc.tv_sec = readl(rtc_base + RTC_DR); - rtc.tv_nsec = 0; - save_time_delta(&rtc_delta, &rtc); - - return 0; -} - -static int rtc_resume(struct amba_device *dev) -{ - struct timespec rtc; - - rtc.tv_sec = readl(rtc_base + RTC_DR); - rtc.tv_nsec = 0; - restore_time_delta(&rtc_delta, &rtc); - - return 0; -} - -static struct amba_id rtc_ids[] = { - { - .id = 0x00041030, - .mask = 0x000fffff, - }, - { 0, 0 }, -}; - -static struct amba_driver rtc_driver = { - .drv = { - .name = "rtc-pl030", - }, - .probe = rtc_probe, - .remove = rtc_remove, - .suspend = rtc_suspend, - .resume = rtc_resume, - .id_table = rtc_ids, -}; - -static int __init integrator_rtc_init(void) -{ - return amba_driver_register(&rtc_driver); -} - -static void __exit integrator_rtc_exit(void) -{ - amba_driver_unregister(&rtc_driver); -} - -module_init(integrator_rtc_init); -module_exit(integrator_rtc_exit); |
