diff options
author | Gabor Juhos <juhosg@openwrt.org> | 2011-01-04 15:28:14 -0500 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2011-01-18 13:30:24 -0500 |
commit | d4a67d9dc8a5a80c4ec1814791af8c0252c158b8 (patch) | |
tree | 28c9797f2ec5bf46325e1d5dd7db675ac0ac6713 /arch/mips/ath79 | |
parent | 94bb0c1ab293c298a8852e4f10c4215bad6daa9b (diff) |
MIPS: Add initial support for the Atheros AR71XX/AR724X/AR931X SoCs
This patch adds initial support for various Atheros SoCs based on the
MIPS 24Kc core. The following models are supported at the moment:
- AR7130
- AR7141
- AR7161
- AR9130
- AR9132
- AR7240
- AR7241
- AR7242
The current patch contains minimal support only, but the resulting
kernel can boot into user-space with using of an initramfs image on
various boards which are using these SoCs. Support for more built-in
devices and individual boards will be implemented in further patches.
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
Cc: linux-mips@linux-mips.org
Cc: Luis R. Rodriguez <lrodriguez@atheros.com>
Cc: Cliff Holden <Cliff.Holden@Atheros.com>
Cc: Kathy Giori <Kathy.Giori@Atheros.com>
Patchwork: https://patchwork.linux-mips.org/patch/1947/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/ath79')
-rw-r--r-- | arch/mips/ath79/Kconfig | 12 | ||||
-rw-r--r-- | arch/mips/ath79/Makefile | 18 | ||||
-rw-r--r-- | arch/mips/ath79/Platform | 7 | ||||
-rw-r--r-- | arch/mips/ath79/clock.c | 183 | ||||
-rw-r--r-- | arch/mips/ath79/common.c | 97 | ||||
-rw-r--r-- | arch/mips/ath79/common.h | 26 | ||||
-rw-r--r-- | arch/mips/ath79/dev-common.c | 67 | ||||
-rw-r--r-- | arch/mips/ath79/dev-common.h | 17 | ||||
-rw-r--r-- | arch/mips/ath79/early_printk.c | 36 | ||||
-rw-r--r-- | arch/mips/ath79/irq.c | 187 | ||||
-rw-r--r-- | arch/mips/ath79/prom.c | 57 | ||||
-rw-r--r-- | arch/mips/ath79/setup.c | 190 |
12 files changed, 897 insertions, 0 deletions
diff --git a/arch/mips/ath79/Kconfig b/arch/mips/ath79/Kconfig new file mode 100644 index 000000000000..50b933446cc0 --- /dev/null +++ b/arch/mips/ath79/Kconfig | |||
@@ -0,0 +1,12 @@ | |||
1 | if ATH79 | ||
2 | |||
3 | config SOC_AR71XX | ||
4 | def_bool n | ||
5 | |||
6 | config SOC_AR724X | ||
7 | def_bool n | ||
8 | |||
9 | config SOC_AR913X | ||
10 | def_bool n | ||
11 | |||
12 | endif | ||
diff --git a/arch/mips/ath79/Makefile b/arch/mips/ath79/Makefile new file mode 100644 index 000000000000..31e0f83ddf68 --- /dev/null +++ b/arch/mips/ath79/Makefile | |||
@@ -0,0 +1,18 @@ | |||
1 | # | ||
2 | # Makefile for the Atheros AR71XX/AR724X/AR913X specific parts of the kernel | ||
3 | # | ||
4 | # Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> | ||
5 | # Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | ||
6 | # | ||
7 | # This program is free software; you can redistribute it and/or modify it | ||
8 | # under the terms of the GNU General Public License version 2 as published | ||
9 | # by the Free Software Foundation. | ||
10 | |||
11 | obj-y := prom.o setup.o irq.o common.o clock.o | ||
12 | |||
13 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o | ||
14 | |||
15 | # | ||
16 | # Devices | ||
17 | # | ||
18 | obj-y += dev-common.o | ||
diff --git a/arch/mips/ath79/Platform b/arch/mips/ath79/Platform new file mode 100644 index 000000000000..2bd663647d27 --- /dev/null +++ b/arch/mips/ath79/Platform | |||
@@ -0,0 +1,7 @@ | |||
1 | # | ||
2 | # Atheros AR71xx/AR724x/AR913x | ||
3 | # | ||
4 | |||
5 | platform-$(CONFIG_ATH79) += ath79/ | ||
6 | cflags-$(CONFIG_ATH79) += -I$(srctree)/arch/mips/include/asm/mach-ath79 | ||
7 | load-$(CONFIG_ATH79) = 0xffffffff80060000 | ||
diff --git a/arch/mips/ath79/clock.c b/arch/mips/ath79/clock.c new file mode 100644 index 000000000000..680bde99a26c --- /dev/null +++ b/arch/mips/ath79/clock.c | |||
@@ -0,0 +1,183 @@ | |||
1 | /* | ||
2 | * Atheros AR71XX/AR724X/AR913X common routines | ||
3 | * | ||
4 | * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License version 2 as published | ||
8 | * by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/err.h> | ||
15 | #include <linux/clk.h> | ||
16 | |||
17 | #include <asm/mach-ath79/ath79.h> | ||
18 | #include <asm/mach-ath79/ar71xx_regs.h> | ||
19 | #include "common.h" | ||
20 | |||
21 | #define AR71XX_BASE_FREQ 40000000 | ||
22 | #define AR724X_BASE_FREQ 5000000 | ||
23 | #define AR913X_BASE_FREQ 5000000 | ||
24 | |||
25 | struct clk { | ||
26 | unsigned long rate; | ||
27 | }; | ||
28 | |||
29 | static struct clk ath79_ref_clk; | ||
30 | static struct clk ath79_cpu_clk; | ||
31 | static struct clk ath79_ddr_clk; | ||
32 | static struct clk ath79_ahb_clk; | ||
33 | static struct clk ath79_wdt_clk; | ||
34 | static struct clk ath79_uart_clk; | ||
35 | |||
36 | static void __init ar71xx_clocks_init(void) | ||
37 | { | ||
38 | u32 pll; | ||
39 | u32 freq; | ||
40 | u32 div; | ||
41 | |||
42 | ath79_ref_clk.rate = AR71XX_BASE_FREQ; | ||
43 | |||
44 | pll = ath79_pll_rr(AR71XX_PLL_REG_CPU_CONFIG); | ||
45 | |||
46 | div = ((pll >> AR71XX_PLL_DIV_SHIFT) & AR71XX_PLL_DIV_MASK) + 1; | ||
47 | freq = div * ath79_ref_clk.rate; | ||
48 | |||
49 | div = ((pll >> AR71XX_CPU_DIV_SHIFT) & AR71XX_CPU_DIV_MASK) + 1; | ||
50 | ath79_cpu_clk.rate = freq / div; | ||
51 | |||
52 | div = ((pll >> AR71XX_DDR_DIV_SHIFT) & AR71XX_DDR_DIV_MASK) + 1; | ||
53 | ath79_ddr_clk.rate = freq / div; | ||
54 | |||
55 | div = (((pll >> AR71XX_AHB_DIV_SHIFT) & AR71XX_AHB_DIV_MASK) + 1) * 2; | ||
56 | ath79_ahb_clk.rate = ath79_cpu_clk.rate / div; | ||
57 | |||
58 | ath79_wdt_clk.rate = ath79_ahb_clk.rate; | ||
59 | ath79_uart_clk.rate = ath79_ahb_clk.rate; | ||
60 | } | ||
61 | |||
62 | static void __init ar724x_clocks_init(void) | ||
63 | { | ||
64 | u32 pll; | ||
65 | u32 freq; | ||
66 | u32 div; | ||
67 | |||
68 | ath79_ref_clk.rate = AR724X_BASE_FREQ; | ||
69 | pll = ath79_pll_rr(AR724X_PLL_REG_CPU_CONFIG); | ||
70 | |||
71 | div = ((pll >> AR724X_PLL_DIV_SHIFT) & AR724X_PLL_DIV_MASK); | ||
72 | freq = div * ath79_ref_clk.rate; | ||
73 | |||
74 | div = ((pll >> AR724X_PLL_REF_DIV_SHIFT) & AR724X_PLL_REF_DIV_MASK); | ||
75 | freq *= div; | ||
76 | |||
77 | ath79_cpu_clk.rate = freq; | ||
78 | |||
79 | div = ((pll >> AR724X_DDR_DIV_SHIFT) & AR724X_DDR_DIV_MASK) + 1; | ||
80 | ath79_ddr_clk.rate = freq / div; | ||
81 | |||
82 | div = (((pll >> AR724X_AHB_DIV_SHIFT) & AR724X_AHB_DIV_MASK) + 1) * 2; | ||
83 | ath79_ahb_clk.rate = ath79_cpu_clk.rate / div; | ||
84 | |||
85 | ath79_wdt_clk.rate = ath79_ahb_clk.rate; | ||
86 | ath79_uart_clk.rate = ath79_ahb_clk.rate; | ||
87 | } | ||
88 | |||
89 | static void __init ar913x_clocks_init(void) | ||
90 | { | ||
91 | u32 pll; | ||
92 | u32 freq; | ||
93 | u32 div; | ||
94 | |||
95 | ath79_ref_clk.rate = AR913X_BASE_FREQ; | ||
96 | pll = ath79_pll_rr(AR913X_PLL_REG_CPU_CONFIG); | ||
97 | |||
98 | div = ((pll >> AR913X_PLL_DIV_SHIFT) & AR913X_PLL_DIV_MASK); | ||
99 | freq = div * ath79_ref_clk.rate; | ||
100 | |||
101 | ath79_cpu_clk.rate = freq; | ||
102 | |||
103 | div = ((pll >> AR913X_DDR_DIV_SHIFT) & AR913X_DDR_DIV_MASK) + 1; | ||
104 | ath79_ddr_clk.rate = freq / div; | ||
105 | |||
106 | div = (((pll >> AR913X_AHB_DIV_SHIFT) & AR913X_AHB_DIV_MASK) + 1) * 2; | ||
107 | ath79_ahb_clk.rate = ath79_cpu_clk.rate / div; | ||
108 | |||
109 | ath79_wdt_clk.rate = ath79_ahb_clk.rate; | ||
110 | ath79_uart_clk.rate = ath79_ahb_clk.rate; | ||
111 | } | ||
112 | |||
113 | void __init ath79_clocks_init(void) | ||
114 | { | ||
115 | if (soc_is_ar71xx()) | ||
116 | ar71xx_clocks_init(); | ||
117 | else if (soc_is_ar724x()) | ||
118 | ar724x_clocks_init(); | ||
119 | else if (soc_is_ar913x()) | ||
120 | ar913x_clocks_init(); | ||
121 | else | ||
122 | BUG(); | ||
123 | |||
124 | pr_info("Clocks: CPU:%lu.%03luMHz, DDR:%lu.%03luMHz, AHB:%lu.%03luMHz, " | ||
125 | "Ref:%lu.%03luMHz", | ||
126 | ath79_cpu_clk.rate / 1000000, | ||
127 | (ath79_cpu_clk.rate / 1000) % 1000, | ||
128 | ath79_ddr_clk.rate / 1000000, | ||
129 | (ath79_ddr_clk.rate / 1000) % 1000, | ||
130 | ath79_ahb_clk.rate / 1000000, | ||
131 | (ath79_ahb_clk.rate / 1000) % 1000, | ||
132 | ath79_ref_clk.rate / 1000000, | ||
133 | (ath79_ref_clk.rate / 1000) % 1000); | ||
134 | } | ||
135 | |||
136 | /* | ||
137 | * Linux clock API | ||
138 | */ | ||
139 | struct clk *clk_get(struct device *dev, const char *id) | ||
140 | { | ||
141 | if (!strcmp(id, "ref")) | ||
142 | return &ath79_ref_clk; | ||
143 | |||
144 | if (!strcmp(id, "cpu")) | ||
145 | return &ath79_cpu_clk; | ||
146 | |||
147 | if (!strcmp(id, "ddr")) | ||
148 | return &ath79_ddr_clk; | ||
149 | |||
150 | if (!strcmp(id, "ahb")) | ||
151 | return &ath79_ahb_clk; | ||
152 | |||
153 | if (!strcmp(id, "wdt")) | ||
154 | return &ath79_wdt_clk; | ||
155 | |||
156 | if (!strcmp(id, "uart")) | ||
157 | return &ath79_uart_clk; | ||
158 | |||
159 | return ERR_PTR(-ENOENT); | ||
160 | } | ||
161 | EXPORT_SYMBOL(clk_get); | ||
162 | |||
163 | int clk_enable(struct clk *clk) | ||
164 | { | ||
165 | return 0; | ||
166 | } | ||
167 | EXPORT_SYMBOL(clk_enable); | ||
168 | |||
169 | void clk_disable(struct clk *clk) | ||
170 | { | ||
171 | } | ||
172 | EXPORT_SYMBOL(clk_disable); | ||
173 | |||
174 | unsigned long clk_get_rate(struct clk *clk) | ||
175 | { | ||
176 | return clk->rate; | ||
177 | } | ||
178 | EXPORT_SYMBOL(clk_get_rate); | ||
179 | |||
180 | void clk_put(struct clk *clk) | ||
181 | { | ||
182 | } | ||
183 | EXPORT_SYMBOL(clk_put); | ||
diff --git a/arch/mips/ath79/common.c b/arch/mips/ath79/common.c new file mode 100644 index 000000000000..58f60e722a03 --- /dev/null +++ b/arch/mips/ath79/common.c | |||
@@ -0,0 +1,97 @@ | |||
1 | /* | ||
2 | * Atheros AR71XX/AR724X/AR913X common routines | ||
3 | * | ||
4 | * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> | ||
5 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published | ||
9 | * by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/types.h> | ||
15 | #include <linux/spinlock.h> | ||
16 | |||
17 | #include <asm/mach-ath79/ath79.h> | ||
18 | #include <asm/mach-ath79/ar71xx_regs.h> | ||
19 | #include "common.h" | ||
20 | |||
21 | static DEFINE_SPINLOCK(ath79_device_reset_lock); | ||
22 | |||
23 | u32 ath79_cpu_freq; | ||
24 | EXPORT_SYMBOL_GPL(ath79_cpu_freq); | ||
25 | |||
26 | u32 ath79_ahb_freq; | ||
27 | EXPORT_SYMBOL_GPL(ath79_ahb_freq); | ||
28 | |||
29 | u32 ath79_ddr_freq; | ||
30 | EXPORT_SYMBOL_GPL(ath79_ddr_freq); | ||
31 | |||
32 | enum ath79_soc_type ath79_soc; | ||
33 | |||
34 | void __iomem *ath79_pll_base; | ||
35 | void __iomem *ath79_reset_base; | ||
36 | EXPORT_SYMBOL_GPL(ath79_reset_base); | ||
37 | void __iomem *ath79_ddr_base; | ||
38 | |||
39 | void ath79_ddr_wb_flush(u32 reg) | ||
40 | { | ||
41 | void __iomem *flush_reg = ath79_ddr_base + reg; | ||
42 | |||
43 | /* Flush the DDR write buffer. */ | ||
44 | __raw_writel(0x1, flush_reg); | ||
45 | while (__raw_readl(flush_reg) & 0x1) | ||
46 | ; | ||
47 | |||
48 | /* It must be run twice. */ | ||
49 | __raw_writel(0x1, flush_reg); | ||
50 | while (__raw_readl(flush_reg) & 0x1) | ||
51 | ; | ||
52 | } | ||
53 | EXPORT_SYMBOL_GPL(ath79_ddr_wb_flush); | ||
54 | |||
55 | void ath79_device_reset_set(u32 mask) | ||
56 | { | ||
57 | unsigned long flags; | ||
58 | u32 reg; | ||
59 | u32 t; | ||
60 | |||
61 | if (soc_is_ar71xx()) | ||
62 | reg = AR71XX_RESET_REG_RESET_MODULE; | ||
63 | else if (soc_is_ar724x()) | ||
64 | reg = AR724X_RESET_REG_RESET_MODULE; | ||
65 | else if (soc_is_ar913x()) | ||
66 | reg = AR913X_RESET_REG_RESET_MODULE; | ||
67 | else | ||
68 | BUG(); | ||
69 | |||
70 | spin_lock_irqsave(&ath79_device_reset_lock, flags); | ||
71 | t = ath79_reset_rr(reg); | ||
72 | ath79_reset_wr(reg, t | mask); | ||
73 | spin_unlock_irqrestore(&ath79_device_reset_lock, flags); | ||
74 | } | ||
75 | EXPORT_SYMBOL_GPL(ath79_device_reset_set); | ||
76 | |||
77 | void ath79_device_reset_clear(u32 mask) | ||
78 | { | ||
79 | unsigned long flags; | ||
80 | u32 reg; | ||
81 | u32 t; | ||
82 | |||
83 | if (soc_is_ar71xx()) | ||
84 | reg = AR71XX_RESET_REG_RESET_MODULE; | ||
85 | else if (soc_is_ar724x()) | ||
86 | reg = AR724X_RESET_REG_RESET_MODULE; | ||
87 | else if (soc_is_ar913x()) | ||
88 | reg = AR913X_RESET_REG_RESET_MODULE; | ||
89 | else | ||
90 | BUG(); | ||
91 | |||
92 | spin_lock_irqsave(&ath79_device_reset_lock, flags); | ||
93 | t = ath79_reset_rr(reg); | ||
94 | ath79_reset_wr(reg, t & ~mask); | ||
95 | spin_unlock_irqrestore(&ath79_device_reset_lock, flags); | ||
96 | } | ||
97 | EXPORT_SYMBOL_GPL(ath79_device_reset_clear); | ||
diff --git a/arch/mips/ath79/common.h b/arch/mips/ath79/common.h new file mode 100644 index 000000000000..612a6b5d8702 --- /dev/null +++ b/arch/mips/ath79/common.h | |||
@@ -0,0 +1,26 @@ | |||
1 | /* | ||
2 | * Atheros AR71XX/AR724X/AR913X common definitions | ||
3 | * | ||
4 | * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> | ||
5 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | ||
6 | * | ||
7 | * Parts of this file are based on Atheros' 2.6.15 BSP | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License version 2 as published | ||
11 | * by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #ifndef __ATH79_COMMON_H | ||
15 | #define __ATH79_COMMON_H | ||
16 | |||
17 | #include <linux/types.h> | ||
18 | #include <linux/init.h> | ||
19 | |||
20 | #define ATH79_MEM_SIZE_MIN (2 * 1024 * 1024) | ||
21 | #define ATH79_MEM_SIZE_MAX (128 * 1024 * 1024) | ||
22 | |||
23 | void ath79_clocks_init(void); | ||
24 | void ath79_ddr_wb_flush(unsigned int reg); | ||
25 | |||
26 | #endif /* __ATH79_COMMON_H */ | ||
diff --git a/arch/mips/ath79/dev-common.c b/arch/mips/ath79/dev-common.c new file mode 100644 index 000000000000..3cfa10065d68 --- /dev/null +++ b/arch/mips/ath79/dev-common.c | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | * Atheros AR71XX/AR724X/AR913X common devices | ||
3 | * | ||
4 | * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> | ||
5 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | ||
6 | * | ||
7 | * Parts of this file are based on Atheros' 2.6.15 BSP | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License version 2 as published | ||
11 | * by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | #include <linux/serial_8250.h> | ||
18 | #include <linux/clk.h> | ||
19 | #include <linux/err.h> | ||
20 | |||
21 | #include <asm/mach-ath79/ath79.h> | ||
22 | #include <asm/mach-ath79/ar71xx_regs.h> | ||
23 | #include "common.h" | ||
24 | #include "dev-common.h" | ||
25 | |||
26 | static struct resource ath79_uart_resources[] = { | ||
27 | { | ||
28 | .start = AR71XX_UART_BASE, | ||
29 | .end = AR71XX_UART_BASE + AR71XX_UART_SIZE - 1, | ||
30 | .flags = IORESOURCE_MEM, | ||
31 | }, | ||
32 | }; | ||
33 | |||
34 | #define AR71XX_UART_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP) | ||
35 | static struct plat_serial8250_port ath79_uart_data[] = { | ||
36 | { | ||
37 | .mapbase = AR71XX_UART_BASE, | ||
38 | .irq = ATH79_MISC_IRQ_UART, | ||
39 | .flags = AR71XX_UART_FLAGS, | ||
40 | .iotype = UPIO_MEM32, | ||
41 | .regshift = 2, | ||
42 | }, { | ||
43 | /* terminating entry */ | ||
44 | } | ||
45 | }; | ||
46 | |||
47 | static struct platform_device ath79_uart_device = { | ||
48 | .name = "serial8250", | ||
49 | .id = PLAT8250_DEV_PLATFORM, | ||
50 | .resource = ath79_uart_resources, | ||
51 | .num_resources = ARRAY_SIZE(ath79_uart_resources), | ||
52 | .dev = { | ||
53 | .platform_data = ath79_uart_data | ||
54 | }, | ||
55 | }; | ||
56 | |||
57 | void __init ath79_register_uart(void) | ||
58 | { | ||
59 | struct clk *clk; | ||
60 | |||
61 | clk = clk_get(NULL, "uart"); | ||
62 | if (IS_ERR(clk)) | ||
63 | panic("unable to get UART clock, err=%ld", PTR_ERR(clk)); | ||
64 | |||
65 | ath79_uart_data[0].uartclk = clk_get_rate(clk); | ||
66 | platform_device_register(&ath79_uart_device); | ||
67 | } | ||
diff --git a/arch/mips/ath79/dev-common.h b/arch/mips/ath79/dev-common.h new file mode 100644 index 000000000000..248622cc7cd6 --- /dev/null +++ b/arch/mips/ath79/dev-common.h | |||
@@ -0,0 +1,17 @@ | |||
1 | /* | ||
2 | * Atheros AR71XX/AR724X/AR913X common devices | ||
3 | * | ||
4 | * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> | ||
5 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published | ||
9 | * by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #ifndef _ATH79_DEV_COMMON_H | ||
13 | #define _ATH79_DEV_COMMON_H | ||
14 | |||
15 | void ath79_register_uart(void); | ||
16 | |||
17 | #endif /* _ATH79_DEV_COMMON_H */ | ||
diff --git a/arch/mips/ath79/early_printk.c b/arch/mips/ath79/early_printk.c new file mode 100644 index 000000000000..7499b0e9df26 --- /dev/null +++ b/arch/mips/ath79/early_printk.c | |||
@@ -0,0 +1,36 @@ | |||
1 | /* | ||
2 | * Atheros AR71XX/AR724X/AR913X SoC early printk support | ||
3 | * | ||
4 | * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> | ||
5 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published | ||
9 | * by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/io.h> | ||
13 | #include <linux/serial_reg.h> | ||
14 | #include <asm/addrspace.h> | ||
15 | |||
16 | #include <asm/mach-ath79/ar71xx_regs.h> | ||
17 | |||
18 | static inline void prom_wait_thre(void __iomem *base) | ||
19 | { | ||
20 | u32 lsr; | ||
21 | |||
22 | do { | ||
23 | lsr = __raw_readl(base + UART_LSR * 4); | ||
24 | if (lsr & UART_LSR_THRE) | ||
25 | break; | ||
26 | } while (1); | ||
27 | } | ||
28 | |||
29 | void prom_putchar(unsigned char ch) | ||
30 | { | ||
31 | void __iomem *base = (void __iomem *)(KSEG1ADDR(AR71XX_UART_BASE)); | ||
32 | |||
33 | prom_wait_thre(base); | ||
34 | __raw_writel(ch, base + UART_TX * 4); | ||
35 | prom_wait_thre(base); | ||
36 | } | ||
diff --git a/arch/mips/ath79/irq.c b/arch/mips/ath79/irq.c new file mode 100644 index 000000000000..1bf7f719ba53 --- /dev/null +++ b/arch/mips/ath79/irq.c | |||
@@ -0,0 +1,187 @@ | |||
1 | /* | ||
2 | * Atheros AR71xx/AR724x/AR913x specific interrupt handling | ||
3 | * | ||
4 | * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> | ||
5 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | ||
6 | * | ||
7 | * Parts of this file are based on Atheros' 2.6.15 BSP | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License version 2 as published | ||
11 | * by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/irq.h> | ||
18 | |||
19 | #include <asm/irq_cpu.h> | ||
20 | #include <asm/mipsregs.h> | ||
21 | |||
22 | #include <asm/mach-ath79/ath79.h> | ||
23 | #include <asm/mach-ath79/ar71xx_regs.h> | ||
24 | #include "common.h" | ||
25 | |||
26 | static unsigned int ath79_ip2_flush_reg; | ||
27 | static unsigned int ath79_ip3_flush_reg; | ||
28 | |||
29 | static void ath79_misc_irq_handler(unsigned int irq, struct irq_desc *desc) | ||
30 | { | ||
31 | void __iomem *base = ath79_reset_base; | ||
32 | u32 pending; | ||
33 | |||
34 | pending = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS) & | ||
35 | __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); | ||
36 | |||
37 | if (pending & MISC_INT_UART) | ||
38 | generic_handle_irq(ATH79_MISC_IRQ_UART); | ||
39 | |||
40 | else if (pending & MISC_INT_DMA) | ||
41 | generic_handle_irq(ATH79_MISC_IRQ_DMA); | ||
42 | |||
43 | else if (pending & MISC_INT_PERFC) | ||
44 | generic_handle_irq(ATH79_MISC_IRQ_PERFC); | ||
45 | |||
46 | else if (pending & MISC_INT_TIMER) | ||
47 | generic_handle_irq(ATH79_MISC_IRQ_TIMER); | ||
48 | |||
49 | else if (pending & MISC_INT_OHCI) | ||
50 | generic_handle_irq(ATH79_MISC_IRQ_OHCI); | ||
51 | |||
52 | else if (pending & MISC_INT_ERROR) | ||
53 | generic_handle_irq(ATH79_MISC_IRQ_ERROR); | ||
54 | |||
55 | else if (pending & MISC_INT_GPIO) | ||
56 | generic_handle_irq(ATH79_MISC_IRQ_GPIO); | ||
57 | |||
58 | else if (pending & MISC_INT_WDOG) | ||
59 | generic_handle_irq(ATH79_MISC_IRQ_WDOG); | ||
60 | |||
61 | else | ||
62 | spurious_interrupt(); | ||
63 | } | ||
64 | |||
65 | static void ar71xx_misc_irq_unmask(unsigned int irq) | ||
66 | { | ||
67 | void __iomem *base = ath79_reset_base; | ||
68 | u32 t; | ||
69 | |||
70 | irq -= ATH79_MISC_IRQ_BASE; | ||
71 | |||
72 | t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); | ||
73 | __raw_writel(t | (1 << irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE); | ||
74 | |||
75 | /* flush write */ | ||
76 | __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); | ||
77 | } | ||
78 | |||
79 | static void ar71xx_misc_irq_mask(unsigned int irq) | ||
80 | { | ||
81 | void __iomem *base = ath79_reset_base; | ||
82 | u32 t; | ||
83 | |||
84 | irq -= ATH79_MISC_IRQ_BASE; | ||
85 | |||
86 | t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); | ||
87 | __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE); | ||
88 | |||
89 | /* flush write */ | ||
90 | __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); | ||
91 | } | ||
92 | |||
93 | static void ar724x_misc_irq_ack(unsigned int irq) | ||
94 | { | ||
95 | void __iomem *base = ath79_reset_base; | ||
96 | u32 t; | ||
97 | |||
98 | irq -= ATH79_MISC_IRQ_BASE; | ||
99 | |||
100 | t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS); | ||
101 | __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_MISC_INT_STATUS); | ||
102 | |||
103 | /* flush write */ | ||
104 | __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS); | ||
105 | } | ||
106 | |||
107 | static struct irq_chip ath79_misc_irq_chip = { | ||
108 | .name = "MISC", | ||
109 | .unmask = ar71xx_misc_irq_unmask, | ||
110 | .mask = ar71xx_misc_irq_mask, | ||
111 | }; | ||
112 | |||
113 | static void __init ath79_misc_irq_init(void) | ||
114 | { | ||
115 | void __iomem *base = ath79_reset_base; | ||
116 | int i; | ||
117 | |||
118 | __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_ENABLE); | ||
119 | __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_STATUS); | ||
120 | |||
121 | if (soc_is_ar71xx() || soc_is_ar913x()) | ||
122 | ath79_misc_irq_chip.mask_ack = ar71xx_misc_irq_mask; | ||
123 | else if (soc_is_ar724x()) | ||
124 | ath79_misc_irq_chip.ack = ar724x_misc_irq_ack; | ||
125 | else | ||
126 | BUG(); | ||
127 | |||
128 | for (i = ATH79_MISC_IRQ_BASE; | ||
129 | i < ATH79_MISC_IRQ_BASE + ATH79_MISC_IRQ_COUNT; i++) { | ||
130 | irq_desc[i].status = IRQ_DISABLED; | ||
131 | set_irq_chip_and_handler(i, &ath79_misc_irq_chip, | ||
132 | handle_level_irq); | ||
133 | } | ||
134 | |||
135 | set_irq_chained_handler(ATH79_CPU_IRQ_MISC, ath79_misc_irq_handler); | ||
136 | } | ||
137 | |||
138 | asmlinkage void plat_irq_dispatch(void) | ||
139 | { | ||
140 | unsigned long pending; | ||
141 | |||
142 | pending = read_c0_status() & read_c0_cause() & ST0_IM; | ||
143 | |||
144 | if (pending & STATUSF_IP7) | ||
145 | do_IRQ(ATH79_CPU_IRQ_TIMER); | ||
146 | |||
147 | else if (pending & STATUSF_IP2) { | ||
148 | ath79_ddr_wb_flush(ath79_ip2_flush_reg); | ||
149 | do_IRQ(ATH79_CPU_IRQ_IP2); | ||
150 | } | ||
151 | |||
152 | else if (pending & STATUSF_IP4) | ||
153 | do_IRQ(ATH79_CPU_IRQ_GE0); | ||
154 | |||
155 | else if (pending & STATUSF_IP5) | ||
156 | do_IRQ(ATH79_CPU_IRQ_GE1); | ||
157 | |||
158 | else if (pending & STATUSF_IP3) { | ||
159 | ath79_ddr_wb_flush(ath79_ip3_flush_reg); | ||
160 | do_IRQ(ATH79_CPU_IRQ_USB); | ||
161 | } | ||
162 | |||
163 | else if (pending & STATUSF_IP6) | ||
164 | do_IRQ(ATH79_CPU_IRQ_MISC); | ||
165 | |||
166 | else | ||
167 | spurious_interrupt(); | ||
168 | } | ||
169 | |||
170 | void __init arch_init_irq(void) | ||
171 | { | ||
172 | if (soc_is_ar71xx()) { | ||
173 | ath79_ip2_flush_reg = AR71XX_DDR_REG_FLUSH_PCI; | ||
174 | ath79_ip3_flush_reg = AR71XX_DDR_REG_FLUSH_USB; | ||
175 | } else if (soc_is_ar724x()) { | ||
176 | ath79_ip2_flush_reg = AR724X_DDR_REG_FLUSH_PCIE; | ||
177 | ath79_ip3_flush_reg = AR724X_DDR_REG_FLUSH_USB; | ||
178 | } else if (soc_is_ar913x()) { | ||
179 | ath79_ip2_flush_reg = AR913X_DDR_REG_FLUSH_WMAC; | ||
180 | ath79_ip3_flush_reg = AR913X_DDR_REG_FLUSH_USB; | ||
181 | } else | ||
182 | BUG(); | ||
183 | |||
184 | cp0_perfcount_irq = ATH79_MISC_IRQ_PERFC; | ||
185 | mips_cpu_irq_init(); | ||
186 | ath79_misc_irq_init(); | ||
187 | } | ||
diff --git a/arch/mips/ath79/prom.c b/arch/mips/ath79/prom.c new file mode 100644 index 000000000000..e9cbd7c2918f --- /dev/null +++ b/arch/mips/ath79/prom.c | |||
@@ -0,0 +1,57 @@ | |||
1 | /* | ||
2 | * Atheros AR71XX/AR724X/AR913X specific prom routines | ||
3 | * | ||
4 | * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> | ||
5 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published | ||
9 | * by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/io.h> | ||
15 | #include <linux/string.h> | ||
16 | |||
17 | #include <asm/bootinfo.h> | ||
18 | #include <asm/addrspace.h> | ||
19 | |||
20 | #include "common.h" | ||
21 | |||
22 | static inline int is_valid_ram_addr(void *addr) | ||
23 | { | ||
24 | if (((u32) addr > KSEG0) && | ||
25 | ((u32) addr < (KSEG0 + ATH79_MEM_SIZE_MAX))) | ||
26 | return 1; | ||
27 | |||
28 | if (((u32) addr > KSEG1) && | ||
29 | ((u32) addr < (KSEG1 + ATH79_MEM_SIZE_MAX))) | ||
30 | return 1; | ||
31 | |||
32 | return 0; | ||
33 | } | ||
34 | |||
35 | static __init void ath79_prom_init_cmdline(int argc, char **argv) | ||
36 | { | ||
37 | int i; | ||
38 | |||
39 | if (!is_valid_ram_addr(argv)) | ||
40 | return; | ||
41 | |||
42 | for (i = 0; i < argc; i++) | ||
43 | if (is_valid_ram_addr(argv[i])) { | ||
44 | strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline)); | ||
45 | strlcat(arcs_cmdline, argv[i], sizeof(arcs_cmdline)); | ||
46 | } | ||
47 | } | ||
48 | |||
49 | void __init prom_init(void) | ||
50 | { | ||
51 | ath79_prom_init_cmdline(fw_arg0, (char **)fw_arg1); | ||
52 | } | ||
53 | |||
54 | void __init prom_free_prom_memory(void) | ||
55 | { | ||
56 | /* We do not have to prom memory to free */ | ||
57 | } | ||
diff --git a/arch/mips/ath79/setup.c b/arch/mips/ath79/setup.c new file mode 100644 index 000000000000..175def860165 --- /dev/null +++ b/arch/mips/ath79/setup.c | |||
@@ -0,0 +1,190 @@ | |||
1 | /* | ||
2 | * Atheros AR71XX/AR724X/AR913X specific setup | ||
3 | * | ||
4 | * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> | ||
5 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | ||
6 | * | ||
7 | * Parts of this file are based on Atheros' 2.6.15 BSP | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License version 2 as published | ||
11 | * by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/bootmem.h> | ||
17 | #include <linux/err.h> | ||
18 | #include <linux/clk.h> | ||
19 | |||
20 | #include <asm/bootinfo.h> | ||
21 | #include <asm/time.h> /* for mips_hpt_frequency */ | ||
22 | #include <asm/reboot.h> /* for _machine_{restart,halt} */ | ||
23 | |||
24 | #include <asm/mach-ath79/ath79.h> | ||
25 | #include <asm/mach-ath79/ar71xx_regs.h> | ||
26 | #include "common.h" | ||
27 | #include "dev-common.h" | ||
28 | |||
29 | #define ATH79_SYS_TYPE_LEN 64 | ||
30 | |||
31 | #define AR71XX_BASE_FREQ 40000000 | ||
32 | #define AR724X_BASE_FREQ 5000000 | ||
33 | #define AR913X_BASE_FREQ 5000000 | ||
34 | |||
35 | static char ath79_sys_type[ATH79_SYS_TYPE_LEN]; | ||
36 | |||
37 | static void ath79_restart(char *command) | ||
38 | { | ||
39 | ath79_device_reset_set(AR71XX_RESET_FULL_CHIP); | ||
40 | for (;;) | ||
41 | if (cpu_wait) | ||
42 | cpu_wait(); | ||
43 | } | ||
44 | |||
45 | static void ath79_halt(void) | ||
46 | { | ||
47 | while (1) | ||
48 | cpu_wait(); | ||
49 | } | ||
50 | |||
51 | static void __init ath79_detect_mem_size(void) | ||
52 | { | ||
53 | unsigned long size; | ||
54 | |||
55 | for (size = ATH79_MEM_SIZE_MIN; size < ATH79_MEM_SIZE_MAX; | ||
56 | size <<= 1) { | ||
57 | if (!memcmp(ath79_detect_mem_size, | ||
58 | ath79_detect_mem_size + size, 1024)) | ||
59 | break; | ||
60 | } | ||
61 | |||
62 | add_memory_region(0, size, BOOT_MEM_RAM); | ||
63 | } | ||
64 | |||
65 | static void __init ath79_detect_sys_type(void) | ||
66 | { | ||
67 | char *chip = "????"; | ||
68 | u32 id; | ||
69 | u32 major; | ||
70 | u32 minor; | ||
71 | u32 rev = 0; | ||
72 | |||
73 | id = ath79_reset_rr(AR71XX_RESET_REG_REV_ID); | ||
74 | major = id & REV_ID_MAJOR_MASK; | ||
75 | |||
76 | switch (major) { | ||
77 | case REV_ID_MAJOR_AR71XX: | ||
78 | minor = id & AR71XX_REV_ID_MINOR_MASK; | ||
79 | rev = id >> AR71XX_REV_ID_REVISION_SHIFT; | ||
80 | rev &= AR71XX_REV_ID_REVISION_MASK; | ||
81 | switch (minor) { | ||
82 | case AR71XX_REV_ID_MINOR_AR7130: | ||
83 | ath79_soc = ATH79_SOC_AR7130; | ||
84 | chip = "7130"; | ||
85 | break; | ||
86 | |||
87 | case AR71XX_REV_ID_MINOR_AR7141: | ||
88 | ath79_soc = ATH79_SOC_AR7141; | ||
89 | chip = "7141"; | ||
90 | break; | ||
91 | |||
92 | case AR71XX_REV_ID_MINOR_AR7161: | ||
93 | ath79_soc = ATH79_SOC_AR7161; | ||
94 | chip = "7161"; | ||
95 | break; | ||
96 | } | ||
97 | break; | ||
98 | |||
99 | case REV_ID_MAJOR_AR7240: | ||
100 | ath79_soc = ATH79_SOC_AR7240; | ||
101 | chip = "7240"; | ||
102 | rev = (id & AR724X_REV_ID_REVISION_MASK); | ||
103 | break; | ||
104 | |||
105 | case REV_ID_MAJOR_AR7241: | ||
106 | ath79_soc = ATH79_SOC_AR7241; | ||
107 | chip = "7241"; | ||
108 | rev = (id & AR724X_REV_ID_REVISION_MASK); | ||
109 | break; | ||
110 | |||
111 | case REV_ID_MAJOR_AR7242: | ||
112 | ath79_soc = ATH79_SOC_AR7242; | ||
113 | chip = "7242"; | ||
114 | rev = (id & AR724X_REV_ID_REVISION_MASK); | ||
115 | break; | ||
116 | |||
117 | case REV_ID_MAJOR_AR913X: | ||
118 | minor = id & AR913X_REV_ID_MINOR_MASK; | ||
119 | rev = id >> AR913X_REV_ID_REVISION_SHIFT; | ||
120 | rev &= AR913X_REV_ID_REVISION_MASK; | ||
121 | switch (minor) { | ||
122 | case AR913X_REV_ID_MINOR_AR9130: | ||
123 | ath79_soc = ATH79_SOC_AR9130; | ||
124 | chip = "9130"; | ||
125 | break; | ||
126 | |||
127 | case AR913X_REV_ID_MINOR_AR9132: | ||
128 | ath79_soc = ATH79_SOC_AR9132; | ||
129 | chip = "9132"; | ||
130 | break; | ||
131 | } | ||
132 | break; | ||
133 | |||
134 | default: | ||
135 | panic("ath79: unknown SoC, id:0x%08x\n", id); | ||
136 | } | ||
137 | |||
138 | sprintf(ath79_sys_type, "Atheros AR%s rev %u", chip, rev); | ||
139 | pr_info("SoC: %s\n", ath79_sys_type); | ||
140 | } | ||
141 | |||
142 | const char *get_system_type(void) | ||
143 | { | ||
144 | return ath79_sys_type; | ||
145 | } | ||
146 | |||
147 | unsigned int __cpuinit get_c0_compare_int(void) | ||
148 | { | ||
149 | return CP0_LEGACY_COMPARE_IRQ; | ||
150 | } | ||
151 | |||
152 | void __init plat_mem_setup(void) | ||
153 | { | ||
154 | set_io_port_base(KSEG1); | ||
155 | |||
156 | ath79_reset_base = ioremap_nocache(AR71XX_RESET_BASE, | ||
157 | AR71XX_RESET_SIZE); | ||
158 | ath79_pll_base = ioremap_nocache(AR71XX_PLL_BASE, | ||
159 | AR71XX_PLL_SIZE); | ||
160 | |||
161 | ath79_ddr_base = ioremap_nocache(AR71XX_DDR_CTRL_BASE, | ||
162 | AR71XX_DDR_CTRL_SIZE); | ||
163 | |||
164 | ath79_detect_sys_type(); | ||
165 | ath79_detect_mem_size(); | ||
166 | ath79_clocks_init(); | ||
167 | |||
168 | _machine_restart = ath79_restart; | ||
169 | _machine_halt = ath79_halt; | ||
170 | pm_power_off = ath79_halt; | ||
171 | } | ||
172 | |||
173 | void __init plat_time_init(void) | ||
174 | { | ||
175 | struct clk *clk; | ||
176 | |||
177 | clk = clk_get(NULL, "cpu"); | ||
178 | if (IS_ERR(clk)) | ||
179 | panic("unable to get CPU clock, err=%ld", PTR_ERR(clk)); | ||
180 | |||
181 | mips_hpt_frequency = clk_get_rate(clk) / 2; | ||
182 | } | ||
183 | |||
184 | static int __init ath79_setup(void) | ||
185 | { | ||
186 | ath79_register_uart(); | ||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | arch_initcall(ath79_setup); | ||