Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

MIPS: Lantiq: Add initial support for Lantiq SoCs

Add initial support for Mips based SoCs made by Lantiq. This series will add
support for the XWAY family.

The series allows booting a minimal system using a initramfs or NOR. Missing
drivers and support for Amazon and GPON family will be provided in a later
series.

[Ralf: Remove some cargo cult programming and fixed formatting.]

Signed-off-by: John Crispin <blogic@openwrt.org>
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
Signed-off-by: David Daney <ddaney@caviumnetworks.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/2252/
Patchwork: https://patchwork.linux-mips.org/patch/2371/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

authored by

John Crispin and committed by
Ralf Baechle
171bb2f1 c0a5afb9

+774
+1
arch/mips/Kbuild.platforms
··· 11 11 platforms += emma 12 12 platforms += jazz 13 13 platforms += jz4740 14 + platforms += lantiq 14 15 platforms += lasat 15 16 platforms += loongson 16 17 platforms += mipssim
+17
arch/mips/Kconfig
··· 212 212 select HAVE_PWM 213 213 select HAVE_CLK 214 214 215 + config LANTIQ 216 + bool "Lantiq based platforms" 217 + select DMA_NONCOHERENT 218 + select IRQ_CPU 219 + select CEVT_R4K 220 + select CSRC_R4K 221 + select SYS_HAS_CPU_MIPS32_R1 222 + select SYS_HAS_CPU_MIPS32_R2 223 + select SYS_SUPPORTS_BIG_ENDIAN 224 + select SYS_SUPPORTS_32BIT_KERNEL 225 + select SYS_SUPPORTS_MULTITHREADING 226 + select SYS_HAS_EARLY_PRINTK 227 + select ARCH_REQUIRE_GPIOLIB 228 + select SWAP_IO_SPACE 229 + select BOOT_RAW 230 + select HAVE_CLK 231 + 215 232 config LASAT 216 233 bool "LASAT Networks platforms" 217 234 select CEVT_R4K
+63
arch/mips/include/asm/mach-lantiq/lantiq.h
··· 1 + /* 2 + * This program is free software; you can redistribute it and/or modify it 3 + * under the terms of the GNU General Public License version 2 as published 4 + * by the Free Software Foundation. 5 + * 6 + * Copyright (C) 2010 John Crispin <blogic@openwrt.org> 7 + */ 8 + #ifndef _LANTIQ_H__ 9 + #define _LANTIQ_H__ 10 + 11 + #include <linux/irq.h> 12 + 13 + /* generic reg access functions */ 14 + #define ltq_r32(reg) __raw_readl(reg) 15 + #define ltq_w32(val, reg) __raw_writel(val, reg) 16 + #define ltq_w32_mask(clear, set, reg) \ 17 + ltq_w32((ltq_r32(reg) & ~(clear)) | (set), reg) 18 + #define ltq_r8(reg) __raw_readb(reg) 19 + #define ltq_w8(val, reg) __raw_writeb(val, reg) 20 + 21 + /* register access macros for EBU and CGU */ 22 + #define ltq_ebu_w32(x, y) ltq_w32((x), ltq_ebu_membase + (y)) 23 + #define ltq_ebu_r32(x) ltq_r32(ltq_ebu_membase + (x)) 24 + #define ltq_cgu_w32(x, y) ltq_w32((x), ltq_cgu_membase + (y)) 25 + #define ltq_cgu_r32(x) ltq_r32(ltq_cgu_membase + (x)) 26 + 27 + extern __iomem void *ltq_ebu_membase; 28 + extern __iomem void *ltq_cgu_membase; 29 + 30 + extern unsigned int ltq_get_cpu_ver(void); 31 + extern unsigned int ltq_get_soc_type(void); 32 + 33 + /* clock speeds */ 34 + #define CLOCK_60M 60000000 35 + #define CLOCK_83M 83333333 36 + #define CLOCK_111M 111111111 37 + #define CLOCK_133M 133333333 38 + #define CLOCK_167M 166666667 39 + #define CLOCK_200M 200000000 40 + #define CLOCK_266M 266666666 41 + #define CLOCK_333M 333333333 42 + #define CLOCK_400M 400000000 43 + 44 + /* spinlock all ebu i/o */ 45 + extern spinlock_t ebu_lock; 46 + 47 + /* some irq helpers */ 48 + extern void ltq_disable_irq(struct irq_data *data); 49 + extern void ltq_mask_and_ack_irq(struct irq_data *data); 50 + extern void ltq_enable_irq(struct irq_data *data); 51 + 52 + /* find out what caused the last cpu reset */ 53 + extern int ltq_reset_cause(void); 54 + #define LTQ_RST_CAUSE_WDTRST 0x20 55 + 56 + #define IOPORT_RESOURCE_START 0x10000000 57 + #define IOPORT_RESOURCE_END 0xffffffff 58 + #define IOMEM_RESOURCE_START 0x10000000 59 + #define IOMEM_RESOURCE_END 0xffffffff 60 + #define LTQ_FLASH_START 0x10000000 61 + #define LTQ_FLASH_MAX 0x04000000 62 + 63 + #endif
+24
arch/mips/include/asm/mach-lantiq/war.h
··· 1 + /* 2 + * This file is subject to the terms and conditions of the GNU General Public 3 + * License. See the file "COPYING" in the main directory of this archive 4 + * for more details. 5 + * 6 + */ 7 + #ifndef __ASM_MIPS_MACH_LANTIQ_WAR_H 8 + #define __ASM_MIPS_MACH_LANTIQ_WAR_H 9 + 10 + #define R4600_V1_INDEX_ICACHEOP_WAR 0 11 + #define R4600_V1_HIT_CACHEOP_WAR 0 12 + #define R4600_V2_HIT_CACHEOP_WAR 0 13 + #define R5432_CP0_INTERRUPT_WAR 0 14 + #define BCM1250_M3_WAR 0 15 + #define SIBYTE_1956_WAR 0 16 + #define MIPS4K_ICACHE_REFILL_WAR 0 17 + #define MIPS_CACHE_SYNC_WAR 0 18 + #define TX49XX_ICACHE_INDEX_INV_WAR 0 19 + #define RM9000_CDEX_SMP_WAR 0 20 + #define ICACHE_REFILLS_WORKAROUND_WAR 0 21 + #define R10000_LLSC_WAR 0 22 + #define MIPS34K_MISSED_ITLB_WAR 0 23 + 24 + #endif
+9
arch/mips/lantiq/Makefile
··· 1 + # Copyright (C) 2010 John Crispin <blogic@openwrt.org> 2 + # 3 + # This program is free software; you can redistribute it and/or modify it 4 + # under the terms of the GNU General Public License version 2 as published 5 + # by the Free Software Foundation. 6 + 7 + obj-y := irq.o setup.o clk.o prom.o 8 + 9 + obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
+7
arch/mips/lantiq/Platform
··· 1 + # 2 + # Lantiq 3 + # 4 + 5 + platform-$(CONFIG_LANTIQ) += lantiq/ 6 + cflags-$(CONFIG_LANTIQ) += -I$(srctree)/arch/mips/include/asm/mach-lantiq 7 + load-$(CONFIG_LANTIQ) = 0xffffffff80002000
+140
arch/mips/lantiq/clk.c
··· 1 + /* 2 + * This program is free software; you can redistribute it and/or modify it 3 + * under the terms of the GNU General Public License version 2 as published 4 + * by the Free Software Foundation. 5 + * 6 + * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com> 7 + * Copyright (C) 2010 John Crispin <blogic@openwrt.org> 8 + */ 9 + #include <linux/io.h> 10 + #include <linux/module.h> 11 + #include <linux/init.h> 12 + #include <linux/kernel.h> 13 + #include <linux/types.h> 14 + #include <linux/clk.h> 15 + #include <linux/err.h> 16 + #include <linux/list.h> 17 + 18 + #include <asm/time.h> 19 + #include <asm/irq.h> 20 + #include <asm/div64.h> 21 + 22 + #include <lantiq_soc.h> 23 + 24 + #include "clk.h" 25 + 26 + struct clk { 27 + const char *name; 28 + unsigned long rate; 29 + unsigned long (*get_rate) (void); 30 + }; 31 + 32 + static struct clk *cpu_clk; 33 + static int cpu_clk_cnt; 34 + 35 + /* lantiq socs have 3 static clocks */ 36 + static struct clk cpu_clk_generic[] = { 37 + { 38 + .name = "cpu", 39 + .get_rate = ltq_get_cpu_hz, 40 + }, { 41 + .name = "fpi", 42 + .get_rate = ltq_get_fpi_hz, 43 + }, { 44 + .name = "io", 45 + .get_rate = ltq_get_io_region_clock, 46 + }, 47 + }; 48 + 49 + static struct resource ltq_cgu_resource = { 50 + .name = "cgu", 51 + .start = LTQ_CGU_BASE_ADDR, 52 + .end = LTQ_CGU_BASE_ADDR + LTQ_CGU_SIZE - 1, 53 + .flags = IORESOURCE_MEM, 54 + }; 55 + 56 + /* remapped clock register range */ 57 + void __iomem *ltq_cgu_membase; 58 + 59 + void clk_init(void) 60 + { 61 + cpu_clk = cpu_clk_generic; 62 + cpu_clk_cnt = ARRAY_SIZE(cpu_clk_generic); 63 + } 64 + 65 + static inline int clk_good(struct clk *clk) 66 + { 67 + return clk && !IS_ERR(clk); 68 + } 69 + 70 + unsigned long clk_get_rate(struct clk *clk) 71 + { 72 + if (unlikely(!clk_good(clk))) 73 + return 0; 74 + 75 + if (clk->rate != 0) 76 + return clk->rate; 77 + 78 + if (clk->get_rate != NULL) 79 + return clk->get_rate(); 80 + 81 + return 0; 82 + } 83 + EXPORT_SYMBOL(clk_get_rate); 84 + 85 + struct clk *clk_get(struct device *dev, const char *id) 86 + { 87 + int i; 88 + 89 + for (i = 0; i < cpu_clk_cnt; i++) 90 + if (!strcmp(id, cpu_clk[i].name)) 91 + return &cpu_clk[i]; 92 + BUG(); 93 + return ERR_PTR(-ENOENT); 94 + } 95 + EXPORT_SYMBOL(clk_get); 96 + 97 + void clk_put(struct clk *clk) 98 + { 99 + /* not used */ 100 + } 101 + EXPORT_SYMBOL(clk_put); 102 + 103 + static inline u32 ltq_get_counter_resolution(void) 104 + { 105 + u32 res; 106 + 107 + __asm__ __volatile__( 108 + ".set push\n" 109 + ".set mips32r2\n" 110 + "rdhwr %0, $3\n" 111 + ".set pop\n" 112 + : "=&r" (res) 113 + : /* no input */ 114 + : "memory"); 115 + 116 + return res; 117 + } 118 + 119 + void __init plat_time_init(void) 120 + { 121 + struct clk *clk; 122 + 123 + if (insert_resource(&iomem_resource, &ltq_cgu_resource) < 0) 124 + panic("Failed to insert cgu memory\n"); 125 + 126 + if (request_mem_region(ltq_cgu_resource.start, 127 + resource_size(&ltq_cgu_resource), "cgu") < 0) 128 + panic("Failed to request cgu memory\n"); 129 + 130 + ltq_cgu_membase = ioremap_nocache(ltq_cgu_resource.start, 131 + resource_size(&ltq_cgu_resource)); 132 + if (!ltq_cgu_membase) { 133 + pr_err("Failed to remap cgu memory\n"); 134 + unreachable(); 135 + } 136 + clk = clk_get(0, "cpu"); 137 + mips_hpt_frequency = clk_get_rate(clk) / ltq_get_counter_resolution(); 138 + write_c0_compare(read_c0_count()); 139 + clk_put(clk); 140 + }
+18
arch/mips/lantiq/clk.h
··· 1 + /* 2 + * This program is free software; you can redistribute it and/or modify it 3 + * under the terms of the GNU General Public License version 2 as published 4 + * by the Free Software Foundation. 5 + * 6 + * Copyright (C) 2010 John Crispin <blogic@openwrt.org> 7 + */ 8 + 9 + #ifndef _LTQ_CLK_H__ 10 + #define _LTQ_CLK_H__ 11 + 12 + extern void clk_init(void); 13 + 14 + extern unsigned long ltq_get_cpu_hz(void); 15 + extern unsigned long ltq_get_fpi_hz(void); 16 + extern unsigned long ltq_get_io_region_clock(void); 17 + 18 + #endif
+33
arch/mips/lantiq/early_printk.c
··· 1 + /* 2 + * This program is free software; you can redistribute it and/or modify it 3 + * under the terms of the GNU General Public License version 2 as published 4 + * by the Free Software Foundation. 5 + * 6 + * Copyright (C) 2010 John Crispin <blogic@openwrt.org> 7 + */ 8 + 9 + #include <linux/init.h> 10 + #include <linux/cpu.h> 11 + 12 + #include <lantiq.h> 13 + #include <lantiq_soc.h> 14 + 15 + /* no ioremap possible at this early stage, lets use KSEG1 instead */ 16 + #define LTQ_ASC_BASE KSEG1ADDR(LTQ_ASC1_BASE_ADDR) 17 + #define ASC_BUF 1024 18 + #define LTQ_ASC_FSTAT ((u32 *)(LTQ_ASC_BASE + 0x0048)) 19 + #define LTQ_ASC_TBUF ((u32 *)(LTQ_ASC_BASE + 0x0020)) 20 + #define TXMASK 0x3F00 21 + #define TXOFFSET 8 22 + 23 + void prom_putchar(char c) 24 + { 25 + unsigned long flags; 26 + 27 + local_irq_save(flags); 28 + do { } while ((ltq_r32(LTQ_ASC_FSTAT) & TXMASK) >> TXOFFSET); 29 + if (c == '\n') 30 + ltq_w32('\r', LTQ_ASC_TBUF); 31 + ltq_w32(c, LTQ_ASC_TBUF); 32 + local_irq_restore(flags); 33 + }
+326
arch/mips/lantiq/irq.c
··· 1 + /* 2 + * This program is free software; you can redistribute it and/or modify it 3 + * under the terms of the GNU General Public License version 2 as published 4 + * by the Free Software Foundation. 5 + * 6 + * Copyright (C) 2010 John Crispin <blogic@openwrt.org> 7 + * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com> 8 + */ 9 + 10 + #include <linux/interrupt.h> 11 + #include <linux/ioport.h> 12 + 13 + #include <asm/bootinfo.h> 14 + #include <asm/irq_cpu.h> 15 + 16 + #include <lantiq_soc.h> 17 + #include <irq.h> 18 + 19 + /* register definitions */ 20 + #define LTQ_ICU_IM0_ISR 0x0000 21 + #define LTQ_ICU_IM0_IER 0x0008 22 + #define LTQ_ICU_IM0_IOSR 0x0010 23 + #define LTQ_ICU_IM0_IRSR 0x0018 24 + #define LTQ_ICU_IM0_IMR 0x0020 25 + #define LTQ_ICU_IM1_ISR 0x0028 26 + #define LTQ_ICU_OFFSET (LTQ_ICU_IM1_ISR - LTQ_ICU_IM0_ISR) 27 + 28 + #define LTQ_EIU_EXIN_C 0x0000 29 + #define LTQ_EIU_EXIN_INIC 0x0004 30 + #define LTQ_EIU_EXIN_INEN 0x000C 31 + 32 + /* irq numbers used by the external interrupt unit (EIU) */ 33 + #define LTQ_EIU_IR0 (INT_NUM_IM4_IRL0 + 30) 34 + #define LTQ_EIU_IR1 (INT_NUM_IM3_IRL0 + 31) 35 + #define LTQ_EIU_IR2 (INT_NUM_IM1_IRL0 + 26) 36 + #define LTQ_EIU_IR3 INT_NUM_IM1_IRL0 37 + #define LTQ_EIU_IR4 (INT_NUM_IM1_IRL0 + 1) 38 + #define LTQ_EIU_IR5 (INT_NUM_IM1_IRL0 + 2) 39 + #define LTQ_EIU_IR6 (INT_NUM_IM2_IRL0 + 30) 40 + 41 + #define MAX_EIU 6 42 + 43 + /* irqs generated by device attached to the EBU need to be acked in 44 + * a special manner 45 + */ 46 + #define LTQ_ICU_EBU_IRQ 22 47 + 48 + #define ltq_icu_w32(x, y) ltq_w32((x), ltq_icu_membase + (y)) 49 + #define ltq_icu_r32(x) ltq_r32(ltq_icu_membase + (x)) 50 + 51 + #define ltq_eiu_w32(x, y) ltq_w32((x), ltq_eiu_membase + (y)) 52 + #define ltq_eiu_r32(x) ltq_r32(ltq_eiu_membase + (x)) 53 + 54 + static unsigned short ltq_eiu_irq[MAX_EIU] = { 55 + LTQ_EIU_IR0, 56 + LTQ_EIU_IR1, 57 + LTQ_EIU_IR2, 58 + LTQ_EIU_IR3, 59 + LTQ_EIU_IR4, 60 + LTQ_EIU_IR5, 61 + }; 62 + 63 + static struct resource ltq_icu_resource = { 64 + .name = "icu", 65 + .start = LTQ_ICU_BASE_ADDR, 66 + .end = LTQ_ICU_BASE_ADDR + LTQ_ICU_SIZE - 1, 67 + .flags = IORESOURCE_MEM, 68 + }; 69 + 70 + static struct resource ltq_eiu_resource = { 71 + .name = "eiu", 72 + .start = LTQ_EIU_BASE_ADDR, 73 + .end = LTQ_EIU_BASE_ADDR + LTQ_ICU_SIZE - 1, 74 + .flags = IORESOURCE_MEM, 75 + }; 76 + 77 + static void __iomem *ltq_icu_membase; 78 + static void __iomem *ltq_eiu_membase; 79 + 80 + void ltq_disable_irq(struct irq_data *d) 81 + { 82 + u32 ier = LTQ_ICU_IM0_IER; 83 + int irq_nr = d->irq - INT_NUM_IRQ0; 84 + 85 + ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET); 86 + irq_nr %= INT_NUM_IM_OFFSET; 87 + ltq_icu_w32(ltq_icu_r32(ier) & ~(1 << irq_nr), ier); 88 + } 89 + 90 + void ltq_mask_and_ack_irq(struct irq_data *d) 91 + { 92 + u32 ier = LTQ_ICU_IM0_IER; 93 + u32 isr = LTQ_ICU_IM0_ISR; 94 + int irq_nr = d->irq - INT_NUM_IRQ0; 95 + 96 + ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET); 97 + isr += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET); 98 + irq_nr %= INT_NUM_IM_OFFSET; 99 + ltq_icu_w32(ltq_icu_r32(ier) & ~(1 << irq_nr), ier); 100 + ltq_icu_w32((1 << irq_nr), isr); 101 + } 102 + 103 + static void ltq_ack_irq(struct irq_data *d) 104 + { 105 + u32 isr = LTQ_ICU_IM0_ISR; 106 + int irq_nr = d->irq - INT_NUM_IRQ0; 107 + 108 + isr += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET); 109 + irq_nr %= INT_NUM_IM_OFFSET; 110 + ltq_icu_w32((1 << irq_nr), isr); 111 + } 112 + 113 + void ltq_enable_irq(struct irq_data *d) 114 + { 115 + u32 ier = LTQ_ICU_IM0_IER; 116 + int irq_nr = d->irq - INT_NUM_IRQ0; 117 + 118 + ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET); 119 + irq_nr %= INT_NUM_IM_OFFSET; 120 + ltq_icu_w32(ltq_icu_r32(ier) | (1 << irq_nr), ier); 121 + } 122 + 123 + static unsigned int ltq_startup_eiu_irq(struct irq_data *d) 124 + { 125 + int i; 126 + int irq_nr = d->irq - INT_NUM_IRQ0; 127 + 128 + ltq_enable_irq(d); 129 + for (i = 0; i < MAX_EIU; i++) { 130 + if (irq_nr == ltq_eiu_irq[i]) { 131 + /* low level - we should really handle set_type */ 132 + ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_C) | 133 + (0x6 << (i * 4)), LTQ_EIU_EXIN_C); 134 + /* clear all pending */ 135 + ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INIC) & ~(1 << i), 136 + LTQ_EIU_EXIN_INIC); 137 + /* enable */ 138 + ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) | (1 << i), 139 + LTQ_EIU_EXIN_INEN); 140 + break; 141 + } 142 + } 143 + 144 + return 0; 145 + } 146 + 147 + static void ltq_shutdown_eiu_irq(struct irq_data *d) 148 + { 149 + int i; 150 + int irq_nr = d->irq - INT_NUM_IRQ0; 151 + 152 + ltq_disable_irq(d); 153 + for (i = 0; i < MAX_EIU; i++) { 154 + if (irq_nr == ltq_eiu_irq[i]) { 155 + /* disable */ 156 + ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) & ~(1 << i), 157 + LTQ_EIU_EXIN_INEN); 158 + break; 159 + } 160 + } 161 + } 162 + 163 + static struct irq_chip ltq_irq_type = { 164 + "icu", 165 + .irq_enable = ltq_enable_irq, 166 + .irq_disable = ltq_disable_irq, 167 + .irq_unmask = ltq_enable_irq, 168 + .irq_ack = ltq_ack_irq, 169 + .irq_mask = ltq_disable_irq, 170 + .irq_mask_ack = ltq_mask_and_ack_irq, 171 + }; 172 + 173 + static struct irq_chip ltq_eiu_type = { 174 + "eiu", 175 + .irq_startup = ltq_startup_eiu_irq, 176 + .irq_shutdown = ltq_shutdown_eiu_irq, 177 + .irq_enable = ltq_enable_irq, 178 + .irq_disable = ltq_disable_irq, 179 + .irq_unmask = ltq_enable_irq, 180 + .irq_ack = ltq_ack_irq, 181 + .irq_mask = ltq_disable_irq, 182 + .irq_mask_ack = ltq_mask_and_ack_irq, 183 + }; 184 + 185 + static void ltq_hw_irqdispatch(int module) 186 + { 187 + u32 irq; 188 + 189 + irq = ltq_icu_r32(LTQ_ICU_IM0_IOSR + (module * LTQ_ICU_OFFSET)); 190 + if (irq == 0) 191 + return; 192 + 193 + /* silicon bug causes only the msb set to 1 to be valid. all 194 + * other bits might be bogus 195 + */ 196 + irq = __fls(irq); 197 + do_IRQ((int)irq + INT_NUM_IM0_IRL0 + (INT_NUM_IM_OFFSET * module)); 198 + 199 + /* if this is a EBU irq, we need to ack it or get a deadlock */ 200 + if ((irq == LTQ_ICU_EBU_IRQ) && (module == 0)) 201 + ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_ISTAT) | 0x10, 202 + LTQ_EBU_PCC_ISTAT); 203 + } 204 + 205 + #define DEFINE_HWx_IRQDISPATCH(x) \ 206 + static void ltq_hw ## x ## _irqdispatch(void) \ 207 + { \ 208 + ltq_hw_irqdispatch(x); \ 209 + } 210 + DEFINE_HWx_IRQDISPATCH(0) 211 + DEFINE_HWx_IRQDISPATCH(1) 212 + DEFINE_HWx_IRQDISPATCH(2) 213 + DEFINE_HWx_IRQDISPATCH(3) 214 + DEFINE_HWx_IRQDISPATCH(4) 215 + 216 + static void ltq_hw5_irqdispatch(void) 217 + { 218 + do_IRQ(MIPS_CPU_TIMER_IRQ); 219 + } 220 + 221 + asmlinkage void plat_irq_dispatch(void) 222 + { 223 + unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM; 224 + unsigned int i; 225 + 226 + if (pending & CAUSEF_IP7) { 227 + do_IRQ(MIPS_CPU_TIMER_IRQ); 228 + goto out; 229 + } else { 230 + for (i = 0; i < 5; i++) { 231 + if (pending & (CAUSEF_IP2 << i)) { 232 + ltq_hw_irqdispatch(i); 233 + goto out; 234 + } 235 + } 236 + } 237 + pr_alert("Spurious IRQ: CAUSE=0x%08x\n", read_c0_status()); 238 + 239 + out: 240 + return; 241 + } 242 + 243 + static struct irqaction cascade = { 244 + .handler = no_action, 245 + .flags = IRQF_DISABLED, 246 + .name = "cascade", 247 + }; 248 + 249 + void __init arch_init_irq(void) 250 + { 251 + int i; 252 + 253 + if (insert_resource(&iomem_resource, &ltq_icu_resource) < 0) 254 + panic("Failed to insert icu memory\n"); 255 + 256 + if (request_mem_region(ltq_icu_resource.start, 257 + resource_size(&ltq_icu_resource), "icu") < 0) 258 + panic("Failed to request icu memory\n"); 259 + 260 + ltq_icu_membase = ioremap_nocache(ltq_icu_resource.start, 261 + resource_size(&ltq_icu_resource)); 262 + if (!ltq_icu_membase) 263 + panic("Failed to remap icu memory\n"); 264 + 265 + if (insert_resource(&iomem_resource, &ltq_eiu_resource) < 0) 266 + panic("Failed to insert eiu memory\n"); 267 + 268 + if (request_mem_region(ltq_eiu_resource.start, 269 + resource_size(&ltq_eiu_resource), "eiu") < 0) 270 + panic("Failed to request eiu memory\n"); 271 + 272 + ltq_eiu_membase = ioremap_nocache(ltq_eiu_resource.start, 273 + resource_size(&ltq_eiu_resource)); 274 + if (!ltq_eiu_membase) 275 + panic("Failed to remap eiu memory\n"); 276 + 277 + /* make sure all irqs are turned off by default */ 278 + for (i = 0; i < 5; i++) 279 + ltq_icu_w32(0, LTQ_ICU_IM0_IER + (i * LTQ_ICU_OFFSET)); 280 + 281 + /* clear all possibly pending interrupts */ 282 + ltq_icu_w32(~0, LTQ_ICU_IM0_ISR + (i * LTQ_ICU_OFFSET)); 283 + 284 + mips_cpu_irq_init(); 285 + 286 + for (i = 2; i <= 6; i++) 287 + setup_irq(i, &cascade); 288 + 289 + if (cpu_has_vint) { 290 + pr_info("Setting up vectored interrupts\n"); 291 + set_vi_handler(2, ltq_hw0_irqdispatch); 292 + set_vi_handler(3, ltq_hw1_irqdispatch); 293 + set_vi_handler(4, ltq_hw2_irqdispatch); 294 + set_vi_handler(5, ltq_hw3_irqdispatch); 295 + set_vi_handler(6, ltq_hw4_irqdispatch); 296 + set_vi_handler(7, ltq_hw5_irqdispatch); 297 + } 298 + 299 + for (i = INT_NUM_IRQ0; 300 + i <= (INT_NUM_IRQ0 + (5 * INT_NUM_IM_OFFSET)); i++) 301 + if ((i == LTQ_EIU_IR0) || (i == LTQ_EIU_IR1) || 302 + (i == LTQ_EIU_IR2)) 303 + irq_set_chip_and_handler(i, &ltq_eiu_type, 304 + handle_level_irq); 305 + /* EIU3-5 only exist on ar9 and vr9 */ 306 + else if (((i == LTQ_EIU_IR3) || (i == LTQ_EIU_IR4) || 307 + (i == LTQ_EIU_IR5)) && (ltq_is_ar9() || ltq_is_vr9())) 308 + irq_set_chip_and_handler(i, &ltq_eiu_type, 309 + handle_level_irq); 310 + else 311 + irq_set_chip_and_handler(i, &ltq_irq_type, 312 + handle_level_irq); 313 + 314 + #if !defined(CONFIG_MIPS_MT_SMP) && !defined(CONFIG_MIPS_MT_SMTC) 315 + set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | 316 + IE_IRQ3 | IE_IRQ4 | IE_IRQ5); 317 + #else 318 + set_c0_status(IE_SW0 | IE_SW1 | IE_IRQ0 | IE_IRQ1 | 319 + IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5); 320 + #endif 321 + } 322 + 323 + unsigned int __cpuinit get_c0_compare_int(void) 324 + { 325 + return CP0_LEGACY_COMPARE_IRQ; 326 + }
+71
arch/mips/lantiq/prom.c
··· 1 + /* 2 + * This program is free software; you can redistribute it and/or modify it 3 + * under the terms of the GNU General Public License version 2 as published 4 + * by the Free Software Foundation. 5 + * 6 + * Copyright (C) 2010 John Crispin <blogic@openwrt.org> 7 + */ 8 + 9 + #include <linux/module.h> 10 + #include <linux/clk.h> 11 + #include <asm/bootinfo.h> 12 + #include <asm/time.h> 13 + 14 + #include <lantiq.h> 15 + 16 + #include "prom.h" 17 + #include "clk.h" 18 + 19 + static struct ltq_soc_info soc_info; 20 + 21 + unsigned int ltq_get_cpu_ver(void) 22 + { 23 + return soc_info.rev; 24 + } 25 + EXPORT_SYMBOL(ltq_get_cpu_ver); 26 + 27 + unsigned int ltq_get_soc_type(void) 28 + { 29 + return soc_info.type; 30 + } 31 + EXPORT_SYMBOL(ltq_get_soc_type); 32 + 33 + const char *get_system_type(void) 34 + { 35 + return soc_info.sys_type; 36 + } 37 + 38 + void prom_free_prom_memory(void) 39 + { 40 + } 41 + 42 + static void __init prom_init_cmdline(void) 43 + { 44 + int argc = fw_arg0; 45 + char **argv = (char **) KSEG1ADDR(fw_arg1); 46 + int i; 47 + 48 + for (i = 0; i < argc; i++) { 49 + char *p = (char *) KSEG1ADDR(argv[i]); 50 + 51 + if (p && *p) { 52 + strlcat(arcs_cmdline, p, sizeof(arcs_cmdline)); 53 + strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline)); 54 + } 55 + } 56 + } 57 + 58 + void __init prom_init(void) 59 + { 60 + struct clk *clk; 61 + 62 + ltq_soc_detect(&soc_info); 63 + clk_init(); 64 + clk = clk_get(0, "cpu"); 65 + snprintf(soc_info.sys_type, LTQ_SYS_TYPE_LEN - 1, "%s rev1.%d", 66 + soc_info.name, soc_info.rev); 67 + clk_put(clk); 68 + soc_info.sys_type[LTQ_SYS_TYPE_LEN - 1] = '\0'; 69 + pr_info("SoC: %s\n", soc_info.sys_type); 70 + prom_init_cmdline(); 71 + }
+24
arch/mips/lantiq/prom.h
··· 1 + /* 2 + * This program is free software; you can redistribute it and/or modify it 3 + * under the terms of the GNU General Public License version 2 as published 4 + * by the Free Software Foundation. 5 + * 6 + * Copyright (C) 2010 John Crispin <blogic@openwrt.org> 7 + */ 8 + 9 + #ifndef _LTQ_PROM_H__ 10 + #define _LTQ_PROM_H__ 11 + 12 + #define LTQ_SYS_TYPE_LEN 0x100 13 + 14 + struct ltq_soc_info { 15 + unsigned char *name; 16 + unsigned int rev; 17 + unsigned int partnum; 18 + unsigned int type; 19 + unsigned char sys_type[LTQ_SYS_TYPE_LEN]; 20 + }; 21 + 22 + extern void ltq_soc_detect(struct ltq_soc_info *i); 23 + 24 + #endif
+41
arch/mips/lantiq/setup.c
··· 1 + /* 2 + * This program is free software; you can redistribute it and/or modify it 3 + * under the terms of the GNU General Public License version 2 as published 4 + * by the Free Software Foundation. 5 + * 6 + * Copyright (C) 2010 John Crispin <blogic@openwrt.org> 7 + */ 8 + 9 + #include <linux/kernel.h> 10 + #include <linux/module.h> 11 + #include <linux/io.h> 12 + #include <linux/ioport.h> 13 + #include <asm/bootinfo.h> 14 + 15 + #include <lantiq_soc.h> 16 + 17 + void __init plat_mem_setup(void) 18 + { 19 + /* assume 16M as default incase uboot fails to pass proper ramsize */ 20 + unsigned long memsize = 16; 21 + char **envp = (char **) KSEG1ADDR(fw_arg2); 22 + 23 + ioport_resource.start = IOPORT_RESOURCE_START; 24 + ioport_resource.end = IOPORT_RESOURCE_END; 25 + iomem_resource.start = IOMEM_RESOURCE_START; 26 + iomem_resource.end = IOMEM_RESOURCE_END; 27 + 28 + set_io_port_base((unsigned long) KSEG1); 29 + 30 + while (*envp) { 31 + char *e = (char *)KSEG1ADDR(*envp); 32 + if (!strncmp(e, "memsize=", 8)) { 33 + e += 8; 34 + if (strict_strtoul(e, 0, &memsize)) 35 + pr_warn("bad memsize specified\n"); 36 + } 37 + envp++; 38 + } 39 + memsize *= 1024 * 1024; 40 + add_memory_region(0x00000000, memsize, BOOT_MEM_RAM); 41 + }