From 94a0ad7aea40f0143670cfb6d5794f2f4b6b1aa7 Mon Sep 17 00:00:00 2001 From: John Crispin 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 #include #include +#include #include #include @@ -22,44 +23,32 @@ #include #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, <q_cgu_resource) < 0) - panic("Failed to insert cgu memory"); - - if (request_mem_region(ltq_cgu_resource.start, - resource_size(<q_cgu_resource), "cgu") < 0) - panic("Failed to request cgu memory"); + ltq_soc_init(); - ltq_cgu_membase = ioremap_nocache(ltq_cgu_resource.start, - resource_size(<q_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 -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 #include -/* 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 #include +#include #include #include #include #include +#ifdef CONFIG_SOC_SVIP +#include +#include +#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, <q_icu_resource) < 0) - panic("Failed to insert icu memory"); + for (i=0; i < IM_NUM; i++) { + if (insert_resource(&iomem_resource, <q_icu_resource[i]) < 0) + panic("Failed to insert icu memory\n"); - if (request_mem_region(ltq_icu_resource.start, - resource_size(<q_icu_resource), "icu") < 0) - panic("Failed to request icu memory"); + if (request_mem_region(ltq_icu_resource[i].start, + resource_size(<q_icu_resource[i]), "icu") < 0) + panic("Failed to request icu memory\n"); - ltq_icu_membase = ioremap_nocache(ltq_icu_resource.start, - resource_size(<q_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(<q_icu_resource[i])); + if (!ltq_icu_membase[i]) + panic("Failed to remap icu memory\n"); + } - if (insert_resource(&iomem_resource, <q_eiu_resource) < 0) - panic("Failed to insert eiu memory"); + if (LTQ_EIU_BASE_ADDR) { + if (insert_resource(&iomem_resource, <q_eiu_resource) < 0) + panic("Failed to insert eiu memory\n"); - if (request_mem_region(ltq_eiu_resource.start, - resource_size(<q_eiu_resource), "eiu") < 0) - panic("Failed to request eiu memory"); + if (request_mem_region(ltq_eiu_resource.start, + resource_size(<q_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(<q_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, <q_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, <q_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