diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-18 17:28:48 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-18 17:28:48 -0500 |
commit | 5d7e8af3c5727626b9e7f909c778b9ac9b4a1809 (patch) | |
tree | 13d51e31ee070113538a6d26d9a52503ba4a3cd0 | |
parent | aa891f6b3f440402c6879ad1ecf332d318137422 (diff) | |
parent | 79aa18d557bef02171da42ee928c23509e6ef4f7 (diff) |
Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/upstream-linus
* 'upstream' of git://git.linux-mips.org/pub/scm/upstream-linus: (26 commits)
MIPS: Malta: enable Cirrus FB console
MIPS: add CONFIG_VIRTUALIZATION for virtio support
MIPS: Implement __read_mostly
MIPS: ath79: add common WMAC device for AR913X based boards
MIPS: ath79: Add initial support for the Atheros AP81 reference board
MIPS: ath79: add common SPI controller device
SPI: Add SPI controller driver for the Atheros AR71XX/AR724X/AR913X SoCs
MIPS: ath79: add common GPIO buttons device
MIPS: ath79: add common watchdog device
MIPS: ath79: add common GPIO LEDs device
MIPS: ath79: add initial support for the Atheros PB44 reference board
MIPS: ath79: utilize the MIPS multi-machine support
MIPS: ath79: add GPIOLIB support
MIPS: Add initial support for the Atheros AR71XX/AR724X/AR931X SoCs
MIPS: jump label: Add MIPS support.
MIPS: Use WARN() in uasm for better diagnostics.
MIPS: Optimize TLB handlers for Octeon CPUs
MIPS: Add LDX and LWX instructions to uasm.
MIPS: Use BBIT instructions in TLB handlers
MIPS: Declare uasm bbit0 and bbit1 functions.
...
58 files changed, 3408 insertions, 129 deletions
diff --git a/arch/mips/Kbuild.platforms b/arch/mips/Kbuild.platforms index 78439b8a83c4..7ff9b5492041 100644 --- a/arch/mips/Kbuild.platforms +++ b/arch/mips/Kbuild.platforms | |||
@@ -2,6 +2,7 @@ | |||
2 | 2 | ||
3 | platforms += alchemy | 3 | platforms += alchemy |
4 | platforms += ar7 | 4 | platforms += ar7 |
5 | platforms += ath79 | ||
5 | platforms += bcm47xx | 6 | platforms += bcm47xx |
6 | platforms += bcm63xx | 7 | platforms += bcm63xx |
7 | platforms += cavium-octeon | 8 | platforms += cavium-octeon |
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index f489ec30e071..548e6cc3bc28 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig | |||
@@ -21,6 +21,7 @@ config MIPS | |||
21 | select HAVE_DMA_API_DEBUG | 21 | select HAVE_DMA_API_DEBUG |
22 | select HAVE_GENERIC_HARDIRQS | 22 | select HAVE_GENERIC_HARDIRQS |
23 | select GENERIC_IRQ_PROBE | 23 | select GENERIC_IRQ_PROBE |
24 | select HAVE_ARCH_JUMP_LABEL | ||
24 | 25 | ||
25 | menu "Machine selection" | 26 | menu "Machine selection" |
26 | 27 | ||
@@ -65,6 +66,22 @@ config AR7 | |||
65 | Support for the Texas Instruments AR7 System-on-a-Chip | 66 | Support for the Texas Instruments AR7 System-on-a-Chip |
66 | family: TNETD7100, 7200 and 7300. | 67 | family: TNETD7100, 7200 and 7300. |
67 | 68 | ||
69 | config ATH79 | ||
70 | bool "Atheros AR71XX/AR724X/AR913X based boards" | ||
71 | select ARCH_REQUIRE_GPIOLIB | ||
72 | select BOOT_RAW | ||
73 | select CEVT_R4K | ||
74 | select CSRC_R4K | ||
75 | select DMA_NONCOHERENT | ||
76 | select IRQ_CPU | ||
77 | select MIPS_MACHINE | ||
78 | select SYS_HAS_CPU_MIPS32_R2 | ||
79 | select SYS_HAS_EARLY_PRINTK | ||
80 | select SYS_SUPPORTS_32BIT_KERNEL | ||
81 | select SYS_SUPPORTS_BIG_ENDIAN | ||
82 | help | ||
83 | Support for the Atheros AR71XX/AR724X/AR913X SoCs. | ||
84 | |||
68 | config BCM47XX | 85 | config BCM47XX |
69 | bool "Broadcom BCM47XX based boards" | 86 | bool "Broadcom BCM47XX based boards" |
70 | select CEVT_R4K | 87 | select CEVT_R4K |
@@ -717,6 +734,7 @@ config CAVIUM_OCTEON_REFERENCE_BOARD | |||
717 | endchoice | 734 | endchoice |
718 | 735 | ||
719 | source "arch/mips/alchemy/Kconfig" | 736 | source "arch/mips/alchemy/Kconfig" |
737 | source "arch/mips/ath79/Kconfig" | ||
720 | source "arch/mips/bcm63xx/Kconfig" | 738 | source "arch/mips/bcm63xx/Kconfig" |
721 | source "arch/mips/jazz/Kconfig" | 739 | source "arch/mips/jazz/Kconfig" |
722 | source "arch/mips/jz4740/Kconfig" | 740 | source "arch/mips/jz4740/Kconfig" |
@@ -883,6 +901,9 @@ config MIPS_DISABLE_OBSOLETE_IDE | |||
883 | config SYNC_R4K | 901 | config SYNC_R4K |
884 | bool | 902 | bool |
885 | 903 | ||
904 | config MIPS_MACHINE | ||
905 | def_bool n | ||
906 | |||
886 | config NO_IOPORT | 907 | config NO_IOPORT |
887 | def_bool n | 908 | def_bool n |
888 | 909 | ||
@@ -2400,4 +2421,20 @@ source "security/Kconfig" | |||
2400 | 2421 | ||
2401 | source "crypto/Kconfig" | 2422 | source "crypto/Kconfig" |
2402 | 2423 | ||
2424 | menuconfig VIRTUALIZATION | ||
2425 | bool "Virtualization" | ||
2426 | default n | ||
2427 | ---help--- | ||
2428 | Say Y here to get to see options for using your Linux host to run other | ||
2429 | operating systems inside virtual machines (guests). | ||
2430 | This option alone does not add any kernel code. | ||
2431 | |||
2432 | If you say N, all options in this submenu will be skipped and disabled. | ||
2433 | |||
2434 | if VIRTUALIZATION | ||
2435 | |||
2436 | source drivers/virtio/Kconfig | ||
2437 | |||
2438 | endif # VIRTUALIZATION | ||
2439 | |||
2403 | source "lib/Kconfig" | 2440 | source "lib/Kconfig" |
diff --git a/arch/mips/ath79/Kconfig b/arch/mips/ath79/Kconfig new file mode 100644 index 000000000000..b05828260f7f --- /dev/null +++ b/arch/mips/ath79/Kconfig | |||
@@ -0,0 +1,50 @@ | |||
1 | if ATH79 | ||
2 | |||
3 | menu "Atheros AR71XX/AR724X/AR913X machine selection" | ||
4 | |||
5 | config ATH79_MACH_AP81 | ||
6 | bool "Atheros AP81 reference board" | ||
7 | select SOC_AR913X | ||
8 | select ATH79_DEV_AR913X_WMAC | ||
9 | select ATH79_DEV_GPIO_BUTTONS | ||
10 | select ATH79_DEV_LEDS_GPIO | ||
11 | select ATH79_DEV_SPI | ||
12 | help | ||
13 | Say 'Y' here if you want your kernel to support the | ||
14 | Atheros AP81 reference board. | ||
15 | |||
16 | config ATH79_MACH_PB44 | ||
17 | bool "Atheros PB44 reference board" | ||
18 | select SOC_AR71XX | ||
19 | select ATH79_DEV_GPIO_BUTTONS | ||
20 | select ATH79_DEV_LEDS_GPIO | ||
21 | select ATH79_DEV_SPI | ||
22 | help | ||
23 | Say 'Y' here if you want your kernel to support the | ||
24 | Atheros PB44 reference board. | ||
25 | |||
26 | endmenu | ||
27 | |||
28 | config SOC_AR71XX | ||
29 | def_bool n | ||
30 | |||
31 | config SOC_AR724X | ||
32 | def_bool n | ||
33 | |||
34 | config SOC_AR913X | ||
35 | def_bool n | ||
36 | |||
37 | config ATH79_DEV_AR913X_WMAC | ||
38 | depends on SOC_AR913X | ||
39 | def_bool n | ||
40 | |||
41 | config ATH79_DEV_GPIO_BUTTONS | ||
42 | def_bool n | ||
43 | |||
44 | config ATH79_DEV_LEDS_GPIO | ||
45 | def_bool n | ||
46 | |||
47 | config ATH79_DEV_SPI | ||
48 | def_bool n | ||
49 | |||
50 | endif | ||
diff --git a/arch/mips/ath79/Makefile b/arch/mips/ath79/Makefile new file mode 100644 index 000000000000..c33d4653007c --- /dev/null +++ b/arch/mips/ath79/Makefile | |||
@@ -0,0 +1,28 @@ | |||
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 gpio.o | ||
12 | |||
13 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o | ||
14 | |||
15 | # | ||
16 | # Devices | ||
17 | # | ||
18 | obj-y += dev-common.o | ||
19 | obj-$(CONFIG_ATH79_DEV_AR913X_WMAC) += dev-ar913x-wmac.o | ||
20 | obj-$(CONFIG_ATH79_DEV_GPIO_BUTTONS) += dev-gpio-buttons.o | ||
21 | obj-$(CONFIG_ATH79_DEV_LEDS_GPIO) += dev-leds-gpio.o | ||
22 | obj-$(CONFIG_ATH79_DEV_SPI) += dev-spi.o | ||
23 | |||
24 | # | ||
25 | # Machines | ||
26 | # | ||
27 | obj-$(CONFIG_ATH79_MACH_AP81) += mach-ap81.o | ||
28 | obj-$(CONFIG_ATH79_MACH_PB44) += mach-pb44.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..561906c2345e --- /dev/null +++ b/arch/mips/ath79/common.h | |||
@@ -0,0 +1,31 @@ | |||
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 | void ath79_gpio_function_enable(u32 mask); | ||
27 | void ath79_gpio_function_disable(u32 mask); | ||
28 | void ath79_gpio_function_setup(u32 set, u32 clear); | ||
29 | void ath79_gpio_init(void); | ||
30 | |||
31 | #endif /* __ATH79_COMMON_H */ | ||
diff --git a/arch/mips/ath79/dev-ar913x-wmac.c b/arch/mips/ath79/dev-ar913x-wmac.c new file mode 100644 index 000000000000..48f425a5ba28 --- /dev/null +++ b/arch/mips/ath79/dev-ar913x-wmac.c | |||
@@ -0,0 +1,60 @@ | |||
1 | /* | ||
2 | * Atheros AR913X SoC built-in WMAC device 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/init.h> | ||
13 | #include <linux/delay.h> | ||
14 | #include <linux/irq.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/ath9k_platform.h> | ||
17 | |||
18 | #include <asm/mach-ath79/ath79.h> | ||
19 | #include <asm/mach-ath79/ar71xx_regs.h> | ||
20 | #include "dev-ar913x-wmac.h" | ||
21 | |||
22 | static struct ath9k_platform_data ar913x_wmac_data; | ||
23 | |||
24 | static struct resource ar913x_wmac_resources[] = { | ||
25 | { | ||
26 | .start = AR913X_WMAC_BASE, | ||
27 | .end = AR913X_WMAC_BASE + AR913X_WMAC_SIZE - 1, | ||
28 | .flags = IORESOURCE_MEM, | ||
29 | }, { | ||
30 | .start = ATH79_CPU_IRQ_IP2, | ||
31 | .end = ATH79_CPU_IRQ_IP2, | ||
32 | .flags = IORESOURCE_IRQ, | ||
33 | }, | ||
34 | }; | ||
35 | |||
36 | static struct platform_device ar913x_wmac_device = { | ||
37 | .name = "ath9k", | ||
38 | .id = -1, | ||
39 | .resource = ar913x_wmac_resources, | ||
40 | .num_resources = ARRAY_SIZE(ar913x_wmac_resources), | ||
41 | .dev = { | ||
42 | .platform_data = &ar913x_wmac_data, | ||
43 | }, | ||
44 | }; | ||
45 | |||
46 | void __init ath79_register_ar913x_wmac(u8 *cal_data) | ||
47 | { | ||
48 | if (cal_data) | ||
49 | memcpy(ar913x_wmac_data.eeprom_data, cal_data, | ||
50 | sizeof(ar913x_wmac_data.eeprom_data)); | ||
51 | |||
52 | /* reset the WMAC */ | ||
53 | ath79_device_reset_set(AR913X_RESET_AMBA2WMAC); | ||
54 | mdelay(10); | ||
55 | |||
56 | ath79_device_reset_clear(AR913X_RESET_AMBA2WMAC); | ||
57 | mdelay(10); | ||
58 | |||
59 | platform_device_register(&ar913x_wmac_device); | ||
60 | } | ||
diff --git a/arch/mips/ath79/dev-ar913x-wmac.h b/arch/mips/ath79/dev-ar913x-wmac.h new file mode 100644 index 000000000000..579d562bbda8 --- /dev/null +++ b/arch/mips/ath79/dev-ar913x-wmac.h | |||
@@ -0,0 +1,17 @@ | |||
1 | /* | ||
2 | * Atheros AR913X SoC built-in WMAC device 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 | #ifndef _ATH79_DEV_AR913X_WMAC_H | ||
13 | #define _ATH79_DEV_AR913X_WMAC_H | ||
14 | |||
15 | void ath79_register_ar913x_wmac(u8 *cal_data); | ||
16 | |||
17 | #endif /* _ATH79_DEV_AR913X_WMAC_H */ | ||
diff --git a/arch/mips/ath79/dev-common.c b/arch/mips/ath79/dev-common.c new file mode 100644 index 000000000000..3b82e325bebf --- /dev/null +++ b/arch/mips/ath79/dev-common.c | |||
@@ -0,0 +1,77 @@ | |||
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 | } | ||
68 | |||
69 | static struct platform_device ath79_wdt_device = { | ||
70 | .name = "ath79-wdt", | ||
71 | .id = -1, | ||
72 | }; | ||
73 | |||
74 | void __init ath79_register_wdt(void) | ||
75 | { | ||
76 | platform_device_register(&ath79_wdt_device); | ||
77 | } | ||
diff --git a/arch/mips/ath79/dev-common.h b/arch/mips/ath79/dev-common.h new file mode 100644 index 000000000000..0f514e1affce --- /dev/null +++ b/arch/mips/ath79/dev-common.h | |||
@@ -0,0 +1,18 @@ | |||
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 | void ath79_register_wdt(void); | ||
17 | |||
18 | #endif /* _ATH79_DEV_COMMON_H */ | ||
diff --git a/arch/mips/ath79/dev-gpio-buttons.c b/arch/mips/ath79/dev-gpio-buttons.c new file mode 100644 index 000000000000..4b0168a11c01 --- /dev/null +++ b/arch/mips/ath79/dev-gpio-buttons.c | |||
@@ -0,0 +1,58 @@ | |||
1 | /* | ||
2 | * Atheros AR71XX/AR724X/AR913X GPIO button 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/init.h" | ||
13 | #include "linux/slab.h" | ||
14 | #include <linux/platform_device.h> | ||
15 | |||
16 | #include "dev-gpio-buttons.h" | ||
17 | |||
18 | void __init ath79_register_gpio_keys_polled(int id, | ||
19 | unsigned poll_interval, | ||
20 | unsigned nbuttons, | ||
21 | struct gpio_keys_button *buttons) | ||
22 | { | ||
23 | struct platform_device *pdev; | ||
24 | struct gpio_keys_platform_data pdata; | ||
25 | struct gpio_keys_button *p; | ||
26 | int err; | ||
27 | |||
28 | p = kmalloc(nbuttons * sizeof(*p), GFP_KERNEL); | ||
29 | if (!p) | ||
30 | return; | ||
31 | |||
32 | memcpy(p, buttons, nbuttons * sizeof(*p)); | ||
33 | |||
34 | pdev = platform_device_alloc("gpio-keys-polled", id); | ||
35 | if (!pdev) | ||
36 | goto err_free_buttons; | ||
37 | |||
38 | memset(&pdata, 0, sizeof(pdata)); | ||
39 | pdata.poll_interval = poll_interval; | ||
40 | pdata.nbuttons = nbuttons; | ||
41 | pdata.buttons = p; | ||
42 | |||
43 | err = platform_device_add_data(pdev, &pdata, sizeof(pdata)); | ||
44 | if (err) | ||
45 | goto err_put_pdev; | ||
46 | |||
47 | err = platform_device_add(pdev); | ||
48 | if (err) | ||
49 | goto err_put_pdev; | ||
50 | |||
51 | return; | ||
52 | |||
53 | err_put_pdev: | ||
54 | platform_device_put(pdev); | ||
55 | |||
56 | err_free_buttons: | ||
57 | kfree(p); | ||
58 | } | ||
diff --git a/arch/mips/ath79/dev-gpio-buttons.h b/arch/mips/ath79/dev-gpio-buttons.h new file mode 100644 index 000000000000..481847ac1cba --- /dev/null +++ b/arch/mips/ath79/dev-gpio-buttons.h | |||
@@ -0,0 +1,23 @@ | |||
1 | /* | ||
2 | * Atheros AR71XX/AR724X/AR913X GPIO button 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 | #ifndef _ATH79_DEV_GPIO_BUTTONS_H | ||
13 | #define _ATH79_DEV_GPIO_BUTTONS_H | ||
14 | |||
15 | #include <linux/input.h> | ||
16 | #include <linux/gpio_keys.h> | ||
17 | |||
18 | void ath79_register_gpio_keys_polled(int id, | ||
19 | unsigned poll_interval, | ||
20 | unsigned nbuttons, | ||
21 | struct gpio_keys_button *buttons); | ||
22 | |||
23 | #endif /* _ATH79_DEV_GPIO_BUTTONS_H */ | ||
diff --git a/arch/mips/ath79/dev-leds-gpio.c b/arch/mips/ath79/dev-leds-gpio.c new file mode 100644 index 000000000000..cdade68dcd17 --- /dev/null +++ b/arch/mips/ath79/dev-leds-gpio.c | |||
@@ -0,0 +1,56 @@ | |||
1 | /* | ||
2 | * Atheros AR71XX/AR724X/AR913X common GPIO LEDs 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/init.h> | ||
13 | #include <linux/slab.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | |||
16 | #include "dev-leds-gpio.h" | ||
17 | |||
18 | void __init ath79_register_leds_gpio(int id, | ||
19 | unsigned num_leds, | ||
20 | struct gpio_led *leds) | ||
21 | { | ||
22 | struct platform_device *pdev; | ||
23 | struct gpio_led_platform_data pdata; | ||
24 | struct gpio_led *p; | ||
25 | int err; | ||
26 | |||
27 | p = kmalloc(num_leds * sizeof(*p), GFP_KERNEL); | ||
28 | if (!p) | ||
29 | return; | ||
30 | |||
31 | memcpy(p, leds, num_leds * sizeof(*p)); | ||
32 | |||
33 | pdev = platform_device_alloc("leds-gpio", id); | ||
34 | if (!pdev) | ||
35 | goto err_free_leds; | ||
36 | |||
37 | memset(&pdata, 0, sizeof(pdata)); | ||
38 | pdata.num_leds = num_leds; | ||
39 | pdata.leds = p; | ||
40 | |||
41 | err = platform_device_add_data(pdev, &pdata, sizeof(pdata)); | ||
42 | if (err) | ||
43 | goto err_put_pdev; | ||
44 | |||
45 | err = platform_device_add(pdev); | ||
46 | if (err) | ||
47 | goto err_put_pdev; | ||
48 | |||
49 | return; | ||
50 | |||
51 | err_put_pdev: | ||
52 | platform_device_put(pdev); | ||
53 | |||
54 | err_free_leds: | ||
55 | kfree(p); | ||
56 | } | ||
diff --git a/arch/mips/ath79/dev-leds-gpio.h b/arch/mips/ath79/dev-leds-gpio.h new file mode 100644 index 000000000000..6e5d8851ebcf --- /dev/null +++ b/arch/mips/ath79/dev-leds-gpio.h | |||
@@ -0,0 +1,21 @@ | |||
1 | /* | ||
2 | * Atheros AR71XX/AR724X/AR913X common GPIO LEDs 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 | #ifndef _ATH79_DEV_LEDS_GPIO_H | ||
13 | #define _ATH79_DEV_LEDS_GPIO_H | ||
14 | |||
15 | #include <linux/leds.h> | ||
16 | |||
17 | void ath79_register_leds_gpio(int id, | ||
18 | unsigned num_leds, | ||
19 | struct gpio_led *leds); | ||
20 | |||
21 | #endif /* _ATH79_DEV_LEDS_GPIO_H */ | ||
diff --git a/arch/mips/ath79/dev-spi.c b/arch/mips/ath79/dev-spi.c new file mode 100644 index 000000000000..aa30163efbfd --- /dev/null +++ b/arch/mips/ath79/dev-spi.c | |||
@@ -0,0 +1,38 @@ | |||
1 | /* | ||
2 | * Atheros AR71XX/AR724X/AR913X SPI controller device | ||
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/platform_device.h> | ||
13 | #include <asm/mach-ath79/ar71xx_regs.h> | ||
14 | #include "dev-spi.h" | ||
15 | |||
16 | static struct resource ath79_spi_resources[] = { | ||
17 | { | ||
18 | .start = AR71XX_SPI_BASE, | ||
19 | .end = AR71XX_SPI_BASE + AR71XX_SPI_SIZE - 1, | ||
20 | .flags = IORESOURCE_MEM, | ||
21 | }, | ||
22 | }; | ||
23 | |||
24 | static struct platform_device ath79_spi_device = { | ||
25 | .name = "ath79-spi", | ||
26 | .id = -1, | ||
27 | .resource = ath79_spi_resources, | ||
28 | .num_resources = ARRAY_SIZE(ath79_spi_resources), | ||
29 | }; | ||
30 | |||
31 | void __init ath79_register_spi(struct ath79_spi_platform_data *pdata, | ||
32 | struct spi_board_info const *info, | ||
33 | unsigned n) | ||
34 | { | ||
35 | spi_register_board_info(info, n); | ||
36 | ath79_spi_device.dev.platform_data = pdata; | ||
37 | platform_device_register(&ath79_spi_device); | ||
38 | } | ||
diff --git a/arch/mips/ath79/dev-spi.h b/arch/mips/ath79/dev-spi.h new file mode 100644 index 000000000000..d732565ca736 --- /dev/null +++ b/arch/mips/ath79/dev-spi.h | |||
@@ -0,0 +1,22 @@ | |||
1 | /* | ||
2 | * Atheros AR71XX/AR724X/AR913X SPI controller device | ||
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_SPI_H | ||
13 | #define _ATH79_DEV_SPI_H | ||
14 | |||
15 | #include <linux/spi/spi.h> | ||
16 | #include <asm/mach-ath79/ath79_spi_platform.h> | ||
17 | |||
18 | void ath79_register_spi(struct ath79_spi_platform_data *pdata, | ||
19 | struct spi_board_info const *info, | ||
20 | unsigned n); | ||
21 | |||
22 | #endif /* _ATH79_DEV_SPI_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/gpio.c b/arch/mips/ath79/gpio.c new file mode 100644 index 000000000000..a0c426b82123 --- /dev/null +++ b/arch/mips/ath79/gpio.c | |||
@@ -0,0 +1,197 @@ | |||
1 | /* | ||
2 | * Atheros AR71XX/AR724X/AR913X GPIO API 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/kernel.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/types.h> | ||
16 | #include <linux/spinlock.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/ioport.h> | ||
19 | #include <linux/gpio.h> | ||
20 | |||
21 | #include <asm/mach-ath79/ar71xx_regs.h> | ||
22 | #include <asm/mach-ath79/ath79.h> | ||
23 | #include "common.h" | ||
24 | |||
25 | static void __iomem *ath79_gpio_base; | ||
26 | static unsigned long ath79_gpio_count; | ||
27 | static DEFINE_SPINLOCK(ath79_gpio_lock); | ||
28 | |||
29 | static void __ath79_gpio_set_value(unsigned gpio, int value) | ||
30 | { | ||
31 | void __iomem *base = ath79_gpio_base; | ||
32 | |||
33 | if (value) | ||
34 | __raw_writel(1 << gpio, base + AR71XX_GPIO_REG_SET); | ||
35 | else | ||
36 | __raw_writel(1 << gpio, base + AR71XX_GPIO_REG_CLEAR); | ||
37 | } | ||
38 | |||
39 | static int __ath79_gpio_get_value(unsigned gpio) | ||
40 | { | ||
41 | return (__raw_readl(ath79_gpio_base + AR71XX_GPIO_REG_IN) >> gpio) & 1; | ||
42 | } | ||
43 | |||
44 | static int ath79_gpio_get_value(struct gpio_chip *chip, unsigned offset) | ||
45 | { | ||
46 | return __ath79_gpio_get_value(offset); | ||
47 | } | ||
48 | |||
49 | static void ath79_gpio_set_value(struct gpio_chip *chip, | ||
50 | unsigned offset, int value) | ||
51 | { | ||
52 | __ath79_gpio_set_value(offset, value); | ||
53 | } | ||
54 | |||
55 | static int ath79_gpio_direction_input(struct gpio_chip *chip, | ||
56 | unsigned offset) | ||
57 | { | ||
58 | void __iomem *base = ath79_gpio_base; | ||
59 | unsigned long flags; | ||
60 | |||
61 | spin_lock_irqsave(&ath79_gpio_lock, flags); | ||
62 | |||
63 | __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) & ~(1 << offset), | ||
64 | base + AR71XX_GPIO_REG_OE); | ||
65 | |||
66 | spin_unlock_irqrestore(&ath79_gpio_lock, flags); | ||
67 | |||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | static int ath79_gpio_direction_output(struct gpio_chip *chip, | ||
72 | unsigned offset, int value) | ||
73 | { | ||
74 | void __iomem *base = ath79_gpio_base; | ||
75 | unsigned long flags; | ||
76 | |||
77 | spin_lock_irqsave(&ath79_gpio_lock, flags); | ||
78 | |||
79 | if (value) | ||
80 | __raw_writel(1 << offset, base + AR71XX_GPIO_REG_SET); | ||
81 | else | ||
82 | __raw_writel(1 << offset, base + AR71XX_GPIO_REG_CLEAR); | ||
83 | |||
84 | __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) | (1 << offset), | ||
85 | base + AR71XX_GPIO_REG_OE); | ||
86 | |||
87 | spin_unlock_irqrestore(&ath79_gpio_lock, flags); | ||
88 | |||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | static struct gpio_chip ath79_gpio_chip = { | ||
93 | .label = "ath79", | ||
94 | .get = ath79_gpio_get_value, | ||
95 | .set = ath79_gpio_set_value, | ||
96 | .direction_input = ath79_gpio_direction_input, | ||
97 | .direction_output = ath79_gpio_direction_output, | ||
98 | .base = 0, | ||
99 | }; | ||
100 | |||
101 | void ath79_gpio_function_enable(u32 mask) | ||
102 | { | ||
103 | void __iomem *base = ath79_gpio_base; | ||
104 | unsigned long flags; | ||
105 | |||
106 | spin_lock_irqsave(&ath79_gpio_lock, flags); | ||
107 | |||
108 | __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_FUNC) | mask, | ||
109 | base + AR71XX_GPIO_REG_FUNC); | ||
110 | /* flush write */ | ||
111 | __raw_readl(base + AR71XX_GPIO_REG_FUNC); | ||
112 | |||
113 | spin_unlock_irqrestore(&ath79_gpio_lock, flags); | ||
114 | } | ||
115 | |||
116 | void ath79_gpio_function_disable(u32 mask) | ||
117 | { | ||
118 | void __iomem *base = ath79_gpio_base; | ||
119 | unsigned long flags; | ||
120 | |||
121 | spin_lock_irqsave(&ath79_gpio_lock, flags); | ||
122 | |||
123 | __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_FUNC) & ~mask, | ||
124 | base + AR71XX_GPIO_REG_FUNC); | ||
125 | /* flush write */ | ||
126 | __raw_readl(base + AR71XX_GPIO_REG_FUNC); | ||
127 | |||
128 | spin_unlock_irqrestore(&ath79_gpio_lock, flags); | ||
129 | } | ||
130 | |||
131 | void ath79_gpio_function_setup(u32 set, u32 clear) | ||
132 | { | ||
133 | void __iomem *base = ath79_gpio_base; | ||
134 | unsigned long flags; | ||
135 | |||
136 | spin_lock_irqsave(&ath79_gpio_lock, flags); | ||
137 | |||
138 | __raw_writel((__raw_readl(base + AR71XX_GPIO_REG_FUNC) & ~clear) | set, | ||
139 | base + AR71XX_GPIO_REG_FUNC); | ||
140 | /* flush write */ | ||
141 | __raw_readl(base + AR71XX_GPIO_REG_FUNC); | ||
142 | |||
143 | spin_unlock_irqrestore(&ath79_gpio_lock, flags); | ||
144 | } | ||
145 | |||
146 | void __init ath79_gpio_init(void) | ||
147 | { | ||
148 | int err; | ||
149 | |||
150 | if (soc_is_ar71xx()) | ||
151 | ath79_gpio_count = AR71XX_GPIO_COUNT; | ||
152 | else if (soc_is_ar724x()) | ||
153 | ath79_gpio_count = AR724X_GPIO_COUNT; | ||
154 | else if (soc_is_ar913x()) | ||
155 | ath79_gpio_count = AR913X_GPIO_COUNT; | ||
156 | else | ||
157 | BUG(); | ||
158 | |||
159 | ath79_gpio_base = ioremap_nocache(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE); | ||
160 | ath79_gpio_chip.ngpio = ath79_gpio_count; | ||
161 | |||
162 | err = gpiochip_add(&ath79_gpio_chip); | ||
163 | if (err) | ||
164 | panic("cannot add AR71xx GPIO chip, error=%d", err); | ||
165 | } | ||
166 | |||
167 | int gpio_get_value(unsigned gpio) | ||
168 | { | ||
169 | if (gpio < ath79_gpio_count) | ||
170 | return __ath79_gpio_get_value(gpio); | ||
171 | |||
172 | return __gpio_get_value(gpio); | ||
173 | } | ||
174 | EXPORT_SYMBOL(gpio_get_value); | ||
175 | |||
176 | void gpio_set_value(unsigned gpio, int value) | ||
177 | { | ||
178 | if (gpio < ath79_gpio_count) | ||
179 | __ath79_gpio_set_value(gpio, value); | ||
180 | else | ||
181 | __gpio_set_value(gpio, value); | ||
182 | } | ||
183 | EXPORT_SYMBOL(gpio_set_value); | ||
184 | |||
185 | int gpio_to_irq(unsigned gpio) | ||
186 | { | ||
187 | /* FIXME */ | ||
188 | return -EINVAL; | ||
189 | } | ||
190 | EXPORT_SYMBOL(gpio_to_irq); | ||
191 | |||
192 | int irq_to_gpio(unsigned irq) | ||
193 | { | ||
194 | /* FIXME */ | ||
195 | return -EINVAL; | ||
196 | } | ||
197 | EXPORT_SYMBOL(irq_to_gpio); | ||
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/mach-ap81.c b/arch/mips/ath79/mach-ap81.c new file mode 100644 index 000000000000..eee4c121deb4 --- /dev/null +++ b/arch/mips/ath79/mach-ap81.c | |||
@@ -0,0 +1,98 @@ | |||
1 | /* | ||
2 | * Atheros AP81 board support | ||
3 | * | ||
4 | * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org> | ||
5 | * Copyright (C) 2009 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 "machtypes.h" | ||
13 | #include "dev-ar913x-wmac.h" | ||
14 | #include "dev-gpio-buttons.h" | ||
15 | #include "dev-leds-gpio.h" | ||
16 | #include "dev-spi.h" | ||
17 | |||
18 | #define AP81_GPIO_LED_STATUS 1 | ||
19 | #define AP81_GPIO_LED_AOSS 3 | ||
20 | #define AP81_GPIO_LED_WLAN 6 | ||
21 | #define AP81_GPIO_LED_POWER 14 | ||
22 | |||
23 | #define AP81_GPIO_BTN_SW4 12 | ||
24 | #define AP81_GPIO_BTN_SW1 21 | ||
25 | |||
26 | #define AP81_KEYS_POLL_INTERVAL 20 /* msecs */ | ||
27 | #define AP81_KEYS_DEBOUNCE_INTERVAL (3 * AP81_KEYS_POLL_INTERVAL) | ||
28 | |||
29 | #define AP81_CAL_DATA_ADDR 0x1fff1000 | ||
30 | |||
31 | static struct gpio_led ap81_leds_gpio[] __initdata = { | ||
32 | { | ||
33 | .name = "ap81:green:status", | ||
34 | .gpio = AP81_GPIO_LED_STATUS, | ||
35 | .active_low = 1, | ||
36 | }, { | ||
37 | .name = "ap81:amber:aoss", | ||
38 | .gpio = AP81_GPIO_LED_AOSS, | ||
39 | .active_low = 1, | ||
40 | }, { | ||
41 | .name = "ap81:green:wlan", | ||
42 | .gpio = AP81_GPIO_LED_WLAN, | ||
43 | .active_low = 1, | ||
44 | }, { | ||
45 | .name = "ap81:green:power", | ||
46 | .gpio = AP81_GPIO_LED_POWER, | ||
47 | .active_low = 1, | ||
48 | } | ||
49 | }; | ||
50 | |||
51 | static struct gpio_keys_button ap81_gpio_keys[] __initdata = { | ||
52 | { | ||
53 | .desc = "sw1", | ||
54 | .type = EV_KEY, | ||
55 | .code = BTN_0, | ||
56 | .debounce_interval = AP81_KEYS_DEBOUNCE_INTERVAL, | ||
57 | .gpio = AP81_GPIO_BTN_SW1, | ||
58 | .active_low = 1, | ||
59 | } , { | ||
60 | .desc = "sw4", | ||
61 | .type = EV_KEY, | ||
62 | .code = BTN_1, | ||
63 | .debounce_interval = AP81_KEYS_DEBOUNCE_INTERVAL, | ||
64 | .gpio = AP81_GPIO_BTN_SW4, | ||
65 | .active_low = 1, | ||
66 | } | ||
67 | }; | ||
68 | |||
69 | static struct spi_board_info ap81_spi_info[] = { | ||
70 | { | ||
71 | .bus_num = 0, | ||
72 | .chip_select = 0, | ||
73 | .max_speed_hz = 25000000, | ||
74 | .modalias = "m25p64", | ||
75 | } | ||
76 | }; | ||
77 | |||
78 | static struct ath79_spi_platform_data ap81_spi_data = { | ||
79 | .bus_num = 0, | ||
80 | .num_chipselect = 1, | ||
81 | }; | ||
82 | |||
83 | static void __init ap81_setup(void) | ||
84 | { | ||
85 | u8 *cal_data = (u8 *) KSEG1ADDR(AP81_CAL_DATA_ADDR); | ||
86 | |||
87 | ath79_register_leds_gpio(-1, ARRAY_SIZE(ap81_leds_gpio), | ||
88 | ap81_leds_gpio); | ||
89 | ath79_register_gpio_keys_polled(-1, AP81_KEYS_POLL_INTERVAL, | ||
90 | ARRAY_SIZE(ap81_gpio_keys), | ||
91 | ap81_gpio_keys); | ||
92 | ath79_register_spi(&ap81_spi_data, ap81_spi_info, | ||
93 | ARRAY_SIZE(ap81_spi_info)); | ||
94 | ath79_register_ar913x_wmac(cal_data); | ||
95 | } | ||
96 | |||
97 | MIPS_MACHINE(ATH79_MACH_AP81, "AP81", "Atheros AP81 reference board", | ||
98 | ap81_setup); | ||
diff --git a/arch/mips/ath79/mach-pb44.c b/arch/mips/ath79/mach-pb44.c new file mode 100644 index 000000000000..ec7b7a135d53 --- /dev/null +++ b/arch/mips/ath79/mach-pb44.c | |||
@@ -0,0 +1,118 @@ | |||
1 | /* | ||
2 | * Atheros PB44 reference board support | ||
3 | * | ||
4 | * Copyright (C) 2009-2010 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/init.h> | ||
12 | #include <linux/platform_device.h> | ||
13 | #include <linux/i2c.h> | ||
14 | #include <linux/i2c-gpio.h> | ||
15 | #include <linux/i2c/pcf857x.h> | ||
16 | |||
17 | #include "machtypes.h" | ||
18 | #include "dev-gpio-buttons.h" | ||
19 | #include "dev-leds-gpio.h" | ||
20 | #include "dev-spi.h" | ||
21 | |||
22 | #define PB44_GPIO_I2C_SCL 0 | ||
23 | #define PB44_GPIO_I2C_SDA 1 | ||
24 | |||
25 | #define PB44_GPIO_EXP_BASE 16 | ||
26 | #define PB44_GPIO_SW_RESET (PB44_GPIO_EXP_BASE + 6) | ||
27 | #define PB44_GPIO_SW_JUMP (PB44_GPIO_EXP_BASE + 8) | ||
28 | #define PB44_GPIO_LED_JUMP1 (PB44_GPIO_EXP_BASE + 9) | ||
29 | #define PB44_GPIO_LED_JUMP2 (PB44_GPIO_EXP_BASE + 10) | ||
30 | |||
31 | #define PB44_KEYS_POLL_INTERVAL 20 /* msecs */ | ||
32 | #define PB44_KEYS_DEBOUNCE_INTERVAL (3 * PB44_KEYS_POLL_INTERVAL) | ||
33 | |||
34 | static struct i2c_gpio_platform_data pb44_i2c_gpio_data = { | ||
35 | .sda_pin = PB44_GPIO_I2C_SDA, | ||
36 | .scl_pin = PB44_GPIO_I2C_SCL, | ||
37 | }; | ||
38 | |||
39 | static struct platform_device pb44_i2c_gpio_device = { | ||
40 | .name = "i2c-gpio", | ||
41 | .id = 0, | ||
42 | .dev = { | ||
43 | .platform_data = &pb44_i2c_gpio_data, | ||
44 | } | ||
45 | }; | ||
46 | |||
47 | static struct pcf857x_platform_data pb44_pcf857x_data = { | ||
48 | .gpio_base = PB44_GPIO_EXP_BASE, | ||
49 | }; | ||
50 | |||
51 | static struct i2c_board_info pb44_i2c_board_info[] __initdata = { | ||
52 | { | ||
53 | I2C_BOARD_INFO("pcf8575", 0x20), | ||
54 | .platform_data = &pb44_pcf857x_data, | ||
55 | }, | ||
56 | }; | ||
57 | |||
58 | static struct gpio_led pb44_leds_gpio[] __initdata = { | ||
59 | { | ||
60 | .name = "pb44:amber:jump1", | ||
61 | .gpio = PB44_GPIO_LED_JUMP1, | ||
62 | .active_low = 1, | ||
63 | }, { | ||
64 | .name = "pb44:green:jump2", | ||
65 | .gpio = PB44_GPIO_LED_JUMP2, | ||
66 | .active_low = 1, | ||
67 | }, | ||
68 | }; | ||
69 | |||
70 | static struct gpio_keys_button pb44_gpio_keys[] __initdata = { | ||
71 | { | ||
72 | .desc = "soft_reset", | ||
73 | .type = EV_KEY, | ||
74 | .code = KEY_RESTART, | ||
75 | .debounce_interval = PB44_KEYS_DEBOUNCE_INTERVAL, | ||
76 | .gpio = PB44_GPIO_SW_RESET, | ||
77 | .active_low = 1, | ||
78 | } , { | ||
79 | .desc = "jumpstart", | ||
80 | .type = EV_KEY, | ||
81 | .code = KEY_WPS_BUTTON, | ||
82 | .debounce_interval = PB44_KEYS_DEBOUNCE_INTERVAL, | ||
83 | .gpio = PB44_GPIO_SW_JUMP, | ||
84 | .active_low = 1, | ||
85 | } | ||
86 | }; | ||
87 | |||
88 | static struct spi_board_info pb44_spi_info[] = { | ||
89 | { | ||
90 | .bus_num = 0, | ||
91 | .chip_select = 0, | ||
92 | .max_speed_hz = 25000000, | ||
93 | .modalias = "m25p64", | ||
94 | }, | ||
95 | }; | ||
96 | |||
97 | static struct ath79_spi_platform_data pb44_spi_data = { | ||
98 | .bus_num = 0, | ||
99 | .num_chipselect = 1, | ||
100 | }; | ||
101 | |||
102 | static void __init pb44_init(void) | ||
103 | { | ||
104 | i2c_register_board_info(0, pb44_i2c_board_info, | ||
105 | ARRAY_SIZE(pb44_i2c_board_info)); | ||
106 | platform_device_register(&pb44_i2c_gpio_device); | ||
107 | |||
108 | ath79_register_leds_gpio(-1, ARRAY_SIZE(pb44_leds_gpio), | ||
109 | pb44_leds_gpio); | ||
110 | ath79_register_gpio_keys_polled(-1, PB44_KEYS_POLL_INTERVAL, | ||
111 | ARRAY_SIZE(pb44_gpio_keys), | ||
112 | pb44_gpio_keys); | ||
113 | ath79_register_spi(&pb44_spi_data, pb44_spi_info, | ||
114 | ARRAY_SIZE(pb44_spi_info)); | ||
115 | } | ||
116 | |||
117 | MIPS_MACHINE(ATH79_MACH_PB44, "PB44", "Atheros PB44 reference board", | ||
118 | pb44_init); | ||
diff --git a/arch/mips/ath79/machtypes.h b/arch/mips/ath79/machtypes.h new file mode 100644 index 000000000000..3940fe470b2d --- /dev/null +++ b/arch/mips/ath79/machtypes.h | |||
@@ -0,0 +1,23 @@ | |||
1 | /* | ||
2 | * Atheros AR71XX/AR724X/AR913X machine type definitions | ||
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_MACHTYPE_H | ||
13 | #define _ATH79_MACHTYPE_H | ||
14 | |||
15 | #include <asm/mips_machine.h> | ||
16 | |||
17 | enum ath79_mach_type { | ||
18 | ATH79_MACH_GENERIC = 0, | ||
19 | ATH79_MACH_AP81, /* Atheros AP81 reference board */ | ||
20 | ATH79_MACH_PB44, /* Atheros PB44 reference board */ | ||
21 | }; | ||
22 | |||
23 | #endif /* _ATH79_MACHTYPE_H */ | ||
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..159b42f106b0 --- /dev/null +++ b/arch/mips/ath79/setup.c | |||
@@ -0,0 +1,206 @@ | |||
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 | #include <asm/mips_machine.h> | ||
24 | |||
25 | #include <asm/mach-ath79/ath79.h> | ||
26 | #include <asm/mach-ath79/ar71xx_regs.h> | ||
27 | #include "common.h" | ||
28 | #include "dev-common.h" | ||
29 | #include "machtypes.h" | ||
30 | |||
31 | #define ATH79_SYS_TYPE_LEN 64 | ||
32 | |||
33 | #define AR71XX_BASE_FREQ 40000000 | ||
34 | #define AR724X_BASE_FREQ 5000000 | ||
35 | #define AR913X_BASE_FREQ 5000000 | ||
36 | |||
37 | static char ath79_sys_type[ATH79_SYS_TYPE_LEN]; | ||
38 | |||
39 | static void ath79_restart(char *command) | ||
40 | { | ||
41 | ath79_device_reset_set(AR71XX_RESET_FULL_CHIP); | ||
42 | for (;;) | ||
43 | if (cpu_wait) | ||
44 | cpu_wait(); | ||
45 | } | ||
46 | |||
47 | static void ath79_halt(void) | ||
48 | { | ||
49 | while (1) | ||
50 | cpu_wait(); | ||
51 | } | ||
52 | |||
53 | static void __init ath79_detect_mem_size(void) | ||
54 | { | ||
55 | unsigned long size; | ||
56 | |||
57 | for (size = ATH79_MEM_SIZE_MIN; size < ATH79_MEM_SIZE_MAX; | ||
58 | size <<= 1) { | ||
59 | if (!memcmp(ath79_detect_mem_size, | ||
60 | ath79_detect_mem_size + size, 1024)) | ||
61 | break; | ||
62 | } | ||
63 | |||
64 | add_memory_region(0, size, BOOT_MEM_RAM); | ||
65 | } | ||
66 | |||
67 | static void __init ath79_detect_sys_type(void) | ||
68 | { | ||
69 | char *chip = "????"; | ||
70 | u32 id; | ||
71 | u32 major; | ||
72 | u32 minor; | ||
73 | u32 rev = 0; | ||
74 | |||
75 | id = ath79_reset_rr(AR71XX_RESET_REG_REV_ID); | ||
76 | major = id & REV_ID_MAJOR_MASK; | ||
77 | |||
78 | switch (major) { | ||
79 | case REV_ID_MAJOR_AR71XX: | ||
80 | minor = id & AR71XX_REV_ID_MINOR_MASK; | ||
81 | rev = id >> AR71XX_REV_ID_REVISION_SHIFT; | ||
82 | rev &= AR71XX_REV_ID_REVISION_MASK; | ||
83 | switch (minor) { | ||
84 | case AR71XX_REV_ID_MINOR_AR7130: | ||
85 | ath79_soc = ATH79_SOC_AR7130; | ||
86 | chip = "7130"; | ||
87 | break; | ||
88 | |||
89 | case AR71XX_REV_ID_MINOR_AR7141: | ||
90 | ath79_soc = ATH79_SOC_AR7141; | ||
91 | chip = "7141"; | ||
92 | break; | ||
93 | |||
94 | case AR71XX_REV_ID_MINOR_AR7161: | ||
95 | ath79_soc = ATH79_SOC_AR7161; | ||
96 | chip = "7161"; | ||
97 | break; | ||
98 | } | ||
99 | break; | ||
100 | |||
101 | case REV_ID_MAJOR_AR7240: | ||
102 | ath79_soc = ATH79_SOC_AR7240; | ||
103 | chip = "7240"; | ||
104 | rev = (id & AR724X_REV_ID_REVISION_MASK); | ||
105 | break; | ||
106 | |||
107 | case REV_ID_MAJOR_AR7241: | ||
108 | ath79_soc = ATH79_SOC_AR7241; | ||
109 | chip = "7241"; | ||
110 | rev = (id & AR724X_REV_ID_REVISION_MASK); | ||
111 | break; | ||
112 | |||
113 | case REV_ID_MAJOR_AR7242: | ||
114 | ath79_soc = ATH79_SOC_AR7242; | ||
115 | chip = "7242"; | ||
116 | rev = (id & AR724X_REV_ID_REVISION_MASK); | ||
117 | break; | ||
118 | |||
119 | case REV_ID_MAJOR_AR913X: | ||
120 | minor = id & AR913X_REV_ID_MINOR_MASK; | ||
121 | rev = id >> AR913X_REV_ID_REVISION_SHIFT; | ||
122 | rev &= AR913X_REV_ID_REVISION_MASK; | ||
123 | switch (minor) { | ||
124 | case AR913X_REV_ID_MINOR_AR9130: | ||
125 | ath79_soc = ATH79_SOC_AR9130; | ||
126 | chip = "9130"; | ||
127 | break; | ||
128 | |||
129 | case AR913X_REV_ID_MINOR_AR9132: | ||
130 | ath79_soc = ATH79_SOC_AR9132; | ||
131 | chip = "9132"; | ||
132 | break; | ||
133 | } | ||
134 | break; | ||
135 | |||
136 | default: | ||
137 | panic("ath79: unknown SoC, id:0x%08x\n", id); | ||
138 | } | ||
139 | |||
140 | sprintf(ath79_sys_type, "Atheros AR%s rev %u", chip, rev); | ||
141 | pr_info("SoC: %s\n", ath79_sys_type); | ||
142 | } | ||
143 | |||
144 | const char *get_system_type(void) | ||
145 | { | ||
146 | return ath79_sys_type; | ||
147 | } | ||
148 | |||
149 | unsigned int __cpuinit get_c0_compare_int(void) | ||
150 | { | ||
151 | return CP0_LEGACY_COMPARE_IRQ; | ||
152 | } | ||
153 | |||
154 | void __init plat_mem_setup(void) | ||
155 | { | ||
156 | set_io_port_base(KSEG1); | ||
157 | |||
158 | ath79_reset_base = ioremap_nocache(AR71XX_RESET_BASE, | ||
159 | AR71XX_RESET_SIZE); | ||
160 | ath79_pll_base = ioremap_nocache(AR71XX_PLL_BASE, | ||
161 | AR71XX_PLL_SIZE); | ||
162 | ath79_ddr_base = ioremap_nocache(AR71XX_DDR_CTRL_BASE, | ||
163 | AR71XX_DDR_CTRL_SIZE); | ||
164 | |||
165 | ath79_detect_sys_type(); | ||
166 | ath79_detect_mem_size(); | ||
167 | ath79_clocks_init(); | ||
168 | |||
169 | _machine_restart = ath79_restart; | ||
170 | _machine_halt = ath79_halt; | ||
171 | pm_power_off = ath79_halt; | ||
172 | } | ||
173 | |||
174 | void __init plat_time_init(void) | ||
175 | { | ||
176 | struct clk *clk; | ||
177 | |||
178 | clk = clk_get(NULL, "cpu"); | ||
179 | if (IS_ERR(clk)) | ||
180 | panic("unable to get CPU clock, err=%ld", PTR_ERR(clk)); | ||
181 | |||
182 | mips_hpt_frequency = clk_get_rate(clk) / 2; | ||
183 | } | ||
184 | |||
185 | static int __init ath79_setup(void) | ||
186 | { | ||
187 | ath79_gpio_init(); | ||
188 | ath79_register_uart(); | ||
189 | ath79_register_wdt(); | ||
190 | |||
191 | mips_machine_setup(); | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | arch_initcall(ath79_setup); | ||
197 | |||
198 | static void __init ath79_generic_init(void) | ||
199 | { | ||
200 | /* Nothing to do */ | ||
201 | } | ||
202 | |||
203 | MIPS_MACHINE(ATH79_MACH_GENERIC, | ||
204 | "Generic", | ||
205 | "Generic AR71XX/AR724X/AR913X based board", | ||
206 | ath79_generic_init); | ||
diff --git a/arch/mips/configs/malta_defconfig b/arch/mips/configs/malta_defconfig index b455d0f36486..9d03b68aece8 100644 --- a/arch/mips/configs/malta_defconfig +++ b/arch/mips/configs/malta_defconfig | |||
@@ -369,7 +369,10 @@ CONFIG_VT_HW_CONSOLE_BINDING=y | |||
369 | CONFIG_SERIAL_8250=y | 369 | CONFIG_SERIAL_8250=y |
370 | CONFIG_SERIAL_8250_CONSOLE=y | 370 | CONFIG_SERIAL_8250_CONSOLE=y |
371 | # CONFIG_HWMON is not set | 371 | # CONFIG_HWMON is not set |
372 | CONFIG_FB=y | ||
373 | CONFIG_FB_CIRRUS=y | ||
372 | # CONFIG_VGA_CONSOLE is not set | 374 | # CONFIG_VGA_CONSOLE is not set |
375 | CONFIG_FRAMEBUFFER_CONSOLE=y | ||
373 | CONFIG_HID=m | 376 | CONFIG_HID=m |
374 | CONFIG_LEDS_CLASS=m | 377 | CONFIG_LEDS_CLASS=m |
375 | CONFIG_LEDS_TRIGGER_TIMER=m | 378 | CONFIG_LEDS_TRIGGER_TIMER=m |
diff --git a/arch/mips/include/asm/cache.h b/arch/mips/include/asm/cache.h index 37f175c42bb5..650ac9ba734c 100644 --- a/arch/mips/include/asm/cache.h +++ b/arch/mips/include/asm/cache.h | |||
@@ -17,4 +17,6 @@ | |||
17 | #define SMP_CACHE_SHIFT L1_CACHE_SHIFT | 17 | #define SMP_CACHE_SHIFT L1_CACHE_SHIFT |
18 | #define SMP_CACHE_BYTES L1_CACHE_BYTES | 18 | #define SMP_CACHE_BYTES L1_CACHE_BYTES |
19 | 19 | ||
20 | #define __read_mostly __attribute__((__section__(".data.read_mostly"))) | ||
21 | |||
20 | #endif /* _ASM_CACHE_H */ | 22 | #endif /* _ASM_CACHE_H */ |
diff --git a/arch/mips/include/asm/cpu-info.h b/arch/mips/include/asm/cpu-info.h index b39def3f6e03..c454550eb0c0 100644 --- a/arch/mips/include/asm/cpu-info.h +++ b/arch/mips/include/asm/cpu-info.h | |||
@@ -78,6 +78,7 @@ struct cpuinfo_mips { | |||
78 | unsigned int watch_reg_use_cnt; /* Usable by ptrace */ | 78 | unsigned int watch_reg_use_cnt; /* Usable by ptrace */ |
79 | #define NUM_WATCH_REGS 4 | 79 | #define NUM_WATCH_REGS 4 |
80 | u16 watch_reg_masks[NUM_WATCH_REGS]; | 80 | u16 watch_reg_masks[NUM_WATCH_REGS]; |
81 | unsigned int kscratch_mask; /* Usable KScratch mask. */ | ||
81 | } __attribute__((aligned(SMP_CACHE_BYTES))); | 82 | } __attribute__((aligned(SMP_CACHE_BYTES))); |
82 | 83 | ||
83 | extern struct cpuinfo_mips cpu_data[]; | 84 | extern struct cpuinfo_mips cpu_data[]; |
diff --git a/arch/mips/include/asm/inst.h b/arch/mips/include/asm/inst.h index 444ff71aa0e8..7ebfc392e58d 100644 --- a/arch/mips/include/asm/inst.h +++ b/arch/mips/include/asm/inst.h | |||
@@ -72,6 +72,7 @@ enum spec2_op { | |||
72 | enum spec3_op { | 72 | enum spec3_op { |
73 | ext_op, dextm_op, dextu_op, dext_op, | 73 | ext_op, dextm_op, dextu_op, dext_op, |
74 | ins_op, dinsm_op, dinsu_op, dins_op, | 74 | ins_op, dinsm_op, dinsu_op, dins_op, |
75 | lx_op = 0x0a, | ||
75 | bshfl_op = 0x20, | 76 | bshfl_op = 0x20, |
76 | dbshfl_op = 0x24, | 77 | dbshfl_op = 0x24, |
77 | rdhwr_op = 0x3b | 78 | rdhwr_op = 0x3b |
@@ -179,6 +180,19 @@ enum mad_func { | |||
179 | }; | 180 | }; |
180 | 181 | ||
181 | /* | 182 | /* |
183 | * func field for special3 lx opcodes (Cavium Octeon). | ||
184 | */ | ||
185 | enum lx_func { | ||
186 | lwx_op = 0x00, | ||
187 | lhx_op = 0x04, | ||
188 | lbux_op = 0x06, | ||
189 | ldx_op = 0x08, | ||
190 | lwux_op = 0x10, | ||
191 | lhux_op = 0x14, | ||
192 | lbx_op = 0x16, | ||
193 | }; | ||
194 | |||
195 | /* | ||
182 | * Damn ... bitfields depend from byteorder :-( | 196 | * Damn ... bitfields depend from byteorder :-( |
183 | */ | 197 | */ |
184 | #ifdef __MIPSEB__ | 198 | #ifdef __MIPSEB__ |
diff --git a/arch/mips/include/asm/jump_label.h b/arch/mips/include/asm/jump_label.h new file mode 100644 index 000000000000..7622ccf75076 --- /dev/null +++ b/arch/mips/include/asm/jump_label.h | |||
@@ -0,0 +1,48 @@ | |||
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 | * Copyright (c) 2010 Cavium Networks, Inc. | ||
7 | */ | ||
8 | #ifndef _ASM_MIPS_JUMP_LABEL_H | ||
9 | #define _ASM_MIPS_JUMP_LABEL_H | ||
10 | |||
11 | #include <linux/types.h> | ||
12 | |||
13 | #ifdef __KERNEL__ | ||
14 | |||
15 | #define JUMP_LABEL_NOP_SIZE 4 | ||
16 | |||
17 | #ifdef CONFIG_64BIT | ||
18 | #define WORD_INSN ".dword" | ||
19 | #else | ||
20 | #define WORD_INSN ".word" | ||
21 | #endif | ||
22 | |||
23 | #define JUMP_LABEL(key, label) \ | ||
24 | do { \ | ||
25 | asm goto("1:\tnop\n\t" \ | ||
26 | "nop\n\t" \ | ||
27 | ".pushsection __jump_table, \"a\"\n\t" \ | ||
28 | WORD_INSN " 1b, %l[" #label "], %0\n\t" \ | ||
29 | ".popsection\n\t" \ | ||
30 | : : "i" (key) : : label); \ | ||
31 | } while (0) | ||
32 | |||
33 | |||
34 | #endif /* __KERNEL__ */ | ||
35 | |||
36 | #ifdef CONFIG_64BIT | ||
37 | typedef u64 jump_label_t; | ||
38 | #else | ||
39 | typedef u32 jump_label_t; | ||
40 | #endif | ||
41 | |||
42 | struct jump_entry { | ||
43 | jump_label_t code; | ||
44 | jump_label_t target; | ||
45 | jump_label_t key; | ||
46 | }; | ||
47 | |||
48 | #endif /* _ASM_MIPS_JUMP_LABEL_H */ | ||
diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h new file mode 100644 index 000000000000..cda1c8070b27 --- /dev/null +++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h | |||
@@ -0,0 +1,233 @@ | |||
1 | /* | ||
2 | * Atheros AR71XX/AR724X/AR913X SoC register definitions | ||
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 | #ifndef __ASM_MACH_AR71XX_REGS_H | ||
15 | #define __ASM_MACH_AR71XX_REGS_H | ||
16 | |||
17 | #include <linux/types.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/io.h> | ||
20 | #include <linux/bitops.h> | ||
21 | |||
22 | #define AR71XX_APB_BASE 0x18000000 | ||
23 | #define AR71XX_SPI_BASE 0x1f000000 | ||
24 | #define AR71XX_SPI_SIZE 0x01000000 | ||
25 | |||
26 | #define AR71XX_DDR_CTRL_BASE (AR71XX_APB_BASE + 0x00000000) | ||
27 | #define AR71XX_DDR_CTRL_SIZE 0x100 | ||
28 | #define AR71XX_UART_BASE (AR71XX_APB_BASE + 0x00020000) | ||
29 | #define AR71XX_UART_SIZE 0x100 | ||
30 | #define AR71XX_GPIO_BASE (AR71XX_APB_BASE + 0x00040000) | ||
31 | #define AR71XX_GPIO_SIZE 0x100 | ||
32 | #define AR71XX_PLL_BASE (AR71XX_APB_BASE + 0x00050000) | ||
33 | #define AR71XX_PLL_SIZE 0x100 | ||
34 | #define AR71XX_RESET_BASE (AR71XX_APB_BASE + 0x00060000) | ||
35 | #define AR71XX_RESET_SIZE 0x100 | ||
36 | |||
37 | #define AR913X_WMAC_BASE (AR71XX_APB_BASE + 0x000C0000) | ||
38 | #define AR913X_WMAC_SIZE 0x30000 | ||
39 | |||
40 | /* | ||
41 | * DDR_CTRL block | ||
42 | */ | ||
43 | #define AR71XX_DDR_REG_PCI_WIN0 0x7c | ||
44 | #define AR71XX_DDR_REG_PCI_WIN1 0x80 | ||
45 | #define AR71XX_DDR_REG_PCI_WIN2 0x84 | ||
46 | #define AR71XX_DDR_REG_PCI_WIN3 0x88 | ||
47 | #define AR71XX_DDR_REG_PCI_WIN4 0x8c | ||
48 | #define AR71XX_DDR_REG_PCI_WIN5 0x90 | ||
49 | #define AR71XX_DDR_REG_PCI_WIN6 0x94 | ||
50 | #define AR71XX_DDR_REG_PCI_WIN7 0x98 | ||
51 | #define AR71XX_DDR_REG_FLUSH_GE0 0x9c | ||
52 | #define AR71XX_DDR_REG_FLUSH_GE1 0xa0 | ||
53 | #define AR71XX_DDR_REG_FLUSH_USB 0xa4 | ||
54 | #define AR71XX_DDR_REG_FLUSH_PCI 0xa8 | ||
55 | |||
56 | #define AR724X_DDR_REG_FLUSH_GE0 0x7c | ||
57 | #define AR724X_DDR_REG_FLUSH_GE1 0x80 | ||
58 | #define AR724X_DDR_REG_FLUSH_USB 0x84 | ||
59 | #define AR724X_DDR_REG_FLUSH_PCIE 0x88 | ||
60 | |||
61 | #define AR913X_DDR_REG_FLUSH_GE0 0x7c | ||
62 | #define AR913X_DDR_REG_FLUSH_GE1 0x80 | ||
63 | #define AR913X_DDR_REG_FLUSH_USB 0x84 | ||
64 | #define AR913X_DDR_REG_FLUSH_WMAC 0x88 | ||
65 | |||
66 | /* | ||
67 | * PLL block | ||
68 | */ | ||
69 | #define AR71XX_PLL_REG_CPU_CONFIG 0x00 | ||
70 | #define AR71XX_PLL_REG_SEC_CONFIG 0x04 | ||
71 | #define AR71XX_PLL_REG_ETH0_INT_CLOCK 0x10 | ||
72 | #define AR71XX_PLL_REG_ETH1_INT_CLOCK 0x14 | ||
73 | |||
74 | #define AR71XX_PLL_DIV_SHIFT 3 | ||
75 | #define AR71XX_PLL_DIV_MASK 0x1f | ||
76 | #define AR71XX_CPU_DIV_SHIFT 16 | ||
77 | #define AR71XX_CPU_DIV_MASK 0x3 | ||
78 | #define AR71XX_DDR_DIV_SHIFT 18 | ||
79 | #define AR71XX_DDR_DIV_MASK 0x3 | ||
80 | #define AR71XX_AHB_DIV_SHIFT 20 | ||
81 | #define AR71XX_AHB_DIV_MASK 0x7 | ||
82 | |||
83 | #define AR724X_PLL_REG_CPU_CONFIG 0x00 | ||
84 | #define AR724X_PLL_REG_PCIE_CONFIG 0x18 | ||
85 | |||
86 | #define AR724X_PLL_DIV_SHIFT 0 | ||
87 | #define AR724X_PLL_DIV_MASK 0x3ff | ||
88 | #define AR724X_PLL_REF_DIV_SHIFT 10 | ||
89 | #define AR724X_PLL_REF_DIV_MASK 0xf | ||
90 | #define AR724X_AHB_DIV_SHIFT 19 | ||
91 | #define AR724X_AHB_DIV_MASK 0x1 | ||
92 | #define AR724X_DDR_DIV_SHIFT 22 | ||
93 | #define AR724X_DDR_DIV_MASK 0x3 | ||
94 | |||
95 | #define AR913X_PLL_REG_CPU_CONFIG 0x00 | ||
96 | #define AR913X_PLL_REG_ETH_CONFIG 0x04 | ||
97 | #define AR913X_PLL_REG_ETH0_INT_CLOCK 0x14 | ||
98 | #define AR913X_PLL_REG_ETH1_INT_CLOCK 0x18 | ||
99 | |||
100 | #define AR913X_PLL_DIV_SHIFT 0 | ||
101 | #define AR913X_PLL_DIV_MASK 0x3ff | ||
102 | #define AR913X_DDR_DIV_SHIFT 22 | ||
103 | #define AR913X_DDR_DIV_MASK 0x3 | ||
104 | #define AR913X_AHB_DIV_SHIFT 19 | ||
105 | #define AR913X_AHB_DIV_MASK 0x1 | ||
106 | |||
107 | /* | ||
108 | * RESET block | ||
109 | */ | ||
110 | #define AR71XX_RESET_REG_TIMER 0x00 | ||
111 | #define AR71XX_RESET_REG_TIMER_RELOAD 0x04 | ||
112 | #define AR71XX_RESET_REG_WDOG_CTRL 0x08 | ||
113 | #define AR71XX_RESET_REG_WDOG 0x0c | ||
114 | #define AR71XX_RESET_REG_MISC_INT_STATUS 0x10 | ||
115 | #define AR71XX_RESET_REG_MISC_INT_ENABLE 0x14 | ||
116 | #define AR71XX_RESET_REG_PCI_INT_STATUS 0x18 | ||
117 | #define AR71XX_RESET_REG_PCI_INT_ENABLE 0x1c | ||
118 | #define AR71XX_RESET_REG_GLOBAL_INT_STATUS 0x20 | ||
119 | #define AR71XX_RESET_REG_RESET_MODULE 0x24 | ||
120 | #define AR71XX_RESET_REG_PERFC_CTRL 0x2c | ||
121 | #define AR71XX_RESET_REG_PERFC0 0x30 | ||
122 | #define AR71XX_RESET_REG_PERFC1 0x34 | ||
123 | #define AR71XX_RESET_REG_REV_ID 0x90 | ||
124 | |||
125 | #define AR913X_RESET_REG_GLOBAL_INT_STATUS 0x18 | ||
126 | #define AR913X_RESET_REG_RESET_MODULE 0x1c | ||
127 | #define AR913X_RESET_REG_PERF_CTRL 0x20 | ||
128 | #define AR913X_RESET_REG_PERFC0 0x24 | ||
129 | #define AR913X_RESET_REG_PERFC1 0x28 | ||
130 | |||
131 | #define AR724X_RESET_REG_RESET_MODULE 0x1c | ||
132 | |||
133 | #define MISC_INT_DMA BIT(7) | ||
134 | #define MISC_INT_OHCI BIT(6) | ||
135 | #define MISC_INT_PERFC BIT(5) | ||
136 | #define MISC_INT_WDOG BIT(4) | ||
137 | #define MISC_INT_UART BIT(3) | ||
138 | #define MISC_INT_GPIO BIT(2) | ||
139 | #define MISC_INT_ERROR BIT(1) | ||
140 | #define MISC_INT_TIMER BIT(0) | ||
141 | |||
142 | #define AR71XX_RESET_EXTERNAL BIT(28) | ||
143 | #define AR71XX_RESET_FULL_CHIP BIT(24) | ||
144 | #define AR71XX_RESET_CPU_NMI BIT(21) | ||
145 | #define AR71XX_RESET_CPU_COLD BIT(20) | ||
146 | #define AR71XX_RESET_DMA BIT(19) | ||
147 | #define AR71XX_RESET_SLIC BIT(18) | ||
148 | #define AR71XX_RESET_STEREO BIT(17) | ||
149 | #define AR71XX_RESET_DDR BIT(16) | ||
150 | #define AR71XX_RESET_GE1_MAC BIT(13) | ||
151 | #define AR71XX_RESET_GE1_PHY BIT(12) | ||
152 | #define AR71XX_RESET_USBSUS_OVERRIDE BIT(10) | ||
153 | #define AR71XX_RESET_GE0_MAC BIT(9) | ||
154 | #define AR71XX_RESET_GE0_PHY BIT(8) | ||
155 | #define AR71XX_RESET_USB_OHCI_DLL BIT(6) | ||
156 | #define AR71XX_RESET_USB_HOST BIT(5) | ||
157 | #define AR71XX_RESET_USB_PHY BIT(4) | ||
158 | #define AR71XX_RESET_PCI_BUS BIT(1) | ||
159 | #define AR71XX_RESET_PCI_CORE BIT(0) | ||
160 | |||
161 | #define AR724X_RESET_GE1_MDIO BIT(23) | ||
162 | #define AR724X_RESET_GE0_MDIO BIT(22) | ||
163 | #define AR724X_RESET_PCIE_PHY_SERIAL BIT(10) | ||
164 | #define AR724X_RESET_PCIE_PHY BIT(7) | ||
165 | #define AR724X_RESET_PCIE BIT(6) | ||
166 | #define AR724X_RESET_OHCI_DLL BIT(3) | ||
167 | |||
168 | #define AR913X_RESET_AMBA2WMAC BIT(22) | ||
169 | |||
170 | #define REV_ID_MAJOR_MASK 0xfff0 | ||
171 | #define REV_ID_MAJOR_AR71XX 0x00a0 | ||
172 | #define REV_ID_MAJOR_AR913X 0x00b0 | ||
173 | #define REV_ID_MAJOR_AR7240 0x00c0 | ||
174 | #define REV_ID_MAJOR_AR7241 0x0100 | ||
175 | #define REV_ID_MAJOR_AR7242 0x1100 | ||
176 | |||
177 | #define AR71XX_REV_ID_MINOR_MASK 0x3 | ||
178 | #define AR71XX_REV_ID_MINOR_AR7130 0x0 | ||
179 | #define AR71XX_REV_ID_MINOR_AR7141 0x1 | ||
180 | #define AR71XX_REV_ID_MINOR_AR7161 0x2 | ||
181 | #define AR71XX_REV_ID_REVISION_MASK 0x3 | ||
182 | #define AR71XX_REV_ID_REVISION_SHIFT 2 | ||
183 | |||
184 | #define AR913X_REV_ID_MINOR_MASK 0x3 | ||
185 | #define AR913X_REV_ID_MINOR_AR9130 0x0 | ||
186 | #define AR913X_REV_ID_MINOR_AR9132 0x1 | ||
187 | #define AR913X_REV_ID_REVISION_MASK 0x3 | ||
188 | #define AR913X_REV_ID_REVISION_SHIFT 2 | ||
189 | |||
190 | #define AR724X_REV_ID_REVISION_MASK 0x3 | ||
191 | |||
192 | /* | ||
193 | * SPI block | ||
194 | */ | ||
195 | #define AR71XX_SPI_REG_FS 0x00 /* Function Select */ | ||
196 | #define AR71XX_SPI_REG_CTRL 0x04 /* SPI Control */ | ||
197 | #define AR71XX_SPI_REG_IOC 0x08 /* SPI I/O Control */ | ||
198 | #define AR71XX_SPI_REG_RDS 0x0c /* Read Data Shift */ | ||
199 | |||
200 | #define AR71XX_SPI_FS_GPIO BIT(0) /* Enable GPIO mode */ | ||
201 | |||
202 | #define AR71XX_SPI_CTRL_RD BIT(6) /* Remap Disable */ | ||
203 | #define AR71XX_SPI_CTRL_DIV_MASK 0x3f | ||
204 | |||
205 | #define AR71XX_SPI_IOC_DO BIT(0) /* Data Out pin */ | ||
206 | #define AR71XX_SPI_IOC_CLK BIT(8) /* CLK pin */ | ||
207 | #define AR71XX_SPI_IOC_CS(n) BIT(16 + (n)) | ||
208 | #define AR71XX_SPI_IOC_CS0 AR71XX_SPI_IOC_CS(0) | ||
209 | #define AR71XX_SPI_IOC_CS1 AR71XX_SPI_IOC_CS(1) | ||
210 | #define AR71XX_SPI_IOC_CS2 AR71XX_SPI_IOC_CS(2) | ||
211 | #define AR71XX_SPI_IOC_CS_ALL (AR71XX_SPI_IOC_CS0 | AR71XX_SPI_IOC_CS1 | \ | ||
212 | AR71XX_SPI_IOC_CS2) | ||
213 | |||
214 | /* | ||
215 | * GPIO block | ||
216 | */ | ||
217 | #define AR71XX_GPIO_REG_OE 0x00 | ||
218 | #define AR71XX_GPIO_REG_IN 0x04 | ||
219 | #define AR71XX_GPIO_REG_OUT 0x08 | ||
220 | #define AR71XX_GPIO_REG_SET 0x0c | ||
221 | #define AR71XX_GPIO_REG_CLEAR 0x10 | ||
222 | #define AR71XX_GPIO_REG_INT_MODE 0x14 | ||
223 | #define AR71XX_GPIO_REG_INT_TYPE 0x18 | ||
224 | #define AR71XX_GPIO_REG_INT_POLARITY 0x1c | ||
225 | #define AR71XX_GPIO_REG_INT_PENDING 0x20 | ||
226 | #define AR71XX_GPIO_REG_INT_ENABLE 0x24 | ||
227 | #define AR71XX_GPIO_REG_FUNC 0x28 | ||
228 | |||
229 | #define AR71XX_GPIO_COUNT 16 | ||
230 | #define AR724X_GPIO_COUNT 18 | ||
231 | #define AR913X_GPIO_COUNT 22 | ||
232 | |||
233 | #endif /* __ASM_MACH_AR71XX_REGS_H */ | ||
diff --git a/arch/mips/include/asm/mach-ath79/ath79.h b/arch/mips/include/asm/mach-ath79/ath79.h new file mode 100644 index 000000000000..6a9f168506fe --- /dev/null +++ b/arch/mips/include/asm/mach-ath79/ath79.h | |||
@@ -0,0 +1,96 @@ | |||
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 __ASM_MACH_ATH79_H | ||
15 | #define __ASM_MACH_ATH79_H | ||
16 | |||
17 | #include <linux/types.h> | ||
18 | #include <linux/io.h> | ||
19 | |||
20 | enum ath79_soc_type { | ||
21 | ATH79_SOC_UNKNOWN, | ||
22 | ATH79_SOC_AR7130, | ||
23 | ATH79_SOC_AR7141, | ||
24 | ATH79_SOC_AR7161, | ||
25 | ATH79_SOC_AR7240, | ||
26 | ATH79_SOC_AR7241, | ||
27 | ATH79_SOC_AR7242, | ||
28 | ATH79_SOC_AR9130, | ||
29 | ATH79_SOC_AR9132 | ||
30 | }; | ||
31 | |||
32 | extern enum ath79_soc_type ath79_soc; | ||
33 | |||
34 | static inline int soc_is_ar71xx(void) | ||
35 | { | ||
36 | return (ath79_soc == ATH79_SOC_AR7130 || | ||
37 | ath79_soc == ATH79_SOC_AR7141 || | ||
38 | ath79_soc == ATH79_SOC_AR7161); | ||
39 | } | ||
40 | |||
41 | static inline int soc_is_ar724x(void) | ||
42 | { | ||
43 | return (ath79_soc == ATH79_SOC_AR7240 || | ||
44 | ath79_soc == ATH79_SOC_AR7241 || | ||
45 | ath79_soc == ATH79_SOC_AR7242); | ||
46 | } | ||
47 | |||
48 | static inline int soc_is_ar7240(void) | ||
49 | { | ||
50 | return (ath79_soc == ATH79_SOC_AR7240); | ||
51 | } | ||
52 | |||
53 | static inline int soc_is_ar7241(void) | ||
54 | { | ||
55 | return (ath79_soc == ATH79_SOC_AR7241); | ||
56 | } | ||
57 | |||
58 | static inline int soc_is_ar7242(void) | ||
59 | { | ||
60 | return (ath79_soc == ATH79_SOC_AR7242); | ||
61 | } | ||
62 | |||
63 | static inline int soc_is_ar913x(void) | ||
64 | { | ||
65 | return (ath79_soc == ATH79_SOC_AR9130 || | ||
66 | ath79_soc == ATH79_SOC_AR9132); | ||
67 | } | ||
68 | |||
69 | extern void __iomem *ath79_ddr_base; | ||
70 | extern void __iomem *ath79_pll_base; | ||
71 | extern void __iomem *ath79_reset_base; | ||
72 | |||
73 | static inline void ath79_pll_wr(unsigned reg, u32 val) | ||
74 | { | ||
75 | __raw_writel(val, ath79_pll_base + reg); | ||
76 | } | ||
77 | |||
78 | static inline u32 ath79_pll_rr(unsigned reg) | ||
79 | { | ||
80 | return __raw_readl(ath79_pll_base + reg); | ||
81 | } | ||
82 | |||
83 | static inline void ath79_reset_wr(unsigned reg, u32 val) | ||
84 | { | ||
85 | __raw_writel(val, ath79_reset_base + reg); | ||
86 | } | ||
87 | |||
88 | static inline u32 ath79_reset_rr(unsigned reg) | ||
89 | { | ||
90 | return __raw_readl(ath79_reset_base + reg); | ||
91 | } | ||
92 | |||
93 | void ath79_device_reset_set(u32 mask); | ||
94 | void ath79_device_reset_clear(u32 mask); | ||
95 | |||
96 | #endif /* __ASM_MACH_ATH79_H */ | ||
diff --git a/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h b/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h new file mode 100644 index 000000000000..aa2283e602fc --- /dev/null +++ b/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h | |||
@@ -0,0 +1,23 @@ | |||
1 | /* | ||
2 | * Platform data definition for Atheros AR71XX/AR724X/AR913X SPI controller | ||
3 | * | ||
4 | * Copyright (C) 2008-2010 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 | #ifndef _ATH79_SPI_PLATFORM_H | ||
12 | #define _ATH79_SPI_PLATFORM_H | ||
13 | |||
14 | struct ath79_spi_platform_data { | ||
15 | unsigned bus_num; | ||
16 | unsigned num_chipselect; | ||
17 | }; | ||
18 | |||
19 | struct ath79_spi_controller_data { | ||
20 | unsigned gpio; | ||
21 | }; | ||
22 | |||
23 | #endif /* _ATH79_SPI_PLATFORM_H */ | ||
diff --git a/arch/mips/include/asm/mach-ath79/cpu-feature-overrides.h b/arch/mips/include/asm/mach-ath79/cpu-feature-overrides.h new file mode 100644 index 000000000000..4476fa03bf36 --- /dev/null +++ b/arch/mips/include/asm/mach-ath79/cpu-feature-overrides.h | |||
@@ -0,0 +1,56 @@ | |||
1 | /* | ||
2 | * Atheros AR71XX/AR724X/AR913X specific CPU feature overrides | ||
3 | * | ||
4 | * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> | ||
5 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | ||
6 | * | ||
7 | * This file was derived from: include/asm-mips/cpu-features.h | ||
8 | * Copyright (C) 2003, 2004 Ralf Baechle | ||
9 | * Copyright (C) 2004 Maciej W. Rozycki | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License version 2 as published | ||
13 | * by the Free Software Foundation. | ||
14 | * | ||
15 | */ | ||
16 | #ifndef __ASM_MACH_ATH79_CPU_FEATURE_OVERRIDES_H | ||
17 | #define __ASM_MACH_ATH79_CPU_FEATURE_OVERRIDES_H | ||
18 | |||
19 | #define cpu_has_tlb 1 | ||
20 | #define cpu_has_4kex 1 | ||
21 | #define cpu_has_3k_cache 0 | ||
22 | #define cpu_has_4k_cache 1 | ||
23 | #define cpu_has_tx39_cache 0 | ||
24 | #define cpu_has_sb1_cache 0 | ||
25 | #define cpu_has_fpu 0 | ||
26 | #define cpu_has_32fpr 0 | ||
27 | #define cpu_has_counter 1 | ||
28 | #define cpu_has_watch 1 | ||
29 | #define cpu_has_divec 1 | ||
30 | |||
31 | #define cpu_has_prefetch 1 | ||
32 | #define cpu_has_ejtag 1 | ||
33 | #define cpu_has_llsc 1 | ||
34 | |||
35 | #define cpu_has_mips16 1 | ||
36 | #define cpu_has_mdmx 0 | ||
37 | #define cpu_has_mips3d 0 | ||
38 | #define cpu_has_smartmips 0 | ||
39 | |||
40 | #define cpu_has_mips32r1 1 | ||
41 | #define cpu_has_mips32r2 1 | ||
42 | #define cpu_has_mips64r1 0 | ||
43 | #define cpu_has_mips64r2 0 | ||
44 | |||
45 | #define cpu_has_dsp 0 | ||
46 | #define cpu_has_mipsmt 0 | ||
47 | |||
48 | #define cpu_has_64bits 0 | ||
49 | #define cpu_has_64bit_zero_reg 0 | ||
50 | #define cpu_has_64bit_gp_regs 0 | ||
51 | #define cpu_has_64bit_addresses 0 | ||
52 | |||
53 | #define cpu_dcache_line_size() 32 | ||
54 | #define cpu_icache_line_size() 32 | ||
55 | |||
56 | #endif /* __ASM_MACH_ATH79_CPU_FEATURE_OVERRIDES_H */ | ||
diff --git a/arch/mips/include/asm/mach-ath79/gpio.h b/arch/mips/include/asm/mach-ath79/gpio.h new file mode 100644 index 000000000000..60dcb62785b4 --- /dev/null +++ b/arch/mips/include/asm/mach-ath79/gpio.h | |||
@@ -0,0 +1,26 @@ | |||
1 | /* | ||
2 | * Atheros AR71XX/AR724X/AR913X GPIO API definitions | ||
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 | |||
13 | #ifndef __ASM_MACH_ATH79_GPIO_H | ||
14 | #define __ASM_MACH_ATH79_GPIO_H | ||
15 | |||
16 | #define ARCH_NR_GPIOS 64 | ||
17 | #include <asm-generic/gpio.h> | ||
18 | |||
19 | int gpio_to_irq(unsigned gpio); | ||
20 | int irq_to_gpio(unsigned irq); | ||
21 | int gpio_get_value(unsigned gpio); | ||
22 | void gpio_set_value(unsigned gpio, int value); | ||
23 | |||
24 | #define gpio_cansleep __gpio_cansleep | ||
25 | |||
26 | #endif /* __ASM_MACH_ATH79_GPIO_H */ | ||
diff --git a/arch/mips/include/asm/mach-ath79/irq.h b/arch/mips/include/asm/mach-ath79/irq.h new file mode 100644 index 000000000000..189bc6eb9c10 --- /dev/null +++ b/arch/mips/include/asm/mach-ath79/irq.h | |||
@@ -0,0 +1,36 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> | ||
3 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License version 2 as published | ||
7 | * by the Free Software Foundation. | ||
8 | */ | ||
9 | #ifndef __ASM_MACH_ATH79_IRQ_H | ||
10 | #define __ASM_MACH_ATH79_IRQ_H | ||
11 | |||
12 | #define MIPS_CPU_IRQ_BASE 0 | ||
13 | #define NR_IRQS 16 | ||
14 | |||
15 | #define ATH79_MISC_IRQ_BASE 8 | ||
16 | #define ATH79_MISC_IRQ_COUNT 8 | ||
17 | |||
18 | #define ATH79_CPU_IRQ_IP2 (MIPS_CPU_IRQ_BASE + 2) | ||
19 | #define ATH79_CPU_IRQ_USB (MIPS_CPU_IRQ_BASE + 3) | ||
20 | #define ATH79_CPU_IRQ_GE0 (MIPS_CPU_IRQ_BASE + 4) | ||
21 | #define ATH79_CPU_IRQ_GE1 (MIPS_CPU_IRQ_BASE + 5) | ||
22 | #define ATH79_CPU_IRQ_MISC (MIPS_CPU_IRQ_BASE + 6) | ||
23 | #define ATH79_CPU_IRQ_TIMER (MIPS_CPU_IRQ_BASE + 7) | ||
24 | |||
25 | #define ATH79_MISC_IRQ_TIMER (ATH79_MISC_IRQ_BASE + 0) | ||
26 | #define ATH79_MISC_IRQ_ERROR (ATH79_MISC_IRQ_BASE + 1) | ||
27 | #define ATH79_MISC_IRQ_GPIO (ATH79_MISC_IRQ_BASE + 2) | ||
28 | #define ATH79_MISC_IRQ_UART (ATH79_MISC_IRQ_BASE + 3) | ||
29 | #define ATH79_MISC_IRQ_WDOG (ATH79_MISC_IRQ_BASE + 4) | ||
30 | #define ATH79_MISC_IRQ_PERFC (ATH79_MISC_IRQ_BASE + 5) | ||
31 | #define ATH79_MISC_IRQ_OHCI (ATH79_MISC_IRQ_BASE + 6) | ||
32 | #define ATH79_MISC_IRQ_DMA (ATH79_MISC_IRQ_BASE + 7) | ||
33 | |||
34 | #include_next <irq.h> | ||
35 | |||
36 | #endif /* __ASM_MACH_ATH79_IRQ_H */ | ||
diff --git a/arch/mips/include/asm/mach-ath79/kernel-entry-init.h b/arch/mips/include/asm/mach-ath79/kernel-entry-init.h new file mode 100644 index 000000000000..d8d046bccc8e --- /dev/null +++ b/arch/mips/include/asm/mach-ath79/kernel-entry-init.h | |||
@@ -0,0 +1,32 @@ | |||
1 | /* | ||
2 | * Atheros AR71XX/AR724X/AR913X specific kernel entry setup | ||
3 | * | ||
4 | * Copyright (C) 2009 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 | #ifndef __ASM_MACH_ATH79_KERNEL_ENTRY_H | ||
12 | #define __ASM_MACH_ATH79_KERNEL_ENTRY_H | ||
13 | |||
14 | /* | ||
15 | * Some bootloaders set the 'Kseg0 coherency algorithm' to | ||
16 | * 'Cacheable, noncoherent, write-through, no write allocate' | ||
17 | * and this cause performance issues. Let's go and change it to | ||
18 | * 'Cacheable, noncoherent, write-back, write allocate' | ||
19 | */ | ||
20 | .macro kernel_entry_setup | ||
21 | mfc0 t0, CP0_CONFIG | ||
22 | li t1, ~CONF_CM_CMASK | ||
23 | and t0, t1 | ||
24 | ori t0, CONF_CM_CACHABLE_NONCOHERENT | ||
25 | mtc0 t0, CP0_CONFIG | ||
26 | nop | ||
27 | .endm | ||
28 | |||
29 | .macro smp_slave_setup | ||
30 | .endm | ||
31 | |||
32 | #endif /* __ASM_MACH_ATH79_KERNEL_ENTRY_H */ | ||
diff --git a/arch/mips/include/asm/mach-ath79/war.h b/arch/mips/include/asm/mach-ath79/war.h new file mode 100644 index 000000000000..323d9f1d8c45 --- /dev/null +++ b/arch/mips/include/asm/mach-ath79/war.h | |||
@@ -0,0 +1,25 @@ | |||
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 | * Copyright (C) 2002, 2004, 2007 by Ralf Baechle <ralf@linux-mips.org> | ||
7 | */ | ||
8 | #ifndef __ASM_MACH_ATH79_WAR_H | ||
9 | #define __ASM_MACH_ATH79_WAR_H | ||
10 | |||
11 | #define R4600_V1_INDEX_ICACHEOP_WAR 0 | ||
12 | #define R4600_V1_HIT_CACHEOP_WAR 0 | ||
13 | #define R4600_V2_HIT_CACHEOP_WAR 0 | ||
14 | #define R5432_CP0_INTERRUPT_WAR 0 | ||
15 | #define BCM1250_M3_WAR 0 | ||
16 | #define SIBYTE_1956_WAR 0 | ||
17 | #define MIPS4K_ICACHE_REFILL_WAR 0 | ||
18 | #define MIPS_CACHE_SYNC_WAR 0 | ||
19 | #define TX49XX_ICACHE_INDEX_INV_WAR 0 | ||
20 | #define RM9000_CDEX_SMP_WAR 0 | ||
21 | #define ICACHE_REFILLS_WORKAROUND_WAR 0 | ||
22 | #define R10000_LLSC_WAR 0 | ||
23 | #define MIPS34K_MISSED_ITLB_WAR 0 | ||
24 | |||
25 | #endif /* __ASM_MACH_ATH79_WAR_H */ | ||
diff --git a/arch/mips/include/asm/mips_machine.h b/arch/mips/include/asm/mips_machine.h new file mode 100644 index 000000000000..363bb352c7f7 --- /dev/null +++ b/arch/mips/include/asm/mips_machine.h | |||
@@ -0,0 +1,54 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms of the GNU General Public License version 2 as published | ||
6 | * by the Free Software Foundation. | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | #ifndef __ASM_MIPS_MACHINE_H | ||
11 | #define __ASM_MIPS_MACHINE_H | ||
12 | |||
13 | #include <linux/init.h> | ||
14 | #include <linux/stddef.h> | ||
15 | |||
16 | #include <asm/bootinfo.h> | ||
17 | |||
18 | struct mips_machine { | ||
19 | unsigned long mach_type; | ||
20 | const char *mach_id; | ||
21 | const char *mach_name; | ||
22 | void (*mach_setup)(void); | ||
23 | }; | ||
24 | |||
25 | #define MIPS_MACHINE(_type, _id, _name, _setup) \ | ||
26 | static const char machine_name_##_type[] __initconst \ | ||
27 | __aligned(1) = _name; \ | ||
28 | static const char machine_id_##_type[] __initconst \ | ||
29 | __aligned(1) = _id; \ | ||
30 | static struct mips_machine machine_##_type \ | ||
31 | __used __section(.mips.machines.init) = \ | ||
32 | { \ | ||
33 | .mach_type = _type, \ | ||
34 | .mach_id = machine_id_##_type, \ | ||
35 | .mach_name = machine_name_##_type, \ | ||
36 | .mach_setup = _setup, \ | ||
37 | }; | ||
38 | |||
39 | extern long __mips_machines_start; | ||
40 | extern long __mips_machines_end; | ||
41 | |||
42 | #ifdef CONFIG_MIPS_MACHINE | ||
43 | int mips_machtype_setup(char *id) __init; | ||
44 | void mips_machine_setup(void) __init; | ||
45 | void mips_set_machine_name(const char *name) __init; | ||
46 | char *mips_get_machine_name(void); | ||
47 | #else | ||
48 | static inline int mips_machtype_setup(char *id) { return 1; } | ||
49 | static inline void mips_machine_setup(void) { } | ||
50 | static inline void mips_set_machine_name(const char *name) { } | ||
51 | static inline char *mips_get_machine_name(void) { return NULL; } | ||
52 | #endif /* CONFIG_MIPS_MACHINE */ | ||
53 | |||
54 | #endif /* __ASM_MIPS_MACHINE_H */ | ||
diff --git a/arch/mips/include/asm/mmu_context.h b/arch/mips/include/asm/mmu_context.h index d9592733a7ba..73c0d45798de 100644 --- a/arch/mips/include/asm/mmu_context.h +++ b/arch/mips/include/asm/mmu_context.h | |||
@@ -29,13 +29,7 @@ | |||
29 | #define TLBMISS_HANDLER_SETUP_PGD(pgd) \ | 29 | #define TLBMISS_HANDLER_SETUP_PGD(pgd) \ |
30 | tlbmiss_handler_setup_pgd((unsigned long)(pgd)) | 30 | tlbmiss_handler_setup_pgd((unsigned long)(pgd)) |
31 | 31 | ||
32 | static inline void tlbmiss_handler_setup_pgd(unsigned long pgd) | 32 | extern void tlbmiss_handler_setup_pgd(unsigned long pgd); |
33 | { | ||
34 | /* Check for swapper_pg_dir and convert to physical address. */ | ||
35 | if ((pgd & CKSEG3) == CKSEG0) | ||
36 | pgd = CPHYSADDR(pgd); | ||
37 | write_c0_context(pgd << 11); | ||
38 | } | ||
39 | 33 | ||
40 | #define TLBMISS_HANDLER_SETUP() \ | 34 | #define TLBMISS_HANDLER_SETUP() \ |
41 | do { \ | 35 | do { \ |
diff --git a/arch/mips/include/asm/uasm.h b/arch/mips/include/asm/uasm.h index 892062d6d748..dcbd4bb417ec 100644 --- a/arch/mips/include/asm/uasm.h +++ b/arch/mips/include/asm/uasm.h | |||
@@ -115,7 +115,12 @@ Ip_0(_tlbwr); | |||
115 | Ip_u3u1u2(_xor); | 115 | Ip_u3u1u2(_xor); |
116 | Ip_u2u1u3(_xori); | 116 | Ip_u2u1u3(_xori); |
117 | Ip_u2u1msbu3(_dins); | 117 | Ip_u2u1msbu3(_dins); |
118 | Ip_u2u1msbu3(_dinsm); | ||
118 | Ip_u1(_syscall); | 119 | Ip_u1(_syscall); |
120 | Ip_u1u2s3(_bbit0); | ||
121 | Ip_u1u2s3(_bbit1); | ||
122 | Ip_u3u1u2(_lwx); | ||
123 | Ip_u3u1u2(_ldx); | ||
119 | 124 | ||
120 | /* Handle labels. */ | 125 | /* Handle labels. */ |
121 | struct uasm_label { | 126 | struct uasm_label { |
@@ -153,6 +158,7 @@ static inline void __uasminit uasm_l##lb(struct uasm_label **lab, u32 *addr) \ | |||
153 | # define UASM_i_SUBU(buf, rs, rt, rd) uasm_i_dsubu(buf, rs, rt, rd) | 158 | # define UASM_i_SUBU(buf, rs, rt, rd) uasm_i_dsubu(buf, rs, rt, rd) |
154 | # define UASM_i_LL(buf, rs, rt, off) uasm_i_lld(buf, rs, rt, off) | 159 | # define UASM_i_LL(buf, rs, rt, off) uasm_i_lld(buf, rs, rt, off) |
155 | # define UASM_i_SC(buf, rs, rt, off) uasm_i_scd(buf, rs, rt, off) | 160 | # define UASM_i_SC(buf, rs, rt, off) uasm_i_scd(buf, rs, rt, off) |
161 | # define UASM_i_LWX(buf, rs, rt, rd) uasm_i_ldx(buf, rs, rt, rd) | ||
156 | #else | 162 | #else |
157 | # define UASM_i_LW(buf, rs, rt, off) uasm_i_lw(buf, rs, rt, off) | 163 | # define UASM_i_LW(buf, rs, rt, off) uasm_i_lw(buf, rs, rt, off) |
158 | # define UASM_i_SW(buf, rs, rt, off) uasm_i_sw(buf, rs, rt, off) | 164 | # define UASM_i_SW(buf, rs, rt, off) uasm_i_sw(buf, rs, rt, off) |
@@ -167,6 +173,7 @@ static inline void __uasminit uasm_l##lb(struct uasm_label **lab, u32 *addr) \ | |||
167 | # define UASM_i_SUBU(buf, rs, rt, rd) uasm_i_subu(buf, rs, rt, rd) | 173 | # define UASM_i_SUBU(buf, rs, rt, rd) uasm_i_subu(buf, rs, rt, rd) |
168 | # define UASM_i_LL(buf, rs, rt, off) uasm_i_ll(buf, rs, rt, off) | 174 | # define UASM_i_LL(buf, rs, rt, off) uasm_i_ll(buf, rs, rt, off) |
169 | # define UASM_i_SC(buf, rs, rt, off) uasm_i_sc(buf, rs, rt, off) | 175 | # define UASM_i_SC(buf, rs, rt, off) uasm_i_sc(buf, rs, rt, off) |
176 | # define UASM_i_LWX(buf, rs, rt, rd) uasm_i_lwx(buf, rs, rt, rd) | ||
170 | #endif | 177 | #endif |
171 | 178 | ||
172 | #define uasm_i_b(buf, off) uasm_i_beq(buf, 0, 0, off) | 179 | #define uasm_i_b(buf, off) uasm_i_beq(buf, 0, 0, off) |
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 22b2e0e38617..cedee2bcbd18 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile | |||
@@ -95,6 +95,7 @@ obj-$(CONFIG_GPIO_TXX9) += gpio_txx9.o | |||
95 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o | 95 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o |
96 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o | 96 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o |
97 | obj-$(CONFIG_SPINLOCK_TEST) += spinlock_test.o | 97 | obj-$(CONFIG_SPINLOCK_TEST) += spinlock_test.o |
98 | obj-$(CONFIG_MIPS_MACHINE) += mips_machine.o | ||
98 | 99 | ||
99 | obj-$(CONFIG_OF) += prom.o | 100 | obj-$(CONFIG_OF) += prom.o |
100 | 101 | ||
@@ -106,4 +107,6 @@ obj-$(CONFIG_MIPS_CPUFREQ) += cpufreq/ | |||
106 | 107 | ||
107 | obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o | 108 | obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o |
108 | 109 | ||
110 | obj-$(CONFIG_JUMP_LABEL) += jump_label.o | ||
111 | |||
109 | CPPFLAGS_vmlinux.lds := $(KBUILD_CFLAGS) | 112 | CPPFLAGS_vmlinux.lds := $(KBUILD_CFLAGS) |
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 68dae7b6b5db..f65d4c8c65a6 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c | |||
@@ -739,6 +739,8 @@ static inline unsigned int decode_config4(struct cpuinfo_mips *c) | |||
739 | && cpu_has_tlb) | 739 | && cpu_has_tlb) |
740 | c->tlbsize += (config4 & MIPS_CONF4_MMUSIZEEXT) * 0x40; | 740 | c->tlbsize += (config4 & MIPS_CONF4_MMUSIZEEXT) * 0x40; |
741 | 741 | ||
742 | c->kscratch_mask = (config4 >> 16) & 0xff; | ||
743 | |||
742 | return config4 & MIPS_CONF_M; | 744 | return config4 & MIPS_CONF_M; |
743 | } | 745 | } |
744 | 746 | ||
diff --git a/arch/mips/kernel/jump_label.c b/arch/mips/kernel/jump_label.c new file mode 100644 index 000000000000..6001610cfe55 --- /dev/null +++ b/arch/mips/kernel/jump_label.c | |||
@@ -0,0 +1,54 @@ | |||
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 | * Copyright (c) 2010 Cavium Networks, Inc. | ||
7 | */ | ||
8 | |||
9 | #include <linux/jump_label.h> | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/memory.h> | ||
12 | #include <linux/mutex.h> | ||
13 | #include <linux/types.h> | ||
14 | #include <linux/cpu.h> | ||
15 | |||
16 | #include <asm/cacheflush.h> | ||
17 | #include <asm/inst.h> | ||
18 | |||
19 | #ifdef HAVE_JUMP_LABEL | ||
20 | |||
21 | #define J_RANGE_MASK ((1ul << 28) - 1) | ||
22 | |||
23 | void arch_jump_label_transform(struct jump_entry *e, | ||
24 | enum jump_label_type type) | ||
25 | { | ||
26 | union mips_instruction insn; | ||
27 | union mips_instruction *insn_p = | ||
28 | (union mips_instruction *)(unsigned long)e->code; | ||
29 | |||
30 | /* Jump only works within a 256MB aligned region. */ | ||
31 | BUG_ON((e->target & ~J_RANGE_MASK) != (e->code & ~J_RANGE_MASK)); | ||
32 | |||
33 | /* Target must have 4 byte alignment. */ | ||
34 | BUG_ON((e->target & 3) != 0); | ||
35 | |||
36 | if (type == JUMP_LABEL_ENABLE) { | ||
37 | insn.j_format.opcode = j_op; | ||
38 | insn.j_format.target = (e->target & J_RANGE_MASK) >> 2; | ||
39 | } else { | ||
40 | insn.word = 0; /* nop */ | ||
41 | } | ||
42 | |||
43 | get_online_cpus(); | ||
44 | mutex_lock(&text_mutex); | ||
45 | *insn_p = insn; | ||
46 | |||
47 | flush_icache_range((unsigned long)insn_p, | ||
48 | (unsigned long)insn_p + sizeof(*insn_p)); | ||
49 | |||
50 | mutex_unlock(&text_mutex); | ||
51 | put_online_cpus(); | ||
52 | } | ||
53 | |||
54 | #endif /* HAVE_JUMP_LABEL */ | ||
diff --git a/arch/mips/kernel/mips_machine.c b/arch/mips/kernel/mips_machine.c new file mode 100644 index 000000000000..411a058d2c53 --- /dev/null +++ b/arch/mips/kernel/mips_machine.c | |||
@@ -0,0 +1,86 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms of the GNU General Public License version 2 as published | ||
6 | * by the Free Software Foundation. | ||
7 | * | ||
8 | */ | ||
9 | #include <linux/mm.h> | ||
10 | #include <linux/string.h> | ||
11 | #include <linux/slab.h> | ||
12 | |||
13 | #include <asm/mips_machine.h> | ||
14 | |||
15 | static struct mips_machine *mips_machine __initdata; | ||
16 | static char *mips_machine_name = "Unknown"; | ||
17 | |||
18 | #define for_each_machine(mach) \ | ||
19 | for ((mach) = (struct mips_machine *)&__mips_machines_start; \ | ||
20 | (mach) && \ | ||
21 | (unsigned long)(mach) < (unsigned long)&__mips_machines_end; \ | ||
22 | (mach)++) | ||
23 | |||
24 | __init void mips_set_machine_name(const char *name) | ||
25 | { | ||
26 | char *p; | ||
27 | |||
28 | if (name == NULL) | ||
29 | return; | ||
30 | |||
31 | p = kstrdup(name, GFP_KERNEL); | ||
32 | if (!p) | ||
33 | pr_err("MIPS: no memory for machine_name\n"); | ||
34 | |||
35 | mips_machine_name = p; | ||
36 | } | ||
37 | |||
38 | char *mips_get_machine_name(void) | ||
39 | { | ||
40 | return mips_machine_name; | ||
41 | } | ||
42 | |||
43 | __init int mips_machtype_setup(char *id) | ||
44 | { | ||
45 | struct mips_machine *mach; | ||
46 | |||
47 | for_each_machine(mach) { | ||
48 | if (mach->mach_id == NULL) | ||
49 | continue; | ||
50 | |||
51 | if (strcmp(mach->mach_id, id) == 0) { | ||
52 | mips_machtype = mach->mach_type; | ||
53 | return 0; | ||
54 | } | ||
55 | } | ||
56 | |||
57 | pr_err("MIPS: no machine found for id '%s', supported machines:\n", id); | ||
58 | pr_err("%-24s %s\n", "id", "name"); | ||
59 | for_each_machine(mach) | ||
60 | pr_err("%-24s %s\n", mach->mach_id, mach->mach_name); | ||
61 | |||
62 | return 1; | ||
63 | } | ||
64 | |||
65 | __setup("machtype=", mips_machtype_setup); | ||
66 | |||
67 | __init void mips_machine_setup(void) | ||
68 | { | ||
69 | struct mips_machine *mach; | ||
70 | |||
71 | for_each_machine(mach) { | ||
72 | if (mips_machtype == mach->mach_type) { | ||
73 | mips_machine = mach; | ||
74 | break; | ||
75 | } | ||
76 | } | ||
77 | |||
78 | if (!mips_machine) | ||
79 | return; | ||
80 | |||
81 | mips_set_machine_name(mips_machine->mach_name); | ||
82 | pr_info("MIPS: machine is %s\n", mips_machine_name); | ||
83 | |||
84 | if (mips_machine->mach_setup) | ||
85 | mips_machine->mach_setup(); | ||
86 | } | ||
diff --git a/arch/mips/kernel/module.c b/arch/mips/kernel/module.c index d87a72e9fac7..dd940b701963 100644 --- a/arch/mips/kernel/module.c +++ b/arch/mips/kernel/module.c | |||
@@ -30,6 +30,8 @@ | |||
30 | #include <linux/kernel.h> | 30 | #include <linux/kernel.h> |
31 | #include <linux/module.h> | 31 | #include <linux/module.h> |
32 | #include <linux/spinlock.h> | 32 | #include <linux/spinlock.h> |
33 | #include <linux/jump_label.h> | ||
34 | |||
33 | #include <asm/pgtable.h> /* MODULE_START */ | 35 | #include <asm/pgtable.h> /* MODULE_START */ |
34 | 36 | ||
35 | struct mips_hi16 { | 37 | struct mips_hi16 { |
@@ -382,6 +384,9 @@ int module_finalize(const Elf_Ehdr *hdr, | |||
382 | const Elf_Shdr *s; | 384 | const Elf_Shdr *s; |
383 | char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; | 385 | char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; |
384 | 386 | ||
387 | /* Make jump label nops. */ | ||
388 | jump_label_apply_nops(me); | ||
389 | |||
385 | INIT_LIST_HEAD(&me->arch.dbe_list); | 390 | INIT_LIST_HEAD(&me->arch.dbe_list); |
386 | for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { | 391 | for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { |
387 | if (strcmp("__dbe_table", secstrings + s->sh_name) != 0) | 392 | if (strcmp("__dbe_table", secstrings + s->sh_name) != 0) |
diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index 26109c4d5170..e309665b6c81 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <asm/cpu-features.h> | 12 | #include <asm/cpu-features.h> |
13 | #include <asm/mipsregs.h> | 13 | #include <asm/mipsregs.h> |
14 | #include <asm/processor.h> | 14 | #include <asm/processor.h> |
15 | #include <asm/mips_machine.h> | ||
15 | 16 | ||
16 | unsigned int vced_count, vcei_count; | 17 | unsigned int vced_count, vcei_count; |
17 | 18 | ||
@@ -31,8 +32,12 @@ static int show_cpuinfo(struct seq_file *m, void *v) | |||
31 | /* | 32 | /* |
32 | * For the first processor also print the system type | 33 | * For the first processor also print the system type |
33 | */ | 34 | */ |
34 | if (n == 0) | 35 | if (n == 0) { |
35 | seq_printf(m, "system type\t\t: %s\n", get_system_type()); | 36 | seq_printf(m, "system type\t\t: %s\n", get_system_type()); |
37 | if (mips_get_machine_name()) | ||
38 | seq_printf(m, "machine\t\t\t: %s\n", | ||
39 | mips_get_machine_name()); | ||
40 | } | ||
36 | 41 | ||
37 | seq_printf(m, "processor\t\t: %ld\n", n); | 42 | seq_printf(m, "processor\t\t: %ld\n", n); |
38 | sprintf(fmt, "cpu model\t\t: %%s V%%d.%%d%s\n", | 43 | sprintf(fmt, "cpu model\t\t: %%s V%%d.%%d%s\n", |
@@ -69,6 +74,8 @@ static int show_cpuinfo(struct seq_file *m, void *v) | |||
69 | ); | 74 | ); |
70 | seq_printf(m, "shadow register sets\t: %d\n", | 75 | seq_printf(m, "shadow register sets\t: %d\n", |
71 | cpu_data[n].srsets); | 76 | cpu_data[n].srsets); |
77 | seq_printf(m, "kscratch registers\t: %d\n", | ||
78 | hweight8(cpu_data[n].kscratch_mask)); | ||
72 | seq_printf(m, "core\t\t\t: %d\n", cpu_data[n].core); | 79 | seq_printf(m, "core\t\t\t: %d\n", cpu_data[n].core); |
73 | 80 | ||
74 | sprintf(fmt, "VCE%%c exceptions\t\t: %s\n", | 81 | sprintf(fmt, "VCE%%c exceptions\t\t: %s\n", |
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index acd3f2c49c06..8ad1d5679f14 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c | |||
@@ -70,7 +70,7 @@ static char __initdata builtin_cmdline[COMMAND_LINE_SIZE] = CONFIG_CMDLINE; | |||
70 | * mips_io_port_base is the begin of the address space to which x86 style | 70 | * mips_io_port_base is the begin of the address space to which x86 style |
71 | * I/O ports are mapped. | 71 | * I/O ports are mapped. |
72 | */ | 72 | */ |
73 | const unsigned long mips_io_port_base __read_mostly = -1; | 73 | const unsigned long mips_io_port_base = -1; |
74 | EXPORT_SYMBOL(mips_io_port_base); | 74 | EXPORT_SYMBOL(mips_io_port_base); |
75 | 75 | ||
76 | static struct resource code_resource = { .name = "Kernel code", }; | 76 | static struct resource code_resource = { .name = "Kernel code", }; |
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index e97104302541..71350f7f2d88 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c | |||
@@ -1592,7 +1592,6 @@ void __cpuinit per_cpu_trap_init(void) | |||
1592 | #endif /* CONFIG_MIPS_MT_SMTC */ | 1592 | #endif /* CONFIG_MIPS_MT_SMTC */ |
1593 | 1593 | ||
1594 | cpu_data[cpu].asid_cache = ASID_FIRST_VERSION; | 1594 | cpu_data[cpu].asid_cache = ASID_FIRST_VERSION; |
1595 | TLBMISS_HANDLER_SETUP(); | ||
1596 | 1595 | ||
1597 | atomic_inc(&init_mm.mm_count); | 1596 | atomic_inc(&init_mm.mm_count); |
1598 | current->active_mm = &init_mm; | 1597 | current->active_mm = &init_mm; |
@@ -1614,6 +1613,7 @@ void __cpuinit per_cpu_trap_init(void) | |||
1614 | write_c0_wired(0); | 1613 | write_c0_wired(0); |
1615 | } | 1614 | } |
1616 | #endif /* CONFIG_MIPS_MT_SMTC */ | 1615 | #endif /* CONFIG_MIPS_MT_SMTC */ |
1616 | TLBMISS_HANDLER_SETUP(); | ||
1617 | } | 1617 | } |
1618 | 1618 | ||
1619 | /* Install CPU exception handler */ | 1619 | /* Install CPU exception handler */ |
diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S index f25df73db923..570607b376b5 100644 --- a/arch/mips/kernel/vmlinux.lds.S +++ b/arch/mips/kernel/vmlinux.lds.S | |||
@@ -98,6 +98,13 @@ SECTIONS | |||
98 | INIT_TEXT_SECTION(PAGE_SIZE) | 98 | INIT_TEXT_SECTION(PAGE_SIZE) |
99 | INIT_DATA_SECTION(16) | 99 | INIT_DATA_SECTION(16) |
100 | 100 | ||
101 | . = ALIGN(4); | ||
102 | .mips.machines.init : AT(ADDR(.mips.machines.init) - LOAD_OFFSET) { | ||
103 | __mips_machines_start = .; | ||
104 | *(.mips.machines.init) | ||
105 | __mips_machines_end = .; | ||
106 | } | ||
107 | |||
101 | /* .exit.text is discarded at runtime, not link time, to deal with | 108 | /* .exit.text is discarded at runtime, not link time, to deal with |
102 | * references from .rodata | 109 | * references from .rodata |
103 | */ | 110 | */ |
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index 93816f3bca67..083d3412d0bc 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c | |||
@@ -26,8 +26,10 @@ | |||
26 | #include <linux/smp.h> | 26 | #include <linux/smp.h> |
27 | #include <linux/string.h> | 27 | #include <linux/string.h> |
28 | #include <linux/init.h> | 28 | #include <linux/init.h> |
29 | #include <linux/cache.h> | ||
29 | 30 | ||
30 | #include <asm/mmu_context.h> | 31 | #include <asm/cacheflush.h> |
32 | #include <asm/pgtable.h> | ||
31 | #include <asm/war.h> | 33 | #include <asm/war.h> |
32 | #include <asm/uasm.h> | 34 | #include <asm/uasm.h> |
33 | 35 | ||
@@ -63,6 +65,52 @@ static inline int __maybe_unused r10000_llsc_war(void) | |||
63 | return R10000_LLSC_WAR; | 65 | return R10000_LLSC_WAR; |
64 | } | 66 | } |
65 | 67 | ||
68 | static int use_bbit_insns(void) | ||
69 | { | ||
70 | switch (current_cpu_type()) { | ||
71 | case CPU_CAVIUM_OCTEON: | ||
72 | case CPU_CAVIUM_OCTEON_PLUS: | ||
73 | case CPU_CAVIUM_OCTEON2: | ||
74 | return 1; | ||
75 | default: | ||
76 | return 0; | ||
77 | } | ||
78 | } | ||
79 | |||
80 | static int use_lwx_insns(void) | ||
81 | { | ||
82 | switch (current_cpu_type()) { | ||
83 | case CPU_CAVIUM_OCTEON2: | ||
84 | return 1; | ||
85 | default: | ||
86 | return 0; | ||
87 | } | ||
88 | } | ||
89 | #if defined(CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE) && \ | ||
90 | CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE > 0 | ||
91 | static bool scratchpad_available(void) | ||
92 | { | ||
93 | return true; | ||
94 | } | ||
95 | static int scratchpad_offset(int i) | ||
96 | { | ||
97 | /* | ||
98 | * CVMSEG starts at address -32768 and extends for | ||
99 | * CAVIUM_OCTEON_CVMSEG_SIZE 128 byte cache lines. | ||
100 | */ | ||
101 | i += 1; /* Kernel use starts at the top and works down. */ | ||
102 | return CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE * 128 - (8 * i) - 32768; | ||
103 | } | ||
104 | #else | ||
105 | static bool scratchpad_available(void) | ||
106 | { | ||
107 | return false; | ||
108 | } | ||
109 | static int scratchpad_offset(int i) | ||
110 | { | ||
111 | BUG(); | ||
112 | } | ||
113 | #endif | ||
66 | /* | 114 | /* |
67 | * Found by experiment: At least some revisions of the 4kc throw under | 115 | * Found by experiment: At least some revisions of the 4kc throw under |
68 | * some circumstances a machine check exception, triggered by invalid | 116 | * some circumstances a machine check exception, triggered by invalid |
@@ -173,11 +221,41 @@ static struct uasm_reloc relocs[128] __cpuinitdata; | |||
173 | static int check_for_high_segbits __cpuinitdata; | 221 | static int check_for_high_segbits __cpuinitdata; |
174 | #endif | 222 | #endif |
175 | 223 | ||
224 | static int check_for_high_segbits __cpuinitdata; | ||
225 | |||
226 | static unsigned int kscratch_used_mask __cpuinitdata; | ||
227 | |||
228 | static int __cpuinit allocate_kscratch(void) | ||
229 | { | ||
230 | int r; | ||
231 | unsigned int a = cpu_data[0].kscratch_mask & ~kscratch_used_mask; | ||
232 | |||
233 | r = ffs(a); | ||
234 | |||
235 | if (r == 0) | ||
236 | return -1; | ||
237 | |||
238 | r--; /* make it zero based */ | ||
239 | |||
240 | kscratch_used_mask |= (1 << r); | ||
241 | |||
242 | return r; | ||
243 | } | ||
244 | |||
245 | static int scratch_reg __cpuinitdata; | ||
246 | static int pgd_reg __cpuinitdata; | ||
247 | enum vmalloc64_mode {not_refill, refill_scratch, refill_noscratch}; | ||
248 | |||
176 | #ifndef CONFIG_MIPS_PGD_C0_CONTEXT | 249 | #ifndef CONFIG_MIPS_PGD_C0_CONTEXT |
250 | |||
177 | /* | 251 | /* |
178 | * CONFIG_MIPS_PGD_C0_CONTEXT implies 64 bit and lack of pgd_current, | 252 | * CONFIG_MIPS_PGD_C0_CONTEXT implies 64 bit and lack of pgd_current, |
179 | * we cannot do r3000 under these circumstances. | 253 | * we cannot do r3000 under these circumstances. |
254 | * | ||
255 | * Declare pgd_current here instead of including mmu_context.h to avoid type | ||
256 | * conflicts for tlbmiss_handler_setup_pgd | ||
180 | */ | 257 | */ |
258 | extern unsigned long pgd_current[]; | ||
181 | 259 | ||
182 | /* | 260 | /* |
183 | * The R3000 TLB handler is simple. | 261 | * The R3000 TLB handler is simple. |
@@ -440,21 +518,43 @@ static __cpuinit __maybe_unused void build_convert_pte_to_entrylo(u32 **p, | |||
440 | static __cpuinit void build_restore_pagemask(u32 **p, | 518 | static __cpuinit void build_restore_pagemask(u32 **p, |
441 | struct uasm_reloc **r, | 519 | struct uasm_reloc **r, |
442 | unsigned int tmp, | 520 | unsigned int tmp, |
443 | enum label_id lid) | 521 | enum label_id lid, |
522 | int restore_scratch) | ||
444 | { | 523 | { |
445 | /* Reset default page size */ | 524 | if (restore_scratch) { |
446 | if (PM_DEFAULT_MASK >> 16) { | 525 | /* Reset default page size */ |
447 | uasm_i_lui(p, tmp, PM_DEFAULT_MASK >> 16); | 526 | if (PM_DEFAULT_MASK >> 16) { |
448 | uasm_i_ori(p, tmp, tmp, PM_DEFAULT_MASK & 0xffff); | 527 | uasm_i_lui(p, tmp, PM_DEFAULT_MASK >> 16); |
449 | uasm_il_b(p, r, lid); | 528 | uasm_i_ori(p, tmp, tmp, PM_DEFAULT_MASK & 0xffff); |
450 | uasm_i_mtc0(p, tmp, C0_PAGEMASK); | 529 | uasm_i_mtc0(p, tmp, C0_PAGEMASK); |
451 | } else if (PM_DEFAULT_MASK) { | 530 | uasm_il_b(p, r, lid); |
452 | uasm_i_ori(p, tmp, 0, PM_DEFAULT_MASK); | 531 | } else if (PM_DEFAULT_MASK) { |
453 | uasm_il_b(p, r, lid); | 532 | uasm_i_ori(p, tmp, 0, PM_DEFAULT_MASK); |
454 | uasm_i_mtc0(p, tmp, C0_PAGEMASK); | 533 | uasm_i_mtc0(p, tmp, C0_PAGEMASK); |
534 | uasm_il_b(p, r, lid); | ||
535 | } else { | ||
536 | uasm_i_mtc0(p, 0, C0_PAGEMASK); | ||
537 | uasm_il_b(p, r, lid); | ||
538 | } | ||
539 | if (scratch_reg > 0) | ||
540 | UASM_i_MFC0(p, 1, 31, scratch_reg); | ||
541 | else | ||
542 | UASM_i_LW(p, 1, scratchpad_offset(0), 0); | ||
455 | } else { | 543 | } else { |
456 | uasm_il_b(p, r, lid); | 544 | /* Reset default page size */ |
457 | uasm_i_mtc0(p, 0, C0_PAGEMASK); | 545 | if (PM_DEFAULT_MASK >> 16) { |
546 | uasm_i_lui(p, tmp, PM_DEFAULT_MASK >> 16); | ||
547 | uasm_i_ori(p, tmp, tmp, PM_DEFAULT_MASK & 0xffff); | ||
548 | uasm_il_b(p, r, lid); | ||
549 | uasm_i_mtc0(p, tmp, C0_PAGEMASK); | ||
550 | } else if (PM_DEFAULT_MASK) { | ||
551 | uasm_i_ori(p, tmp, 0, PM_DEFAULT_MASK); | ||
552 | uasm_il_b(p, r, lid); | ||
553 | uasm_i_mtc0(p, tmp, C0_PAGEMASK); | ||
554 | } else { | ||
555 | uasm_il_b(p, r, lid); | ||
556 | uasm_i_mtc0(p, 0, C0_PAGEMASK); | ||
557 | } | ||
458 | } | 558 | } |
459 | } | 559 | } |
460 | 560 | ||
@@ -462,7 +562,8 @@ static __cpuinit void build_huge_tlb_write_entry(u32 **p, | |||
462 | struct uasm_label **l, | 562 | struct uasm_label **l, |
463 | struct uasm_reloc **r, | 563 | struct uasm_reloc **r, |
464 | unsigned int tmp, | 564 | unsigned int tmp, |
465 | enum tlb_write_entry wmode) | 565 | enum tlb_write_entry wmode, |
566 | int restore_scratch) | ||
466 | { | 567 | { |
467 | /* Set huge page tlb entry size */ | 568 | /* Set huge page tlb entry size */ |
468 | uasm_i_lui(p, tmp, PM_HUGE_MASK >> 16); | 569 | uasm_i_lui(p, tmp, PM_HUGE_MASK >> 16); |
@@ -471,7 +572,7 @@ static __cpuinit void build_huge_tlb_write_entry(u32 **p, | |||
471 | 572 | ||
472 | build_tlb_write_entry(p, l, r, wmode); | 573 | build_tlb_write_entry(p, l, r, wmode); |
473 | 574 | ||
474 | build_restore_pagemask(p, r, tmp, label_leave); | 575 | build_restore_pagemask(p, r, tmp, label_leave, restore_scratch); |
475 | } | 576 | } |
476 | 577 | ||
477 | /* | 578 | /* |
@@ -482,8 +583,12 @@ build_is_huge_pte(u32 **p, struct uasm_reloc **r, unsigned int tmp, | |||
482 | unsigned int pmd, int lid) | 583 | unsigned int pmd, int lid) |
483 | { | 584 | { |
484 | UASM_i_LW(p, tmp, 0, pmd); | 585 | UASM_i_LW(p, tmp, 0, pmd); |
485 | uasm_i_andi(p, tmp, tmp, _PAGE_HUGE); | 586 | if (use_bbit_insns()) { |
486 | uasm_il_bnez(p, r, tmp, lid); | 587 | uasm_il_bbit1(p, r, tmp, ilog2(_PAGE_HUGE), lid); |
588 | } else { | ||
589 | uasm_i_andi(p, tmp, tmp, _PAGE_HUGE); | ||
590 | uasm_il_bnez(p, r, tmp, lid); | ||
591 | } | ||
487 | } | 592 | } |
488 | 593 | ||
489 | static __cpuinit void build_huge_update_entries(u32 **p, | 594 | static __cpuinit void build_huge_update_entries(u32 **p, |
@@ -532,7 +637,7 @@ static __cpuinit void build_huge_handler_tail(u32 **p, | |||
532 | UASM_i_SW(p, pte, 0, ptr); | 637 | UASM_i_SW(p, pte, 0, ptr); |
533 | #endif | 638 | #endif |
534 | build_huge_update_entries(p, pte, ptr); | 639 | build_huge_update_entries(p, pte, ptr); |
535 | build_huge_tlb_write_entry(p, l, r, pte, tlb_indexed); | 640 | build_huge_tlb_write_entry(p, l, r, pte, tlb_indexed, 0); |
536 | } | 641 | } |
537 | #endif /* CONFIG_HUGETLB_PAGE */ | 642 | #endif /* CONFIG_HUGETLB_PAGE */ |
538 | 643 | ||
@@ -573,13 +678,22 @@ build_get_pmde64(u32 **p, struct uasm_label **l, struct uasm_reloc **r, | |||
573 | /* No uasm_i_nop needed here, since the next insn doesn't touch TMP. */ | 678 | /* No uasm_i_nop needed here, since the next insn doesn't touch TMP. */ |
574 | 679 | ||
575 | #ifdef CONFIG_MIPS_PGD_C0_CONTEXT | 680 | #ifdef CONFIG_MIPS_PGD_C0_CONTEXT |
576 | /* | 681 | if (pgd_reg != -1) { |
577 | * &pgd << 11 stored in CONTEXT [23..63]. | 682 | /* pgd is in pgd_reg */ |
578 | */ | 683 | UASM_i_MFC0(p, ptr, 31, pgd_reg); |
579 | UASM_i_MFC0(p, ptr, C0_CONTEXT); | 684 | } else { |
580 | uasm_i_dins(p, ptr, 0, 0, 23); /* Clear lower 23 bits of context. */ | 685 | /* |
581 | uasm_i_ori(p, ptr, ptr, 0x540); /* 1 0 1 0 1 << 6 xkphys cached */ | 686 | * &pgd << 11 stored in CONTEXT [23..63]. |
582 | uasm_i_drotr(p, ptr, ptr, 11); | 687 | */ |
688 | UASM_i_MFC0(p, ptr, C0_CONTEXT); | ||
689 | |||
690 | /* Clear lower 23 bits of context. */ | ||
691 | uasm_i_dins(p, ptr, 0, 0, 23); | ||
692 | |||
693 | /* 1 0 1 0 1 << 6 xkphys cached */ | ||
694 | uasm_i_ori(p, ptr, ptr, 0x540); | ||
695 | uasm_i_drotr(p, ptr, ptr, 11); | ||
696 | } | ||
583 | #elif defined(CONFIG_SMP) | 697 | #elif defined(CONFIG_SMP) |
584 | # ifdef CONFIG_MIPS_MT_SMTC | 698 | # ifdef CONFIG_MIPS_MT_SMTC |
585 | /* | 699 | /* |
@@ -620,7 +734,6 @@ build_get_pmde64(u32 **p, struct uasm_label **l, struct uasm_reloc **r, | |||
620 | #endif | 734 | #endif |
621 | } | 735 | } |
622 | 736 | ||
623 | enum vmalloc64_mode {not_refill, refill}; | ||
624 | /* | 737 | /* |
625 | * BVADDR is the faulting address, PTR is scratch. | 738 | * BVADDR is the faulting address, PTR is scratch. |
626 | * PTR will hold the pgd for vmalloc. | 739 | * PTR will hold the pgd for vmalloc. |
@@ -638,7 +751,7 @@ build_get_pgd_vmalloc64(u32 **p, struct uasm_label **l, struct uasm_reloc **r, | |||
638 | 751 | ||
639 | uasm_l_vmalloc(l, *p); | 752 | uasm_l_vmalloc(l, *p); |
640 | 753 | ||
641 | if (mode == refill && check_for_high_segbits) { | 754 | if (mode != not_refill && check_for_high_segbits) { |
642 | if (single_insn_swpd) { | 755 | if (single_insn_swpd) { |
643 | uasm_il_bltz(p, r, bvaddr, label_vmalloc_done); | 756 | uasm_il_bltz(p, r, bvaddr, label_vmalloc_done); |
644 | uasm_i_lui(p, ptr, uasm_rel_hi(swpd)); | 757 | uasm_i_lui(p, ptr, uasm_rel_hi(swpd)); |
@@ -661,7 +774,7 @@ build_get_pgd_vmalloc64(u32 **p, struct uasm_label **l, struct uasm_reloc **r, | |||
661 | uasm_i_daddiu(p, ptr, ptr, uasm_rel_lo(swpd)); | 774 | uasm_i_daddiu(p, ptr, ptr, uasm_rel_lo(swpd)); |
662 | } | 775 | } |
663 | } | 776 | } |
664 | if (mode == refill && check_for_high_segbits) { | 777 | if (mode != not_refill && check_for_high_segbits) { |
665 | uasm_l_large_segbits_fault(l, *p); | 778 | uasm_l_large_segbits_fault(l, *p); |
666 | /* | 779 | /* |
667 | * We get here if we are an xsseg address, or if we are | 780 | * We get here if we are an xsseg address, or if we are |
@@ -677,7 +790,15 @@ build_get_pgd_vmalloc64(u32 **p, struct uasm_label **l, struct uasm_reloc **r, | |||
677 | */ | 790 | */ |
678 | UASM_i_LA(p, ptr, (unsigned long)tlb_do_page_fault_0); | 791 | UASM_i_LA(p, ptr, (unsigned long)tlb_do_page_fault_0); |
679 | uasm_i_jr(p, ptr); | 792 | uasm_i_jr(p, ptr); |
680 | uasm_i_nop(p); | 793 | |
794 | if (mode == refill_scratch) { | ||
795 | if (scratch_reg > 0) | ||
796 | UASM_i_MFC0(p, 1, 31, scratch_reg); | ||
797 | else | ||
798 | UASM_i_LW(p, 1, scratchpad_offset(0), 0); | ||
799 | } else { | ||
800 | uasm_i_nop(p); | ||
801 | } | ||
681 | } | 802 | } |
682 | } | 803 | } |
683 | 804 | ||
@@ -834,6 +955,185 @@ static void __cpuinit build_update_entries(u32 **p, unsigned int tmp, | |||
834 | #endif | 955 | #endif |
835 | } | 956 | } |
836 | 957 | ||
958 | struct mips_huge_tlb_info { | ||
959 | int huge_pte; | ||
960 | int restore_scratch; | ||
961 | }; | ||
962 | |||
963 | static struct mips_huge_tlb_info __cpuinit | ||
964 | build_fast_tlb_refill_handler (u32 **p, struct uasm_label **l, | ||
965 | struct uasm_reloc **r, unsigned int tmp, | ||
966 | unsigned int ptr, int c0_scratch) | ||
967 | { | ||
968 | struct mips_huge_tlb_info rv; | ||
969 | unsigned int even, odd; | ||
970 | int vmalloc_branch_delay_filled = 0; | ||
971 | const int scratch = 1; /* Our extra working register */ | ||
972 | |||
973 | rv.huge_pte = scratch; | ||
974 | rv.restore_scratch = 0; | ||
975 | |||
976 | if (check_for_high_segbits) { | ||
977 | UASM_i_MFC0(p, tmp, C0_BADVADDR); | ||
978 | |||
979 | if (pgd_reg != -1) | ||
980 | UASM_i_MFC0(p, ptr, 31, pgd_reg); | ||
981 | else | ||
982 | UASM_i_MFC0(p, ptr, C0_CONTEXT); | ||
983 | |||
984 | if (c0_scratch >= 0) | ||
985 | UASM_i_MTC0(p, scratch, 31, c0_scratch); | ||
986 | else | ||
987 | UASM_i_SW(p, scratch, scratchpad_offset(0), 0); | ||
988 | |||
989 | uasm_i_dsrl_safe(p, scratch, tmp, | ||
990 | PGDIR_SHIFT + PGD_ORDER + PAGE_SHIFT - 3); | ||
991 | uasm_il_bnez(p, r, scratch, label_vmalloc); | ||
992 | |||
993 | if (pgd_reg == -1) { | ||
994 | vmalloc_branch_delay_filled = 1; | ||
995 | /* Clear lower 23 bits of context. */ | ||
996 | uasm_i_dins(p, ptr, 0, 0, 23); | ||
997 | } | ||
998 | } else { | ||
999 | if (pgd_reg != -1) | ||
1000 | UASM_i_MFC0(p, ptr, 31, pgd_reg); | ||
1001 | else | ||
1002 | UASM_i_MFC0(p, ptr, C0_CONTEXT); | ||
1003 | |||
1004 | UASM_i_MFC0(p, tmp, C0_BADVADDR); | ||
1005 | |||
1006 | if (c0_scratch >= 0) | ||
1007 | UASM_i_MTC0(p, scratch, 31, c0_scratch); | ||
1008 | else | ||
1009 | UASM_i_SW(p, scratch, scratchpad_offset(0), 0); | ||
1010 | |||
1011 | if (pgd_reg == -1) | ||
1012 | /* Clear lower 23 bits of context. */ | ||
1013 | uasm_i_dins(p, ptr, 0, 0, 23); | ||
1014 | |||
1015 | uasm_il_bltz(p, r, tmp, label_vmalloc); | ||
1016 | } | ||
1017 | |||
1018 | if (pgd_reg == -1) { | ||
1019 | vmalloc_branch_delay_filled = 1; | ||
1020 | /* 1 0 1 0 1 << 6 xkphys cached */ | ||
1021 | uasm_i_ori(p, ptr, ptr, 0x540); | ||
1022 | uasm_i_drotr(p, ptr, ptr, 11); | ||
1023 | } | ||
1024 | |||
1025 | #ifdef __PAGETABLE_PMD_FOLDED | ||
1026 | #define LOC_PTEP scratch | ||
1027 | #else | ||
1028 | #define LOC_PTEP ptr | ||
1029 | #endif | ||
1030 | |||
1031 | if (!vmalloc_branch_delay_filled) | ||
1032 | /* get pgd offset in bytes */ | ||
1033 | uasm_i_dsrl_safe(p, scratch, tmp, PGDIR_SHIFT - 3); | ||
1034 | |||
1035 | uasm_l_vmalloc_done(l, *p); | ||
1036 | |||
1037 | /* | ||
1038 | * tmp ptr | ||
1039 | * fall-through case = badvaddr *pgd_current | ||
1040 | * vmalloc case = badvaddr swapper_pg_dir | ||
1041 | */ | ||
1042 | |||
1043 | if (vmalloc_branch_delay_filled) | ||
1044 | /* get pgd offset in bytes */ | ||
1045 | uasm_i_dsrl_safe(p, scratch, tmp, PGDIR_SHIFT - 3); | ||
1046 | |||
1047 | #ifdef __PAGETABLE_PMD_FOLDED | ||
1048 | GET_CONTEXT(p, tmp); /* get context reg */ | ||
1049 | #endif | ||
1050 | uasm_i_andi(p, scratch, scratch, (PTRS_PER_PGD - 1) << 3); | ||
1051 | |||
1052 | if (use_lwx_insns()) { | ||
1053 | UASM_i_LWX(p, LOC_PTEP, scratch, ptr); | ||
1054 | } else { | ||
1055 | uasm_i_daddu(p, ptr, ptr, scratch); /* add in pgd offset */ | ||
1056 | uasm_i_ld(p, LOC_PTEP, 0, ptr); /* get pmd pointer */ | ||
1057 | } | ||
1058 | |||
1059 | #ifndef __PAGETABLE_PMD_FOLDED | ||
1060 | /* get pmd offset in bytes */ | ||
1061 | uasm_i_dsrl_safe(p, scratch, tmp, PMD_SHIFT - 3); | ||
1062 | uasm_i_andi(p, scratch, scratch, (PTRS_PER_PMD - 1) << 3); | ||
1063 | GET_CONTEXT(p, tmp); /* get context reg */ | ||
1064 | |||
1065 | if (use_lwx_insns()) { | ||
1066 | UASM_i_LWX(p, scratch, scratch, ptr); | ||
1067 | } else { | ||
1068 | uasm_i_daddu(p, ptr, ptr, scratch); /* add in pmd offset */ | ||
1069 | UASM_i_LW(p, scratch, 0, ptr); | ||
1070 | } | ||
1071 | #endif | ||
1072 | /* Adjust the context during the load latency. */ | ||
1073 | build_adjust_context(p, tmp); | ||
1074 | |||
1075 | #ifdef CONFIG_HUGETLB_PAGE | ||
1076 | uasm_il_bbit1(p, r, scratch, ilog2(_PAGE_HUGE), label_tlb_huge_update); | ||
1077 | /* | ||
1078 | * The in the LWX case we don't want to do the load in the | ||
1079 | * delay slot. It cannot issue in the same cycle and may be | ||
1080 | * speculative and unneeded. | ||
1081 | */ | ||
1082 | if (use_lwx_insns()) | ||
1083 | uasm_i_nop(p); | ||
1084 | #endif /* CONFIG_HUGETLB_PAGE */ | ||
1085 | |||
1086 | |||
1087 | /* build_update_entries */ | ||
1088 | if (use_lwx_insns()) { | ||
1089 | even = ptr; | ||
1090 | odd = tmp; | ||
1091 | UASM_i_LWX(p, even, scratch, tmp); | ||
1092 | UASM_i_ADDIU(p, tmp, tmp, sizeof(pte_t)); | ||
1093 | UASM_i_LWX(p, odd, scratch, tmp); | ||
1094 | } else { | ||
1095 | UASM_i_ADDU(p, ptr, scratch, tmp); /* add in offset */ | ||
1096 | even = tmp; | ||
1097 | odd = ptr; | ||
1098 | UASM_i_LW(p, even, 0, ptr); /* get even pte */ | ||
1099 | UASM_i_LW(p, odd, sizeof(pte_t), ptr); /* get odd pte */ | ||
1100 | } | ||
1101 | if (kernel_uses_smartmips_rixi) { | ||
1102 | uasm_i_dsrl_safe(p, even, even, ilog2(_PAGE_NO_EXEC)); | ||
1103 | uasm_i_dsrl_safe(p, odd, odd, ilog2(_PAGE_NO_EXEC)); | ||
1104 | uasm_i_drotr(p, even, even, | ||
1105 | ilog2(_PAGE_GLOBAL) - ilog2(_PAGE_NO_EXEC)); | ||
1106 | UASM_i_MTC0(p, even, C0_ENTRYLO0); /* load it */ | ||
1107 | uasm_i_drotr(p, odd, odd, | ||
1108 | ilog2(_PAGE_GLOBAL) - ilog2(_PAGE_NO_EXEC)); | ||
1109 | } else { | ||
1110 | uasm_i_dsrl_safe(p, even, even, ilog2(_PAGE_GLOBAL)); | ||
1111 | UASM_i_MTC0(p, even, C0_ENTRYLO0); /* load it */ | ||
1112 | uasm_i_dsrl_safe(p, odd, odd, ilog2(_PAGE_GLOBAL)); | ||
1113 | } | ||
1114 | UASM_i_MTC0(p, odd, C0_ENTRYLO1); /* load it */ | ||
1115 | |||
1116 | if (c0_scratch >= 0) { | ||
1117 | UASM_i_MFC0(p, scratch, 31, c0_scratch); | ||
1118 | build_tlb_write_entry(p, l, r, tlb_random); | ||
1119 | uasm_l_leave(l, *p); | ||
1120 | rv.restore_scratch = 1; | ||
1121 | } else if (PAGE_SHIFT == 14 || PAGE_SHIFT == 13) { | ||
1122 | build_tlb_write_entry(p, l, r, tlb_random); | ||
1123 | uasm_l_leave(l, *p); | ||
1124 | UASM_i_LW(p, scratch, scratchpad_offset(0), 0); | ||
1125 | } else { | ||
1126 | UASM_i_LW(p, scratch, scratchpad_offset(0), 0); | ||
1127 | build_tlb_write_entry(p, l, r, tlb_random); | ||
1128 | uasm_l_leave(l, *p); | ||
1129 | rv.restore_scratch = 1; | ||
1130 | } | ||
1131 | |||
1132 | uasm_i_eret(p); /* return from trap */ | ||
1133 | |||
1134 | return rv; | ||
1135 | } | ||
1136 | |||
837 | /* | 1137 | /* |
838 | * For a 64-bit kernel, we are using the 64-bit XTLB refill exception | 1138 | * For a 64-bit kernel, we are using the 64-bit XTLB refill exception |
839 | * because EXL == 0. If we wrap, we can also use the 32 instruction | 1139 | * because EXL == 0. If we wrap, we can also use the 32 instruction |
@@ -849,54 +1149,67 @@ static void __cpuinit build_r4000_tlb_refill_handler(void) | |||
849 | struct uasm_reloc *r = relocs; | 1149 | struct uasm_reloc *r = relocs; |
850 | u32 *f; | 1150 | u32 *f; |
851 | unsigned int final_len; | 1151 | unsigned int final_len; |
1152 | struct mips_huge_tlb_info htlb_info; | ||
1153 | enum vmalloc64_mode vmalloc_mode; | ||
852 | 1154 | ||
853 | memset(tlb_handler, 0, sizeof(tlb_handler)); | 1155 | memset(tlb_handler, 0, sizeof(tlb_handler)); |
854 | memset(labels, 0, sizeof(labels)); | 1156 | memset(labels, 0, sizeof(labels)); |
855 | memset(relocs, 0, sizeof(relocs)); | 1157 | memset(relocs, 0, sizeof(relocs)); |
856 | memset(final_handler, 0, sizeof(final_handler)); | 1158 | memset(final_handler, 0, sizeof(final_handler)); |
857 | 1159 | ||
858 | /* | 1160 | if (scratch_reg == 0) |
859 | * create the plain linear handler | 1161 | scratch_reg = allocate_kscratch(); |
860 | */ | ||
861 | if (bcm1250_m3_war()) { | ||
862 | unsigned int segbits = 44; | ||
863 | 1162 | ||
864 | uasm_i_dmfc0(&p, K0, C0_BADVADDR); | 1163 | if ((scratch_reg > 0 || scratchpad_available()) && use_bbit_insns()) { |
865 | uasm_i_dmfc0(&p, K1, C0_ENTRYHI); | 1164 | htlb_info = build_fast_tlb_refill_handler(&p, &l, &r, K0, K1, |
866 | uasm_i_xor(&p, K0, K0, K1); | 1165 | scratch_reg); |
867 | uasm_i_dsrl_safe(&p, K1, K0, 62); | 1166 | vmalloc_mode = refill_scratch; |
868 | uasm_i_dsrl_safe(&p, K0, K0, 12 + 1); | 1167 | } else { |
869 | uasm_i_dsll_safe(&p, K0, K0, 64 + 12 + 1 - segbits); | 1168 | htlb_info.huge_pte = K0; |
870 | uasm_i_or(&p, K0, K0, K1); | 1169 | htlb_info.restore_scratch = 0; |
871 | uasm_il_bnez(&p, &r, K0, label_leave); | 1170 | vmalloc_mode = refill_noscratch; |
872 | /* No need for uasm_i_nop */ | 1171 | /* |
873 | } | 1172 | * create the plain linear handler |
1173 | */ | ||
1174 | if (bcm1250_m3_war()) { | ||
1175 | unsigned int segbits = 44; | ||
1176 | |||
1177 | uasm_i_dmfc0(&p, K0, C0_BADVADDR); | ||
1178 | uasm_i_dmfc0(&p, K1, C0_ENTRYHI); | ||
1179 | uasm_i_xor(&p, K0, K0, K1); | ||
1180 | uasm_i_dsrl_safe(&p, K1, K0, 62); | ||
1181 | uasm_i_dsrl_safe(&p, K0, K0, 12 + 1); | ||
1182 | uasm_i_dsll_safe(&p, K0, K0, 64 + 12 + 1 - segbits); | ||
1183 | uasm_i_or(&p, K0, K0, K1); | ||
1184 | uasm_il_bnez(&p, &r, K0, label_leave); | ||
1185 | /* No need for uasm_i_nop */ | ||
1186 | } | ||
874 | 1187 | ||
875 | #ifdef CONFIG_64BIT | 1188 | #ifdef CONFIG_64BIT |
876 | build_get_pmde64(&p, &l, &r, K0, K1); /* get pmd in K1 */ | 1189 | build_get_pmde64(&p, &l, &r, K0, K1); /* get pmd in K1 */ |
877 | #else | 1190 | #else |
878 | build_get_pgde32(&p, K0, K1); /* get pgd in K1 */ | 1191 | build_get_pgde32(&p, K0, K1); /* get pgd in K1 */ |
879 | #endif | 1192 | #endif |
880 | 1193 | ||
881 | #ifdef CONFIG_HUGETLB_PAGE | 1194 | #ifdef CONFIG_HUGETLB_PAGE |
882 | build_is_huge_pte(&p, &r, K0, K1, label_tlb_huge_update); | 1195 | build_is_huge_pte(&p, &r, K0, K1, label_tlb_huge_update); |
883 | #endif | 1196 | #endif |
884 | 1197 | ||
885 | build_get_ptep(&p, K0, K1); | 1198 | build_get_ptep(&p, K0, K1); |
886 | build_update_entries(&p, K0, K1); | 1199 | build_update_entries(&p, K0, K1); |
887 | build_tlb_write_entry(&p, &l, &r, tlb_random); | 1200 | build_tlb_write_entry(&p, &l, &r, tlb_random); |
888 | uasm_l_leave(&l, p); | 1201 | uasm_l_leave(&l, p); |
889 | uasm_i_eret(&p); /* return from trap */ | 1202 | uasm_i_eret(&p); /* return from trap */ |
890 | 1203 | } | |
891 | #ifdef CONFIG_HUGETLB_PAGE | 1204 | #ifdef CONFIG_HUGETLB_PAGE |
892 | uasm_l_tlb_huge_update(&l, p); | 1205 | uasm_l_tlb_huge_update(&l, p); |
893 | UASM_i_LW(&p, K0, 0, K1); | 1206 | build_huge_update_entries(&p, htlb_info.huge_pte, K1); |
894 | build_huge_update_entries(&p, K0, K1); | 1207 | build_huge_tlb_write_entry(&p, &l, &r, K0, tlb_random, |
895 | build_huge_tlb_write_entry(&p, &l, &r, K0, tlb_random); | 1208 | htlb_info.restore_scratch); |
896 | #endif | 1209 | #endif |
897 | 1210 | ||
898 | #ifdef CONFIG_64BIT | 1211 | #ifdef CONFIG_64BIT |
899 | build_get_pgd_vmalloc64(&p, &l, &r, K0, K1, refill); | 1212 | build_get_pgd_vmalloc64(&p, &l, &r, K0, K1, vmalloc_mode); |
900 | #endif | 1213 | #endif |
901 | 1214 | ||
902 | /* | 1215 | /* |
@@ -1014,6 +1327,55 @@ static void __cpuinit build_r4000_tlb_refill_handler(void) | |||
1014 | u32 handle_tlbl[FASTPATH_SIZE] __cacheline_aligned; | 1327 | u32 handle_tlbl[FASTPATH_SIZE] __cacheline_aligned; |
1015 | u32 handle_tlbs[FASTPATH_SIZE] __cacheline_aligned; | 1328 | u32 handle_tlbs[FASTPATH_SIZE] __cacheline_aligned; |
1016 | u32 handle_tlbm[FASTPATH_SIZE] __cacheline_aligned; | 1329 | u32 handle_tlbm[FASTPATH_SIZE] __cacheline_aligned; |
1330 | #ifdef CONFIG_MIPS_PGD_C0_CONTEXT | ||
1331 | u32 tlbmiss_handler_setup_pgd[16] __cacheline_aligned; | ||
1332 | |||
1333 | static void __cpuinit build_r4000_setup_pgd(void) | ||
1334 | { | ||
1335 | const int a0 = 4; | ||
1336 | const int a1 = 5; | ||
1337 | u32 *p = tlbmiss_handler_setup_pgd; | ||
1338 | struct uasm_label *l = labels; | ||
1339 | struct uasm_reloc *r = relocs; | ||
1340 | |||
1341 | memset(tlbmiss_handler_setup_pgd, 0, sizeof(tlbmiss_handler_setup_pgd)); | ||
1342 | memset(labels, 0, sizeof(labels)); | ||
1343 | memset(relocs, 0, sizeof(relocs)); | ||
1344 | |||
1345 | pgd_reg = allocate_kscratch(); | ||
1346 | |||
1347 | if (pgd_reg == -1) { | ||
1348 | /* PGD << 11 in c0_Context */ | ||
1349 | /* | ||
1350 | * If it is a ckseg0 address, convert to a physical | ||
1351 | * address. Shifting right by 29 and adding 4 will | ||
1352 | * result in zero for these addresses. | ||
1353 | * | ||
1354 | */ | ||
1355 | UASM_i_SRA(&p, a1, a0, 29); | ||
1356 | UASM_i_ADDIU(&p, a1, a1, 4); | ||
1357 | uasm_il_bnez(&p, &r, a1, label_tlbl_goaround1); | ||
1358 | uasm_i_nop(&p); | ||
1359 | uasm_i_dinsm(&p, a0, 0, 29, 64 - 29); | ||
1360 | uasm_l_tlbl_goaround1(&l, p); | ||
1361 | UASM_i_SLL(&p, a0, a0, 11); | ||
1362 | uasm_i_jr(&p, 31); | ||
1363 | UASM_i_MTC0(&p, a0, C0_CONTEXT); | ||
1364 | } else { | ||
1365 | /* PGD in c0_KScratch */ | ||
1366 | uasm_i_jr(&p, 31); | ||
1367 | UASM_i_MTC0(&p, a0, 31, pgd_reg); | ||
1368 | } | ||
1369 | if (p - tlbmiss_handler_setup_pgd > ARRAY_SIZE(tlbmiss_handler_setup_pgd)) | ||
1370 | panic("tlbmiss_handler_setup_pgd space exceeded"); | ||
1371 | uasm_resolve_relocs(relocs, labels); | ||
1372 | pr_debug("Wrote tlbmiss_handler_setup_pgd (%u instructions).\n", | ||
1373 | (unsigned int)(p - tlbmiss_handler_setup_pgd)); | ||
1374 | |||
1375 | dump_handler(tlbmiss_handler_setup_pgd, | ||
1376 | ARRAY_SIZE(tlbmiss_handler_setup_pgd)); | ||
1377 | } | ||
1378 | #endif | ||
1017 | 1379 | ||
1018 | static void __cpuinit | 1380 | static void __cpuinit |
1019 | iPTE_LW(u32 **p, unsigned int pte, unsigned int ptr) | 1381 | iPTE_LW(u32 **p, unsigned int pte, unsigned int ptr) |
@@ -1100,14 +1462,20 @@ build_pte_present(u32 **p, struct uasm_reloc **r, | |||
1100 | unsigned int pte, unsigned int ptr, enum label_id lid) | 1462 | unsigned int pte, unsigned int ptr, enum label_id lid) |
1101 | { | 1463 | { |
1102 | if (kernel_uses_smartmips_rixi) { | 1464 | if (kernel_uses_smartmips_rixi) { |
1103 | uasm_i_andi(p, pte, pte, _PAGE_PRESENT); | 1465 | if (use_bbit_insns()) { |
1104 | uasm_il_beqz(p, r, pte, lid); | 1466 | uasm_il_bbit0(p, r, pte, ilog2(_PAGE_PRESENT), lid); |
1467 | uasm_i_nop(p); | ||
1468 | } else { | ||
1469 | uasm_i_andi(p, pte, pte, _PAGE_PRESENT); | ||
1470 | uasm_il_beqz(p, r, pte, lid); | ||
1471 | iPTE_LW(p, pte, ptr); | ||
1472 | } | ||
1105 | } else { | 1473 | } else { |
1106 | uasm_i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_READ); | 1474 | uasm_i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_READ); |
1107 | uasm_i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_READ); | 1475 | uasm_i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_READ); |
1108 | uasm_il_bnez(p, r, pte, lid); | 1476 | uasm_il_bnez(p, r, pte, lid); |
1477 | iPTE_LW(p, pte, ptr); | ||
1109 | } | 1478 | } |
1110 | iPTE_LW(p, pte, ptr); | ||
1111 | } | 1479 | } |
1112 | 1480 | ||
1113 | /* Make PTE valid, store result in PTR. */ | 1481 | /* Make PTE valid, store result in PTR. */ |
@@ -1128,10 +1496,17 @@ static void __cpuinit | |||
1128 | build_pte_writable(u32 **p, struct uasm_reloc **r, | 1496 | build_pte_writable(u32 **p, struct uasm_reloc **r, |
1129 | unsigned int pte, unsigned int ptr, enum label_id lid) | 1497 | unsigned int pte, unsigned int ptr, enum label_id lid) |
1130 | { | 1498 | { |
1131 | uasm_i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE); | 1499 | if (use_bbit_insns()) { |
1132 | uasm_i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE); | 1500 | uasm_il_bbit0(p, r, pte, ilog2(_PAGE_PRESENT), lid); |
1133 | uasm_il_bnez(p, r, pte, lid); | 1501 | uasm_i_nop(p); |
1134 | iPTE_LW(p, pte, ptr); | 1502 | uasm_il_bbit0(p, r, pte, ilog2(_PAGE_WRITE), lid); |
1503 | uasm_i_nop(p); | ||
1504 | } else { | ||
1505 | uasm_i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE); | ||
1506 | uasm_i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE); | ||
1507 | uasm_il_bnez(p, r, pte, lid); | ||
1508 | iPTE_LW(p, pte, ptr); | ||
1509 | } | ||
1135 | } | 1510 | } |
1136 | 1511 | ||
1137 | /* Make PTE writable, update software status bits as well, then store | 1512 | /* Make PTE writable, update software status bits as well, then store |
@@ -1155,12 +1530,19 @@ static void __cpuinit | |||
1155 | build_pte_modifiable(u32 **p, struct uasm_reloc **r, | 1530 | build_pte_modifiable(u32 **p, struct uasm_reloc **r, |
1156 | unsigned int pte, unsigned int ptr, enum label_id lid) | 1531 | unsigned int pte, unsigned int ptr, enum label_id lid) |
1157 | { | 1532 | { |
1158 | uasm_i_andi(p, pte, pte, _PAGE_WRITE); | 1533 | if (use_bbit_insns()) { |
1159 | uasm_il_beqz(p, r, pte, lid); | 1534 | uasm_il_bbit0(p, r, pte, ilog2(_PAGE_WRITE), lid); |
1160 | iPTE_LW(p, pte, ptr); | 1535 | uasm_i_nop(p); |
1536 | } else { | ||
1537 | uasm_i_andi(p, pte, pte, _PAGE_WRITE); | ||
1538 | uasm_il_beqz(p, r, pte, lid); | ||
1539 | iPTE_LW(p, pte, ptr); | ||
1540 | } | ||
1161 | } | 1541 | } |
1162 | 1542 | ||
1163 | #ifndef CONFIG_MIPS_PGD_C0_CONTEXT | 1543 | #ifndef CONFIG_MIPS_PGD_C0_CONTEXT |
1544 | |||
1545 | |||
1164 | /* | 1546 | /* |
1165 | * R3000 style TLB load/store/modify handlers. | 1547 | * R3000 style TLB load/store/modify handlers. |
1166 | */ | 1548 | */ |
@@ -1402,14 +1784,23 @@ static void __cpuinit build_r4000_tlb_load_handler(void) | |||
1402 | * If the page is not _PAGE_VALID, RI or XI could not | 1784 | * If the page is not _PAGE_VALID, RI or XI could not |
1403 | * have triggered it. Skip the expensive test.. | 1785 | * have triggered it. Skip the expensive test.. |
1404 | */ | 1786 | */ |
1405 | uasm_i_andi(&p, K0, K0, _PAGE_VALID); | 1787 | if (use_bbit_insns()) { |
1406 | uasm_il_beqz(&p, &r, K0, label_tlbl_goaround1); | 1788 | uasm_il_bbit0(&p, &r, K0, ilog2(_PAGE_VALID), |
1789 | label_tlbl_goaround1); | ||
1790 | } else { | ||
1791 | uasm_i_andi(&p, K0, K0, _PAGE_VALID); | ||
1792 | uasm_il_beqz(&p, &r, K0, label_tlbl_goaround1); | ||
1793 | } | ||
1407 | uasm_i_nop(&p); | 1794 | uasm_i_nop(&p); |
1408 | 1795 | ||
1409 | uasm_i_tlbr(&p); | 1796 | uasm_i_tlbr(&p); |
1410 | /* Examine entrylo 0 or 1 based on ptr. */ | 1797 | /* Examine entrylo 0 or 1 based on ptr. */ |
1411 | uasm_i_andi(&p, K0, K1, sizeof(pte_t)); | 1798 | if (use_bbit_insns()) { |
1412 | uasm_i_beqz(&p, K0, 8); | 1799 | uasm_i_bbit0(&p, K1, ilog2(sizeof(pte_t)), 8); |
1800 | } else { | ||
1801 | uasm_i_andi(&p, K0, K1, sizeof(pte_t)); | ||
1802 | uasm_i_beqz(&p, K0, 8); | ||
1803 | } | ||
1413 | 1804 | ||
1414 | UASM_i_MFC0(&p, K0, C0_ENTRYLO0); /* load it in the delay slot*/ | 1805 | UASM_i_MFC0(&p, K0, C0_ENTRYLO0); /* load it in the delay slot*/ |
1415 | UASM_i_MFC0(&p, K0, C0_ENTRYLO1); /* load it if ptr is odd */ | 1806 | UASM_i_MFC0(&p, K0, C0_ENTRYLO1); /* load it if ptr is odd */ |
@@ -1417,12 +1808,18 @@ static void __cpuinit build_r4000_tlb_load_handler(void) | |||
1417 | * If the entryLo (now in K0) is valid (bit 1), RI or | 1808 | * If the entryLo (now in K0) is valid (bit 1), RI or |
1418 | * XI must have triggered it. | 1809 | * XI must have triggered it. |
1419 | */ | 1810 | */ |
1420 | uasm_i_andi(&p, K0, K0, 2); | 1811 | if (use_bbit_insns()) { |
1421 | uasm_il_bnez(&p, &r, K0, label_nopage_tlbl); | 1812 | uasm_il_bbit1(&p, &r, K0, 1, label_nopage_tlbl); |
1422 | 1813 | /* Reload the PTE value */ | |
1423 | uasm_l_tlbl_goaround1(&l, p); | 1814 | iPTE_LW(&p, K0, K1); |
1424 | /* Reload the PTE value */ | 1815 | uasm_l_tlbl_goaround1(&l, p); |
1425 | iPTE_LW(&p, K0, K1); | 1816 | } else { |
1817 | uasm_i_andi(&p, K0, K0, 2); | ||
1818 | uasm_il_bnez(&p, &r, K0, label_nopage_tlbl); | ||
1819 | uasm_l_tlbl_goaround1(&l, p); | ||
1820 | /* Reload the PTE value */ | ||
1821 | iPTE_LW(&p, K0, K1); | ||
1822 | } | ||
1426 | } | 1823 | } |
1427 | build_make_valid(&p, &r, K0, K1); | 1824 | build_make_valid(&p, &r, K0, K1); |
1428 | build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1); | 1825 | build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1); |
@@ -1442,23 +1839,35 @@ static void __cpuinit build_r4000_tlb_load_handler(void) | |||
1442 | * If the page is not _PAGE_VALID, RI or XI could not | 1839 | * If the page is not _PAGE_VALID, RI or XI could not |
1443 | * have triggered it. Skip the expensive test.. | 1840 | * have triggered it. Skip the expensive test.. |
1444 | */ | 1841 | */ |
1445 | uasm_i_andi(&p, K0, K0, _PAGE_VALID); | 1842 | if (use_bbit_insns()) { |
1446 | uasm_il_beqz(&p, &r, K0, label_tlbl_goaround2); | 1843 | uasm_il_bbit0(&p, &r, K0, ilog2(_PAGE_VALID), |
1844 | label_tlbl_goaround2); | ||
1845 | } else { | ||
1846 | uasm_i_andi(&p, K0, K0, _PAGE_VALID); | ||
1847 | uasm_il_beqz(&p, &r, K0, label_tlbl_goaround2); | ||
1848 | } | ||
1447 | uasm_i_nop(&p); | 1849 | uasm_i_nop(&p); |
1448 | 1850 | ||
1449 | uasm_i_tlbr(&p); | 1851 | uasm_i_tlbr(&p); |
1450 | /* Examine entrylo 0 or 1 based on ptr. */ | 1852 | /* Examine entrylo 0 or 1 based on ptr. */ |
1451 | uasm_i_andi(&p, K0, K1, sizeof(pte_t)); | 1853 | if (use_bbit_insns()) { |
1452 | uasm_i_beqz(&p, K0, 8); | 1854 | uasm_i_bbit0(&p, K1, ilog2(sizeof(pte_t)), 8); |
1453 | 1855 | } else { | |
1856 | uasm_i_andi(&p, K0, K1, sizeof(pte_t)); | ||
1857 | uasm_i_beqz(&p, K0, 8); | ||
1858 | } | ||
1454 | UASM_i_MFC0(&p, K0, C0_ENTRYLO0); /* load it in the delay slot*/ | 1859 | UASM_i_MFC0(&p, K0, C0_ENTRYLO0); /* load it in the delay slot*/ |
1455 | UASM_i_MFC0(&p, K0, C0_ENTRYLO1); /* load it if ptr is odd */ | 1860 | UASM_i_MFC0(&p, K0, C0_ENTRYLO1); /* load it if ptr is odd */ |
1456 | /* | 1861 | /* |
1457 | * If the entryLo (now in K0) is valid (bit 1), RI or | 1862 | * If the entryLo (now in K0) is valid (bit 1), RI or |
1458 | * XI must have triggered it. | 1863 | * XI must have triggered it. |
1459 | */ | 1864 | */ |
1460 | uasm_i_andi(&p, K0, K0, 2); | 1865 | if (use_bbit_insns()) { |
1461 | uasm_il_beqz(&p, &r, K0, label_tlbl_goaround2); | 1866 | uasm_il_bbit0(&p, &r, K0, 1, label_tlbl_goaround2); |
1867 | } else { | ||
1868 | uasm_i_andi(&p, K0, K0, 2); | ||
1869 | uasm_il_beqz(&p, &r, K0, label_tlbl_goaround2); | ||
1870 | } | ||
1462 | /* Reload the PTE value */ | 1871 | /* Reload the PTE value */ |
1463 | iPTE_LW(&p, K0, K1); | 1872 | iPTE_LW(&p, K0, K1); |
1464 | 1873 | ||
@@ -1466,7 +1875,7 @@ static void __cpuinit build_r4000_tlb_load_handler(void) | |||
1466 | * We clobbered C0_PAGEMASK, restore it. On the other branch | 1875 | * We clobbered C0_PAGEMASK, restore it. On the other branch |
1467 | * it is restored in build_huge_tlb_write_entry. | 1876 | * it is restored in build_huge_tlb_write_entry. |
1468 | */ | 1877 | */ |
1469 | build_restore_pagemask(&p, &r, K0, label_nopage_tlbl); | 1878 | build_restore_pagemask(&p, &r, K0, label_nopage_tlbl, 0); |
1470 | 1879 | ||
1471 | uasm_l_tlbl_goaround2(&l, p); | 1880 | uasm_l_tlbl_goaround2(&l, p); |
1472 | } | 1881 | } |
@@ -1623,13 +2032,16 @@ void __cpuinit build_tlb_refill_handler(void) | |||
1623 | break; | 2032 | break; |
1624 | 2033 | ||
1625 | default: | 2034 | default: |
1626 | build_r4000_tlb_refill_handler(); | ||
1627 | if (!run_once) { | 2035 | if (!run_once) { |
2036 | #ifdef CONFIG_MIPS_PGD_C0_CONTEXT | ||
2037 | build_r4000_setup_pgd(); | ||
2038 | #endif | ||
1628 | build_r4000_tlb_load_handler(); | 2039 | build_r4000_tlb_load_handler(); |
1629 | build_r4000_tlb_store_handler(); | 2040 | build_r4000_tlb_store_handler(); |
1630 | build_r4000_tlb_modify_handler(); | 2041 | build_r4000_tlb_modify_handler(); |
1631 | run_once++; | 2042 | run_once++; |
1632 | } | 2043 | } |
2044 | build_r4000_tlb_refill_handler(); | ||
1633 | } | 2045 | } |
1634 | } | 2046 | } |
1635 | 2047 | ||
@@ -1641,4 +2053,8 @@ void __cpuinit flush_tlb_handlers(void) | |||
1641 | (unsigned long)handle_tlbs + sizeof(handle_tlbs)); | 2053 | (unsigned long)handle_tlbs + sizeof(handle_tlbs)); |
1642 | local_flush_icache_range((unsigned long)handle_tlbm, | 2054 | local_flush_icache_range((unsigned long)handle_tlbm, |
1643 | (unsigned long)handle_tlbm + sizeof(handle_tlbm)); | 2055 | (unsigned long)handle_tlbm + sizeof(handle_tlbm)); |
2056 | #ifdef CONFIG_MIPS_PGD_C0_CONTEXT | ||
2057 | local_flush_icache_range((unsigned long)tlbmiss_handler_setup_pgd, | ||
2058 | (unsigned long)tlbmiss_handler_setup_pgd + sizeof(handle_tlbm)); | ||
2059 | #endif | ||
1644 | } | 2060 | } |
diff --git a/arch/mips/mm/uasm.c b/arch/mips/mm/uasm.c index 23afdebc8e5c..5fa185151fc8 100644 --- a/arch/mips/mm/uasm.c +++ b/arch/mips/mm/uasm.c | |||
@@ -68,7 +68,8 @@ enum opcode { | |||
68 | insn_pref, insn_rfe, insn_sc, insn_scd, insn_sd, insn_sll, | 68 | insn_pref, insn_rfe, insn_sc, insn_scd, insn_sd, insn_sll, |
69 | insn_sra, insn_srl, insn_rotr, insn_subu, insn_sw, insn_tlbp, | 69 | insn_sra, insn_srl, insn_rotr, insn_subu, insn_sw, insn_tlbp, |
70 | insn_tlbr, insn_tlbwi, insn_tlbwr, insn_xor, insn_xori, | 70 | insn_tlbr, insn_tlbwi, insn_tlbwr, insn_xor, insn_xori, |
71 | insn_dins, insn_syscall, insn_bbit0, insn_bbit1 | 71 | insn_dins, insn_dinsm, insn_syscall, insn_bbit0, insn_bbit1, |
72 | insn_lwx, insn_ldx | ||
72 | }; | 73 | }; |
73 | 74 | ||
74 | struct insn { | 75 | struct insn { |
@@ -142,9 +143,12 @@ static struct insn insn_table[] __uasminitdata = { | |||
142 | { insn_xor, M(spec_op, 0, 0, 0, 0, xor_op), RS | RT | RD }, | 143 | { insn_xor, M(spec_op, 0, 0, 0, 0, xor_op), RS | RT | RD }, |
143 | { insn_xori, M(xori_op, 0, 0, 0, 0, 0), RS | RT | UIMM }, | 144 | { insn_xori, M(xori_op, 0, 0, 0, 0, 0), RS | RT | UIMM }, |
144 | { insn_dins, M(spec3_op, 0, 0, 0, 0, dins_op), RS | RT | RD | RE }, | 145 | { insn_dins, M(spec3_op, 0, 0, 0, 0, dins_op), RS | RT | RD | RE }, |
146 | { insn_dinsm, M(spec3_op, 0, 0, 0, 0, dinsm_op), RS | RT | RD | RE }, | ||
145 | { insn_syscall, M(spec_op, 0, 0, 0, 0, syscall_op), SCIMM}, | 147 | { insn_syscall, M(spec_op, 0, 0, 0, 0, syscall_op), SCIMM}, |
146 | { insn_bbit0, M(lwc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM }, | 148 | { insn_bbit0, M(lwc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM }, |
147 | { insn_bbit1, M(swc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM }, | 149 | { insn_bbit1, M(swc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM }, |
150 | { insn_lwx, M(spec3_op, 0, 0, 0, lwx_op, lx_op), RS | RT | RD }, | ||
151 | { insn_ldx, M(spec3_op, 0, 0, 0, ldx_op, lx_op), RS | RT | RD }, | ||
148 | { insn_invalid, 0, 0 } | 152 | { insn_invalid, 0, 0 } |
149 | }; | 153 | }; |
150 | 154 | ||
@@ -152,91 +156,83 @@ static struct insn insn_table[] __uasminitdata = { | |||
152 | 156 | ||
153 | static inline __uasminit u32 build_rs(u32 arg) | 157 | static inline __uasminit u32 build_rs(u32 arg) |
154 | { | 158 | { |
155 | if (arg & ~RS_MASK) | 159 | WARN(arg & ~RS_MASK, KERN_WARNING "Micro-assembler field overflow\n"); |
156 | printk(KERN_WARNING "Micro-assembler field overflow\n"); | ||
157 | 160 | ||
158 | return (arg & RS_MASK) << RS_SH; | 161 | return (arg & RS_MASK) << RS_SH; |
159 | } | 162 | } |
160 | 163 | ||
161 | static inline __uasminit u32 build_rt(u32 arg) | 164 | static inline __uasminit u32 build_rt(u32 arg) |
162 | { | 165 | { |
163 | if (arg & ~RT_MASK) | 166 | WARN(arg & ~RT_MASK, KERN_WARNING "Micro-assembler field overflow\n"); |
164 | printk(KERN_WARNING "Micro-assembler field overflow\n"); | ||
165 | 167 | ||
166 | return (arg & RT_MASK) << RT_SH; | 168 | return (arg & RT_MASK) << RT_SH; |
167 | } | 169 | } |
168 | 170 | ||
169 | static inline __uasminit u32 build_rd(u32 arg) | 171 | static inline __uasminit u32 build_rd(u32 arg) |
170 | { | 172 | { |
171 | if (arg & ~RD_MASK) | 173 | WARN(arg & ~RD_MASK, KERN_WARNING "Micro-assembler field overflow\n"); |
172 | printk(KERN_WARNING "Micro-assembler field overflow\n"); | ||
173 | 174 | ||
174 | return (arg & RD_MASK) << RD_SH; | 175 | return (arg & RD_MASK) << RD_SH; |
175 | } | 176 | } |
176 | 177 | ||
177 | static inline __uasminit u32 build_re(u32 arg) | 178 | static inline __uasminit u32 build_re(u32 arg) |
178 | { | 179 | { |
179 | if (arg & ~RE_MASK) | 180 | WARN(arg & ~RE_MASK, KERN_WARNING "Micro-assembler field overflow\n"); |
180 | printk(KERN_WARNING "Micro-assembler field overflow\n"); | ||
181 | 181 | ||
182 | return (arg & RE_MASK) << RE_SH; | 182 | return (arg & RE_MASK) << RE_SH; |
183 | } | 183 | } |
184 | 184 | ||
185 | static inline __uasminit u32 build_simm(s32 arg) | 185 | static inline __uasminit u32 build_simm(s32 arg) |
186 | { | 186 | { |
187 | if (arg > 0x7fff || arg < -0x8000) | 187 | WARN(arg > 0x7fff || arg < -0x8000, |
188 | printk(KERN_WARNING "Micro-assembler field overflow\n"); | 188 | KERN_WARNING "Micro-assembler field overflow\n"); |
189 | 189 | ||
190 | return arg & 0xffff; | 190 | return arg & 0xffff; |
191 | } | 191 | } |
192 | 192 | ||
193 | static inline __uasminit u32 build_uimm(u32 arg) | 193 | static inline __uasminit u32 build_uimm(u32 arg) |
194 | { | 194 | { |
195 | if (arg & ~IMM_MASK) | 195 | WARN(arg & ~IMM_MASK, KERN_WARNING "Micro-assembler field overflow\n"); |
196 | printk(KERN_WARNING "Micro-assembler field overflow\n"); | ||
197 | 196 | ||
198 | return arg & IMM_MASK; | 197 | return arg & IMM_MASK; |
199 | } | 198 | } |
200 | 199 | ||
201 | static inline __uasminit u32 build_bimm(s32 arg) | 200 | static inline __uasminit u32 build_bimm(s32 arg) |
202 | { | 201 | { |
203 | if (arg > 0x1ffff || arg < -0x20000) | 202 | WARN(arg > 0x1ffff || arg < -0x20000, |
204 | printk(KERN_WARNING "Micro-assembler field overflow\n"); | 203 | KERN_WARNING "Micro-assembler field overflow\n"); |
205 | 204 | ||
206 | if (arg & 0x3) | 205 | WARN(arg & 0x3, KERN_WARNING "Invalid micro-assembler branch target\n"); |
207 | printk(KERN_WARNING "Invalid micro-assembler branch target\n"); | ||
208 | 206 | ||
209 | return ((arg < 0) ? (1 << 15) : 0) | ((arg >> 2) & 0x7fff); | 207 | return ((arg < 0) ? (1 << 15) : 0) | ((arg >> 2) & 0x7fff); |
210 | } | 208 | } |
211 | 209 | ||
212 | static inline __uasminit u32 build_jimm(u32 arg) | 210 | static inline __uasminit u32 build_jimm(u32 arg) |
213 | { | 211 | { |
214 | if (arg & ~((JIMM_MASK) << 2)) | 212 | WARN(arg & ~(JIMM_MASK << 2), |
215 | printk(KERN_WARNING "Micro-assembler field overflow\n"); | 213 | KERN_WARNING "Micro-assembler field overflow\n"); |
216 | 214 | ||
217 | return (arg >> 2) & JIMM_MASK; | 215 | return (arg >> 2) & JIMM_MASK; |
218 | } | 216 | } |
219 | 217 | ||
220 | static inline __uasminit u32 build_scimm(u32 arg) | 218 | static inline __uasminit u32 build_scimm(u32 arg) |
221 | { | 219 | { |
222 | if (arg & ~SCIMM_MASK) | 220 | WARN(arg & ~SCIMM_MASK, |
223 | printk(KERN_WARNING "Micro-assembler field overflow\n"); | 221 | KERN_WARNING "Micro-assembler field overflow\n"); |
224 | 222 | ||
225 | return (arg & SCIMM_MASK) << SCIMM_SH; | 223 | return (arg & SCIMM_MASK) << SCIMM_SH; |
226 | } | 224 | } |
227 | 225 | ||
228 | static inline __uasminit u32 build_func(u32 arg) | 226 | static inline __uasminit u32 build_func(u32 arg) |
229 | { | 227 | { |
230 | if (arg & ~FUNC_MASK) | 228 | WARN(arg & ~FUNC_MASK, KERN_WARNING "Micro-assembler field overflow\n"); |
231 | printk(KERN_WARNING "Micro-assembler field overflow\n"); | ||
232 | 229 | ||
233 | return arg & FUNC_MASK; | 230 | return arg & FUNC_MASK; |
234 | } | 231 | } |
235 | 232 | ||
236 | static inline __uasminit u32 build_set(u32 arg) | 233 | static inline __uasminit u32 build_set(u32 arg) |
237 | { | 234 | { |
238 | if (arg & ~SET_MASK) | 235 | WARN(arg & ~SET_MASK, KERN_WARNING "Micro-assembler field overflow\n"); |
239 | printk(KERN_WARNING "Micro-assembler field overflow\n"); | ||
240 | 236 | ||
241 | return arg & SET_MASK; | 237 | return arg & SET_MASK; |
242 | } | 238 | } |
@@ -340,6 +336,13 @@ Ip_u2u1msbu3(op) \ | |||
340 | } \ | 336 | } \ |
341 | UASM_EXPORT_SYMBOL(uasm_i##op); | 337 | UASM_EXPORT_SYMBOL(uasm_i##op); |
342 | 338 | ||
339 | #define I_u2u1msb32u3(op) \ | ||
340 | Ip_u2u1msbu3(op) \ | ||
341 | { \ | ||
342 | build_insn(buf, insn##op, b, a, c+d-33, c); \ | ||
343 | } \ | ||
344 | UASM_EXPORT_SYMBOL(uasm_i##op); | ||
345 | |||
343 | #define I_u1u2(op) \ | 346 | #define I_u1u2(op) \ |
344 | Ip_u1u2(op) \ | 347 | Ip_u1u2(op) \ |
345 | { \ | 348 | { \ |
@@ -422,9 +425,12 @@ I_0(_tlbwr) | |||
422 | I_u3u1u2(_xor) | 425 | I_u3u1u2(_xor) |
423 | I_u2u1u3(_xori) | 426 | I_u2u1u3(_xori) |
424 | I_u2u1msbu3(_dins); | 427 | I_u2u1msbu3(_dins); |
428 | I_u2u1msb32u3(_dinsm); | ||
425 | I_u1(_syscall); | 429 | I_u1(_syscall); |
426 | I_u1u2s3(_bbit0); | 430 | I_u1u2s3(_bbit0); |
427 | I_u1u2s3(_bbit1); | 431 | I_u1u2s3(_bbit1); |
432 | I_u3u1u2(_lwx) | ||
433 | I_u3u1u2(_ldx) | ||
428 | 434 | ||
429 | #ifdef CONFIG_CPU_CAVIUM_OCTEON | 435 | #ifdef CONFIG_CPU_CAVIUM_OCTEON |
430 | #include <asm/octeon/octeon.h> | 436 | #include <asm/octeon/octeon.h> |
diff --git a/arch/mips/sibyte/common/sb_tbprof.c b/arch/mips/sibyte/common/sb_tbprof.c index 87ccdb4b5ac9..48853ab5bcf0 100644 --- a/arch/mips/sibyte/common/sb_tbprof.c +++ b/arch/mips/sibyte/common/sb_tbprof.c | |||
@@ -410,14 +410,13 @@ static int sbprof_tb_open(struct inode *inode, struct file *filp) | |||
410 | return -EBUSY; | 410 | return -EBUSY; |
411 | 411 | ||
412 | memset(&sbp, 0, sizeof(struct sbprof_tb)); | 412 | memset(&sbp, 0, sizeof(struct sbprof_tb)); |
413 | sbp.sbprof_tbbuf = vmalloc(MAX_TBSAMPLE_BYTES); | 413 | sbp.sbprof_tbbuf = vzalloc(MAX_TBSAMPLE_BYTES); |
414 | if (!sbp.sbprof_tbbuf) { | 414 | if (!sbp.sbprof_tbbuf) { |
415 | sbp.open = SB_CLOSED; | 415 | sbp.open = SB_CLOSED; |
416 | wmb(); | 416 | wmb(); |
417 | return -ENOMEM; | 417 | return -ENOMEM; |
418 | } | 418 | } |
419 | 419 | ||
420 | memset(sbp.sbprof_tbbuf, 0, MAX_TBSAMPLE_BYTES); | ||
421 | init_waitqueue_head(&sbp.tb_sync); | 420 | init_waitqueue_head(&sbp.tb_sync); |
422 | init_waitqueue_head(&sbp.tb_read); | 421 | init_waitqueue_head(&sbp.tb_read); |
423 | mutex_init(&sbp.lock); | 422 | mutex_init(&sbp.lock); |
diff --git a/arch/mips/txx9/generic/pci.c b/arch/mips/txx9/generic/pci.c index 96e69a00ffc8..85a87de17eb4 100644 --- a/arch/mips/txx9/generic/pci.c +++ b/arch/mips/txx9/generic/pci.c | |||
@@ -213,11 +213,8 @@ txx9_alloc_pci_controller(struct pci_controller *pcic, | |||
213 | 213 | ||
214 | pcic->mem_offset = 0; /* busaddr == physaddr */ | 214 | pcic->mem_offset = 0; /* busaddr == physaddr */ |
215 | 215 | ||
216 | printk(KERN_INFO "PCI: IO 0x%08llx-0x%08llx MEM 0x%08llx-0x%08llx\n", | 216 | printk(KERN_INFO "PCI: IO %pR MEM %pR\n", |
217 | (unsigned long long)pcic->mem_resource[1].start, | 217 | &pcic->mem_resource[1], &pcic->mem_resource[0]); |
218 | (unsigned long long)pcic->mem_resource[1].end, | ||
219 | (unsigned long long)pcic->mem_resource[0].start, | ||
220 | (unsigned long long)pcic->mem_resource[0].end); | ||
221 | 218 | ||
222 | /* register_pci_controller() will request MEM resource */ | 219 | /* register_pci_controller() will request MEM resource */ |
223 | release_resource(&pcic->mem_resource[0]); | 220 | release_resource(&pcic->mem_resource[0]); |
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 13bfa9d48082..bb233a9cbad2 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig | |||
@@ -53,6 +53,14 @@ if SPI_MASTER | |||
53 | 53 | ||
54 | comment "SPI Master Controller Drivers" | 54 | comment "SPI Master Controller Drivers" |
55 | 55 | ||
56 | config SPI_ATH79 | ||
57 | tristate "Atheros AR71XX/AR724X/AR913X SPI controller driver" | ||
58 | depends on ATH79 && GENERIC_GPIO | ||
59 | select SPI_BITBANG | ||
60 | help | ||
61 | This enables support for the SPI controller present on the | ||
62 | Atheros AR71XX/AR724X/AR913X SoCs. | ||
63 | |||
56 | config SPI_ATMEL | 64 | config SPI_ATMEL |
57 | tristate "Atmel SPI Controller" | 65 | tristate "Atmel SPI Controller" |
58 | depends on (ARCH_AT91 || AVR32) | 66 | depends on (ARCH_AT91 || AVR32) |
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 3a42463c92a4..86d1b5f9bbd9 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile | |||
@@ -10,6 +10,7 @@ obj-$(CONFIG_SPI_MASTER) += spi.o | |||
10 | 10 | ||
11 | # SPI master controller drivers (bus) | 11 | # SPI master controller drivers (bus) |
12 | obj-$(CONFIG_SPI_ATMEL) += atmel_spi.o | 12 | obj-$(CONFIG_SPI_ATMEL) += atmel_spi.o |
13 | obj-$(CONFIG_SPI_ATH79) += ath79_spi.o | ||
13 | obj-$(CONFIG_SPI_BFIN) += spi_bfin5xx.o | 14 | obj-$(CONFIG_SPI_BFIN) += spi_bfin5xx.o |
14 | obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o | 15 | obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o |
15 | obj-$(CONFIG_SPI_AU1550) += au1550_spi.o | 16 | obj-$(CONFIG_SPI_AU1550) += au1550_spi.o |
diff --git a/drivers/spi/ath79_spi.c b/drivers/spi/ath79_spi.c new file mode 100644 index 000000000000..fcff810ea3b0 --- /dev/null +++ b/drivers/spi/ath79_spi.c | |||
@@ -0,0 +1,292 @@ | |||
1 | /* | ||
2 | * SPI controller driver for the Atheros AR71XX/AR724X/AR913X SoCs | ||
3 | * | ||
4 | * Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org> | ||
5 | * | ||
6 | * This driver has been based on the spi-gpio.c: | ||
7 | * Copyright (C) 2006,2008 David Brownell | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/spinlock.h> | ||
19 | #include <linux/workqueue.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/io.h> | ||
22 | #include <linux/spi/spi.h> | ||
23 | #include <linux/spi/spi_bitbang.h> | ||
24 | #include <linux/bitops.h> | ||
25 | #include <linux/gpio.h> | ||
26 | |||
27 | #include <asm/mach-ath79/ar71xx_regs.h> | ||
28 | #include <asm/mach-ath79/ath79_spi_platform.h> | ||
29 | |||
30 | #define DRV_NAME "ath79-spi" | ||
31 | |||
32 | struct ath79_spi { | ||
33 | struct spi_bitbang bitbang; | ||
34 | u32 ioc_base; | ||
35 | u32 reg_ctrl; | ||
36 | void __iomem *base; | ||
37 | }; | ||
38 | |||
39 | static inline u32 ath79_spi_rr(struct ath79_spi *sp, unsigned reg) | ||
40 | { | ||
41 | return ioread32(sp->base + reg); | ||
42 | } | ||
43 | |||
44 | static inline void ath79_spi_wr(struct ath79_spi *sp, unsigned reg, u32 val) | ||
45 | { | ||
46 | iowrite32(val, sp->base + reg); | ||
47 | } | ||
48 | |||
49 | static inline struct ath79_spi *ath79_spidev_to_sp(struct spi_device *spi) | ||
50 | { | ||
51 | return spi_master_get_devdata(spi->master); | ||
52 | } | ||
53 | |||
54 | static void ath79_spi_chipselect(struct spi_device *spi, int is_active) | ||
55 | { | ||
56 | struct ath79_spi *sp = ath79_spidev_to_sp(spi); | ||
57 | int cs_high = (spi->mode & SPI_CS_HIGH) ? is_active : !is_active; | ||
58 | |||
59 | if (is_active) { | ||
60 | /* set initial clock polarity */ | ||
61 | if (spi->mode & SPI_CPOL) | ||
62 | sp->ioc_base |= AR71XX_SPI_IOC_CLK; | ||
63 | else | ||
64 | sp->ioc_base &= ~AR71XX_SPI_IOC_CLK; | ||
65 | |||
66 | ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base); | ||
67 | } | ||
68 | |||
69 | if (spi->chip_select) { | ||
70 | struct ath79_spi_controller_data *cdata = spi->controller_data; | ||
71 | |||
72 | /* SPI is normally active-low */ | ||
73 | gpio_set_value(cdata->gpio, cs_high); | ||
74 | } else { | ||
75 | if (cs_high) | ||
76 | sp->ioc_base |= AR71XX_SPI_IOC_CS0; | ||
77 | else | ||
78 | sp->ioc_base &= ~AR71XX_SPI_IOC_CS0; | ||
79 | |||
80 | ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base); | ||
81 | } | ||
82 | |||
83 | } | ||
84 | |||
85 | static int ath79_spi_setup_cs(struct spi_device *spi) | ||
86 | { | ||
87 | struct ath79_spi *sp = ath79_spidev_to_sp(spi); | ||
88 | struct ath79_spi_controller_data *cdata; | ||
89 | |||
90 | cdata = spi->controller_data; | ||
91 | if (spi->chip_select && !cdata) | ||
92 | return -EINVAL; | ||
93 | |||
94 | /* enable GPIO mode */ | ||
95 | ath79_spi_wr(sp, AR71XX_SPI_REG_FS, AR71XX_SPI_FS_GPIO); | ||
96 | |||
97 | /* save CTRL register */ | ||
98 | sp->reg_ctrl = ath79_spi_rr(sp, AR71XX_SPI_REG_CTRL); | ||
99 | sp->ioc_base = ath79_spi_rr(sp, AR71XX_SPI_REG_IOC); | ||
100 | |||
101 | /* TODO: setup speed? */ | ||
102 | ath79_spi_wr(sp, AR71XX_SPI_REG_CTRL, 0x43); | ||
103 | |||
104 | if (spi->chip_select) { | ||
105 | int status = 0; | ||
106 | |||
107 | status = gpio_request(cdata->gpio, dev_name(&spi->dev)); | ||
108 | if (status) | ||
109 | return status; | ||
110 | |||
111 | status = gpio_direction_output(cdata->gpio, | ||
112 | spi->mode & SPI_CS_HIGH); | ||
113 | if (status) { | ||
114 | gpio_free(cdata->gpio); | ||
115 | return status; | ||
116 | } | ||
117 | } else { | ||
118 | if (spi->mode & SPI_CS_HIGH) | ||
119 | sp->ioc_base |= AR71XX_SPI_IOC_CS0; | ||
120 | else | ||
121 | sp->ioc_base &= ~AR71XX_SPI_IOC_CS0; | ||
122 | ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base); | ||
123 | } | ||
124 | |||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | static void ath79_spi_cleanup_cs(struct spi_device *spi) | ||
129 | { | ||
130 | struct ath79_spi *sp = ath79_spidev_to_sp(spi); | ||
131 | |||
132 | if (spi->chip_select) { | ||
133 | struct ath79_spi_controller_data *cdata = spi->controller_data; | ||
134 | gpio_free(cdata->gpio); | ||
135 | } | ||
136 | |||
137 | /* restore CTRL register */ | ||
138 | ath79_spi_wr(sp, AR71XX_SPI_REG_CTRL, sp->reg_ctrl); | ||
139 | /* disable GPIO mode */ | ||
140 | ath79_spi_wr(sp, AR71XX_SPI_REG_FS, 0); | ||
141 | } | ||
142 | |||
143 | static int ath79_spi_setup(struct spi_device *spi) | ||
144 | { | ||
145 | int status = 0; | ||
146 | |||
147 | if (spi->bits_per_word > 32) | ||
148 | return -EINVAL; | ||
149 | |||
150 | if (!spi->controller_state) { | ||
151 | status = ath79_spi_setup_cs(spi); | ||
152 | if (status) | ||
153 | return status; | ||
154 | } | ||
155 | |||
156 | status = spi_bitbang_setup(spi); | ||
157 | if (status && !spi->controller_state) | ||
158 | ath79_spi_cleanup_cs(spi); | ||
159 | |||
160 | return status; | ||
161 | } | ||
162 | |||
163 | static void ath79_spi_cleanup(struct spi_device *spi) | ||
164 | { | ||
165 | ath79_spi_cleanup_cs(spi); | ||
166 | spi_bitbang_cleanup(spi); | ||
167 | } | ||
168 | |||
169 | static u32 ath79_spi_txrx_mode0(struct spi_device *spi, unsigned nsecs, | ||
170 | u32 word, u8 bits) | ||
171 | { | ||
172 | struct ath79_spi *sp = ath79_spidev_to_sp(spi); | ||
173 | u32 ioc = sp->ioc_base; | ||
174 | |||
175 | /* clock starts at inactive polarity */ | ||
176 | for (word <<= (32 - bits); likely(bits); bits--) { | ||
177 | u32 out; | ||
178 | |||
179 | if (word & (1 << 31)) | ||
180 | out = ioc | AR71XX_SPI_IOC_DO; | ||
181 | else | ||
182 | out = ioc & ~AR71XX_SPI_IOC_DO; | ||
183 | |||
184 | /* setup MSB (to slave) on trailing edge */ | ||
185 | ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, out); | ||
186 | ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, out | AR71XX_SPI_IOC_CLK); | ||
187 | |||
188 | word <<= 1; | ||
189 | } | ||
190 | |||
191 | return ath79_spi_rr(sp, AR71XX_SPI_REG_RDS); | ||
192 | } | ||
193 | |||
194 | static __devinit int ath79_spi_probe(struct platform_device *pdev) | ||
195 | { | ||
196 | struct spi_master *master; | ||
197 | struct ath79_spi *sp; | ||
198 | struct ath79_spi_platform_data *pdata; | ||
199 | struct resource *r; | ||
200 | int ret; | ||
201 | |||
202 | master = spi_alloc_master(&pdev->dev, sizeof(*sp)); | ||
203 | if (master == NULL) { | ||
204 | dev_err(&pdev->dev, "failed to allocate spi master\n"); | ||
205 | return -ENOMEM; | ||
206 | } | ||
207 | |||
208 | sp = spi_master_get_devdata(master); | ||
209 | platform_set_drvdata(pdev, sp); | ||
210 | |||
211 | pdata = pdev->dev.platform_data; | ||
212 | |||
213 | master->setup = ath79_spi_setup; | ||
214 | master->cleanup = ath79_spi_cleanup; | ||
215 | if (pdata) { | ||
216 | master->bus_num = pdata->bus_num; | ||
217 | master->num_chipselect = pdata->num_chipselect; | ||
218 | } else { | ||
219 | master->bus_num = -1; | ||
220 | master->num_chipselect = 1; | ||
221 | } | ||
222 | |||
223 | sp->bitbang.master = spi_master_get(master); | ||
224 | sp->bitbang.chipselect = ath79_spi_chipselect; | ||
225 | sp->bitbang.txrx_word[SPI_MODE_0] = ath79_spi_txrx_mode0; | ||
226 | sp->bitbang.setup_transfer = spi_bitbang_setup_transfer; | ||
227 | sp->bitbang.flags = SPI_CS_HIGH; | ||
228 | |||
229 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
230 | if (r == NULL) { | ||
231 | ret = -ENOENT; | ||
232 | goto err_put_master; | ||
233 | } | ||
234 | |||
235 | sp->base = ioremap(r->start, r->end - r->start + 1); | ||
236 | if (!sp->base) { | ||
237 | ret = -ENXIO; | ||
238 | goto err_put_master; | ||
239 | } | ||
240 | |||
241 | ret = spi_bitbang_start(&sp->bitbang); | ||
242 | if (ret) | ||
243 | goto err_unmap; | ||
244 | |||
245 | return 0; | ||
246 | |||
247 | err_unmap: | ||
248 | iounmap(sp->base); | ||
249 | err_put_master: | ||
250 | platform_set_drvdata(pdev, NULL); | ||
251 | spi_master_put(sp->bitbang.master); | ||
252 | |||
253 | return ret; | ||
254 | } | ||
255 | |||
256 | static __devexit int ath79_spi_remove(struct platform_device *pdev) | ||
257 | { | ||
258 | struct ath79_spi *sp = platform_get_drvdata(pdev); | ||
259 | |||
260 | spi_bitbang_stop(&sp->bitbang); | ||
261 | iounmap(sp->base); | ||
262 | platform_set_drvdata(pdev, NULL); | ||
263 | spi_master_put(sp->bitbang.master); | ||
264 | |||
265 | return 0; | ||
266 | } | ||
267 | |||
268 | static struct platform_driver ath79_spi_driver = { | ||
269 | .probe = ath79_spi_probe, | ||
270 | .remove = __devexit_p(ath79_spi_remove), | ||
271 | .driver = { | ||
272 | .name = DRV_NAME, | ||
273 | .owner = THIS_MODULE, | ||
274 | }, | ||
275 | }; | ||
276 | |||
277 | static __init int ath79_spi_init(void) | ||
278 | { | ||
279 | return platform_driver_register(&ath79_spi_driver); | ||
280 | } | ||
281 | module_init(ath79_spi_init); | ||
282 | |||
283 | static __exit void ath79_spi_exit(void) | ||
284 | { | ||
285 | platform_driver_unregister(&ath79_spi_driver); | ||
286 | } | ||
287 | module_exit(ath79_spi_exit); | ||
288 | |||
289 | MODULE_DESCRIPTION("SPI controller driver for Atheros AR71XX/AR724X/AR913X"); | ||
290 | MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>"); | ||
291 | MODULE_LICENSE("GPL v2"); | ||
292 | MODULE_ALIAS("platform:" DRV_NAME); | ||