aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips
diff options
context:
space:
mode:
authorJohn Crispin <blogic@openwrt.org>2011-03-30 03:27:47 -0400
committerRalf Baechle <ralf@linux-mips.org>2011-05-19 04:55:41 -0400
commit171bb2f19ed6f3627f4f783f658f2f475b2fbd50 (patch)
treedd3d282809d7f8cae07485417f149660572743fe /arch/mips
parentc0a5afb9bcf6b5aa5685e4fcf1282cad5fab3d91 (diff)
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>
Diffstat (limited to 'arch/mips')
-rw-r--r--arch/mips/Kbuild.platforms1
-rw-r--r--arch/mips/Kconfig17
-rw-r--r--arch/mips/include/asm/mach-lantiq/lantiq.h63
-rw-r--r--arch/mips/include/asm/mach-lantiq/war.h24
-rw-r--r--arch/mips/lantiq/Makefile9
-rw-r--r--arch/mips/lantiq/Platform7
-rw-r--r--arch/mips/lantiq/clk.c140
-rw-r--r--arch/mips/lantiq/clk.h18
-rw-r--r--arch/mips/lantiq/early_printk.c33
-rw-r--r--arch/mips/lantiq/irq.c326
-rw-r--r--arch/mips/lantiq/prom.c71
-rw-r--r--arch/mips/lantiq/prom.h24
-rw-r--r--arch/mips/lantiq/setup.c41
13 files changed, 774 insertions, 0 deletions
diff --git a/arch/mips/Kbuild.platforms b/arch/mips/Kbuild.platforms
index 7ff9b5492041..aef6c917b45a 100644
--- a/arch/mips/Kbuild.platforms
+++ b/arch/mips/Kbuild.platforms
@@ -11,6 +11,7 @@ platforms += dec
11platforms += emma 11platforms += emma
12platforms += jazz 12platforms += jazz
13platforms += jz4740 13platforms += jz4740
14platforms += lantiq
14platforms += lasat 15platforms += lasat
15platforms += loongson 16platforms += loongson
16platforms += mipssim 17platforms += mipssim
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 5016caac6b91..1787572a76c3 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -212,6 +212,23 @@ config MACH_JZ4740
212 select HAVE_PWM 212 select HAVE_PWM
213 select HAVE_CLK 213 select HAVE_CLK
214 214
215config 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
215config LASAT 232config LASAT
216 bool "LASAT Networks platforms" 233 bool "LASAT Networks platforms"
217 select CEVT_R4K 234 select CEVT_R4K
diff --git a/arch/mips/include/asm/mach-lantiq/lantiq.h b/arch/mips/include/asm/mach-lantiq/lantiq.h
new file mode 100644
index 000000000000..ce2f02929d22
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/lantiq.h
@@ -0,0 +1,63 @@
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
27extern __iomem void *ltq_ebu_membase;
28extern __iomem void *ltq_cgu_membase;
29
30extern unsigned int ltq_get_cpu_ver(void);
31extern 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 */
45extern spinlock_t ebu_lock;
46
47/* some irq helpers */
48extern void ltq_disable_irq(struct irq_data *data);
49extern void ltq_mask_and_ack_irq(struct irq_data *data);
50extern void ltq_enable_irq(struct irq_data *data);
51
52/* find out what caused the last cpu reset */
53extern 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
diff --git a/arch/mips/include/asm/mach-lantiq/war.h b/arch/mips/include/asm/mach-lantiq/war.h
new file mode 100644
index 000000000000..01b08ef368d1
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/war.h
@@ -0,0 +1,24 @@
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
diff --git a/arch/mips/lantiq/Makefile b/arch/mips/lantiq/Makefile
new file mode 100644
index 000000000000..6a30de671f23
--- /dev/null
+++ b/arch/mips/lantiq/Makefile
@@ -0,0 +1,9 @@
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
7obj-y := irq.o setup.o clk.o prom.o
8
9obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
diff --git a/arch/mips/lantiq/Platform b/arch/mips/lantiq/Platform
new file mode 100644
index 000000000000..eef587f2d872
--- /dev/null
+++ b/arch/mips/lantiq/Platform
@@ -0,0 +1,7 @@
1#
2# Lantiq
3#
4
5platform-$(CONFIG_LANTIQ) += lantiq/
6cflags-$(CONFIG_LANTIQ) += -I$(srctree)/arch/mips/include/asm/mach-lantiq
7load-$(CONFIG_LANTIQ) = 0xffffffff80002000
diff --git a/arch/mips/lantiq/clk.c b/arch/mips/lantiq/clk.c
new file mode 100644
index 000000000000..94560899d13e
--- /dev/null
+++ b/arch/mips/lantiq/clk.c
@@ -0,0 +1,140 @@
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
26struct clk {
27 const char *name;
28 unsigned long rate;
29 unsigned long (*get_rate) (void);
30};
31
32static struct clk *cpu_clk;
33static int cpu_clk_cnt;
34
35/* lantiq socs have 3 static clocks */
36static 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
49static 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 */
57void __iomem *ltq_cgu_membase;
58
59void clk_init(void)
60{
61 cpu_clk = cpu_clk_generic;
62 cpu_clk_cnt = ARRAY_SIZE(cpu_clk_generic);
63}
64
65static inline int clk_good(struct clk *clk)
66{
67 return clk && !IS_ERR(clk);
68}
69
70unsigned 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}
83EXPORT_SYMBOL(clk_get_rate);
84
85struct 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}
95EXPORT_SYMBOL(clk_get);
96
97void clk_put(struct clk *clk)
98{
99 /* not used */
100}
101EXPORT_SYMBOL(clk_put);
102
103static 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
119void __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}
diff --git a/arch/mips/lantiq/clk.h b/arch/mips/lantiq/clk.h
new file mode 100644
index 000000000000..3328925f2c3f
--- /dev/null
+++ b/arch/mips/lantiq/clk.h
@@ -0,0 +1,18 @@
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
12extern void clk_init(void);
13
14extern unsigned long ltq_get_cpu_hz(void);
15extern unsigned long ltq_get_fpi_hz(void);
16extern unsigned long ltq_get_io_region_clock(void);
17
18#endif
diff --git a/arch/mips/lantiq/early_printk.c b/arch/mips/lantiq/early_printk.c
new file mode 100644
index 000000000000..972e05f87631
--- /dev/null
+++ b/arch/mips/lantiq/early_printk.c
@@ -0,0 +1,33 @@
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
23void 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}
diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c
new file mode 100644
index 000000000000..fc89795cafdb
--- /dev/null
+++ b/arch/mips/lantiq/irq.c
@@ -0,0 +1,326 @@
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
54static 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
63static 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
70static 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
77static void __iomem *ltq_icu_membase;
78static void __iomem *ltq_eiu_membase;
79
80void 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
90void 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
103static 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
113void 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
123static 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
147static 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
163static 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
173static 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
185static 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 }
210DEFINE_HWx_IRQDISPATCH(0)
211DEFINE_HWx_IRQDISPATCH(1)
212DEFINE_HWx_IRQDISPATCH(2)
213DEFINE_HWx_IRQDISPATCH(3)
214DEFINE_HWx_IRQDISPATCH(4)
215
216static void ltq_hw5_irqdispatch(void)
217{
218 do_IRQ(MIPS_CPU_TIMER_IRQ);
219}
220
221asmlinkage 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
239out:
240 return;
241}
242
243static struct irqaction cascade = {
244 .handler = no_action,
245 .flags = IRQF_DISABLED,
246 .name = "cascade",
247};
248
249void __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
323unsigned int __cpuinit get_c0_compare_int(void)
324{
325 return CP0_LEGACY_COMPARE_IRQ;
326}
diff --git a/arch/mips/lantiq/prom.c b/arch/mips/lantiq/prom.c
new file mode 100644
index 000000000000..56ba007bf1e5
--- /dev/null
+++ b/arch/mips/lantiq/prom.c
@@ -0,0 +1,71 @@
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
19static struct ltq_soc_info soc_info;
20
21unsigned int ltq_get_cpu_ver(void)
22{
23 return soc_info.rev;
24}
25EXPORT_SYMBOL(ltq_get_cpu_ver);
26
27unsigned int ltq_get_soc_type(void)
28{
29 return soc_info.type;
30}
31EXPORT_SYMBOL(ltq_get_soc_type);
32
33const char *get_system_type(void)
34{
35 return soc_info.sys_type;
36}
37
38void prom_free_prom_memory(void)
39{
40}
41
42static 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
58void __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}
diff --git a/arch/mips/lantiq/prom.h b/arch/mips/lantiq/prom.h
new file mode 100644
index 000000000000..4165ad156782
--- /dev/null
+++ b/arch/mips/lantiq/prom.h
@@ -0,0 +1,24 @@
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
14struct 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
22extern void ltq_soc_detect(struct ltq_soc_info *i);
23
24#endif
diff --git a/arch/mips/lantiq/setup.c b/arch/mips/lantiq/setup.c
new file mode 100644
index 000000000000..79a2b0c5cc65
--- /dev/null
+++ b/arch/mips/lantiq/setup.c
@@ -0,0 +1,41 @@
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
17void __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}