aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/lantiq/patches-3.3/0004-lantiq-core-support.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/lantiq/patches-3.3/0004-lantiq-core-support.patch')
-rw-r--r--target/linux/lantiq/patches-3.3/0004-lantiq-core-support.patch1009
1 files changed, 1009 insertions, 0 deletions
diff --git a/target/linux/lantiq/patches-3.3/0004-lantiq-core-support.patch b/target/linux/lantiq/patches-3.3/0004-lantiq-core-support.patch
new file mode 100644
index 000000000..d048988eb
--- /dev/null
+++ b/target/linux/lantiq/patches-3.3/0004-lantiq-core-support.patch
@@ -0,0 +1,1009 @@
+From 94a0ad7aea40f0143670cfb6d5794f2f4b6b1aa7 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Fri, 3 Aug 2012 09:51:32 +0200
+Subject: [PATCH 04/25] lantiq core support
+
+---
+ arch/mips/Kconfig | 6 +-
+ arch/mips/lantiq/Kconfig | 10 ++
+ arch/mips/lantiq/Makefile | 2 +
+ arch/mips/lantiq/Platform | 2 +
+ arch/mips/lantiq/clk.c | 136 +++++++++++----------
+ arch/mips/lantiq/clk.h | 59 ++++++++-
+ arch/mips/lantiq/devices.c | 30 +----
+ arch/mips/lantiq/devices.h | 4 +
+ arch/mips/lantiq/early_printk.c | 14 ++-
+ arch/mips/lantiq/irq.c | 262 +++++++++++++++++++++++++++++++--------
+ arch/mips/lantiq/machtypes.h | 5 +
+ arch/mips/lantiq/prom.c | 63 ++++++++--
+ arch/mips/lantiq/prom.h | 4 +
+ 13 files changed, 435 insertions(+), 162 deletions(-)
+
+diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
+index cffcae6..0e2ce5d 100644
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -228,8 +228,11 @@ config LANTIQ
+ select ARCH_REQUIRE_GPIOLIB
+ select SWAP_IO_SPACE
+ select BOOT_RAW
+- select HAVE_CLK
++ select HAVE_MACH_CLKDEV
++ select CLKDEV_LOOKUP
++ select HAVE_OPROFILE
+ select MIPS_MACHINE
++ select USB_ARCH_HAS_HCD
+
+ config LASAT
+ bool "LASAT Networks platforms"
+@@ -2391,6 +2394,7 @@ config PCI_DOMAINS
+ bool
+
+ source "drivers/pci/Kconfig"
++source "drivers/pci/pcie/Kconfig"
+
+ #
+ # ISA support is now enabled via select. Too many systems still have the one
+diff --git a/arch/mips/lantiq/Kconfig b/arch/mips/lantiq/Kconfig
+index 3fccf21..b7ba0fe 100644
+--- a/arch/mips/lantiq/Kconfig
++++ b/arch/mips/lantiq/Kconfig
+@@ -16,8 +16,18 @@ config SOC_XWAY
+ bool "XWAY"
+ select SOC_TYPE_XWAY
+ select HW_HAS_PCI
++
++config SOC_FALCON
++ bool "FALCON"
++
++config SOC_SVIP
++ bool "SVIP"
++ select MIPS_CPU_SCACHE
++
+ endchoice
+
+ source "arch/mips/lantiq/xway/Kconfig"
++source "arch/mips/lantiq/falcon/Kconfig"
++source "arch/mips/lantiq/svip/Kconfig"
+
+ endif
+diff --git a/arch/mips/lantiq/Makefile b/arch/mips/lantiq/Makefile
+index e5dae0e..db1ce50 100644
+--- a/arch/mips/lantiq/Makefile
++++ b/arch/mips/lantiq/Makefile
+@@ -9,3 +9,5 @@ obj-y := irq.o setup.o clk.o prom.o devices.o
+ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
+
+ obj-$(CONFIG_SOC_TYPE_XWAY) += xway/
++obj-$(CONFIG_SOC_FALCON) += falcon/
++obj-$(CONFIG_SOC_SVIP) += svip/
+diff --git a/arch/mips/lantiq/Platform b/arch/mips/lantiq/Platform
+index f3dff05..857548c 100644
+--- a/arch/mips/lantiq/Platform
++++ b/arch/mips/lantiq/Platform
+@@ -6,3 +6,5 @@ platform-$(CONFIG_LANTIQ) += lantiq/
+ cflags-$(CONFIG_LANTIQ) += -I$(srctree)/arch/mips/include/asm/mach-lantiq
+ load-$(CONFIG_LANTIQ) = 0xffffffff80002000
+ cflags-$(CONFIG_SOC_TYPE_XWAY) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/xway
++cflags-$(CONFIG_SOC_FALCON) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/falcon
++cflags-$(CONFIG_SOC_SVIP) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/svip
+diff --git a/arch/mips/lantiq/clk.c b/arch/mips/lantiq/clk.c
+index 412814f..6c95f5e 100644
+--- a/arch/mips/lantiq/clk.c
++++ b/arch/mips/lantiq/clk.c
+@@ -12,6 +12,7 @@
+ #include <linux/kernel.h>
+ #include <linux/types.h>
+ #include <linux/clk.h>
++#include <linux/clkdev.h>
+ #include <linux/err.h>
+ #include <linux/list.h>
+
+@@ -22,44 +23,32 @@
+ #include <lantiq_soc.h>
+
+ #include "clk.h"
++#include "prom.h"
+
+-struct clk {
+- const char *name;
+- unsigned long rate;
+- unsigned long (*get_rate) (void);
+-};
++/* lantiq socs have 3 static clocks */
++static struct clk cpu_clk_generic[3];
+
+-static struct clk *cpu_clk;
+-static int cpu_clk_cnt;
++void clkdev_add_static(unsigned long cpu, unsigned long fpi, unsigned long io)
++{
++ cpu_clk_generic[0].rate = cpu;
++ cpu_clk_generic[1].rate = fpi;
++ cpu_clk_generic[2].rate = io;
++}
+
+-/* lantiq socs have 3 static clocks */
+-static struct clk cpu_clk_generic[] = {
+- {
+- .name = "cpu",
+- .get_rate = ltq_get_cpu_hz,
+- }, {
+- .name = "fpi",
+- .get_rate = ltq_get_fpi_hz,
+- }, {
+- .name = "io",
+- .get_rate = ltq_get_io_region_clock,
+- },
+-};
+-
+-static struct resource ltq_cgu_resource = {
+- .name = "cgu",
+- .start = LTQ_CGU_BASE_ADDR,
+- .end = LTQ_CGU_BASE_ADDR + LTQ_CGU_SIZE - 1,
+- .flags = IORESOURCE_MEM,
+-};
+-
+-/* remapped clock register range */
+-void __iomem *ltq_cgu_membase;
+-
+-void clk_init(void)
++struct clk *clk_get_cpu(void)
+ {
+- cpu_clk = cpu_clk_generic;
+- cpu_clk_cnt = ARRAY_SIZE(cpu_clk_generic);
++ return &cpu_clk_generic[0];
++}
++
++struct clk *clk_get_fpi(void)
++{
++ return &cpu_clk_generic[1];
++}
++EXPORT_SYMBOL_GPL(clk_get_fpi);
++
++struct clk *clk_get_io(void)
++{
++ return &cpu_clk_generic[2];
+ }
+
+ static inline int clk_good(struct clk *clk)
+@@ -82,37 +71,60 @@ unsigned long clk_get_rate(struct clk *clk)
+ }
+ EXPORT_SYMBOL(clk_get_rate);
+
+-struct clk *clk_get(struct device *dev, const char *id)
++int clk_set_rate(struct clk *clk, unsigned long rate)
+ {
+- int i;
+-
+- for (i = 0; i < cpu_clk_cnt; i++)
+- if (!strcmp(id, cpu_clk[i].name))
+- return &cpu_clk[i];
+- BUG();
+- return ERR_PTR(-ENOENT);
+-}
+-EXPORT_SYMBOL(clk_get);
++ if (unlikely(!clk_good(clk)))
++ return 0;
+
+-void clk_put(struct clk *clk)
+-{
+- /* not used */
++ clk->rate = rate;
++ return 0;
+ }
+-EXPORT_SYMBOL(clk_put);
++EXPORT_SYMBOL(clk_set_rate);
+
+ int clk_enable(struct clk *clk)
+ {
+- /* not used */
+- return 0;
++ if (unlikely(!clk_good(clk)))
++ return -1;
++
++ if (clk->enable)
++ return clk->enable(clk);
++
++ return -1;
+ }
+ EXPORT_SYMBOL(clk_enable);
+
+ void clk_disable(struct clk *clk)
+ {
+- /* not used */
++ if (unlikely(!clk_good(clk)))
++ return;
++
++ if (clk->disable)
++ clk->disable(clk);
+ }
+ EXPORT_SYMBOL(clk_disable);
+
++int clk_activate(struct clk *clk)
++{
++ if (unlikely(!clk_good(clk)))
++ return -1;
++
++ if (clk->activate)
++ return clk->activate(clk);
++
++ return -1;
++}
++EXPORT_SYMBOL(clk_activate);
++
++void clk_deactivate(struct clk *clk)
++{
++ if (unlikely(!clk_good(clk)))
++ return;
++
++ if (clk->deactivate)
++ clk->deactivate(clk);
++}
++EXPORT_SYMBOL(clk_deactivate);
++
+ static inline u32 ltq_get_counter_resolution(void)
+ {
+ u32 res;
+@@ -133,21 +145,17 @@ void __init plat_time_init(void)
+ {
+ struct clk *clk;
+
+- if (insert_resource(&iomem_resource, &ltq_cgu_resource) < 0)
+- panic("Failed to insert cgu memory");
+-
+- if (request_mem_region(ltq_cgu_resource.start,
+- resource_size(&ltq_cgu_resource), "cgu") < 0)
+- panic("Failed to request cgu memory");
++ ltq_soc_init();
+
+- ltq_cgu_membase = ioremap_nocache(ltq_cgu_resource.start,
+- resource_size(&ltq_cgu_resource));
+- if (!ltq_cgu_membase) {
+- pr_err("Failed to remap cgu memory\n");
+- unreachable();
+- }
+- clk = clk_get(0, "cpu");
++ clk = clk_get_cpu();
+ mips_hpt_frequency = clk_get_rate(clk) / ltq_get_counter_resolution();
++#ifdef CONFIG_SOC_SVIP
++ write_c0_count(0);
++ write_c0_compare(mips_hpt_frequency / HZ);
++ enable_irq(MIPS_CPU_TIMER_IRQ);
++#else
+ write_c0_compare(read_c0_count());
++#endif
++ pr_info("CPU Clock: %ldMHz\n", clk_get_rate(clk) / 1000000);
+ clk_put(clk);
+ }
+diff --git a/arch/mips/lantiq/clk.h b/arch/mips/lantiq/clk.h
+index 3328925..564ef03 100644
+--- a/arch/mips/lantiq/clk.h
++++ b/arch/mips/lantiq/clk.h
+@@ -9,10 +9,61 @@
+ #ifndef _LTQ_CLK_H__
+ #define _LTQ_CLK_H__
+
+-extern void clk_init(void);
++#include <linux/clkdev.h>
+
+-extern unsigned long ltq_get_cpu_hz(void);
+-extern unsigned long ltq_get_fpi_hz(void);
+-extern unsigned long ltq_get_io_region_clock(void);
++/* clock speeds */
++#define CLOCK_33M 33333333
++#define CLOCK_60M 60000000
++#define CLOCK_62_5M 62500000
++#define CLOCK_83M 83333333
++#define CLOCK_83_5M 83500000
++#define CLOCK_98_304M 98304000
++#define CLOCK_100M 100000000
++#define CLOCK_111M 111111111
++#define CLOCK_125M 125000000
++#define CLOCK_133M 133333333
++#define CLOCK_150M 150000000
++#define CLOCK_166M 166666666
++#define CLOCK_167M 166666667
++#define CLOCK_196_608M 196608000
++#define CLOCK_200M 200000000
++#define CLOCK_250M 250000000
++#define CLOCK_266M 266666666
++#define CLOCK_300M 300000000
++#define CLOCK_333M 333333333
++#define CLOCK_393M 393215332
++#define CLOCK_400M 400000000
++#define CLOCK_500M 500000000
++#define CLOCK_600M 600000000
++
++struct clk {
++ struct clk_lookup cl;
++ unsigned long rate;
++ unsigned int module;
++ unsigned int bits;
++ unsigned long (*get_rate) (void);
++ int (*enable) (struct clk *clk);
++ void (*disable) (struct clk *clk);
++ int (*activate) (struct clk *clk);
++ void (*deactivate) (struct clk *clk);
++ void (*reboot) (struct clk *clk);
++};
++
++extern void clkdev_add_static(unsigned long cpu, unsigned long fpi,
++ unsigned long io);
++
++extern unsigned long ltq_danube_cpu_hz(void);
++extern unsigned long ltq_danube_fpi_hz(void);
++extern unsigned long ltq_danube_io_region_clock(void);
++
++extern unsigned long ltq_svip_cpu_hz(void);
++extern unsigned long ltq_svip_fpi_hz(void);
++extern unsigned long ltq_svip_io_region_clock(void);
++
++extern unsigned long ltq_ar9_cpu_hz(void);
++extern unsigned long ltq_ar9_fpi_hz(void);
++
++extern unsigned long ltq_vr9_cpu_hz(void);
++extern unsigned long ltq_vr9_fpi_hz(void);
+
+ #endif
+diff --git a/arch/mips/lantiq/devices.c b/arch/mips/lantiq/devices.c
+index de1cb2b..7193d78 100644
+--- a/arch/mips/lantiq/devices.c
++++ b/arch/mips/lantiq/devices.c
+@@ -27,12 +27,8 @@
+ #include "devices.h"
+
+ /* nor flash */
+-static struct resource ltq_nor_resource = {
+- .name = "nor",
+- .start = LTQ_FLASH_START,
+- .end = LTQ_FLASH_START + LTQ_FLASH_MAX - 1,
+- .flags = IORESOURCE_MEM,
+-};
++static struct resource ltq_nor_resource =
++ MEM_RES("nor", LTQ_FLASH_START, LTQ_FLASH_MAX);
+
+ static struct platform_device ltq_nor = {
+ .name = "ltq_nor",
+@@ -47,12 +43,8 @@ void __init ltq_register_nor(struct physmap_flash_data *data)
+ }
+
+ /* watchdog */
+-static struct resource ltq_wdt_resource = {
+- .name = "watchdog",
+- .start = LTQ_WDT_BASE_ADDR,
+- .end = LTQ_WDT_BASE_ADDR + LTQ_WDT_SIZE - 1,
+- .flags = IORESOURCE_MEM,
+-};
++static struct resource ltq_wdt_resource =
++ MEM_RES("watchdog", LTQ_WDT_BASE_ADDR, LTQ_WDT_SIZE);
+
+ void __init ltq_register_wdt(void)
+ {
+@@ -61,24 +53,14 @@ void __init ltq_register_wdt(void)
+
+ /* asc ports */
+ static struct resource ltq_asc0_resources[] = {
+- {
+- .name = "asc0",
+- .start = LTQ_ASC0_BASE_ADDR,
+- .end = LTQ_ASC0_BASE_ADDR + LTQ_ASC_SIZE - 1,
+- .flags = IORESOURCE_MEM,
+- },
++ MEM_RES("asc0", LTQ_ASC0_BASE_ADDR, LTQ_ASC_SIZE),
+ IRQ_RES(tx, LTQ_ASC_TIR(0)),
+ IRQ_RES(rx, LTQ_ASC_RIR(0)),
+ IRQ_RES(err, LTQ_ASC_EIR(0)),
+ };
+
+ static struct resource ltq_asc1_resources[] = {
+- {
+- .name = "asc1",
+- .start = LTQ_ASC1_BASE_ADDR,
+- .end = LTQ_ASC1_BASE_ADDR + LTQ_ASC_SIZE - 1,
+- .flags = IORESOURCE_MEM,
+- },
++ MEM_RES("asc1", LTQ_ASC1_BASE_ADDR, LTQ_ASC_SIZE),
+ IRQ_RES(tx, LTQ_ASC_TIR(1)),
+ IRQ_RES(rx, LTQ_ASC_RIR(1)),
+ IRQ_RES(err, LTQ_ASC_EIR(1)),
+diff --git a/arch/mips/lantiq/devices.h b/arch/mips/lantiq/devices.h
+index 2947bb1..a03c23f 100644
+--- a/arch/mips/lantiq/devices.h
++++ b/arch/mips/lantiq/devices.h
+@@ -14,6 +14,10 @@
+
+ #define IRQ_RES(resname, irq) \
+ {.name = #resname, .start = (irq), .flags = IORESOURCE_IRQ}
++#define MEM_RES(resname, adr_start, adr_size) \
++ { .name = resname, .flags = IORESOURCE_MEM, \
++ .start = ((adr_start) & ~KSEG1), \
++ .end = ((adr_start + adr_size - 1) & ~KSEG1) }
+
+ extern void ltq_register_nor(struct physmap_flash_data *data);
+ extern void ltq_register_wdt(void);
+diff --git a/arch/mips/lantiq/early_printk.c b/arch/mips/lantiq/early_printk.c
+index 972e05f..5089075 100644
+--- a/arch/mips/lantiq/early_printk.c
++++ b/arch/mips/lantiq/early_printk.c
+@@ -12,11 +12,13 @@
+ #include <lantiq.h>
+ #include <lantiq_soc.h>
+
+-/* no ioremap possible at this early stage, lets use KSEG1 instead */
+-#define LTQ_ASC_BASE KSEG1ADDR(LTQ_ASC1_BASE_ADDR)
+ #define ASC_BUF 1024
+-#define LTQ_ASC_FSTAT ((u32 *)(LTQ_ASC_BASE + 0x0048))
+-#define LTQ_ASC_TBUF ((u32 *)(LTQ_ASC_BASE + 0x0020))
++#define LTQ_ASC_FSTAT ((u32 *)(LTQ_EARLY_ASC + 0x0048))
++#ifdef __BIG_ENDIAN
++#define LTQ_ASC_TBUF ((u32 *)(LTQ_EARLY_ASC + 0x0020 + 3))
++#else
++#define LTQ_ASC_TBUF ((u32 *)(LTQ_EARLY_ASC + 0x0020))
++#endif
+ #define TXMASK 0x3F00
+ #define TXOFFSET 8
+
+@@ -27,7 +29,7 @@ void prom_putchar(char c)
+ local_irq_save(flags);
+ do { } while ((ltq_r32(LTQ_ASC_FSTAT) & TXMASK) >> TXOFFSET);
+ if (c == '\n')
+- ltq_w32('\r', LTQ_ASC_TBUF);
+- ltq_w32(c, LTQ_ASC_TBUF);
++ ltq_w8('\r', LTQ_ASC_TBUF);
++ ltq_w8(c, LTQ_ASC_TBUF);
+ local_irq_restore(flags);
+ }
+diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c
+index d673731..63dbb83 100644
+--- a/arch/mips/lantiq/irq.c
++++ b/arch/mips/lantiq/irq.c
+@@ -9,12 +9,17 @@
+
+ #include <linux/interrupt.h>
+ #include <linux/ioport.h>
++#include <linux/sched.h>
+
+ #include <asm/bootinfo.h>
+ #include <asm/irq_cpu.h>
+
+ #include <lantiq_soc.h>
+ #include <irq.h>
++#ifdef CONFIG_SOC_SVIP
++#include <ebu_reg.h>
++#include <base_reg.h>
++#endif
+
+ /* register definitions */
+ #define LTQ_ICU_IM0_ISR 0x0000
+@@ -40,17 +45,28 @@
+
+ #define MAX_EIU 6
+
++/* the performance counter */
++#define LTQ_PERF_IRQ (INT_NUM_IM4_IRL0 + 31)
++
+ /* irqs generated by device attached to the EBU need to be acked in
+ * a special manner
+ */
+ #define LTQ_ICU_EBU_IRQ 22
+
+-#define ltq_icu_w32(x, y) ltq_w32((x), ltq_icu_membase + (y))
+-#define ltq_icu_r32(x) ltq_r32(ltq_icu_membase + (x))
++#define ltq_icu_w32(x, y, m) ltq_w32((x), ltq_icu_membase[m] + (y))
++#define ltq_icu_r32(x, m) ltq_r32(ltq_icu_membase[m] + (x))
+
+ #define ltq_eiu_w32(x, y) ltq_w32((x), ltq_eiu_membase + (y))
+ #define ltq_eiu_r32(x) ltq_r32(ltq_eiu_membase + (x))
+
++/* our 2 ipi interrupts for VSMP */
++#define MIPS_CPU_IPI_RESCHED_IRQ 0
++#define MIPS_CPU_IPI_CALL_IRQ 1
++
++#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC)
++int gic_present;
++#endif
++
+ static unsigned short ltq_eiu_irq[MAX_EIU] = {
+ LTQ_EIU_IR0,
+ LTQ_EIU_IR1,
+@@ -60,11 +76,78 @@ static unsigned short ltq_eiu_irq[MAX_EIU] = {
+ LTQ_EIU_IR5,
+ };
+
+-static struct resource ltq_icu_resource = {
+- .name = "icu",
+- .start = LTQ_ICU_BASE_ADDR,
+- .end = LTQ_ICU_BASE_ADDR + LTQ_ICU_SIZE - 1,
+- .flags = IORESOURCE_MEM,
++static struct resource ltq_icu_resource[IM_NUM] = {
++{
++ .name = "icu_im0",
++ .start = LTQ_ICU_BASE_ADDR,
++ .end = LTQ_ICU_BASE_ADDR + LTQ_ICU_OFFSET - 1,
++ .flags = IORESOURCE_MEM,
++},
++#if IM_NUM >= 2
++{
++ .name = "icu_im1",
++#ifdef LTQ_ICU_BASE_ADDR1
++ .start = LTQ_ICU_BASE_ADDR1,
++ .end = LTQ_ICU_BASE_ADDR1 + LTQ_ICU_OFFSET - 1,
++#else
++ .start = LTQ_ICU_BASE_ADDR + (LTQ_ICU_OFFSET * 1),
++ .end = LTQ_ICU_BASE_ADDR + (LTQ_ICU_OFFSET * 2) - 1,
++#endif
++ .flags = IORESOURCE_MEM,
++},
++#endif
++#if IM_NUM >= 3
++{
++ .name = "icu_im2",
++#ifdef LTQ_ICU_BASE_ADDR2
++ .start = LTQ_ICU_BASE_ADDR2,
++ .end = LTQ_ICU_BASE_ADDR2 + LTQ_ICU_OFFSET - 1,
++#else
++ .start = LTQ_ICU_BASE_ADDR + (LTQ_ICU_OFFSET * 2),
++ .end = LTQ_ICU_BASE_ADDR + (LTQ_ICU_OFFSET * 3) - 1,
++#endif
++ .flags = IORESOURCE_MEM,
++},
++#endif
++#if IM_NUM >= 4
++{
++ .name = "icu_im3",
++#ifdef LTQ_ICU_BASE_ADDR3
++ .start = LTQ_ICU_BASE_ADDR3,
++ .end = LTQ_ICU_BASE_ADDR3 + LTQ_ICU_OFFSET - 1,
++#else
++ .start = LTQ_ICU_BASE_ADDR + (LTQ_ICU_OFFSET * 3),
++ .end = LTQ_ICU_BASE_ADDR + (LTQ_ICU_OFFSET * 4) - 1,
++#endif
++ .flags = IORESOURCE_MEM,
++},
++#endif
++#if IM_NUM >= 5
++{
++ .name = "icu_im4",
++#ifdef LTQ_ICU_BASE_ADDR4
++ .start = LTQ_ICU_BASE_ADDR4,
++ .end = LTQ_ICU_BASE_ADDR4 + LTQ_ICU_OFFSET - 1,
++#else
++ .start = LTQ_ICU_BASE_ADDR + (LTQ_ICU_OFFSET * 4),
++ .end = LTQ_ICU_BASE_ADDR + (LTQ_ICU_OFFSET * 5) - 1,
++#endif
++ .flags = IORESOURCE_MEM,
++},
++#endif
++#if IM_NUM >= 6
++{
++ .name = "icu_im5",
++#ifdef LTQ_ICU_BASE_ADDR5
++ .start = LTQ_ICU_BASE_ADDR5,
++ .end = LTQ_ICU_BASE_ADDR5 + LTQ_ICU_OFFSET - 1,
++#else
++ .start = LTQ_ICU_BASE_ADDR + (LTQ_ICU_OFFSET * 5),
++ .end = LTQ_ICU_BASE_ADDR + (LTQ_ICU_OFFSET * 6) - 1,
++#endif
++ .flags = IORESOURCE_MEM,
++},
++#endif
+ };
+
+ static struct resource ltq_eiu_resource = {
+@@ -74,50 +157,53 @@ static struct resource ltq_eiu_resource = {
+ .flags = IORESOURCE_MEM,
+ };
+
+-static void __iomem *ltq_icu_membase;
++static void __iomem *ltq_icu_membase[IM_NUM];
+ static void __iomem *ltq_eiu_membase;
+
+ void ltq_disable_irq(struct irq_data *d)
+ {
+- u32 ier = LTQ_ICU_IM0_IER;
+ int irq_nr = d->irq - INT_NUM_IRQ0;
++ unsigned int im_nr;
+
+- ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
++ im_nr = (irq_nr / INT_NUM_IM_OFFSET);
+ irq_nr %= INT_NUM_IM_OFFSET;
+- ltq_icu_w32(ltq_icu_r32(ier) & ~(1 << irq_nr), ier);
++
++ ltq_icu_w32(ltq_icu_r32(LTQ_ICU_IM0_IER, im_nr) & ~(1 << irq_nr),
++ LTQ_ICU_IM0_IER, im_nr);
+ }
+
+ void ltq_mask_and_ack_irq(struct irq_data *d)
+ {
+- u32 ier = LTQ_ICU_IM0_IER;
+- u32 isr = LTQ_ICU_IM0_ISR;
+ int irq_nr = d->irq - INT_NUM_IRQ0;
++ unsigned int im_nr;
+
+- ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
+- isr += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
++ im_nr = (irq_nr / INT_NUM_IM_OFFSET);
+ irq_nr %= INT_NUM_IM_OFFSET;
+- ltq_icu_w32(ltq_icu_r32(ier) & ~(1 << irq_nr), ier);
+- ltq_icu_w32((1 << irq_nr), isr);
++
++ ltq_icu_w32(ltq_icu_r32(LTQ_ICU_IM0_IER, im_nr) & ~(1 << irq_nr), LTQ_ICU_IM0_IER, im_nr);
++ ltq_icu_w32((1 << irq_nr), LTQ_ICU_IM0_ISR, im_nr);
+ }
+
+ static void ltq_ack_irq(struct irq_data *d)
+ {
+- u32 isr = LTQ_ICU_IM0_ISR;
+ int irq_nr = d->irq - INT_NUM_IRQ0;
++ unsigned int im_nr;
+
+- isr += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
++ im_nr = (irq_nr / INT_NUM_IM_OFFSET);
+ irq_nr %= INT_NUM_IM_OFFSET;
+- ltq_icu_w32((1 << irq_nr), isr);
++
++ ltq_icu_w32((1 << irq_nr), LTQ_ICU_IM0_ISR, im_nr);
+ }
+
+ void ltq_enable_irq(struct irq_data *d)
+ {
+- u32 ier = LTQ_ICU_IM0_IER;
+ int irq_nr = d->irq - INT_NUM_IRQ0;
++ unsigned int im_nr;
+
+- ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
++ im_nr = (irq_nr / INT_NUM_IM_OFFSET);
+ irq_nr %= INT_NUM_IM_OFFSET;
+- ltq_icu_w32(ltq_icu_r32(ier) | (1 << irq_nr), ier);
++
++ ltq_icu_w32(ltq_icu_r32(LTQ_ICU_IM0_IER, im_nr) | (1 << irq_nr), LTQ_ICU_IM0_IER, im_nr);
+ }
+
+ static unsigned int ltq_startup_eiu_irq(struct irq_data *d)
+@@ -184,7 +270,7 @@ static void ltq_hw_irqdispatch(int module)
+ {
+ u32 irq;
+
+- irq = ltq_icu_r32(LTQ_ICU_IM0_IOSR + (module * LTQ_ICU_OFFSET));
++ irq = ltq_icu_r32(LTQ_ICU_IM0_IOSR, module);
+ if (irq == 0)
+ return;
+
+@@ -194,10 +280,12 @@ static void ltq_hw_irqdispatch(int module)
+ irq = __fls(irq);
+ do_IRQ((int)irq + INT_NUM_IM0_IRL0 + (INT_NUM_IM_OFFSET * module));
+
++#ifndef CONFIG_SOC_SVIP
+ /* if this is a EBU irq, we need to ack it or get a deadlock */
+- if ((irq == LTQ_ICU_EBU_IRQ) && (module == 0))
++ if ((irq == LTQ_ICU_EBU_IRQ) && (module == 0) && LTQ_EBU_PCC_ISTAT)
+ ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_ISTAT) | 0x10,
+ LTQ_EBU_PCC_ISTAT);
++#endif
+ }
+
+ #define DEFINE_HWx_IRQDISPATCH(x) \
+@@ -211,21 +299,66 @@ DEFINE_HWx_IRQDISPATCH(2)
+ DEFINE_HWx_IRQDISPATCH(3)
+ DEFINE_HWx_IRQDISPATCH(4)
+
++#if MIPS_CPU_TIMER_IRQ == 7
+ static void ltq_hw5_irqdispatch(void)
+ {
+ do_IRQ(MIPS_CPU_TIMER_IRQ);
+ }
++#else
++DEFINE_HWx_IRQDISPATCH(5)
++#endif
++
++#ifdef CONFIG_MIPS_MT_SMP
++void __init arch_init_ipiirq(int irq, struct irqaction *action)
++{
++ setup_irq(irq, action);
++ irq_set_handler(irq, handle_percpu_irq);
++}
++
++static void ltq_sw0_irqdispatch(void)
++{
++ do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ);
++}
++
++static void ltq_sw1_irqdispatch(void)
++{
++ do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ);
++}
++static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
++{
++ scheduler_ipi();
++ return IRQ_HANDLED;
++}
++
++static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
++{
++ smp_call_function_interrupt();
++ return IRQ_HANDLED;
++}
++
++static struct irqaction irq_resched = {
++ .handler = ipi_resched_interrupt,
++ .flags = IRQF_PERCPU,
++ .name = "IPI_resched"
++};
++
++static struct irqaction irq_call = {
++ .handler = ipi_call_interrupt,
++ .flags = IRQF_PERCPU,
++ .name = "IPI_call"
++};
++#endif
+
+ asmlinkage void plat_irq_dispatch(void)
+ {
+ unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
+ unsigned int i;
+
+- if (pending & CAUSEF_IP7) {
++ if ((MIPS_CPU_TIMER_IRQ == 7) && (pending & CAUSEF_IP7)) {
+ do_IRQ(MIPS_CPU_TIMER_IRQ);
+ goto out;
+ } else {
+- for (i = 0; i < 5; i++) {
++ for (i = 0; i < IM_NUM; i++) {
+ if (pending & (CAUSEF_IP2 << i)) {
+ ltq_hw_irqdispatch(i);
+ goto out;
+@@ -247,41 +380,45 @@ void __init arch_init_irq(void)
+ {
+ int i;
+
+- if (insert_resource(&iomem_resource, &ltq_icu_resource) < 0)
+- panic("Failed to insert icu memory");
++ for (i=0; i < IM_NUM; i++) {
++ if (insert_resource(&iomem_resource, &ltq_icu_resource[i]) < 0)
++ panic("Failed to insert icu memory\n");
+
+- if (request_mem_region(ltq_icu_resource.start,
+- resource_size(&ltq_icu_resource), "icu") < 0)
+- panic("Failed to request icu memory");
++ if (request_mem_region(ltq_icu_resource[i].start,
++ resource_size(&ltq_icu_resource[i]), "icu") < 0)
++ panic("Failed to request icu memory\n");
+
+- ltq_icu_membase = ioremap_nocache(ltq_icu_resource.start,
+- resource_size(&ltq_icu_resource));
+- if (!ltq_icu_membase)
+- panic("Failed to remap icu memory");
++ ltq_icu_membase[i] = ioremap_nocache(ltq_icu_resource[i].start,
++ resource_size(&ltq_icu_resource[i]));
++ if (!ltq_icu_membase[i])
++ panic("Failed to remap icu memory\n");
++ }
+
+- if (insert_resource(&iomem_resource, &ltq_eiu_resource) < 0)
+- panic("Failed to insert eiu memory");
++ if (LTQ_EIU_BASE_ADDR) {
++ if (insert_resource(&iomem_resource, &ltq_eiu_resource) < 0)
++ panic("Failed to insert eiu memory\n");
+
+- if (request_mem_region(ltq_eiu_resource.start,
+- resource_size(&ltq_eiu_resource), "eiu") < 0)
+- panic("Failed to request eiu memory");
++ if (request_mem_region(ltq_eiu_resource.start,
++ resource_size(&ltq_eiu_resource), "eiu") < 0)
++ panic("Failed to request eiu memory\n");
+
+- ltq_eiu_membase = ioremap_nocache(ltq_eiu_resource.start,
++ ltq_eiu_membase = ioremap_nocache(ltq_eiu_resource.start,
+ resource_size(&ltq_eiu_resource));
+- if (!ltq_eiu_membase)
+- panic("Failed to remap eiu memory");
++ if (!ltq_eiu_membase)
++ panic("Failed to remap eiu memory\n");
++ }
+
+ /* make sure all irqs are turned off by default */
+- for (i = 0; i < 5; i++)
+- ltq_icu_w32(0, LTQ_ICU_IM0_IER + (i * LTQ_ICU_OFFSET));
+-
+- /* clear all possibly pending interrupts */
+- ltq_icu_w32(~0, LTQ_ICU_IM0_ISR + (i * LTQ_ICU_OFFSET));
++ for (i = 0; i < IM_NUM; i++) {
++ ltq_icu_w32(0, LTQ_ICU_IM0_IER, i);
++ /* clear all possibly pending interrupts */
++ ltq_icu_w32(~0, LTQ_ICU_IM0_ISR, i);
++ }
+
+ mips_cpu_irq_init();
+
+- for (i = 2; i <= 6; i++)
+- setup_irq(i, &cascade);
++ for (i = 0; i < IM_NUM; i++)
++ setup_irq(i + 2, &cascade);
+
+ if (cpu_has_vint) {
+ pr_info("Setting up vectored interrupts\n");
+@@ -294,9 +431,9 @@ void __init arch_init_irq(void)
+ }
+
+ for (i = INT_NUM_IRQ0;
+- i <= (INT_NUM_IRQ0 + (5 * INT_NUM_IM_OFFSET)); i++)
+- if ((i == LTQ_EIU_IR0) || (i == LTQ_EIU_IR1) ||
+- (i == LTQ_EIU_IR2))
++ i <= (INT_NUM_IRQ0 + (IM_NUM * INT_NUM_IM_OFFSET)); i++)
++ if (((i == LTQ_EIU_IR0) || (i == LTQ_EIU_IR1) ||
++ (i == LTQ_EIU_IR2)) && LTQ_EIU_BASE_ADDR)
+ irq_set_chip_and_handler(i, &ltq_eiu_type,
+ handle_level_irq);
+ /* EIU3-5 only exist on ar9 and vr9 */
+@@ -308,6 +445,17 @@ void __init arch_init_irq(void)
+ irq_set_chip_and_handler(i, &ltq_irq_type,
+ handle_level_irq);
+
++#if defined(CONFIG_MIPS_MT_SMP)
++ if (cpu_has_vint) {
++ pr_info("Setting up IPI vectored interrupts\n");
++ set_vi_handler(MIPS_CPU_IPI_RESCHED_IRQ, ltq_sw0_irqdispatch);
++ set_vi_handler(MIPS_CPU_IPI_CALL_IRQ, ltq_sw1_irqdispatch);
++ }
++ arch_init_ipiirq(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ,
++ &irq_resched);
++ arch_init_ipiirq(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ, &irq_call);
++#endif
++
+ #if !defined(CONFIG_MIPS_MT_SMP) && !defined(CONFIG_MIPS_MT_SMTC)
+ set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 |
+ IE_IRQ3 | IE_IRQ4 | IE_IRQ5);
+@@ -315,9 +463,15 @@ void __init arch_init_irq(void)
+ set_c0_status(IE_SW0 | IE_SW1 | IE_IRQ0 | IE_IRQ1 |
+ IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5);
+ #endif
++
++ cp0_perfcount_irq = LTQ_PERF_IRQ;
+ }
+
+ unsigned int __cpuinit get_c0_compare_int(void)
+ {
++#ifdef CONFIG_SOC_SVIP
++ return MIPS_CPU_TIMER_IRQ;
++#else
+ return CP0_LEGACY_COMPARE_IRQ;
++#endif
+ }
+diff --git a/arch/mips/lantiq/machtypes.h b/arch/mips/lantiq/machtypes.h
+index 7e01b8c..dfc6af7 100644
+--- a/arch/mips/lantiq/machtypes.h
++++ b/arch/mips/lantiq/machtypes.h
+@@ -15,6 +15,11 @@ enum lantiq_mach_type {
+ LTQ_MACH_GENERIC = 0,
+ LTQ_MACH_EASY50712, /* Danube evaluation board */
+ LTQ_MACH_EASY50601, /* Amazon SE evaluation board */
++
++ /* FALCON */
++ LANTIQ_MACH_EASY98000, /* Falcon Eval Board, NOR Flash */
++ LANTIQ_MACH_EASY98000SF, /* Falcon Eval Board, Serial Flash */
++ LANTIQ_MACH_EASY98000NAND, /* Falcon Eval Board, NAND Flash */
+ };
+
+ #endif
+diff --git a/arch/mips/lantiq/prom.c b/arch/mips/lantiq/prom.c
+index e34fcfd..00ad59c 100644
+--- a/arch/mips/lantiq/prom.c
++++ b/arch/mips/lantiq/prom.c
+@@ -16,6 +16,10 @@
+ #include "prom.h"
+ #include "clk.h"
+
++/* access to the ebu needs to be locked between different drivers */
++DEFINE_SPINLOCK(ebu_lock);
++EXPORT_SYMBOL_GPL(ebu_lock);
++
+ static struct ltq_soc_info soc_info;
+
+ unsigned int ltq_get_cpu_ver(void)
+@@ -45,27 +49,68 @@ static void __init prom_init_cmdline(void)
+ char **argv = (char **) KSEG1ADDR(fw_arg1);
+ int i;
+
++ arcs_cmdline[0] = '\0';
++
+ for (i = 0; i < argc; i++) {
+- char *p = (char *) KSEG1ADDR(argv[i]);
++ char *p = (char *) KSEG1ADDR(argv[i]);
+
+- if (p && *p) {
++ if (CPHYSADDR(p) && *p) {
+ strlcat(arcs_cmdline, p, sizeof(arcs_cmdline));
+ strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline));
+ }
+ }
+ }
+
+-void __init prom_init(void)
++void __iomem *ltq_remap_resource(struct resource *res)
+ {
+- struct clk *clk;
++ __iomem void *ret = NULL;
++ struct resource *lookup = lookup_resource(&iomem_resource, res->start);
++
++ if (lookup && strcmp(lookup->name, res->name)) {
++ pr_err("conflicting memory range %s\n", res->name);
++ return NULL;
++ }
++ if (!lookup) {
++ if (insert_resource(&iomem_resource, res) < 0) {
++ pr_err("Failed to insert %s memory\n", res->name);
++ return NULL;
++ }
++ }
++ if (request_mem_region(res->start,
++ resource_size(res), res->name) < 0) {
++ pr_err("Failed to request %s memory\n", res->name);
++ goto err_res;
++ }
+
++ ret = ioremap_nocache(res->start, resource_size(res));
++ if (!ret)
++ goto err_mem;
++
++ pr_debug("remap: 0x%08X-0x%08X : \"%s\"\n",
++ res->start, res->end, res->name);
++ return ret;
++
++err_mem:
++ panic("Failed to remap %s memory\n", res->name);
++ release_mem_region(res->start, resource_size(res));
++
++err_res:
++ release_resource(res);
++ return NULL;
++}
++EXPORT_SYMBOL(ltq_remap_resource);
++
++void __init prom_init(void)
++{
+ ltq_soc_detect(&soc_info);
+- clk_init();
+- clk = clk_get(0, "cpu");
+- snprintf(soc_info.sys_type, LTQ_SYS_TYPE_LEN - 1, "%s rev1.%d",
+- soc_info.name, soc_info.rev);
+- clk_put(clk);
++ snprintf(soc_info.sys_type, LTQ_SYS_TYPE_LEN - 1, "%s rev %s",
++ soc_info.name, soc_info.rev_type);
+ soc_info.sys_type[LTQ_SYS_TYPE_LEN - 1] = '\0';
+ pr_info("SoC: %s\n", soc_info.sys_type);
+ prom_init_cmdline();
++
++#if defined(CONFIG_MIPS_MT_SMP)
++ if (register_vsmp_smp_ops())
++ panic("failed to register_vsmp_smp_ops()");
++#endif
+ }
+diff --git a/arch/mips/lantiq/prom.h b/arch/mips/lantiq/prom.h
+index b4229d9..51dba1b 100644
+--- a/arch/mips/lantiq/prom.h
++++ b/arch/mips/lantiq/prom.h
+@@ -9,17 +9,21 @@
+ #ifndef _LTQ_PROM_H__
+ #define _LTQ_PROM_H__
+
++#define LTQ_SYS_REV_LEN 0x10
+ #define LTQ_SYS_TYPE_LEN 0x100
+
+ struct ltq_soc_info {
+ unsigned char *name;
+ unsigned int rev;
++ unsigned char rev_type[LTQ_SYS_REV_LEN];
++ unsigned int srev;
+ unsigned int partnum;
+ unsigned int type;
+ unsigned char sys_type[LTQ_SYS_TYPE_LEN];
+ };
+
+ extern void ltq_soc_detect(struct ltq_soc_info *i);
++extern void ltq_soc_init(void);
+ extern void ltq_soc_setup(void);
+
+ #endif
+--
+1.7.9.1
+