diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2008-09-16 13:12:16 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2008-10-11 11:18:50 -0400 |
commit | e8c7c482347574ecdd45c43e32c332d5fc2ece61 (patch) | |
tree | c741aa6cdb4e897df9f9476d83a816a7a2b058dd /arch/mips/alchemy/common | |
parent | 8d2d91e86b4153cc2305ec86fe908048f459ff7f (diff) |
MIPS: Alchemy: rename directory
It's more than the au1000 these days.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/alchemy/common')
-rw-r--r-- | arch/mips/alchemy/common/Makefile | 14 | ||||
-rw-r--r-- | arch/mips/alchemy/common/au1xxx_irqmap.c | 205 | ||||
-rw-r--r-- | arch/mips/alchemy/common/clocks.c | 93 | ||||
-rw-r--r-- | arch/mips/alchemy/common/cputable.c | 52 | ||||
-rw-r--r-- | arch/mips/alchemy/common/dbdma.c | 978 | ||||
-rw-r--r-- | arch/mips/alchemy/common/dma.c | 238 | ||||
-rw-r--r-- | arch/mips/alchemy/common/gpio.c | 148 | ||||
-rw-r--r-- | arch/mips/alchemy/common/irq.c | 596 | ||||
-rw-r--r-- | arch/mips/alchemy/common/pci.c | 104 | ||||
-rw-r--r-- | arch/mips/alchemy/common/platform.c | 319 | ||||
-rw-r--r-- | arch/mips/alchemy/common/power.c | 465 | ||||
-rw-r--r-- | arch/mips/alchemy/common/prom.c | 146 | ||||
-rw-r--r-- | arch/mips/alchemy/common/puts.c | 68 | ||||
-rw-r--r-- | arch/mips/alchemy/common/reset.c | 189 | ||||
-rw-r--r-- | arch/mips/alchemy/common/setup.c | 160 | ||||
-rw-r--r-- | arch/mips/alchemy/common/sleeper.S | 154 | ||||
-rw-r--r-- | arch/mips/alchemy/common/time.c | 266 |
17 files changed, 4195 insertions, 0 deletions
diff --git a/arch/mips/alchemy/common/Makefile b/arch/mips/alchemy/common/Makefile new file mode 100644 index 000000000000..df48fd65bbf3 --- /dev/null +++ b/arch/mips/alchemy/common/Makefile | |||
@@ -0,0 +1,14 @@ | |||
1 | # | ||
2 | # Copyright 2000, 2008 MontaVista Software Inc. | ||
3 | # Author: MontaVista Software, Inc. <source@mvista.com> | ||
4 | # | ||
5 | # Makefile for the Alchemy Au1xx0 CPUs, generic files. | ||
6 | # | ||
7 | |||
8 | obj-y += prom.o irq.o puts.o time.o reset.o \ | ||
9 | au1xxx_irqmap.o clocks.o platform.o power.o setup.o \ | ||
10 | sleeper.o cputable.o dma.o dbdma.o gpio.o | ||
11 | |||
12 | obj-$(CONFIG_PCI) += pci.o | ||
13 | |||
14 | EXTRA_CFLAGS += -Werror | ||
diff --git a/arch/mips/alchemy/common/au1xxx_irqmap.c b/arch/mips/alchemy/common/au1xxx_irqmap.c new file mode 100644 index 000000000000..c7ca1596394c --- /dev/null +++ b/arch/mips/alchemy/common/au1xxx_irqmap.c | |||
@@ -0,0 +1,205 @@ | |||
1 | /* | ||
2 | * BRIEF MODULE DESCRIPTION | ||
3 | * Au1xxx processor specific IRQ tables | ||
4 | * | ||
5 | * Copyright 2004 Embedded Edge, LLC | ||
6 | * dan@embeddededge.com | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
14 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
15 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
16 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
17 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
18 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
19 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
20 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
22 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License along | ||
25 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
26 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
27 | */ | ||
28 | #include <linux/init.h> | ||
29 | #include <linux/kernel.h> | ||
30 | |||
31 | #include <au1000.h> | ||
32 | |||
33 | /* The IC0 interrupt table. This is processor, rather than | ||
34 | * board dependent, so no reason to keep this info in the board | ||
35 | * dependent files. | ||
36 | * | ||
37 | * Careful if you change match 2 request! | ||
38 | * The interrupt handler is called directly from the low level dispatch code. | ||
39 | */ | ||
40 | struct au1xxx_irqmap __initdata au1xxx_ic0_map[] = { | ||
41 | |||
42 | #if defined(CONFIG_SOC_AU1000) | ||
43 | { AU1000_UART0_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
44 | { AU1000_UART1_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
45 | { AU1000_UART2_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
46 | { AU1000_UART3_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
47 | { AU1000_SSI0_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
48 | { AU1000_SSI1_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
49 | { AU1000_DMA_INT_BASE, INTC_INT_HIGH_LEVEL, 0 }, | ||
50 | { AU1000_DMA_INT_BASE+1, INTC_INT_HIGH_LEVEL, 0 }, | ||
51 | { AU1000_DMA_INT_BASE+2, INTC_INT_HIGH_LEVEL, 0 }, | ||
52 | { AU1000_DMA_INT_BASE+3, INTC_INT_HIGH_LEVEL, 0 }, | ||
53 | { AU1000_DMA_INT_BASE+4, INTC_INT_HIGH_LEVEL, 0 }, | ||
54 | { AU1000_DMA_INT_BASE+5, INTC_INT_HIGH_LEVEL, 0 }, | ||
55 | { AU1000_DMA_INT_BASE+6, INTC_INT_HIGH_LEVEL, 0 }, | ||
56 | { AU1000_DMA_INT_BASE+7, INTC_INT_HIGH_LEVEL, 0 }, | ||
57 | { AU1000_TOY_INT, INTC_INT_RISE_EDGE, 0 }, | ||
58 | { AU1000_TOY_MATCH0_INT, INTC_INT_RISE_EDGE, 0 }, | ||
59 | { AU1000_TOY_MATCH1_INT, INTC_INT_RISE_EDGE, 0 }, | ||
60 | { AU1000_TOY_MATCH2_INT, INTC_INT_RISE_EDGE, 1 }, | ||
61 | { AU1000_RTC_INT, INTC_INT_RISE_EDGE, 0 }, | ||
62 | { AU1000_RTC_MATCH0_INT, INTC_INT_RISE_EDGE, 0 }, | ||
63 | { AU1000_RTC_MATCH1_INT, INTC_INT_RISE_EDGE, 0 }, | ||
64 | { AU1000_RTC_MATCH2_INT, INTC_INT_RISE_EDGE, 0 }, | ||
65 | { AU1000_IRDA_TX_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
66 | { AU1000_IRDA_RX_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
67 | { AU1000_USB_DEV_REQ_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
68 | { AU1000_USB_DEV_SUS_INT, INTC_INT_RISE_EDGE, 0 }, | ||
69 | { AU1000_USB_HOST_INT, INTC_INT_LOW_LEVEL, 0 }, | ||
70 | { AU1000_ACSYNC_INT, INTC_INT_RISE_EDGE, 0 }, | ||
71 | { AU1000_MAC0_DMA_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
72 | { AU1000_MAC1_DMA_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
73 | { AU1000_AC97C_INT, INTC_INT_RISE_EDGE, 0 }, | ||
74 | |||
75 | #elif defined(CONFIG_SOC_AU1500) | ||
76 | |||
77 | { AU1500_UART0_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
78 | { AU1000_PCI_INTA, INTC_INT_LOW_LEVEL, 0 }, | ||
79 | { AU1000_PCI_INTB, INTC_INT_LOW_LEVEL, 0 }, | ||
80 | { AU1500_UART3_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
81 | { AU1000_PCI_INTC, INTC_INT_LOW_LEVEL, 0 }, | ||
82 | { AU1000_PCI_INTD, INTC_INT_LOW_LEVEL, 0 }, | ||
83 | { AU1000_DMA_INT_BASE, INTC_INT_HIGH_LEVEL, 0 }, | ||
84 | { AU1000_DMA_INT_BASE+1, INTC_INT_HIGH_LEVEL, 0 }, | ||
85 | { AU1000_DMA_INT_BASE+2, INTC_INT_HIGH_LEVEL, 0 }, | ||
86 | { AU1000_DMA_INT_BASE+3, INTC_INT_HIGH_LEVEL, 0 }, | ||
87 | { AU1000_DMA_INT_BASE+4, INTC_INT_HIGH_LEVEL, 0 }, | ||
88 | { AU1000_DMA_INT_BASE+5, INTC_INT_HIGH_LEVEL, 0 }, | ||
89 | { AU1000_DMA_INT_BASE+6, INTC_INT_HIGH_LEVEL, 0 }, | ||
90 | { AU1000_DMA_INT_BASE+7, INTC_INT_HIGH_LEVEL, 0 }, | ||
91 | { AU1000_TOY_INT, INTC_INT_RISE_EDGE, 0 }, | ||
92 | { AU1000_TOY_MATCH0_INT, INTC_INT_RISE_EDGE, 0 }, | ||
93 | { AU1000_TOY_MATCH1_INT, INTC_INT_RISE_EDGE, 0 }, | ||
94 | { AU1000_TOY_MATCH2_INT, INTC_INT_RISE_EDGE, 1 }, | ||
95 | { AU1000_RTC_INT, INTC_INT_RISE_EDGE, 0 }, | ||
96 | { AU1000_RTC_MATCH0_INT, INTC_INT_RISE_EDGE, 0 }, | ||
97 | { AU1000_RTC_MATCH1_INT, INTC_INT_RISE_EDGE, 0 }, | ||
98 | { AU1000_RTC_MATCH2_INT, INTC_INT_RISE_EDGE, 0 }, | ||
99 | { AU1000_USB_DEV_REQ_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
100 | { AU1000_USB_DEV_SUS_INT, INTC_INT_RISE_EDGE, 0 }, | ||
101 | { AU1000_USB_HOST_INT, INTC_INT_LOW_LEVEL, 0 }, | ||
102 | { AU1000_ACSYNC_INT, INTC_INT_RISE_EDGE, 0 }, | ||
103 | { AU1500_MAC0_DMA_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
104 | { AU1500_MAC1_DMA_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
105 | { AU1000_AC97C_INT, INTC_INT_RISE_EDGE, 0 }, | ||
106 | |||
107 | #elif defined(CONFIG_SOC_AU1100) | ||
108 | |||
109 | { AU1100_UART0_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
110 | { AU1100_UART1_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
111 | { AU1100_SD_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
112 | { AU1100_UART3_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
113 | { AU1000_SSI0_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
114 | { AU1000_SSI1_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
115 | { AU1000_DMA_INT_BASE, INTC_INT_HIGH_LEVEL, 0 }, | ||
116 | { AU1000_DMA_INT_BASE+1, INTC_INT_HIGH_LEVEL, 0 }, | ||
117 | { AU1000_DMA_INT_BASE+2, INTC_INT_HIGH_LEVEL, 0 }, | ||
118 | { AU1000_DMA_INT_BASE+3, INTC_INT_HIGH_LEVEL, 0 }, | ||
119 | { AU1000_DMA_INT_BASE+4, INTC_INT_HIGH_LEVEL, 0 }, | ||
120 | { AU1000_DMA_INT_BASE+5, INTC_INT_HIGH_LEVEL, 0 }, | ||
121 | { AU1000_DMA_INT_BASE+6, INTC_INT_HIGH_LEVEL, 0 }, | ||
122 | { AU1000_DMA_INT_BASE+7, INTC_INT_HIGH_LEVEL, 0 }, | ||
123 | { AU1000_TOY_INT, INTC_INT_RISE_EDGE, 0 }, | ||
124 | { AU1000_TOY_MATCH0_INT, INTC_INT_RISE_EDGE, 0 }, | ||
125 | { AU1000_TOY_MATCH1_INT, INTC_INT_RISE_EDGE, 0 }, | ||
126 | { AU1000_TOY_MATCH2_INT, INTC_INT_RISE_EDGE, 1 }, | ||
127 | { AU1000_RTC_INT, INTC_INT_RISE_EDGE, 0 }, | ||
128 | { AU1000_RTC_MATCH0_INT, INTC_INT_RISE_EDGE, 0 }, | ||
129 | { AU1000_RTC_MATCH1_INT, INTC_INT_RISE_EDGE, 0 }, | ||
130 | { AU1000_RTC_MATCH2_INT, INTC_INT_RISE_EDGE, 0 }, | ||
131 | { AU1000_IRDA_TX_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
132 | { AU1000_IRDA_RX_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
133 | { AU1000_USB_DEV_REQ_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
134 | { AU1000_USB_DEV_SUS_INT, INTC_INT_RISE_EDGE, 0 }, | ||
135 | { AU1000_USB_HOST_INT, INTC_INT_LOW_LEVEL, 0 }, | ||
136 | { AU1000_ACSYNC_INT, INTC_INT_RISE_EDGE, 0 }, | ||
137 | { AU1100_MAC0_DMA_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
138 | /* { AU1000_GPIO215_208_INT, INTC_INT_HIGH_LEVEL, 0 }, */ | ||
139 | { AU1100_LCD_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
140 | { AU1000_AC97C_INT, INTC_INT_RISE_EDGE, 0 }, | ||
141 | |||
142 | #elif defined(CONFIG_SOC_AU1550) | ||
143 | |||
144 | { AU1550_UART0_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
145 | { AU1550_PCI_INTA, INTC_INT_LOW_LEVEL, 0 }, | ||
146 | { AU1550_PCI_INTB, INTC_INT_LOW_LEVEL, 0 }, | ||
147 | { AU1550_DDMA_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
148 | { AU1550_CRYPTO_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
149 | { AU1550_PCI_INTC, INTC_INT_LOW_LEVEL, 0 }, | ||
150 | { AU1550_PCI_INTD, INTC_INT_LOW_LEVEL, 0 }, | ||
151 | { AU1550_PCI_RST_INT, INTC_INT_LOW_LEVEL, 0 }, | ||
152 | { AU1550_UART1_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
153 | { AU1550_UART3_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
154 | { AU1550_PSC0_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
155 | { AU1550_PSC1_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
156 | { AU1550_PSC2_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
157 | { AU1550_PSC3_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
158 | { AU1000_TOY_INT, INTC_INT_RISE_EDGE, 0 }, | ||
159 | { AU1000_TOY_MATCH0_INT, INTC_INT_RISE_EDGE, 0 }, | ||
160 | { AU1000_TOY_MATCH1_INT, INTC_INT_RISE_EDGE, 0 }, | ||
161 | { AU1000_TOY_MATCH2_INT, INTC_INT_RISE_EDGE, 1 }, | ||
162 | { AU1000_RTC_INT, INTC_INT_RISE_EDGE, 0 }, | ||
163 | { AU1000_RTC_MATCH0_INT, INTC_INT_RISE_EDGE, 0 }, | ||
164 | { AU1000_RTC_MATCH1_INT, INTC_INT_RISE_EDGE, 0 }, | ||
165 | { AU1000_RTC_MATCH2_INT, INTC_INT_RISE_EDGE, 0 }, | ||
166 | { AU1550_NAND_INT, INTC_INT_RISE_EDGE, 0 }, | ||
167 | { AU1550_USB_DEV_REQ_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
168 | { AU1550_USB_DEV_SUS_INT, INTC_INT_RISE_EDGE, 0 }, | ||
169 | { AU1550_USB_HOST_INT, INTC_INT_LOW_LEVEL, 0 }, | ||
170 | { AU1550_MAC0_DMA_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
171 | { AU1550_MAC1_DMA_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
172 | |||
173 | #elif defined(CONFIG_SOC_AU1200) | ||
174 | |||
175 | { AU1200_UART0_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
176 | { AU1200_SWT_INT, INTC_INT_RISE_EDGE, 0 }, | ||
177 | { AU1200_SD_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
178 | { AU1200_DDMA_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
179 | { AU1200_MAE_BE_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
180 | { AU1200_UART1_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
181 | { AU1200_MAE_FE_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
182 | { AU1200_PSC0_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
183 | { AU1200_PSC1_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
184 | { AU1200_AES_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
185 | { AU1200_CAMERA_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
186 | { AU1000_TOY_INT, INTC_INT_RISE_EDGE, 0 }, | ||
187 | { AU1000_TOY_MATCH0_INT, INTC_INT_RISE_EDGE, 0 }, | ||
188 | { AU1000_TOY_MATCH1_INT, INTC_INT_RISE_EDGE, 0 }, | ||
189 | { AU1000_TOY_MATCH2_INT, INTC_INT_RISE_EDGE, 1 }, | ||
190 | { AU1000_RTC_INT, INTC_INT_RISE_EDGE, 0 }, | ||
191 | { AU1000_RTC_MATCH0_INT, INTC_INT_RISE_EDGE, 0 }, | ||
192 | { AU1000_RTC_MATCH1_INT, INTC_INT_RISE_EDGE, 0 }, | ||
193 | { AU1000_RTC_MATCH2_INT, INTC_INT_RISE_EDGE, 0 }, | ||
194 | { AU1200_NAND_INT, INTC_INT_RISE_EDGE, 0 }, | ||
195 | { AU1200_USB_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
196 | { AU1200_LCD_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
197 | { AU1200_MAE_BOTH_INT, INTC_INT_HIGH_LEVEL, 0 }, | ||
198 | |||
199 | #else | ||
200 | #error "Error: Unknown Alchemy SOC" | ||
201 | #endif | ||
202 | |||
203 | }; | ||
204 | |||
205 | int __initdata au1xxx_ic0_nr_irqs = ARRAY_SIZE(au1xxx_ic0_map); | ||
diff --git a/arch/mips/alchemy/common/clocks.c b/arch/mips/alchemy/common/clocks.c new file mode 100644 index 000000000000..043429d17c5f --- /dev/null +++ b/arch/mips/alchemy/common/clocks.c | |||
@@ -0,0 +1,93 @@ | |||
1 | /* | ||
2 | * BRIEF MODULE DESCRIPTION | ||
3 | * Simple Au1xx0 clocks routines. | ||
4 | * | ||
5 | * Copyright 2001, 2008 MontaVista Software Inc. | ||
6 | * Author: MontaVista Software, Inc. <source@mvista.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
14 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
15 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
16 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
17 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
18 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
19 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
20 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
22 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License along | ||
25 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
26 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
27 | */ | ||
28 | |||
29 | #include <linux/module.h> | ||
30 | #include <asm/mach-au1x00/au1000.h> | ||
31 | |||
32 | static unsigned int au1x00_clock; /* Hz */ | ||
33 | static unsigned int lcd_clock; /* KHz */ | ||
34 | static unsigned long uart_baud_base; | ||
35 | |||
36 | /* | ||
37 | * Set the au1000_clock | ||
38 | */ | ||
39 | void set_au1x00_speed(unsigned int new_freq) | ||
40 | { | ||
41 | au1x00_clock = new_freq; | ||
42 | } | ||
43 | |||
44 | unsigned int get_au1x00_speed(void) | ||
45 | { | ||
46 | return au1x00_clock; | ||
47 | } | ||
48 | EXPORT_SYMBOL(get_au1x00_speed); | ||
49 | |||
50 | /* | ||
51 | * The UART baud base is not known at compile time ... if | ||
52 | * we want to be able to use the same code on different | ||
53 | * speed CPUs. | ||
54 | */ | ||
55 | unsigned long get_au1x00_uart_baud_base(void) | ||
56 | { | ||
57 | return uart_baud_base; | ||
58 | } | ||
59 | |||
60 | void set_au1x00_uart_baud_base(unsigned long new_baud_base) | ||
61 | { | ||
62 | uart_baud_base = new_baud_base; | ||
63 | } | ||
64 | |||
65 | /* | ||
66 | * Calculate the Au1x00's LCD clock based on the current | ||
67 | * cpu clock and the system bus clock, and try to keep it | ||
68 | * below 40 MHz (the Pb1000 board can lock-up if the LCD | ||
69 | * clock is over 40 MHz). | ||
70 | */ | ||
71 | void set_au1x00_lcd_clock(void) | ||
72 | { | ||
73 | unsigned int static_cfg0; | ||
74 | unsigned int sys_busclk = (get_au1x00_speed() / 1000) / | ||
75 | ((int)(au_readl(SYS_POWERCTRL) & 0x03) + 2); | ||
76 | |||
77 | static_cfg0 = au_readl(MEM_STCFG0); | ||
78 | |||
79 | if (static_cfg0 & (1 << 11)) | ||
80 | lcd_clock = sys_busclk / 5; /* note: BCLK switching fails with D5 */ | ||
81 | else | ||
82 | lcd_clock = sys_busclk / 4; | ||
83 | |||
84 | if (lcd_clock > 50000) /* Epson MAX */ | ||
85 | printk(KERN_WARNING "warning: LCD clock too high (%u KHz)\n", | ||
86 | lcd_clock); | ||
87 | } | ||
88 | |||
89 | unsigned int get_au1x00_lcd_clock(void) | ||
90 | { | ||
91 | return lcd_clock; | ||
92 | } | ||
93 | EXPORT_SYMBOL(get_au1x00_lcd_clock); | ||
diff --git a/arch/mips/alchemy/common/cputable.c b/arch/mips/alchemy/common/cputable.c new file mode 100644 index 000000000000..ba6430bc2d03 --- /dev/null +++ b/arch/mips/alchemy/common/cputable.c | |||
@@ -0,0 +1,52 @@ | |||
1 | /* | ||
2 | * arch/mips/au1000/common/cputable.c | ||
3 | * | ||
4 | * Copyright (C) 2004 Dan Malek (dan@embeddededge.com) | ||
5 | * Copied from PowerPC and updated for Alchemy Au1xxx processors. | ||
6 | * | ||
7 | * Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org) | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * as published by the Free Software Foundation; either version | ||
12 | * 2 of the License, or (at your option) any later version. | ||
13 | */ | ||
14 | |||
15 | #include <asm/mach-au1x00/au1000.h> | ||
16 | |||
17 | struct cpu_spec *cur_cpu_spec[NR_CPUS]; | ||
18 | |||
19 | /* With some thought, we can probably use the mask to reduce the | ||
20 | * size of the table. | ||
21 | */ | ||
22 | struct cpu_spec cpu_specs[] = { | ||
23 | { 0xffffffff, 0x00030100, "Au1000 DA", 1, 0, 1 }, | ||
24 | { 0xffffffff, 0x00030201, "Au1000 HA", 1, 0, 1 }, | ||
25 | { 0xffffffff, 0x00030202, "Au1000 HB", 1, 0, 1 }, | ||
26 | { 0xffffffff, 0x00030203, "Au1000 HC", 1, 1, 0 }, | ||
27 | { 0xffffffff, 0x00030204, "Au1000 HD", 1, 1, 0 }, | ||
28 | { 0xffffffff, 0x01030200, "Au1500 AB", 1, 1, 0 }, | ||
29 | { 0xffffffff, 0x01030201, "Au1500 AC", 0, 1, 0 }, | ||
30 | { 0xffffffff, 0x01030202, "Au1500 AD", 0, 1, 0 }, | ||
31 | { 0xffffffff, 0x02030200, "Au1100 AB", 1, 1, 0 }, | ||
32 | { 0xffffffff, 0x02030201, "Au1100 BA", 1, 1, 0 }, | ||
33 | { 0xffffffff, 0x02030202, "Au1100 BC", 1, 1, 0 }, | ||
34 | { 0xffffffff, 0x02030203, "Au1100 BD", 0, 1, 0 }, | ||
35 | { 0xffffffff, 0x02030204, "Au1100 BE", 0, 1, 0 }, | ||
36 | { 0xffffffff, 0x03030200, "Au1550 AA", 0, 1, 0 }, | ||
37 | { 0xffffffff, 0x04030200, "Au1200 AB", 0, 0, 0 }, | ||
38 | { 0xffffffff, 0x04030201, "Au1200 AC", 1, 0, 0 }, | ||
39 | { 0x00000000, 0x00000000, "Unknown Au1xxx", 1, 0, 0 } | ||
40 | }; | ||
41 | |||
42 | void set_cpuspec(void) | ||
43 | { | ||
44 | struct cpu_spec *sp; | ||
45 | u32 prid; | ||
46 | |||
47 | prid = read_c0_prid(); | ||
48 | sp = cpu_specs; | ||
49 | while ((prid & sp->prid_mask) != sp->prid_value) | ||
50 | sp++; | ||
51 | cur_cpu_spec[0] = sp; | ||
52 | } | ||
diff --git a/arch/mips/alchemy/common/dbdma.c b/arch/mips/alchemy/common/dbdma.c new file mode 100644 index 000000000000..601ee9180ee4 --- /dev/null +++ b/arch/mips/alchemy/common/dbdma.c | |||
@@ -0,0 +1,978 @@ | |||
1 | /* | ||
2 | * | ||
3 | * BRIEF MODULE DESCRIPTION | ||
4 | * The Descriptor Based DMA channel manager that first appeared | ||
5 | * on the Au1550. I started with dma.c, but I think all that is | ||
6 | * left is this initial comment :-) | ||
7 | * | ||
8 | * Copyright 2004 Embedded Edge, LLC | ||
9 | * dan@embeddededge.com | ||
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 as published by the | ||
13 | * Free Software Foundation; either version 2 of the License, or (at your | ||
14 | * option) any later version. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
17 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
18 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
19 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
21 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
22 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
23 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | * | ||
27 | * You should have received a copy of the GNU General Public License along | ||
28 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
29 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
30 | * | ||
31 | */ | ||
32 | |||
33 | #include <linux/kernel.h> | ||
34 | #include <linux/slab.h> | ||
35 | #include <linux/spinlock.h> | ||
36 | #include <linux/interrupt.h> | ||
37 | #include <linux/module.h> | ||
38 | #include <asm/mach-au1x00/au1000.h> | ||
39 | #include <asm/mach-au1x00/au1xxx_dbdma.h> | ||
40 | |||
41 | #if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200) | ||
42 | |||
43 | /* | ||
44 | * The Descriptor Based DMA supports up to 16 channels. | ||
45 | * | ||
46 | * There are 32 devices defined. We keep an internal structure | ||
47 | * of devices using these channels, along with additional | ||
48 | * information. | ||
49 | * | ||
50 | * We allocate the descriptors and allow access to them through various | ||
51 | * functions. The drivers allocate the data buffers and assign them | ||
52 | * to the descriptors. | ||
53 | */ | ||
54 | static DEFINE_SPINLOCK(au1xxx_dbdma_spin_lock); | ||
55 | |||
56 | /* I couldn't find a macro that did this... */ | ||
57 | #define ALIGN_ADDR(x, a) ((((u32)(x)) + (a-1)) & ~(a-1)) | ||
58 | |||
59 | static dbdma_global_t *dbdma_gptr = (dbdma_global_t *)DDMA_GLOBAL_BASE; | ||
60 | static int dbdma_initialized; | ||
61 | static void au1xxx_dbdma_init(void); | ||
62 | |||
63 | static dbdev_tab_t dbdev_tab[] = { | ||
64 | #ifdef CONFIG_SOC_AU1550 | ||
65 | /* UARTS */ | ||
66 | { DSCR_CMD0_UART0_TX, DEV_FLAGS_OUT, 0, 8, 0x11100004, 0, 0 }, | ||
67 | { DSCR_CMD0_UART0_RX, DEV_FLAGS_IN, 0, 8, 0x11100000, 0, 0 }, | ||
68 | { DSCR_CMD0_UART3_TX, DEV_FLAGS_OUT, 0, 8, 0x11400004, 0, 0 }, | ||
69 | { DSCR_CMD0_UART3_RX, DEV_FLAGS_IN, 0, 8, 0x11400000, 0, 0 }, | ||
70 | |||
71 | /* EXT DMA */ | ||
72 | { DSCR_CMD0_DMA_REQ0, 0, 0, 0, 0x00000000, 0, 0 }, | ||
73 | { DSCR_CMD0_DMA_REQ1, 0, 0, 0, 0x00000000, 0, 0 }, | ||
74 | { DSCR_CMD0_DMA_REQ2, 0, 0, 0, 0x00000000, 0, 0 }, | ||
75 | { DSCR_CMD0_DMA_REQ3, 0, 0, 0, 0x00000000, 0, 0 }, | ||
76 | |||
77 | /* USB DEV */ | ||
78 | { DSCR_CMD0_USBDEV_RX0, DEV_FLAGS_IN, 4, 8, 0x10200000, 0, 0 }, | ||
79 | { DSCR_CMD0_USBDEV_TX0, DEV_FLAGS_OUT, 4, 8, 0x10200004, 0, 0 }, | ||
80 | { DSCR_CMD0_USBDEV_TX1, DEV_FLAGS_OUT, 4, 8, 0x10200008, 0, 0 }, | ||
81 | { DSCR_CMD0_USBDEV_TX2, DEV_FLAGS_OUT, 4, 8, 0x1020000c, 0, 0 }, | ||
82 | { DSCR_CMD0_USBDEV_RX3, DEV_FLAGS_IN, 4, 8, 0x10200010, 0, 0 }, | ||
83 | { DSCR_CMD0_USBDEV_RX4, DEV_FLAGS_IN, 4, 8, 0x10200014, 0, 0 }, | ||
84 | |||
85 | /* PSC 0 */ | ||
86 | { DSCR_CMD0_PSC0_TX, DEV_FLAGS_OUT, 0, 0, 0x11a0001c, 0, 0 }, | ||
87 | { DSCR_CMD0_PSC0_RX, DEV_FLAGS_IN, 0, 0, 0x11a0001c, 0, 0 }, | ||
88 | |||
89 | /* PSC 1 */ | ||
90 | { DSCR_CMD0_PSC1_TX, DEV_FLAGS_OUT, 0, 0, 0x11b0001c, 0, 0 }, | ||
91 | { DSCR_CMD0_PSC1_RX, DEV_FLAGS_IN, 0, 0, 0x11b0001c, 0, 0 }, | ||
92 | |||
93 | /* PSC 2 */ | ||
94 | { DSCR_CMD0_PSC2_TX, DEV_FLAGS_OUT, 0, 0, 0x10a0001c, 0, 0 }, | ||
95 | { DSCR_CMD0_PSC2_RX, DEV_FLAGS_IN, 0, 0, 0x10a0001c, 0, 0 }, | ||
96 | |||
97 | /* PSC 3 */ | ||
98 | { DSCR_CMD0_PSC3_TX, DEV_FLAGS_OUT, 0, 0, 0x10b0001c, 0, 0 }, | ||
99 | { DSCR_CMD0_PSC3_RX, DEV_FLAGS_IN, 0, 0, 0x10b0001c, 0, 0 }, | ||
100 | |||
101 | { DSCR_CMD0_PCI_WRITE, 0, 0, 0, 0x00000000, 0, 0 }, /* PCI */ | ||
102 | { DSCR_CMD0_NAND_FLASH, 0, 0, 0, 0x00000000, 0, 0 }, /* NAND */ | ||
103 | |||
104 | /* MAC 0 */ | ||
105 | { DSCR_CMD0_MAC0_RX, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 }, | ||
106 | { DSCR_CMD0_MAC0_TX, DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 }, | ||
107 | |||
108 | /* MAC 1 */ | ||
109 | { DSCR_CMD0_MAC1_RX, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 }, | ||
110 | { DSCR_CMD0_MAC1_TX, DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 }, | ||
111 | |||
112 | #endif /* CONFIG_SOC_AU1550 */ | ||
113 | |||
114 | #ifdef CONFIG_SOC_AU1200 | ||
115 | { DSCR_CMD0_UART0_TX, DEV_FLAGS_OUT, 0, 8, 0x11100004, 0, 0 }, | ||
116 | { DSCR_CMD0_UART0_RX, DEV_FLAGS_IN, 0, 8, 0x11100000, 0, 0 }, | ||
117 | { DSCR_CMD0_UART1_TX, DEV_FLAGS_OUT, 0, 8, 0x11200004, 0, 0 }, | ||
118 | { DSCR_CMD0_UART1_RX, DEV_FLAGS_IN, 0, 8, 0x11200000, 0, 0 }, | ||
119 | |||
120 | { DSCR_CMD0_DMA_REQ0, 0, 0, 0, 0x00000000, 0, 0 }, | ||
121 | { DSCR_CMD0_DMA_REQ1, 0, 0, 0, 0x00000000, 0, 0 }, | ||
122 | |||
123 | { DSCR_CMD0_MAE_BE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, | ||
124 | { DSCR_CMD0_MAE_FE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, | ||
125 | { DSCR_CMD0_MAE_BOTH, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, | ||
126 | { DSCR_CMD0_LCD, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, | ||
127 | |||
128 | { DSCR_CMD0_SDMS_TX0, DEV_FLAGS_OUT, 4, 8, 0x10600000, 0, 0 }, | ||
129 | { DSCR_CMD0_SDMS_RX0, DEV_FLAGS_IN, 4, 8, 0x10600004, 0, 0 }, | ||
130 | { DSCR_CMD0_SDMS_TX1, DEV_FLAGS_OUT, 4, 8, 0x10680000, 0, 0 }, | ||
131 | { DSCR_CMD0_SDMS_RX1, DEV_FLAGS_IN, 4, 8, 0x10680004, 0, 0 }, | ||
132 | |||
133 | { DSCR_CMD0_AES_RX, DEV_FLAGS_IN , 4, 32, 0x10300008, 0, 0 }, | ||
134 | { DSCR_CMD0_AES_TX, DEV_FLAGS_OUT, 4, 32, 0x10300004, 0, 0 }, | ||
135 | |||
136 | { DSCR_CMD0_PSC0_TX, DEV_FLAGS_OUT, 0, 16, 0x11a0001c, 0, 0 }, | ||
137 | { DSCR_CMD0_PSC0_RX, DEV_FLAGS_IN, 0, 16, 0x11a0001c, 0, 0 }, | ||
138 | { DSCR_CMD0_PSC0_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, | ||
139 | |||
140 | { DSCR_CMD0_PSC1_TX, DEV_FLAGS_OUT, 0, 16, 0x11b0001c, 0, 0 }, | ||
141 | { DSCR_CMD0_PSC1_RX, DEV_FLAGS_IN, 0, 16, 0x11b0001c, 0, 0 }, | ||
142 | { DSCR_CMD0_PSC1_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, | ||
143 | |||
144 | { DSCR_CMD0_CIM_RXA, DEV_FLAGS_IN, 0, 32, 0x14004020, 0, 0 }, | ||
145 | { DSCR_CMD0_CIM_RXB, DEV_FLAGS_IN, 0, 32, 0x14004040, 0, 0 }, | ||
146 | { DSCR_CMD0_CIM_RXC, DEV_FLAGS_IN, 0, 32, 0x14004060, 0, 0 }, | ||
147 | { DSCR_CMD0_CIM_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, | ||
148 | |||
149 | { DSCR_CMD0_NAND_FLASH, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 }, | ||
150 | |||
151 | #endif /* CONFIG_SOC_AU1200 */ | ||
152 | |||
153 | { DSCR_CMD0_THROTTLE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, | ||
154 | { DSCR_CMD0_ALWAYS, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, | ||
155 | |||
156 | /* Provide 16 user definable device types */ | ||
157 | { ~0, 0, 0, 0, 0, 0, 0 }, | ||
158 | { ~0, 0, 0, 0, 0, 0, 0 }, | ||
159 | { ~0, 0, 0, 0, 0, 0, 0 }, | ||
160 | { ~0, 0, 0, 0, 0, 0, 0 }, | ||
161 | { ~0, 0, 0, 0, 0, 0, 0 }, | ||
162 | { ~0, 0, 0, 0, 0, 0, 0 }, | ||
163 | { ~0, 0, 0, 0, 0, 0, 0 }, | ||
164 | { ~0, 0, 0, 0, 0, 0, 0 }, | ||
165 | { ~0, 0, 0, 0, 0, 0, 0 }, | ||
166 | { ~0, 0, 0, 0, 0, 0, 0 }, | ||
167 | { ~0, 0, 0, 0, 0, 0, 0 }, | ||
168 | { ~0, 0, 0, 0, 0, 0, 0 }, | ||
169 | { ~0, 0, 0, 0, 0, 0, 0 }, | ||
170 | { ~0, 0, 0, 0, 0, 0, 0 }, | ||
171 | { ~0, 0, 0, 0, 0, 0, 0 }, | ||
172 | { ~0, 0, 0, 0, 0, 0, 0 }, | ||
173 | }; | ||
174 | |||
175 | #define DBDEV_TAB_SIZE ARRAY_SIZE(dbdev_tab) | ||
176 | |||
177 | static chan_tab_t *chan_tab_ptr[NUM_DBDMA_CHANS]; | ||
178 | |||
179 | static dbdev_tab_t *find_dbdev_id(u32 id) | ||
180 | { | ||
181 | int i; | ||
182 | dbdev_tab_t *p; | ||
183 | for (i = 0; i < DBDEV_TAB_SIZE; ++i) { | ||
184 | p = &dbdev_tab[i]; | ||
185 | if (p->dev_id == id) | ||
186 | return p; | ||
187 | } | ||
188 | return NULL; | ||
189 | } | ||
190 | |||
191 | void *au1xxx_ddma_get_nextptr_virt(au1x_ddma_desc_t *dp) | ||
192 | { | ||
193 | return phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr)); | ||
194 | } | ||
195 | EXPORT_SYMBOL(au1xxx_ddma_get_nextptr_virt); | ||
196 | |||
197 | u32 au1xxx_ddma_add_device(dbdev_tab_t *dev) | ||
198 | { | ||
199 | u32 ret = 0; | ||
200 | dbdev_tab_t *p; | ||
201 | static u16 new_id = 0x1000; | ||
202 | |||
203 | p = find_dbdev_id(~0); | ||
204 | if (NULL != p) { | ||
205 | memcpy(p, dev, sizeof(dbdev_tab_t)); | ||
206 | p->dev_id = DSCR_DEV2CUSTOM_ID(new_id, dev->dev_id); | ||
207 | ret = p->dev_id; | ||
208 | new_id++; | ||
209 | #if 0 | ||
210 | printk(KERN_DEBUG "add_device: id:%x flags:%x padd:%x\n", | ||
211 | p->dev_id, p->dev_flags, p->dev_physaddr); | ||
212 | #endif | ||
213 | } | ||
214 | |||
215 | return ret; | ||
216 | } | ||
217 | EXPORT_SYMBOL(au1xxx_ddma_add_device); | ||
218 | |||
219 | void au1xxx_ddma_del_device(u32 devid) | ||
220 | { | ||
221 | dbdev_tab_t *p = find_dbdev_id(devid); | ||
222 | |||
223 | if (p != NULL) { | ||
224 | memset(p, 0, sizeof(dbdev_tab_t)); | ||
225 | p->dev_id = ~0; | ||
226 | } | ||
227 | } | ||
228 | EXPORT_SYMBOL(au1xxx_ddma_del_device); | ||
229 | |||
230 | /* Allocate a channel and return a non-zero descriptor if successful. */ | ||
231 | u32 au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid, | ||
232 | void (*callback)(int, void *), void *callparam) | ||
233 | { | ||
234 | unsigned long flags; | ||
235 | u32 used, chan, rv; | ||
236 | u32 dcp; | ||
237 | int i; | ||
238 | dbdev_tab_t *stp, *dtp; | ||
239 | chan_tab_t *ctp; | ||
240 | au1x_dma_chan_t *cp; | ||
241 | |||
242 | /* | ||
243 | * We do the intialization on the first channel allocation. | ||
244 | * We have to wait because of the interrupt handler initialization | ||
245 | * which can't be done successfully during board set up. | ||
246 | */ | ||
247 | if (!dbdma_initialized) | ||
248 | au1xxx_dbdma_init(); | ||
249 | dbdma_initialized = 1; | ||
250 | |||
251 | stp = find_dbdev_id(srcid); | ||
252 | if (stp == NULL) | ||
253 | return 0; | ||
254 | dtp = find_dbdev_id(destid); | ||
255 | if (dtp == NULL) | ||
256 | return 0; | ||
257 | |||
258 | used = 0; | ||
259 | rv = 0; | ||
260 | |||
261 | /* Check to see if we can get both channels. */ | ||
262 | spin_lock_irqsave(&au1xxx_dbdma_spin_lock, flags); | ||
263 | if (!(stp->dev_flags & DEV_FLAGS_INUSE) || | ||
264 | (stp->dev_flags & DEV_FLAGS_ANYUSE)) { | ||
265 | /* Got source */ | ||
266 | stp->dev_flags |= DEV_FLAGS_INUSE; | ||
267 | if (!(dtp->dev_flags & DEV_FLAGS_INUSE) || | ||
268 | (dtp->dev_flags & DEV_FLAGS_ANYUSE)) { | ||
269 | /* Got destination */ | ||
270 | dtp->dev_flags |= DEV_FLAGS_INUSE; | ||
271 | } else { | ||
272 | /* Can't get dest. Release src. */ | ||
273 | stp->dev_flags &= ~DEV_FLAGS_INUSE; | ||
274 | used++; | ||
275 | } | ||
276 | } else | ||
277 | used++; | ||
278 | spin_unlock_irqrestore(&au1xxx_dbdma_spin_lock, flags); | ||
279 | |||
280 | if (!used) { | ||
281 | /* Let's see if we can allocate a channel for it. */ | ||
282 | ctp = NULL; | ||
283 | chan = 0; | ||
284 | spin_lock_irqsave(&au1xxx_dbdma_spin_lock, flags); | ||
285 | for (i = 0; i < NUM_DBDMA_CHANS; i++) | ||
286 | if (chan_tab_ptr[i] == NULL) { | ||
287 | /* | ||
288 | * If kmalloc fails, it is caught below same | ||
289 | * as a channel not available. | ||
290 | */ | ||
291 | ctp = kmalloc(sizeof(chan_tab_t), GFP_ATOMIC); | ||
292 | chan_tab_ptr[i] = ctp; | ||
293 | break; | ||
294 | } | ||
295 | spin_unlock_irqrestore(&au1xxx_dbdma_spin_lock, flags); | ||
296 | |||
297 | if (ctp != NULL) { | ||
298 | memset(ctp, 0, sizeof(chan_tab_t)); | ||
299 | ctp->chan_index = chan = i; | ||
300 | dcp = DDMA_CHANNEL_BASE; | ||
301 | dcp += (0x0100 * chan); | ||
302 | ctp->chan_ptr = (au1x_dma_chan_t *)dcp; | ||
303 | cp = (au1x_dma_chan_t *)dcp; | ||
304 | ctp->chan_src = stp; | ||
305 | ctp->chan_dest = dtp; | ||
306 | ctp->chan_callback = callback; | ||
307 | ctp->chan_callparam = callparam; | ||
308 | |||
309 | /* Initialize channel configuration. */ | ||
310 | i = 0; | ||
311 | if (stp->dev_intlevel) | ||
312 | i |= DDMA_CFG_SED; | ||
313 | if (stp->dev_intpolarity) | ||
314 | i |= DDMA_CFG_SP; | ||
315 | if (dtp->dev_intlevel) | ||
316 | i |= DDMA_CFG_DED; | ||
317 | if (dtp->dev_intpolarity) | ||
318 | i |= DDMA_CFG_DP; | ||
319 | if ((stp->dev_flags & DEV_FLAGS_SYNC) || | ||
320 | (dtp->dev_flags & DEV_FLAGS_SYNC)) | ||
321 | i |= DDMA_CFG_SYNC; | ||
322 | cp->ddma_cfg = i; | ||
323 | au_sync(); | ||
324 | |||
325 | /* Return a non-zero value that can be used to | ||
326 | * find the channel information in subsequent | ||
327 | * operations. | ||
328 | */ | ||
329 | rv = (u32)(&chan_tab_ptr[chan]); | ||
330 | } else { | ||
331 | /* Release devices */ | ||
332 | stp->dev_flags &= ~DEV_FLAGS_INUSE; | ||
333 | dtp->dev_flags &= ~DEV_FLAGS_INUSE; | ||
334 | } | ||
335 | } | ||
336 | return rv; | ||
337 | } | ||
338 | EXPORT_SYMBOL(au1xxx_dbdma_chan_alloc); | ||
339 | |||
340 | /* | ||
341 | * Set the device width if source or destination is a FIFO. | ||
342 | * Should be 8, 16, or 32 bits. | ||
343 | */ | ||
344 | u32 au1xxx_dbdma_set_devwidth(u32 chanid, int bits) | ||
345 | { | ||
346 | u32 rv; | ||
347 | chan_tab_t *ctp; | ||
348 | dbdev_tab_t *stp, *dtp; | ||
349 | |||
350 | ctp = *((chan_tab_t **)chanid); | ||
351 | stp = ctp->chan_src; | ||
352 | dtp = ctp->chan_dest; | ||
353 | rv = 0; | ||
354 | |||
355 | if (stp->dev_flags & DEV_FLAGS_IN) { /* Source in fifo */ | ||
356 | rv = stp->dev_devwidth; | ||
357 | stp->dev_devwidth = bits; | ||
358 | } | ||
359 | if (dtp->dev_flags & DEV_FLAGS_OUT) { /* Destination out fifo */ | ||
360 | rv = dtp->dev_devwidth; | ||
361 | dtp->dev_devwidth = bits; | ||
362 | } | ||
363 | |||
364 | return rv; | ||
365 | } | ||
366 | EXPORT_SYMBOL(au1xxx_dbdma_set_devwidth); | ||
367 | |||
368 | /* Allocate a descriptor ring, initializing as much as possible. */ | ||
369 | u32 au1xxx_dbdma_ring_alloc(u32 chanid, int entries) | ||
370 | { | ||
371 | int i; | ||
372 | u32 desc_base, srcid, destid; | ||
373 | u32 cmd0, cmd1, src1, dest1; | ||
374 | u32 src0, dest0; | ||
375 | chan_tab_t *ctp; | ||
376 | dbdev_tab_t *stp, *dtp; | ||
377 | au1x_ddma_desc_t *dp; | ||
378 | |||
379 | /* | ||
380 | * I guess we could check this to be within the | ||
381 | * range of the table...... | ||
382 | */ | ||
383 | ctp = *((chan_tab_t **)chanid); | ||
384 | stp = ctp->chan_src; | ||
385 | dtp = ctp->chan_dest; | ||
386 | |||
387 | /* | ||
388 | * The descriptors must be 32-byte aligned. There is a | ||
389 | * possibility the allocation will give us such an address, | ||
390 | * and if we try that first we are likely to not waste larger | ||
391 | * slabs of memory. | ||
392 | */ | ||
393 | desc_base = (u32)kmalloc(entries * sizeof(au1x_ddma_desc_t), | ||
394 | GFP_KERNEL|GFP_DMA); | ||
395 | if (desc_base == 0) | ||
396 | return 0; | ||
397 | |||
398 | if (desc_base & 0x1f) { | ||
399 | /* | ||
400 | * Lost....do it again, allocate extra, and round | ||
401 | * the address base. | ||
402 | */ | ||
403 | kfree((const void *)desc_base); | ||
404 | i = entries * sizeof(au1x_ddma_desc_t); | ||
405 | i += (sizeof(au1x_ddma_desc_t) - 1); | ||
406 | desc_base = (u32)kmalloc(i, GFP_KERNEL|GFP_DMA); | ||
407 | if (desc_base == 0) | ||
408 | return 0; | ||
409 | |||
410 | desc_base = ALIGN_ADDR(desc_base, sizeof(au1x_ddma_desc_t)); | ||
411 | } | ||
412 | dp = (au1x_ddma_desc_t *)desc_base; | ||
413 | |||
414 | /* Keep track of the base descriptor. */ | ||
415 | ctp->chan_desc_base = dp; | ||
416 | |||
417 | /* Initialize the rings with as much information as we know. */ | ||
418 | srcid = stp->dev_id; | ||
419 | destid = dtp->dev_id; | ||
420 | |||
421 | cmd0 = cmd1 = src1 = dest1 = 0; | ||
422 | src0 = dest0 = 0; | ||
423 | |||
424 | cmd0 |= DSCR_CMD0_SID(srcid); | ||
425 | cmd0 |= DSCR_CMD0_DID(destid); | ||
426 | cmd0 |= DSCR_CMD0_IE | DSCR_CMD0_CV; | ||
427 | cmd0 |= DSCR_CMD0_ST(DSCR_CMD0_ST_NOCHANGE); | ||
428 | |||
429 | /* Is it mem to mem transfer? */ | ||
430 | if (((DSCR_CUSTOM2DEV_ID(srcid) == DSCR_CMD0_THROTTLE) || | ||
431 | (DSCR_CUSTOM2DEV_ID(srcid) == DSCR_CMD0_ALWAYS)) && | ||
432 | ((DSCR_CUSTOM2DEV_ID(destid) == DSCR_CMD0_THROTTLE) || | ||
433 | (DSCR_CUSTOM2DEV_ID(destid) == DSCR_CMD0_ALWAYS))) | ||
434 | cmd0 |= DSCR_CMD0_MEM; | ||
435 | |||
436 | switch (stp->dev_devwidth) { | ||
437 | case 8: | ||
438 | cmd0 |= DSCR_CMD0_SW(DSCR_CMD0_BYTE); | ||
439 | break; | ||
440 | case 16: | ||
441 | cmd0 |= DSCR_CMD0_SW(DSCR_CMD0_HALFWORD); | ||
442 | break; | ||
443 | case 32: | ||
444 | default: | ||
445 | cmd0 |= DSCR_CMD0_SW(DSCR_CMD0_WORD); | ||
446 | break; | ||
447 | } | ||
448 | |||
449 | switch (dtp->dev_devwidth) { | ||
450 | case 8: | ||
451 | cmd0 |= DSCR_CMD0_DW(DSCR_CMD0_BYTE); | ||
452 | break; | ||
453 | case 16: | ||
454 | cmd0 |= DSCR_CMD0_DW(DSCR_CMD0_HALFWORD); | ||
455 | break; | ||
456 | case 32: | ||
457 | default: | ||
458 | cmd0 |= DSCR_CMD0_DW(DSCR_CMD0_WORD); | ||
459 | break; | ||
460 | } | ||
461 | |||
462 | /* | ||
463 | * If the device is marked as an in/out FIFO, ensure it is | ||
464 | * set non-coherent. | ||
465 | */ | ||
466 | if (stp->dev_flags & DEV_FLAGS_IN) | ||
467 | cmd0 |= DSCR_CMD0_SN; /* Source in FIFO */ | ||
468 | if (dtp->dev_flags & DEV_FLAGS_OUT) | ||
469 | cmd0 |= DSCR_CMD0_DN; /* Destination out FIFO */ | ||
470 | |||
471 | /* | ||
472 | * Set up source1. For now, assume no stride and increment. | ||
473 | * A channel attribute update can change this later. | ||
474 | */ | ||
475 | switch (stp->dev_tsize) { | ||
476 | case 1: | ||
477 | src1 |= DSCR_SRC1_STS(DSCR_xTS_SIZE1); | ||
478 | break; | ||
479 | case 2: | ||
480 | src1 |= DSCR_SRC1_STS(DSCR_xTS_SIZE2); | ||
481 | break; | ||
482 | case 4: | ||
483 | src1 |= DSCR_SRC1_STS(DSCR_xTS_SIZE4); | ||
484 | break; | ||
485 | case 8: | ||
486 | default: | ||
487 | src1 |= DSCR_SRC1_STS(DSCR_xTS_SIZE8); | ||
488 | break; | ||
489 | } | ||
490 | |||
491 | /* If source input is FIFO, set static address. */ | ||
492 | if (stp->dev_flags & DEV_FLAGS_IN) { | ||
493 | if (stp->dev_flags & DEV_FLAGS_BURSTABLE) | ||
494 | src1 |= DSCR_SRC1_SAM(DSCR_xAM_BURST); | ||
495 | else | ||
496 | src1 |= DSCR_SRC1_SAM(DSCR_xAM_STATIC); | ||
497 | } | ||
498 | |||
499 | if (stp->dev_physaddr) | ||
500 | src0 = stp->dev_physaddr; | ||
501 | |||
502 | /* | ||
503 | * Set up dest1. For now, assume no stride and increment. | ||
504 | * A channel attribute update can change this later. | ||
505 | */ | ||
506 | switch (dtp->dev_tsize) { | ||
507 | case 1: | ||
508 | dest1 |= DSCR_DEST1_DTS(DSCR_xTS_SIZE1); | ||
509 | break; | ||
510 | case 2: | ||
511 | dest1 |= DSCR_DEST1_DTS(DSCR_xTS_SIZE2); | ||
512 | break; | ||
513 | case 4: | ||
514 | dest1 |= DSCR_DEST1_DTS(DSCR_xTS_SIZE4); | ||
515 | break; | ||
516 | case 8: | ||
517 | default: | ||
518 | dest1 |= DSCR_DEST1_DTS(DSCR_xTS_SIZE8); | ||
519 | break; | ||
520 | } | ||
521 | |||
522 | /* If destination output is FIFO, set static address. */ | ||
523 | if (dtp->dev_flags & DEV_FLAGS_OUT) { | ||
524 | if (dtp->dev_flags & DEV_FLAGS_BURSTABLE) | ||
525 | dest1 |= DSCR_DEST1_DAM(DSCR_xAM_BURST); | ||
526 | else | ||
527 | dest1 |= DSCR_DEST1_DAM(DSCR_xAM_STATIC); | ||
528 | } | ||
529 | |||
530 | if (dtp->dev_physaddr) | ||
531 | dest0 = dtp->dev_physaddr; | ||
532 | |||
533 | #if 0 | ||
534 | printk(KERN_DEBUG "did:%x sid:%x cmd0:%x cmd1:%x source0:%x " | ||
535 | "source1:%x dest0:%x dest1:%x\n", | ||
536 | dtp->dev_id, stp->dev_id, cmd0, cmd1, src0, | ||
537 | src1, dest0, dest1); | ||
538 | #endif | ||
539 | for (i = 0; i < entries; i++) { | ||
540 | dp->dscr_cmd0 = cmd0; | ||
541 | dp->dscr_cmd1 = cmd1; | ||
542 | dp->dscr_source0 = src0; | ||
543 | dp->dscr_source1 = src1; | ||
544 | dp->dscr_dest0 = dest0; | ||
545 | dp->dscr_dest1 = dest1; | ||
546 | dp->dscr_stat = 0; | ||
547 | dp->sw_context = 0; | ||
548 | dp->sw_status = 0; | ||
549 | dp->dscr_nxtptr = DSCR_NXTPTR(virt_to_phys(dp + 1)); | ||
550 | dp++; | ||
551 | } | ||
552 | |||
553 | /* Make last descrptor point to the first. */ | ||
554 | dp--; | ||
555 | dp->dscr_nxtptr = DSCR_NXTPTR(virt_to_phys(ctp->chan_desc_base)); | ||
556 | ctp->get_ptr = ctp->put_ptr = ctp->cur_ptr = ctp->chan_desc_base; | ||
557 | |||
558 | return (u32)ctp->chan_desc_base; | ||
559 | } | ||
560 | EXPORT_SYMBOL(au1xxx_dbdma_ring_alloc); | ||
561 | |||
562 | /* | ||
563 | * Put a source buffer into the DMA ring. | ||
564 | * This updates the source pointer and byte count. Normally used | ||
565 | * for memory to fifo transfers. | ||
566 | */ | ||
567 | u32 _au1xxx_dbdma_put_source(u32 chanid, void *buf, int nbytes, u32 flags) | ||
568 | { | ||
569 | chan_tab_t *ctp; | ||
570 | au1x_ddma_desc_t *dp; | ||
571 | |||
572 | /* | ||
573 | * I guess we could check this to be within the | ||
574 | * range of the table...... | ||
575 | */ | ||
576 | ctp = *(chan_tab_t **)chanid; | ||
577 | |||
578 | /* | ||
579 | * We should have multiple callers for a particular channel, | ||
580 | * an interrupt doesn't affect this pointer nor the descriptor, | ||
581 | * so no locking should be needed. | ||
582 | */ | ||
583 | dp = ctp->put_ptr; | ||
584 | |||
585 | /* | ||
586 | * If the descriptor is valid, we are way ahead of the DMA | ||
587 | * engine, so just return an error condition. | ||
588 | */ | ||
589 | if (dp->dscr_cmd0 & DSCR_CMD0_V) | ||
590 | return 0; | ||
591 | |||
592 | /* Load up buffer address and byte count. */ | ||
593 | dp->dscr_source0 = virt_to_phys(buf); | ||
594 | dp->dscr_cmd1 = nbytes; | ||
595 | /* Check flags */ | ||
596 | if (flags & DDMA_FLAGS_IE) | ||
597 | dp->dscr_cmd0 |= DSCR_CMD0_IE; | ||
598 | if (flags & DDMA_FLAGS_NOIE) | ||
599 | dp->dscr_cmd0 &= ~DSCR_CMD0_IE; | ||
600 | |||
601 | /* | ||
602 | * There is an errata on the Au1200/Au1550 parts that could result | ||
603 | * in "stale" data being DMA'ed. It has to do with the snoop logic on | ||
604 | * the cache eviction buffer. DMA_NONCOHERENT is on by default for | ||
605 | * these parts. If it is fixed in the future, these dma_cache_inv will | ||
606 | * just be nothing more than empty macros. See io.h. | ||
607 | */ | ||
608 | dma_cache_wback_inv((unsigned long)buf, nbytes); | ||
609 | dp->dscr_cmd0 |= DSCR_CMD0_V; /* Let it rip */ | ||
610 | au_sync(); | ||
611 | dma_cache_wback_inv((unsigned long)dp, sizeof(dp)); | ||
612 | ctp->chan_ptr->ddma_dbell = 0; | ||
613 | |||
614 | /* Get next descriptor pointer. */ | ||
615 | ctp->put_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr)); | ||
616 | |||
617 | /* Return something non-zero. */ | ||
618 | return nbytes; | ||
619 | } | ||
620 | EXPORT_SYMBOL(_au1xxx_dbdma_put_source); | ||
621 | |||
622 | /* Put a destination buffer into the DMA ring. | ||
623 | * This updates the destination pointer and byte count. Normally used | ||
624 | * to place an empty buffer into the ring for fifo to memory transfers. | ||
625 | */ | ||
626 | u32 | ||
627 | _au1xxx_dbdma_put_dest(u32 chanid, void *buf, int nbytes, u32 flags) | ||
628 | { | ||
629 | chan_tab_t *ctp; | ||
630 | au1x_ddma_desc_t *dp; | ||
631 | |||
632 | /* I guess we could check this to be within the | ||
633 | * range of the table...... | ||
634 | */ | ||
635 | ctp = *((chan_tab_t **)chanid); | ||
636 | |||
637 | /* We should have multiple callers for a particular channel, | ||
638 | * an interrupt doesn't affect this pointer nor the descriptor, | ||
639 | * so no locking should be needed. | ||
640 | */ | ||
641 | dp = ctp->put_ptr; | ||
642 | |||
643 | /* If the descriptor is valid, we are way ahead of the DMA | ||
644 | * engine, so just return an error condition. | ||
645 | */ | ||
646 | if (dp->dscr_cmd0 & DSCR_CMD0_V) | ||
647 | return 0; | ||
648 | |||
649 | /* Load up buffer address and byte count */ | ||
650 | |||
651 | /* Check flags */ | ||
652 | if (flags & DDMA_FLAGS_IE) | ||
653 | dp->dscr_cmd0 |= DSCR_CMD0_IE; | ||
654 | if (flags & DDMA_FLAGS_NOIE) | ||
655 | dp->dscr_cmd0 &= ~DSCR_CMD0_IE; | ||
656 | |||
657 | dp->dscr_dest0 = virt_to_phys(buf); | ||
658 | dp->dscr_cmd1 = nbytes; | ||
659 | #if 0 | ||
660 | printk(KERN_DEBUG "cmd0:%x cmd1:%x source0:%x source1:%x dest0:%x dest1:%x\n", | ||
661 | dp->dscr_cmd0, dp->dscr_cmd1, dp->dscr_source0, | ||
662 | dp->dscr_source1, dp->dscr_dest0, dp->dscr_dest1); | ||
663 | #endif | ||
664 | /* | ||
665 | * There is an errata on the Au1200/Au1550 parts that could result in | ||
666 | * "stale" data being DMA'ed. It has to do with the snoop logic on the | ||
667 | * cache eviction buffer. DMA_NONCOHERENT is on by default for these | ||
668 | * parts. If it is fixed in the future, these dma_cache_inv will just | ||
669 | * be nothing more than empty macros. See io.h. | ||
670 | */ | ||
671 | dma_cache_inv((unsigned long)buf, nbytes); | ||
672 | dp->dscr_cmd0 |= DSCR_CMD0_V; /* Let it rip */ | ||
673 | au_sync(); | ||
674 | dma_cache_wback_inv((unsigned long)dp, sizeof(dp)); | ||
675 | ctp->chan_ptr->ddma_dbell = 0; | ||
676 | |||
677 | /* Get next descriptor pointer. */ | ||
678 | ctp->put_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr)); | ||
679 | |||
680 | /* Return something non-zero. */ | ||
681 | return nbytes; | ||
682 | } | ||
683 | EXPORT_SYMBOL(_au1xxx_dbdma_put_dest); | ||
684 | |||
685 | /* | ||
686 | * Get a destination buffer into the DMA ring. | ||
687 | * Normally used to get a full buffer from the ring during fifo | ||
688 | * to memory transfers. This does not set the valid bit, you will | ||
689 | * have to put another destination buffer to keep the DMA going. | ||
690 | */ | ||
691 | u32 au1xxx_dbdma_get_dest(u32 chanid, void **buf, int *nbytes) | ||
692 | { | ||
693 | chan_tab_t *ctp; | ||
694 | au1x_ddma_desc_t *dp; | ||
695 | u32 rv; | ||
696 | |||
697 | /* | ||
698 | * I guess we could check this to be within the | ||
699 | * range of the table...... | ||
700 | */ | ||
701 | ctp = *((chan_tab_t **)chanid); | ||
702 | |||
703 | /* | ||
704 | * We should have multiple callers for a particular channel, | ||
705 | * an interrupt doesn't affect this pointer nor the descriptor, | ||
706 | * so no locking should be needed. | ||
707 | */ | ||
708 | dp = ctp->get_ptr; | ||
709 | |||
710 | /* | ||
711 | * If the descriptor is valid, we are way ahead of the DMA | ||
712 | * engine, so just return an error condition. | ||
713 | */ | ||
714 | if (dp->dscr_cmd0 & DSCR_CMD0_V) | ||
715 | return 0; | ||
716 | |||
717 | /* Return buffer address and byte count. */ | ||
718 | *buf = (void *)(phys_to_virt(dp->dscr_dest0)); | ||
719 | *nbytes = dp->dscr_cmd1; | ||
720 | rv = dp->dscr_stat; | ||
721 | |||
722 | /* Get next descriptor pointer. */ | ||
723 | ctp->get_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr)); | ||
724 | |||
725 | /* Return something non-zero. */ | ||
726 | return rv; | ||
727 | } | ||
728 | EXPORT_SYMBOL_GPL(au1xxx_dbdma_get_dest); | ||
729 | |||
730 | void au1xxx_dbdma_stop(u32 chanid) | ||
731 | { | ||
732 | chan_tab_t *ctp; | ||
733 | au1x_dma_chan_t *cp; | ||
734 | int halt_timeout = 0; | ||
735 | |||
736 | ctp = *((chan_tab_t **)chanid); | ||
737 | |||
738 | cp = ctp->chan_ptr; | ||
739 | cp->ddma_cfg &= ~DDMA_CFG_EN; /* Disable channel */ | ||
740 | au_sync(); | ||
741 | while (!(cp->ddma_stat & DDMA_STAT_H)) { | ||
742 | udelay(1); | ||
743 | halt_timeout++; | ||
744 | if (halt_timeout > 100) { | ||
745 | printk(KERN_WARNING "warning: DMA channel won't halt\n"); | ||
746 | break; | ||
747 | } | ||
748 | } | ||
749 | /* clear current desc valid and doorbell */ | ||
750 | cp->ddma_stat |= (DDMA_STAT_DB | DDMA_STAT_V); | ||
751 | au_sync(); | ||
752 | } | ||
753 | EXPORT_SYMBOL(au1xxx_dbdma_stop); | ||
754 | |||
755 | /* | ||
756 | * Start using the current descriptor pointer. If the DBDMA encounters | ||
757 | * a non-valid descriptor, it will stop. In this case, we can just | ||
758 | * continue by adding a buffer to the list and starting again. | ||
759 | */ | ||
760 | void au1xxx_dbdma_start(u32 chanid) | ||
761 | { | ||
762 | chan_tab_t *ctp; | ||
763 | au1x_dma_chan_t *cp; | ||
764 | |||
765 | ctp = *((chan_tab_t **)chanid); | ||
766 | cp = ctp->chan_ptr; | ||
767 | cp->ddma_desptr = virt_to_phys(ctp->cur_ptr); | ||
768 | cp->ddma_cfg |= DDMA_CFG_EN; /* Enable channel */ | ||
769 | au_sync(); | ||
770 | cp->ddma_dbell = 0; | ||
771 | au_sync(); | ||
772 | } | ||
773 | EXPORT_SYMBOL(au1xxx_dbdma_start); | ||
774 | |||
775 | void au1xxx_dbdma_reset(u32 chanid) | ||
776 | { | ||
777 | chan_tab_t *ctp; | ||
778 | au1x_ddma_desc_t *dp; | ||
779 | |||
780 | au1xxx_dbdma_stop(chanid); | ||
781 | |||
782 | ctp = *((chan_tab_t **)chanid); | ||
783 | ctp->get_ptr = ctp->put_ptr = ctp->cur_ptr = ctp->chan_desc_base; | ||
784 | |||
785 | /* Run through the descriptors and reset the valid indicator. */ | ||
786 | dp = ctp->chan_desc_base; | ||
787 | |||
788 | do { | ||
789 | dp->dscr_cmd0 &= ~DSCR_CMD0_V; | ||
790 | /* | ||
791 | * Reset our software status -- this is used to determine | ||
792 | * if a descriptor is in use by upper level software. Since | ||
793 | * posting can reset 'V' bit. | ||
794 | */ | ||
795 | dp->sw_status = 0; | ||
796 | dp = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr)); | ||
797 | } while (dp != ctp->chan_desc_base); | ||
798 | } | ||
799 | EXPORT_SYMBOL(au1xxx_dbdma_reset); | ||
800 | |||
801 | u32 au1xxx_get_dma_residue(u32 chanid) | ||
802 | { | ||
803 | chan_tab_t *ctp; | ||
804 | au1x_dma_chan_t *cp; | ||
805 | u32 rv; | ||
806 | |||
807 | ctp = *((chan_tab_t **)chanid); | ||
808 | cp = ctp->chan_ptr; | ||
809 | |||
810 | /* This is only valid if the channel is stopped. */ | ||
811 | rv = cp->ddma_bytecnt; | ||
812 | au_sync(); | ||
813 | |||
814 | return rv; | ||
815 | } | ||
816 | EXPORT_SYMBOL_GPL(au1xxx_get_dma_residue); | ||
817 | |||
818 | void au1xxx_dbdma_chan_free(u32 chanid) | ||
819 | { | ||
820 | chan_tab_t *ctp; | ||
821 | dbdev_tab_t *stp, *dtp; | ||
822 | |||
823 | ctp = *((chan_tab_t **)chanid); | ||
824 | stp = ctp->chan_src; | ||
825 | dtp = ctp->chan_dest; | ||
826 | |||
827 | au1xxx_dbdma_stop(chanid); | ||
828 | |||
829 | kfree((void *)ctp->chan_desc_base); | ||
830 | |||
831 | stp->dev_flags &= ~DEV_FLAGS_INUSE; | ||
832 | dtp->dev_flags &= ~DEV_FLAGS_INUSE; | ||
833 | chan_tab_ptr[ctp->chan_index] = NULL; | ||
834 | |||
835 | kfree(ctp); | ||
836 | } | ||
837 | EXPORT_SYMBOL(au1xxx_dbdma_chan_free); | ||
838 | |||
839 | static irqreturn_t dbdma_interrupt(int irq, void *dev_id) | ||
840 | { | ||
841 | u32 intstat; | ||
842 | u32 chan_index; | ||
843 | chan_tab_t *ctp; | ||
844 | au1x_ddma_desc_t *dp; | ||
845 | au1x_dma_chan_t *cp; | ||
846 | |||
847 | intstat = dbdma_gptr->ddma_intstat; | ||
848 | au_sync(); | ||
849 | chan_index = __ffs(intstat); | ||
850 | |||
851 | ctp = chan_tab_ptr[chan_index]; | ||
852 | cp = ctp->chan_ptr; | ||
853 | dp = ctp->cur_ptr; | ||
854 | |||
855 | /* Reset interrupt. */ | ||
856 | cp->ddma_irq = 0; | ||
857 | au_sync(); | ||
858 | |||
859 | if (ctp->chan_callback) | ||
860 | ctp->chan_callback(irq, ctp->chan_callparam); | ||
861 | |||
862 | ctp->cur_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr)); | ||
863 | return IRQ_RETVAL(1); | ||
864 | } | ||
865 | |||
866 | static void au1xxx_dbdma_init(void) | ||
867 | { | ||
868 | int irq_nr; | ||
869 | |||
870 | dbdma_gptr->ddma_config = 0; | ||
871 | dbdma_gptr->ddma_throttle = 0; | ||
872 | dbdma_gptr->ddma_inten = 0xffff; | ||
873 | au_sync(); | ||
874 | |||
875 | #if defined(CONFIG_SOC_AU1550) | ||
876 | irq_nr = AU1550_DDMA_INT; | ||
877 | #elif defined(CONFIG_SOC_AU1200) | ||
878 | irq_nr = AU1200_DDMA_INT; | ||
879 | #else | ||
880 | #error Unknown Au1x00 SOC | ||
881 | #endif | ||
882 | |||
883 | if (request_irq(irq_nr, dbdma_interrupt, IRQF_DISABLED, | ||
884 | "Au1xxx dbdma", (void *)dbdma_gptr)) | ||
885 | printk(KERN_ERR "Can't get 1550 dbdma irq"); | ||
886 | } | ||
887 | |||
888 | void au1xxx_dbdma_dump(u32 chanid) | ||
889 | { | ||
890 | chan_tab_t *ctp; | ||
891 | au1x_ddma_desc_t *dp; | ||
892 | dbdev_tab_t *stp, *dtp; | ||
893 | au1x_dma_chan_t *cp; | ||
894 | u32 i = 0; | ||
895 | |||
896 | ctp = *((chan_tab_t **)chanid); | ||
897 | stp = ctp->chan_src; | ||
898 | dtp = ctp->chan_dest; | ||
899 | cp = ctp->chan_ptr; | ||
900 | |||
901 | printk(KERN_DEBUG "Chan %x, stp %x (dev %d) dtp %x (dev %d) \n", | ||
902 | (u32)ctp, (u32)stp, stp - dbdev_tab, (u32)dtp, | ||
903 | dtp - dbdev_tab); | ||
904 | printk(KERN_DEBUG "desc base %x, get %x, put %x, cur %x\n", | ||
905 | (u32)(ctp->chan_desc_base), (u32)(ctp->get_ptr), | ||
906 | (u32)(ctp->put_ptr), (u32)(ctp->cur_ptr)); | ||
907 | |||
908 | printk(KERN_DEBUG "dbdma chan %x\n", (u32)cp); | ||
909 | printk(KERN_DEBUG "cfg %08x, desptr %08x, statptr %08x\n", | ||
910 | cp->ddma_cfg, cp->ddma_desptr, cp->ddma_statptr); | ||
911 | printk(KERN_DEBUG "dbell %08x, irq %08x, stat %08x, bytecnt %08x\n", | ||
912 | cp->ddma_dbell, cp->ddma_irq, cp->ddma_stat, | ||
913 | cp->ddma_bytecnt); | ||
914 | |||
915 | /* Run through the descriptors */ | ||
916 | dp = ctp->chan_desc_base; | ||
917 | |||
918 | do { | ||
919 | printk(KERN_DEBUG "Dp[%d]= %08x, cmd0 %08x, cmd1 %08x\n", | ||
920 | i++, (u32)dp, dp->dscr_cmd0, dp->dscr_cmd1); | ||
921 | printk(KERN_DEBUG "src0 %08x, src1 %08x, dest0 %08x, dest1 %08x\n", | ||
922 | dp->dscr_source0, dp->dscr_source1, | ||
923 | dp->dscr_dest0, dp->dscr_dest1); | ||
924 | printk(KERN_DEBUG "stat %08x, nxtptr %08x\n", | ||
925 | dp->dscr_stat, dp->dscr_nxtptr); | ||
926 | dp = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr)); | ||
927 | } while (dp != ctp->chan_desc_base); | ||
928 | } | ||
929 | |||
930 | /* Put a descriptor into the DMA ring. | ||
931 | * This updates the source/destination pointers and byte count. | ||
932 | */ | ||
933 | u32 au1xxx_dbdma_put_dscr(u32 chanid, au1x_ddma_desc_t *dscr) | ||
934 | { | ||
935 | chan_tab_t *ctp; | ||
936 | au1x_ddma_desc_t *dp; | ||
937 | u32 nbytes = 0; | ||
938 | |||
939 | /* | ||
940 | * I guess we could check this to be within the | ||
941 | * range of the table...... | ||
942 | */ | ||
943 | ctp = *((chan_tab_t **)chanid); | ||
944 | |||
945 | /* | ||
946 | * We should have multiple callers for a particular channel, | ||
947 | * an interrupt doesn't affect this pointer nor the descriptor, | ||
948 | * so no locking should be needed. | ||
949 | */ | ||
950 | dp = ctp->put_ptr; | ||
951 | |||
952 | /* | ||
953 | * If the descriptor is valid, we are way ahead of the DMA | ||
954 | * engine, so just return an error condition. | ||
955 | */ | ||
956 | if (dp->dscr_cmd0 & DSCR_CMD0_V) | ||
957 | return 0; | ||
958 | |||
959 | /* Load up buffer addresses and byte count. */ | ||
960 | dp->dscr_dest0 = dscr->dscr_dest0; | ||
961 | dp->dscr_source0 = dscr->dscr_source0; | ||
962 | dp->dscr_dest1 = dscr->dscr_dest1; | ||
963 | dp->dscr_source1 = dscr->dscr_source1; | ||
964 | dp->dscr_cmd1 = dscr->dscr_cmd1; | ||
965 | nbytes = dscr->dscr_cmd1; | ||
966 | /* Allow the caller to specifiy if an interrupt is generated */ | ||
967 | dp->dscr_cmd0 &= ~DSCR_CMD0_IE; | ||
968 | dp->dscr_cmd0 |= dscr->dscr_cmd0 | DSCR_CMD0_V; | ||
969 | ctp->chan_ptr->ddma_dbell = 0; | ||
970 | |||
971 | /* Get next descriptor pointer. */ | ||
972 | ctp->put_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr)); | ||
973 | |||
974 | /* Return something non-zero. */ | ||
975 | return nbytes; | ||
976 | } | ||
977 | |||
978 | #endif /* defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200) */ | ||
diff --git a/arch/mips/alchemy/common/dma.c b/arch/mips/alchemy/common/dma.c new file mode 100644 index 000000000000..d6fbda232e6a --- /dev/null +++ b/arch/mips/alchemy/common/dma.c | |||
@@ -0,0 +1,238 @@ | |||
1 | /* | ||
2 | * | ||
3 | * BRIEF MODULE DESCRIPTION | ||
4 | * A DMA channel allocator for Au1x00. API is modeled loosely off of | ||
5 | * linux/kernel/dma.c. | ||
6 | * | ||
7 | * Copyright 2000, 2008 MontaVista Software Inc. | ||
8 | * Author: MontaVista Software, Inc. <source@mvista.com> | ||
9 | * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org) | ||
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 as published by the | ||
13 | * Free Software Foundation; either version 2 of the License, or (at your | ||
14 | * option) any later version. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
17 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
18 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
19 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
21 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
22 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
23 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | * | ||
27 | * You should have received a copy of the GNU General Public License along | ||
28 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
29 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
30 | * | ||
31 | */ | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/kernel.h> | ||
34 | #include <linux/errno.h> | ||
35 | #include <linux/spinlock.h> | ||
36 | #include <linux/interrupt.h> | ||
37 | |||
38 | #include <asm/mach-au1x00/au1000.h> | ||
39 | #include <asm/mach-au1x00/au1000_dma.h> | ||
40 | |||
41 | #if defined(CONFIG_SOC_AU1000) || defined(CONFIG_SOC_AU1500) || \ | ||
42 | defined(CONFIG_SOC_AU1100) | ||
43 | /* | ||
44 | * A note on resource allocation: | ||
45 | * | ||
46 | * All drivers needing DMA channels, should allocate and release them | ||
47 | * through the public routines `request_dma()' and `free_dma()'. | ||
48 | * | ||
49 | * In order to avoid problems, all processes should allocate resources in | ||
50 | * the same sequence and release them in the reverse order. | ||
51 | * | ||
52 | * So, when allocating DMAs and IRQs, first allocate the DMA, then the IRQ. | ||
53 | * When releasing them, first release the IRQ, then release the DMA. The | ||
54 | * main reason for this order is that, if you are requesting the DMA buffer | ||
55 | * done interrupt, you won't know the irq number until the DMA channel is | ||
56 | * returned from request_dma. | ||
57 | */ | ||
58 | |||
59 | DEFINE_SPINLOCK(au1000_dma_spin_lock); | ||
60 | |||
61 | struct dma_chan au1000_dma_table[NUM_AU1000_DMA_CHANNELS] = { | ||
62 | {.dev_id = -1,}, | ||
63 | {.dev_id = -1,}, | ||
64 | {.dev_id = -1,}, | ||
65 | {.dev_id = -1,}, | ||
66 | {.dev_id = -1,}, | ||
67 | {.dev_id = -1,}, | ||
68 | {.dev_id = -1,}, | ||
69 | {.dev_id = -1,} | ||
70 | }; | ||
71 | EXPORT_SYMBOL(au1000_dma_table); | ||
72 | |||
73 | /* Device FIFO addresses and default DMA modes */ | ||
74 | static const struct dma_dev { | ||
75 | unsigned int fifo_addr; | ||
76 | unsigned int dma_mode; | ||
77 | } dma_dev_table[DMA_NUM_DEV] = { | ||
78 | {UART0_ADDR + UART_TX, 0}, | ||
79 | {UART0_ADDR + UART_RX, 0}, | ||
80 | {0, 0}, | ||
81 | {0, 0}, | ||
82 | {AC97C_DATA, DMA_DW16 }, /* coherent */ | ||
83 | {AC97C_DATA, DMA_DR | DMA_DW16 }, /* coherent */ | ||
84 | {UART3_ADDR + UART_TX, DMA_DW8 | DMA_NC}, | ||
85 | {UART3_ADDR + UART_RX, DMA_DR | DMA_DW8 | DMA_NC}, | ||
86 | {USBD_EP0RD, DMA_DR | DMA_DW8 | DMA_NC}, | ||
87 | {USBD_EP0WR, DMA_DW8 | DMA_NC}, | ||
88 | {USBD_EP2WR, DMA_DW8 | DMA_NC}, | ||
89 | {USBD_EP3WR, DMA_DW8 | DMA_NC}, | ||
90 | {USBD_EP4RD, DMA_DR | DMA_DW8 | DMA_NC}, | ||
91 | {USBD_EP5RD, DMA_DR | DMA_DW8 | DMA_NC}, | ||
92 | {I2S_DATA, DMA_DW32 | DMA_NC}, | ||
93 | {I2S_DATA, DMA_DR | DMA_DW32 | DMA_NC} | ||
94 | }; | ||
95 | |||
96 | int au1000_dma_read_proc(char *buf, char **start, off_t fpos, | ||
97 | int length, int *eof, void *data) | ||
98 | { | ||
99 | int i, len = 0; | ||
100 | struct dma_chan *chan; | ||
101 | |||
102 | for (i = 0; i < NUM_AU1000_DMA_CHANNELS; i++) { | ||
103 | chan = get_dma_chan(i); | ||
104 | if (chan != NULL) | ||
105 | len += sprintf(buf + len, "%2d: %s\n", | ||
106 | i, chan->dev_str); | ||
107 | } | ||
108 | |||
109 | if (fpos >= len) { | ||
110 | *start = buf; | ||
111 | *eof = 1; | ||
112 | return 0; | ||
113 | } | ||
114 | *start = buf + fpos; | ||
115 | len -= fpos; | ||
116 | if (len > length) | ||
117 | return length; | ||
118 | *eof = 1; | ||
119 | return len; | ||
120 | } | ||
121 | |||
122 | /* Device FIFO addresses and default DMA modes - 2nd bank */ | ||
123 | static const struct dma_dev dma_dev_table_bank2[DMA_NUM_DEV_BANK2] = { | ||
124 | { SD0_XMIT_FIFO, DMA_DS | DMA_DW8 }, /* coherent */ | ||
125 | { SD0_RECV_FIFO, DMA_DS | DMA_DR | DMA_DW8 }, /* coherent */ | ||
126 | { SD1_XMIT_FIFO, DMA_DS | DMA_DW8 }, /* coherent */ | ||
127 | { SD1_RECV_FIFO, DMA_DS | DMA_DR | DMA_DW8 } /* coherent */ | ||
128 | }; | ||
129 | |||
130 | void dump_au1000_dma_channel(unsigned int dmanr) | ||
131 | { | ||
132 | struct dma_chan *chan; | ||
133 | |||
134 | if (dmanr >= NUM_AU1000_DMA_CHANNELS) | ||
135 | return; | ||
136 | chan = &au1000_dma_table[dmanr]; | ||
137 | |||
138 | printk(KERN_INFO "Au1000 DMA%d Register Dump:\n", dmanr); | ||
139 | printk(KERN_INFO " mode = 0x%08x\n", | ||
140 | au_readl(chan->io + DMA_MODE_SET)); | ||
141 | printk(KERN_INFO " addr = 0x%08x\n", | ||
142 | au_readl(chan->io + DMA_PERIPHERAL_ADDR)); | ||
143 | printk(KERN_INFO " start0 = 0x%08x\n", | ||
144 | au_readl(chan->io + DMA_BUFFER0_START)); | ||
145 | printk(KERN_INFO " start1 = 0x%08x\n", | ||
146 | au_readl(chan->io + DMA_BUFFER1_START)); | ||
147 | printk(KERN_INFO " count0 = 0x%08x\n", | ||
148 | au_readl(chan->io + DMA_BUFFER0_COUNT)); | ||
149 | printk(KERN_INFO " count1 = 0x%08x\n", | ||
150 | au_readl(chan->io + DMA_BUFFER1_COUNT)); | ||
151 | } | ||
152 | |||
153 | /* | ||
154 | * Finds a free channel, and binds the requested device to it. | ||
155 | * Returns the allocated channel number, or negative on error. | ||
156 | * Requests the DMA done IRQ if irqhandler != NULL. | ||
157 | */ | ||
158 | int request_au1000_dma(int dev_id, const char *dev_str, | ||
159 | irq_handler_t irqhandler, | ||
160 | unsigned long irqflags, | ||
161 | void *irq_dev_id) | ||
162 | { | ||
163 | struct dma_chan *chan; | ||
164 | const struct dma_dev *dev; | ||
165 | int i, ret; | ||
166 | |||
167 | #if defined(CONFIG_SOC_AU1100) | ||
168 | if (dev_id < 0 || dev_id >= (DMA_NUM_DEV + DMA_NUM_DEV_BANK2)) | ||
169 | return -EINVAL; | ||
170 | #else | ||
171 | if (dev_id < 0 || dev_id >= DMA_NUM_DEV) | ||
172 | return -EINVAL; | ||
173 | #endif | ||
174 | |||
175 | for (i = 0; i < NUM_AU1000_DMA_CHANNELS; i++) | ||
176 | if (au1000_dma_table[i].dev_id < 0) | ||
177 | break; | ||
178 | |||
179 | if (i == NUM_AU1000_DMA_CHANNELS) | ||
180 | return -ENODEV; | ||
181 | |||
182 | chan = &au1000_dma_table[i]; | ||
183 | |||
184 | if (dev_id >= DMA_NUM_DEV) { | ||
185 | dev_id -= DMA_NUM_DEV; | ||
186 | dev = &dma_dev_table_bank2[dev_id]; | ||
187 | } else | ||
188 | dev = &dma_dev_table[dev_id]; | ||
189 | |||
190 | if (irqhandler) { | ||
191 | chan->irq = AU1000_DMA_INT_BASE + i; | ||
192 | chan->irq_dev = irq_dev_id; | ||
193 | ret = request_irq(chan->irq, irqhandler, irqflags, dev_str, | ||
194 | chan->irq_dev); | ||
195 | if (ret) { | ||
196 | chan->irq = 0; | ||
197 | chan->irq_dev = NULL; | ||
198 | return ret; | ||
199 | } | ||
200 | } else { | ||
201 | chan->irq = 0; | ||
202 | chan->irq_dev = NULL; | ||
203 | } | ||
204 | |||
205 | /* fill it in */ | ||
206 | chan->io = DMA_CHANNEL_BASE + i * DMA_CHANNEL_LEN; | ||
207 | chan->dev_id = dev_id; | ||
208 | chan->dev_str = dev_str; | ||
209 | chan->fifo_addr = dev->fifo_addr; | ||
210 | chan->mode = dev->dma_mode; | ||
211 | |||
212 | /* initialize the channel before returning */ | ||
213 | init_dma(i); | ||
214 | |||
215 | return i; | ||
216 | } | ||
217 | EXPORT_SYMBOL(request_au1000_dma); | ||
218 | |||
219 | void free_au1000_dma(unsigned int dmanr) | ||
220 | { | ||
221 | struct dma_chan *chan = get_dma_chan(dmanr); | ||
222 | |||
223 | if (!chan) { | ||
224 | printk(KERN_ERR "Error trying to free DMA%d\n", dmanr); | ||
225 | return; | ||
226 | } | ||
227 | |||
228 | disable_dma(dmanr); | ||
229 | if (chan->irq) | ||
230 | free_irq(chan->irq, chan->irq_dev); | ||
231 | |||
232 | chan->irq = 0; | ||
233 | chan->irq_dev = NULL; | ||
234 | chan->dev_id = -1; | ||
235 | } | ||
236 | EXPORT_SYMBOL(free_au1000_dma); | ||
237 | |||
238 | #endif /* AU1000 AU1500 AU1100 */ | ||
diff --git a/arch/mips/alchemy/common/gpio.c b/arch/mips/alchemy/common/gpio.c new file mode 100644 index 000000000000..e660ddd611c4 --- /dev/null +++ b/arch/mips/alchemy/common/gpio.c | |||
@@ -0,0 +1,148 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007, OpenWrt.org, Florian Fainelli <florian@openwrt.org> | ||
3 | * Architecture specific GPIO support | ||
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 as published by the | ||
7 | * Free Software Foundation; either version 2 of the License, or (at your | ||
8 | * option) any later version. | ||
9 | * | ||
10 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
11 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
12 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
13 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
14 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
15 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
16 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
17 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
18 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
19 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License along | ||
22 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
23 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
24 | * | ||
25 | * Notes : | ||
26 | * au1000 SoC have only one GPIO line : GPIO1 | ||
27 | * others have a second one : GPIO2 | ||
28 | */ | ||
29 | |||
30 | #include <linux/module.h> | ||
31 | |||
32 | #include <asm/mach-au1x00/au1000.h> | ||
33 | #include <asm/gpio.h> | ||
34 | |||
35 | #define gpio1 sys | ||
36 | #if !defined(CONFIG_SOC_AU1000) | ||
37 | |||
38 | static struct au1x00_gpio2 *const gpio2 = (struct au1x00_gpio2 *) GPIO2_BASE; | ||
39 | #define GPIO2_OUTPUT_ENABLE_MASK 0x00010000 | ||
40 | |||
41 | static int au1xxx_gpio2_read(unsigned gpio) | ||
42 | { | ||
43 | gpio -= AU1XXX_GPIO_BASE; | ||
44 | return ((gpio2->pinstate >> gpio) & 0x01); | ||
45 | } | ||
46 | |||
47 | static void au1xxx_gpio2_write(unsigned gpio, int value) | ||
48 | { | ||
49 | gpio -= AU1XXX_GPIO_BASE; | ||
50 | |||
51 | gpio2->output = (GPIO2_OUTPUT_ENABLE_MASK << gpio) | ((!!value) << gpio); | ||
52 | } | ||
53 | |||
54 | static int au1xxx_gpio2_direction_input(unsigned gpio) | ||
55 | { | ||
56 | gpio -= AU1XXX_GPIO_BASE; | ||
57 | gpio2->dir &= ~(0x01 << gpio); | ||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | static int au1xxx_gpio2_direction_output(unsigned gpio, int value) | ||
62 | { | ||
63 | gpio -= AU1XXX_GPIO_BASE; | ||
64 | gpio2->dir |= 0x01 << gpio; | ||
65 | gpio2->output = (GPIO2_OUTPUT_ENABLE_MASK << gpio) | ((!!value) << gpio); | ||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | #endif /* !defined(CONFIG_SOC_AU1000) */ | ||
70 | |||
71 | static int au1xxx_gpio1_read(unsigned gpio) | ||
72 | { | ||
73 | return (gpio1->pinstaterd >> gpio) & 0x01; | ||
74 | } | ||
75 | |||
76 | static void au1xxx_gpio1_write(unsigned gpio, int value) | ||
77 | { | ||
78 | if (value) | ||
79 | gpio1->outputset = (0x01 << gpio); | ||
80 | else | ||
81 | /* Output a zero */ | ||
82 | gpio1->outputclr = (0x01 << gpio); | ||
83 | } | ||
84 | |||
85 | static int au1xxx_gpio1_direction_input(unsigned gpio) | ||
86 | { | ||
87 | gpio1->pininputen = (0x01 << gpio); | ||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | static int au1xxx_gpio1_direction_output(unsigned gpio, int value) | ||
92 | { | ||
93 | gpio1->trioutclr = (0x01 & gpio); | ||
94 | au1xxx_gpio1_write(gpio, value); | ||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | int au1xxx_gpio_get_value(unsigned gpio) | ||
99 | { | ||
100 | if (gpio >= AU1XXX_GPIO_BASE) | ||
101 | #if defined(CONFIG_SOC_AU1000) | ||
102 | return 0; | ||
103 | #else | ||
104 | return au1xxx_gpio2_read(gpio); | ||
105 | #endif | ||
106 | else | ||
107 | return au1xxx_gpio1_read(gpio); | ||
108 | } | ||
109 | EXPORT_SYMBOL(au1xxx_gpio_get_value); | ||
110 | |||
111 | void au1xxx_gpio_set_value(unsigned gpio, int value) | ||
112 | { | ||
113 | if (gpio >= AU1XXX_GPIO_BASE) | ||
114 | #if defined(CONFIG_SOC_AU1000) | ||
115 | ; | ||
116 | #else | ||
117 | au1xxx_gpio2_write(gpio, value); | ||
118 | #endif | ||
119 | else | ||
120 | au1xxx_gpio1_write(gpio, value); | ||
121 | } | ||
122 | EXPORT_SYMBOL(au1xxx_gpio_set_value); | ||
123 | |||
124 | int au1xxx_gpio_direction_input(unsigned gpio) | ||
125 | { | ||
126 | if (gpio >= AU1XXX_GPIO_BASE) | ||
127 | #if defined(CONFIG_SOC_AU1000) | ||
128 | return -ENODEV; | ||
129 | #else | ||
130 | return au1xxx_gpio2_direction_input(gpio); | ||
131 | #endif | ||
132 | |||
133 | return au1xxx_gpio1_direction_input(gpio); | ||
134 | } | ||
135 | EXPORT_SYMBOL(au1xxx_gpio_direction_input); | ||
136 | |||
137 | int au1xxx_gpio_direction_output(unsigned gpio, int value) | ||
138 | { | ||
139 | if (gpio >= AU1XXX_GPIO_BASE) | ||
140 | #if defined(CONFIG_SOC_AU1000) | ||
141 | return -ENODEV; | ||
142 | #else | ||
143 | return au1xxx_gpio2_direction_output(gpio, value); | ||
144 | #endif | ||
145 | |||
146 | return au1xxx_gpio1_direction_output(gpio, value); | ||
147 | } | ||
148 | EXPORT_SYMBOL(au1xxx_gpio_direction_output); | ||
diff --git a/arch/mips/alchemy/common/irq.c b/arch/mips/alchemy/common/irq.c new file mode 100644 index 000000000000..40c6ceceb5f9 --- /dev/null +++ b/arch/mips/alchemy/common/irq.c | |||
@@ -0,0 +1,596 @@ | |||
1 | /* | ||
2 | * Copyright 2001, 2007-2008 MontaVista Software Inc. | ||
3 | * Author: MontaVista Software, Inc. <source@mvista.com> | ||
4 | * | ||
5 | * Copyright (C) 2007 Ralf Baechle (ralf@linux-mips.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 as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
13 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
14 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
15 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
16 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
17 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
18 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
19 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
20 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
21 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License along | ||
24 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
25 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
26 | */ | ||
27 | #include <linux/bitops.h> | ||
28 | #include <linux/init.h> | ||
29 | #include <linux/interrupt.h> | ||
30 | #include <linux/irq.h> | ||
31 | |||
32 | #include <asm/irq_cpu.h> | ||
33 | #include <asm/mipsregs.h> | ||
34 | #include <asm/mach-au1x00/au1000.h> | ||
35 | #ifdef CONFIG_MIPS_PB1000 | ||
36 | #include <asm/mach-pb1x00/pb1000.h> | ||
37 | #endif | ||
38 | |||
39 | #define EXT_INTC0_REQ0 2 /* IP 2 */ | ||
40 | #define EXT_INTC0_REQ1 3 /* IP 3 */ | ||
41 | #define EXT_INTC1_REQ0 4 /* IP 4 */ | ||
42 | #define EXT_INTC1_REQ1 5 /* IP 5 */ | ||
43 | #define MIPS_TIMER_IP 7 /* IP 7 */ | ||
44 | |||
45 | void (*board_init_irq)(void) __initdata = NULL; | ||
46 | |||
47 | static DEFINE_SPINLOCK(irq_lock); | ||
48 | |||
49 | #ifdef CONFIG_PM | ||
50 | |||
51 | /* | ||
52 | * Save/restore the interrupt controller state. | ||
53 | * Called from the save/restore core registers as part of the | ||
54 | * au_sleep function in power.c.....maybe I should just pm_register() | ||
55 | * them instead? | ||
56 | */ | ||
57 | static unsigned int sleep_intctl_config0[2]; | ||
58 | static unsigned int sleep_intctl_config1[2]; | ||
59 | static unsigned int sleep_intctl_config2[2]; | ||
60 | static unsigned int sleep_intctl_src[2]; | ||
61 | static unsigned int sleep_intctl_assign[2]; | ||
62 | static unsigned int sleep_intctl_wake[2]; | ||
63 | static unsigned int sleep_intctl_mask[2]; | ||
64 | |||
65 | void save_au1xxx_intctl(void) | ||
66 | { | ||
67 | sleep_intctl_config0[0] = au_readl(IC0_CFG0RD); | ||
68 | sleep_intctl_config1[0] = au_readl(IC0_CFG1RD); | ||
69 | sleep_intctl_config2[0] = au_readl(IC0_CFG2RD); | ||
70 | sleep_intctl_src[0] = au_readl(IC0_SRCRD); | ||
71 | sleep_intctl_assign[0] = au_readl(IC0_ASSIGNRD); | ||
72 | sleep_intctl_wake[0] = au_readl(IC0_WAKERD); | ||
73 | sleep_intctl_mask[0] = au_readl(IC0_MASKRD); | ||
74 | |||
75 | sleep_intctl_config0[1] = au_readl(IC1_CFG0RD); | ||
76 | sleep_intctl_config1[1] = au_readl(IC1_CFG1RD); | ||
77 | sleep_intctl_config2[1] = au_readl(IC1_CFG2RD); | ||
78 | sleep_intctl_src[1] = au_readl(IC1_SRCRD); | ||
79 | sleep_intctl_assign[1] = au_readl(IC1_ASSIGNRD); | ||
80 | sleep_intctl_wake[1] = au_readl(IC1_WAKERD); | ||
81 | sleep_intctl_mask[1] = au_readl(IC1_MASKRD); | ||
82 | } | ||
83 | |||
84 | /* | ||
85 | * For most restore operations, we clear the entire register and | ||
86 | * then set the bits we found during the save. | ||
87 | */ | ||
88 | void restore_au1xxx_intctl(void) | ||
89 | { | ||
90 | au_writel(0xffffffff, IC0_MASKCLR); au_sync(); | ||
91 | |||
92 | au_writel(0xffffffff, IC0_CFG0CLR); au_sync(); | ||
93 | au_writel(sleep_intctl_config0[0], IC0_CFG0SET); au_sync(); | ||
94 | au_writel(0xffffffff, IC0_CFG1CLR); au_sync(); | ||
95 | au_writel(sleep_intctl_config1[0], IC0_CFG1SET); au_sync(); | ||
96 | au_writel(0xffffffff, IC0_CFG2CLR); au_sync(); | ||
97 | au_writel(sleep_intctl_config2[0], IC0_CFG2SET); au_sync(); | ||
98 | au_writel(0xffffffff, IC0_SRCCLR); au_sync(); | ||
99 | au_writel(sleep_intctl_src[0], IC0_SRCSET); au_sync(); | ||
100 | au_writel(0xffffffff, IC0_ASSIGNCLR); au_sync(); | ||
101 | au_writel(sleep_intctl_assign[0], IC0_ASSIGNSET); au_sync(); | ||
102 | au_writel(0xffffffff, IC0_WAKECLR); au_sync(); | ||
103 | au_writel(sleep_intctl_wake[0], IC0_WAKESET); au_sync(); | ||
104 | au_writel(0xffffffff, IC0_RISINGCLR); au_sync(); | ||
105 | au_writel(0xffffffff, IC0_FALLINGCLR); au_sync(); | ||
106 | au_writel(0x00000000, IC0_TESTBIT); au_sync(); | ||
107 | |||
108 | au_writel(0xffffffff, IC1_MASKCLR); au_sync(); | ||
109 | |||
110 | au_writel(0xffffffff, IC1_CFG0CLR); au_sync(); | ||
111 | au_writel(sleep_intctl_config0[1], IC1_CFG0SET); au_sync(); | ||
112 | au_writel(0xffffffff, IC1_CFG1CLR); au_sync(); | ||
113 | au_writel(sleep_intctl_config1[1], IC1_CFG1SET); au_sync(); | ||
114 | au_writel(0xffffffff, IC1_CFG2CLR); au_sync(); | ||
115 | au_writel(sleep_intctl_config2[1], IC1_CFG2SET); au_sync(); | ||
116 | au_writel(0xffffffff, IC1_SRCCLR); au_sync(); | ||
117 | au_writel(sleep_intctl_src[1], IC1_SRCSET); au_sync(); | ||
118 | au_writel(0xffffffff, IC1_ASSIGNCLR); au_sync(); | ||
119 | au_writel(sleep_intctl_assign[1], IC1_ASSIGNSET); au_sync(); | ||
120 | au_writel(0xffffffff, IC1_WAKECLR); au_sync(); | ||
121 | au_writel(sleep_intctl_wake[1], IC1_WAKESET); au_sync(); | ||
122 | au_writel(0xffffffff, IC1_RISINGCLR); au_sync(); | ||
123 | au_writel(0xffffffff, IC1_FALLINGCLR); au_sync(); | ||
124 | au_writel(0x00000000, IC1_TESTBIT); au_sync(); | ||
125 | |||
126 | au_writel(sleep_intctl_mask[1], IC1_MASKSET); au_sync(); | ||
127 | |||
128 | au_writel(sleep_intctl_mask[0], IC0_MASKSET); au_sync(); | ||
129 | } | ||
130 | #endif /* CONFIG_PM */ | ||
131 | |||
132 | |||
133 | inline void local_enable_irq(unsigned int irq_nr) | ||
134 | { | ||
135 | unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE; | ||
136 | |||
137 | if (bit >= 32) { | ||
138 | au_writel(1 << (bit - 32), IC1_MASKSET); | ||
139 | au_writel(1 << (bit - 32), IC1_WAKESET); | ||
140 | } else { | ||
141 | au_writel(1 << bit, IC0_MASKSET); | ||
142 | au_writel(1 << bit, IC0_WAKESET); | ||
143 | } | ||
144 | au_sync(); | ||
145 | } | ||
146 | |||
147 | |||
148 | inline void local_disable_irq(unsigned int irq_nr) | ||
149 | { | ||
150 | unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE; | ||
151 | |||
152 | if (bit >= 32) { | ||
153 | au_writel(1 << (bit - 32), IC1_MASKCLR); | ||
154 | au_writel(1 << (bit - 32), IC1_WAKECLR); | ||
155 | } else { | ||
156 | au_writel(1 << bit, IC0_MASKCLR); | ||
157 | au_writel(1 << bit, IC0_WAKECLR); | ||
158 | } | ||
159 | au_sync(); | ||
160 | } | ||
161 | |||
162 | |||
163 | static inline void mask_and_ack_rise_edge_irq(unsigned int irq_nr) | ||
164 | { | ||
165 | unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE; | ||
166 | |||
167 | if (bit >= 32) { | ||
168 | au_writel(1 << (bit - 32), IC1_RISINGCLR); | ||
169 | au_writel(1 << (bit - 32), IC1_MASKCLR); | ||
170 | } else { | ||
171 | au_writel(1 << bit, IC0_RISINGCLR); | ||
172 | au_writel(1 << bit, IC0_MASKCLR); | ||
173 | } | ||
174 | au_sync(); | ||
175 | } | ||
176 | |||
177 | |||
178 | static inline void mask_and_ack_fall_edge_irq(unsigned int irq_nr) | ||
179 | { | ||
180 | unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE; | ||
181 | |||
182 | if (bit >= 32) { | ||
183 | au_writel(1 << (bit - 32), IC1_FALLINGCLR); | ||
184 | au_writel(1 << (bit - 32), IC1_MASKCLR); | ||
185 | } else { | ||
186 | au_writel(1 << bit, IC0_FALLINGCLR); | ||
187 | au_writel(1 << bit, IC0_MASKCLR); | ||
188 | } | ||
189 | au_sync(); | ||
190 | } | ||
191 | |||
192 | |||
193 | static inline void mask_and_ack_either_edge_irq(unsigned int irq_nr) | ||
194 | { | ||
195 | unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE; | ||
196 | |||
197 | /* | ||
198 | * This may assume that we don't get interrupts from | ||
199 | * both edges at once, or if we do, that we don't care. | ||
200 | */ | ||
201 | if (bit >= 32) { | ||
202 | au_writel(1 << (bit - 32), IC1_FALLINGCLR); | ||
203 | au_writel(1 << (bit - 32), IC1_RISINGCLR); | ||
204 | au_writel(1 << (bit - 32), IC1_MASKCLR); | ||
205 | } else { | ||
206 | au_writel(1 << bit, IC0_FALLINGCLR); | ||
207 | au_writel(1 << bit, IC0_RISINGCLR); | ||
208 | au_writel(1 << bit, IC0_MASKCLR); | ||
209 | } | ||
210 | au_sync(); | ||
211 | } | ||
212 | |||
213 | static inline void mask_and_ack_level_irq(unsigned int irq_nr) | ||
214 | { | ||
215 | local_disable_irq(irq_nr); | ||
216 | au_sync(); | ||
217 | #if defined(CONFIG_MIPS_PB1000) | ||
218 | if (irq_nr == AU1000_GPIO_15) { | ||
219 | au_writel(0x8000, PB1000_MDR); /* ack int */ | ||
220 | au_sync(); | ||
221 | } | ||
222 | #endif | ||
223 | } | ||
224 | |||
225 | static void end_irq(unsigned int irq_nr) | ||
226 | { | ||
227 | if (!(irq_desc[irq_nr].status & (IRQ_DISABLED | IRQ_INPROGRESS))) | ||
228 | local_enable_irq(irq_nr); | ||
229 | |||
230 | #if defined(CONFIG_MIPS_PB1000) | ||
231 | if (irq_nr == AU1000_GPIO_15) { | ||
232 | au_writel(0x4000, PB1000_MDR); /* enable int */ | ||
233 | au_sync(); | ||
234 | } | ||
235 | #endif | ||
236 | } | ||
237 | |||
238 | unsigned long save_local_and_disable(int controller) | ||
239 | { | ||
240 | int i; | ||
241 | unsigned long flags, mask; | ||
242 | |||
243 | spin_lock_irqsave(&irq_lock, flags); | ||
244 | if (controller) { | ||
245 | mask = au_readl(IC1_MASKSET); | ||
246 | for (i = 32; i < 64; i++) | ||
247 | local_disable_irq(i); | ||
248 | } else { | ||
249 | mask = au_readl(IC0_MASKSET); | ||
250 | for (i = 0; i < 32; i++) | ||
251 | local_disable_irq(i); | ||
252 | } | ||
253 | spin_unlock_irqrestore(&irq_lock, flags); | ||
254 | |||
255 | return mask; | ||
256 | } | ||
257 | |||
258 | void restore_local_and_enable(int controller, unsigned long mask) | ||
259 | { | ||
260 | int i; | ||
261 | unsigned long flags, new_mask; | ||
262 | |||
263 | spin_lock_irqsave(&irq_lock, flags); | ||
264 | for (i = 0; i < 32; i++) | ||
265 | if (mask & (1 << i)) { | ||
266 | if (controller) | ||
267 | local_enable_irq(i + 32); | ||
268 | else | ||
269 | local_enable_irq(i); | ||
270 | } | ||
271 | |||
272 | if (controller) | ||
273 | new_mask = au_readl(IC1_MASKSET); | ||
274 | else | ||
275 | new_mask = au_readl(IC0_MASKSET); | ||
276 | |||
277 | spin_unlock_irqrestore(&irq_lock, flags); | ||
278 | } | ||
279 | |||
280 | |||
281 | static struct irq_chip rise_edge_irq_type = { | ||
282 | .name = "Au1000 Rise Edge", | ||
283 | .ack = mask_and_ack_rise_edge_irq, | ||
284 | .mask = local_disable_irq, | ||
285 | .mask_ack = mask_and_ack_rise_edge_irq, | ||
286 | .unmask = local_enable_irq, | ||
287 | .end = end_irq, | ||
288 | }; | ||
289 | |||
290 | static struct irq_chip fall_edge_irq_type = { | ||
291 | .name = "Au1000 Fall Edge", | ||
292 | .ack = mask_and_ack_fall_edge_irq, | ||
293 | .mask = local_disable_irq, | ||
294 | .mask_ack = mask_and_ack_fall_edge_irq, | ||
295 | .unmask = local_enable_irq, | ||
296 | .end = end_irq, | ||
297 | }; | ||
298 | |||
299 | static struct irq_chip either_edge_irq_type = { | ||
300 | .name = "Au1000 Rise or Fall Edge", | ||
301 | .ack = mask_and_ack_either_edge_irq, | ||
302 | .mask = local_disable_irq, | ||
303 | .mask_ack = mask_and_ack_either_edge_irq, | ||
304 | .unmask = local_enable_irq, | ||
305 | .end = end_irq, | ||
306 | }; | ||
307 | |||
308 | static struct irq_chip level_irq_type = { | ||
309 | .name = "Au1000 Level", | ||
310 | .ack = mask_and_ack_level_irq, | ||
311 | .mask = local_disable_irq, | ||
312 | .mask_ack = mask_and_ack_level_irq, | ||
313 | .unmask = local_enable_irq, | ||
314 | .end = end_irq, | ||
315 | }; | ||
316 | |||
317 | static void __init setup_local_irq(unsigned int irq_nr, int type, int int_req) | ||
318 | { | ||
319 | unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE; | ||
320 | |||
321 | if (irq_nr > AU1000_MAX_INTR) | ||
322 | return; | ||
323 | |||
324 | /* Config2[n], Config1[n], Config0[n] */ | ||
325 | if (bit >= 32) { | ||
326 | switch (type) { | ||
327 | case INTC_INT_RISE_EDGE: /* 0:0:1 */ | ||
328 | au_writel(1 << (bit - 32), IC1_CFG2CLR); | ||
329 | au_writel(1 << (bit - 32), IC1_CFG1CLR); | ||
330 | au_writel(1 << (bit - 32), IC1_CFG0SET); | ||
331 | set_irq_chip(irq_nr, &rise_edge_irq_type); | ||
332 | break; | ||
333 | case INTC_INT_FALL_EDGE: /* 0:1:0 */ | ||
334 | au_writel(1 << (bit - 32), IC1_CFG2CLR); | ||
335 | au_writel(1 << (bit - 32), IC1_CFG1SET); | ||
336 | au_writel(1 << (bit - 32), IC1_CFG0CLR); | ||
337 | set_irq_chip(irq_nr, &fall_edge_irq_type); | ||
338 | break; | ||
339 | case INTC_INT_RISE_AND_FALL_EDGE: /* 0:1:1 */ | ||
340 | au_writel(1 << (bit - 32), IC1_CFG2CLR); | ||
341 | au_writel(1 << (bit - 32), IC1_CFG1SET); | ||
342 | au_writel(1 << (bit - 32), IC1_CFG0SET); | ||
343 | set_irq_chip(irq_nr, &either_edge_irq_type); | ||
344 | break; | ||
345 | case INTC_INT_HIGH_LEVEL: /* 1:0:1 */ | ||
346 | au_writel(1 << (bit - 32), IC1_CFG2SET); | ||
347 | au_writel(1 << (bit - 32), IC1_CFG1CLR); | ||
348 | au_writel(1 << (bit - 32), IC1_CFG0SET); | ||
349 | set_irq_chip(irq_nr, &level_irq_type); | ||
350 | break; | ||
351 | case INTC_INT_LOW_LEVEL: /* 1:1:0 */ | ||
352 | au_writel(1 << (bit - 32), IC1_CFG2SET); | ||
353 | au_writel(1 << (bit - 32), IC1_CFG1SET); | ||
354 | au_writel(1 << (bit - 32), IC1_CFG0CLR); | ||
355 | set_irq_chip(irq_nr, &level_irq_type); | ||
356 | break; | ||
357 | case INTC_INT_DISABLED: /* 0:0:0 */ | ||
358 | au_writel(1 << (bit - 32), IC1_CFG0CLR); | ||
359 | au_writel(1 << (bit - 32), IC1_CFG1CLR); | ||
360 | au_writel(1 << (bit - 32), IC1_CFG2CLR); | ||
361 | break; | ||
362 | default: /* disable the interrupt */ | ||
363 | printk(KERN_WARNING "unexpected int type %d (irq %d)\n", | ||
364 | type, irq_nr); | ||
365 | au_writel(1 << (bit - 32), IC1_CFG0CLR); | ||
366 | au_writel(1 << (bit - 32), IC1_CFG1CLR); | ||
367 | au_writel(1 << (bit - 32), IC1_CFG2CLR); | ||
368 | return; | ||
369 | } | ||
370 | if (int_req) /* assign to interrupt request 1 */ | ||
371 | au_writel(1 << (bit - 32), IC1_ASSIGNCLR); | ||
372 | else /* assign to interrupt request 0 */ | ||
373 | au_writel(1 << (bit - 32), IC1_ASSIGNSET); | ||
374 | au_writel(1 << (bit - 32), IC1_SRCSET); | ||
375 | au_writel(1 << (bit - 32), IC1_MASKCLR); | ||
376 | au_writel(1 << (bit - 32), IC1_WAKECLR); | ||
377 | } else { | ||
378 | switch (type) { | ||
379 | case INTC_INT_RISE_EDGE: /* 0:0:1 */ | ||
380 | au_writel(1 << bit, IC0_CFG2CLR); | ||
381 | au_writel(1 << bit, IC0_CFG1CLR); | ||
382 | au_writel(1 << bit, IC0_CFG0SET); | ||
383 | set_irq_chip(irq_nr, &rise_edge_irq_type); | ||
384 | break; | ||
385 | case INTC_INT_FALL_EDGE: /* 0:1:0 */ | ||
386 | au_writel(1 << bit, IC0_CFG2CLR); | ||
387 | au_writel(1 << bit, IC0_CFG1SET); | ||
388 | au_writel(1 << bit, IC0_CFG0CLR); | ||
389 | set_irq_chip(irq_nr, &fall_edge_irq_type); | ||
390 | break; | ||
391 | case INTC_INT_RISE_AND_FALL_EDGE: /* 0:1:1 */ | ||
392 | au_writel(1 << bit, IC0_CFG2CLR); | ||
393 | au_writel(1 << bit, IC0_CFG1SET); | ||
394 | au_writel(1 << bit, IC0_CFG0SET); | ||
395 | set_irq_chip(irq_nr, &either_edge_irq_type); | ||
396 | break; | ||
397 | case INTC_INT_HIGH_LEVEL: /* 1:0:1 */ | ||
398 | au_writel(1 << bit, IC0_CFG2SET); | ||
399 | au_writel(1 << bit, IC0_CFG1CLR); | ||
400 | au_writel(1 << bit, IC0_CFG0SET); | ||
401 | set_irq_chip(irq_nr, &level_irq_type); | ||
402 | break; | ||
403 | case INTC_INT_LOW_LEVEL: /* 1:1:0 */ | ||
404 | au_writel(1 << bit, IC0_CFG2SET); | ||
405 | au_writel(1 << bit, IC0_CFG1SET); | ||
406 | au_writel(1 << bit, IC0_CFG0CLR); | ||
407 | set_irq_chip(irq_nr, &level_irq_type); | ||
408 | break; | ||
409 | case INTC_INT_DISABLED: /* 0:0:0 */ | ||
410 | au_writel(1 << bit, IC0_CFG0CLR); | ||
411 | au_writel(1 << bit, IC0_CFG1CLR); | ||
412 | au_writel(1 << bit, IC0_CFG2CLR); | ||
413 | break; | ||
414 | default: /* disable the interrupt */ | ||
415 | printk(KERN_WARNING "unexpected int type %d (irq %d)\n", | ||
416 | type, irq_nr); | ||
417 | au_writel(1 << bit, IC0_CFG0CLR); | ||
418 | au_writel(1 << bit, IC0_CFG1CLR); | ||
419 | au_writel(1 << bit, IC0_CFG2CLR); | ||
420 | return; | ||
421 | } | ||
422 | if (int_req) /* assign to interrupt request 1 */ | ||
423 | au_writel(1 << bit, IC0_ASSIGNCLR); | ||
424 | else /* assign to interrupt request 0 */ | ||
425 | au_writel(1 << bit, IC0_ASSIGNSET); | ||
426 | au_writel(1 << bit, IC0_SRCSET); | ||
427 | au_writel(1 << bit, IC0_MASKCLR); | ||
428 | au_writel(1 << bit, IC0_WAKECLR); | ||
429 | } | ||
430 | au_sync(); | ||
431 | } | ||
432 | |||
433 | /* | ||
434 | * Interrupts are nested. Even if an interrupt handler is registered | ||
435 | * as "fast", we might get another interrupt before we return from | ||
436 | * intcX_reqX_irqdispatch(). | ||
437 | */ | ||
438 | |||
439 | static void intc0_req0_irqdispatch(void) | ||
440 | { | ||
441 | static unsigned long intc0_req0; | ||
442 | unsigned int bit; | ||
443 | |||
444 | intc0_req0 |= au_readl(IC0_REQ0INT); | ||
445 | |||
446 | if (!intc0_req0) | ||
447 | return; | ||
448 | |||
449 | #ifdef AU1000_USB_DEV_REQ_INT | ||
450 | /* | ||
451 | * Because of the tight timing of SETUP token to reply | ||
452 | * transactions, the USB devices-side packet complete | ||
453 | * interrupt needs the highest priority. | ||
454 | */ | ||
455 | if ((intc0_req0 & (1 << AU1000_USB_DEV_REQ_INT))) { | ||
456 | intc0_req0 &= ~(1 << AU1000_USB_DEV_REQ_INT); | ||
457 | do_IRQ(AU1000_USB_DEV_REQ_INT); | ||
458 | return; | ||
459 | } | ||
460 | #endif | ||
461 | bit = __ffs(intc0_req0); | ||
462 | intc0_req0 &= ~(1 << bit); | ||
463 | do_IRQ(AU1000_INTC0_INT_BASE + bit); | ||
464 | } | ||
465 | |||
466 | |||
467 | static void intc0_req1_irqdispatch(void) | ||
468 | { | ||
469 | static unsigned long intc0_req1; | ||
470 | unsigned int bit; | ||
471 | |||
472 | intc0_req1 |= au_readl(IC0_REQ1INT); | ||
473 | |||
474 | if (!intc0_req1) | ||
475 | return; | ||
476 | |||
477 | bit = __ffs(intc0_req1); | ||
478 | intc0_req1 &= ~(1 << bit); | ||
479 | do_IRQ(AU1000_INTC0_INT_BASE + bit); | ||
480 | } | ||
481 | |||
482 | |||
483 | /* | ||
484 | * Interrupt Controller 1: | ||
485 | * interrupts 32 - 63 | ||
486 | */ | ||
487 | static void intc1_req0_irqdispatch(void) | ||
488 | { | ||
489 | static unsigned long intc1_req0; | ||
490 | unsigned int bit; | ||
491 | |||
492 | intc1_req0 |= au_readl(IC1_REQ0INT); | ||
493 | |||
494 | if (!intc1_req0) | ||
495 | return; | ||
496 | |||
497 | bit = __ffs(intc1_req0); | ||
498 | intc1_req0 &= ~(1 << bit); | ||
499 | do_IRQ(AU1000_INTC1_INT_BASE + bit); | ||
500 | } | ||
501 | |||
502 | |||
503 | static void intc1_req1_irqdispatch(void) | ||
504 | { | ||
505 | static unsigned long intc1_req1; | ||
506 | unsigned int bit; | ||
507 | |||
508 | intc1_req1 |= au_readl(IC1_REQ1INT); | ||
509 | |||
510 | if (!intc1_req1) | ||
511 | return; | ||
512 | |||
513 | bit = __ffs(intc1_req1); | ||
514 | intc1_req1 &= ~(1 << bit); | ||
515 | do_IRQ(AU1000_INTC1_INT_BASE + bit); | ||
516 | } | ||
517 | |||
518 | asmlinkage void plat_irq_dispatch(void) | ||
519 | { | ||
520 | unsigned int pending = read_c0_status() & read_c0_cause(); | ||
521 | |||
522 | if (pending & CAUSEF_IP7) | ||
523 | do_IRQ(MIPS_CPU_IRQ_BASE + 7); | ||
524 | else if (pending & CAUSEF_IP2) | ||
525 | intc0_req0_irqdispatch(); | ||
526 | else if (pending & CAUSEF_IP3) | ||
527 | intc0_req1_irqdispatch(); | ||
528 | else if (pending & CAUSEF_IP4) | ||
529 | intc1_req0_irqdispatch(); | ||
530 | else if (pending & CAUSEF_IP5) | ||
531 | intc1_req1_irqdispatch(); | ||
532 | else | ||
533 | spurious_interrupt(); | ||
534 | } | ||
535 | |||
536 | void __init arch_init_irq(void) | ||
537 | { | ||
538 | int i; | ||
539 | struct au1xxx_irqmap *imp; | ||
540 | extern struct au1xxx_irqmap au1xxx_irq_map[]; | ||
541 | extern struct au1xxx_irqmap au1xxx_ic0_map[]; | ||
542 | extern int au1xxx_nr_irqs; | ||
543 | extern int au1xxx_ic0_nr_irqs; | ||
544 | |||
545 | /* | ||
546 | * Initialize interrupt controllers to a safe state. | ||
547 | */ | ||
548 | au_writel(0xffffffff, IC0_CFG0CLR); | ||
549 | au_writel(0xffffffff, IC0_CFG1CLR); | ||
550 | au_writel(0xffffffff, IC0_CFG2CLR); | ||
551 | au_writel(0xffffffff, IC0_MASKCLR); | ||
552 | au_writel(0xffffffff, IC0_ASSIGNSET); | ||
553 | au_writel(0xffffffff, IC0_WAKECLR); | ||
554 | au_writel(0xffffffff, IC0_SRCSET); | ||
555 | au_writel(0xffffffff, IC0_FALLINGCLR); | ||
556 | au_writel(0xffffffff, IC0_RISINGCLR); | ||
557 | au_writel(0x00000000, IC0_TESTBIT); | ||
558 | |||
559 | au_writel(0xffffffff, IC1_CFG0CLR); | ||
560 | au_writel(0xffffffff, IC1_CFG1CLR); | ||
561 | au_writel(0xffffffff, IC1_CFG2CLR); | ||
562 | au_writel(0xffffffff, IC1_MASKCLR); | ||
563 | au_writel(0xffffffff, IC1_ASSIGNSET); | ||
564 | au_writel(0xffffffff, IC1_WAKECLR); | ||
565 | au_writel(0xffffffff, IC1_SRCSET); | ||
566 | au_writel(0xffffffff, IC1_FALLINGCLR); | ||
567 | au_writel(0xffffffff, IC1_RISINGCLR); | ||
568 | au_writel(0x00000000, IC1_TESTBIT); | ||
569 | |||
570 | mips_cpu_irq_init(); | ||
571 | |||
572 | /* | ||
573 | * Initialize IC0, which is fixed per processor. | ||
574 | */ | ||
575 | imp = au1xxx_ic0_map; | ||
576 | for (i = 0; i < au1xxx_ic0_nr_irqs; i++) { | ||
577 | setup_local_irq(imp->im_irq, imp->im_type, imp->im_request); | ||
578 | imp++; | ||
579 | } | ||
580 | |||
581 | /* | ||
582 | * Now set up the irq mapping for the board. | ||
583 | */ | ||
584 | imp = au1xxx_irq_map; | ||
585 | for (i = 0; i < au1xxx_nr_irqs; i++) { | ||
586 | setup_local_irq(imp->im_irq, imp->im_type, imp->im_request); | ||
587 | imp++; | ||
588 | } | ||
589 | |||
590 | set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4); | ||
591 | |||
592 | /* Board specific IRQ initialization. | ||
593 | */ | ||
594 | if (board_init_irq) | ||
595 | board_init_irq(); | ||
596 | } | ||
diff --git a/arch/mips/alchemy/common/pci.c b/arch/mips/alchemy/common/pci.c new file mode 100644 index 000000000000..7866cf50cf99 --- /dev/null +++ b/arch/mips/alchemy/common/pci.c | |||
@@ -0,0 +1,104 @@ | |||
1 | /* | ||
2 | * BRIEF MODULE DESCRIPTION | ||
3 | * Alchemy/AMD Au1x00 PCI support. | ||
4 | * | ||
5 | * Copyright 2001-2003, 2007-2008 MontaVista Software Inc. | ||
6 | * Author: MontaVista Software, Inc. <source@mvista.com> | ||
7 | * | ||
8 | * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org) | ||
9 | * | ||
10 | * Support for all devices (greater than 16) added by David Gathright. | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify it | ||
13 | * under the terms of the GNU General Public License as published by the | ||
14 | * Free Software Foundation; either version 2 of the License, or (at your | ||
15 | * option) any later version. | ||
16 | * | ||
17 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
19 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
20 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
23 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
24 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
27 | * | ||
28 | * You should have received a copy of the GNU General Public License along | ||
29 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
30 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
31 | */ | ||
32 | |||
33 | #include <linux/pci.h> | ||
34 | #include <linux/kernel.h> | ||
35 | #include <linux/init.h> | ||
36 | |||
37 | #include <asm/mach-au1x00/au1000.h> | ||
38 | |||
39 | /* TBD */ | ||
40 | static struct resource pci_io_resource = { | ||
41 | .start = PCI_IO_START, | ||
42 | .end = PCI_IO_END, | ||
43 | .name = "PCI IO space", | ||
44 | .flags = IORESOURCE_IO | ||
45 | }; | ||
46 | |||
47 | static struct resource pci_mem_resource = { | ||
48 | .start = PCI_MEM_START, | ||
49 | .end = PCI_MEM_END, | ||
50 | .name = "PCI memory space", | ||
51 | .flags = IORESOURCE_MEM | ||
52 | }; | ||
53 | |||
54 | extern struct pci_ops au1x_pci_ops; | ||
55 | |||
56 | static struct pci_controller au1x_controller = { | ||
57 | .pci_ops = &au1x_pci_ops, | ||
58 | .io_resource = &pci_io_resource, | ||
59 | .mem_resource = &pci_mem_resource, | ||
60 | }; | ||
61 | |||
62 | #if defined(CONFIG_SOC_AU1500) || defined(CONFIG_SOC_AU1550) | ||
63 | static unsigned long virt_io_addr; | ||
64 | #endif | ||
65 | |||
66 | static int __init au1x_pci_setup(void) | ||
67 | { | ||
68 | extern void au1x_pci_cfg_init(void); | ||
69 | |||
70 | #if defined(CONFIG_SOC_AU1500) || defined(CONFIG_SOC_AU1550) | ||
71 | virt_io_addr = (unsigned long)ioremap(Au1500_PCI_IO_START, | ||
72 | Au1500_PCI_IO_END - Au1500_PCI_IO_START + 1); | ||
73 | |||
74 | if (!virt_io_addr) { | ||
75 | printk(KERN_ERR "Unable to ioremap pci space\n"); | ||
76 | return 1; | ||
77 | } | ||
78 | au1x_controller.io_map_base = virt_io_addr; | ||
79 | |||
80 | #ifdef CONFIG_DMA_NONCOHERENT | ||
81 | { | ||
82 | /* | ||
83 | * Set the NC bit in controller for Au1500 pre-AC silicon | ||
84 | */ | ||
85 | u32 prid = read_c0_prid(); | ||
86 | |||
87 | if ((prid & 0xFF000000) == 0x01000000 && prid < 0x01030202) { | ||
88 | au_writel((1 << 16) | au_readl(Au1500_PCI_CFG), | ||
89 | Au1500_PCI_CFG); | ||
90 | printk(KERN_INFO "Non-coherent PCI accesses enabled\n"); | ||
91 | } | ||
92 | } | ||
93 | #endif | ||
94 | |||
95 | set_io_port_base(virt_io_addr); | ||
96 | #endif | ||
97 | |||
98 | au1x_pci_cfg_init(); | ||
99 | |||
100 | register_pci_controller(&au1x_controller); | ||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | arch_initcall(au1x_pci_setup); | ||
diff --git a/arch/mips/alchemy/common/platform.c b/arch/mips/alchemy/common/platform.c new file mode 100644 index 000000000000..dc8a67efac28 --- /dev/null +++ b/arch/mips/alchemy/common/platform.c | |||
@@ -0,0 +1,319 @@ | |||
1 | /* | ||
2 | * Platform device support for Au1x00 SoCs. | ||
3 | * | ||
4 | * Copyright 2004, Matt Porter <mporter@kernel.crashing.org> | ||
5 | * | ||
6 | * (C) Copyright Embedded Alley Solutions, Inc 2005 | ||
7 | * Author: Pantelis Antoniou <pantelis@embeddedalley.com> | ||
8 | * | ||
9 | * This file is licensed under the terms of the GNU General Public | ||
10 | * License version 2. This program is licensed "as is" without any | ||
11 | * warranty of any kind, whether express or implied. | ||
12 | */ | ||
13 | |||
14 | #include <linux/dma-mapping.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/serial_8250.h> | ||
17 | #include <linux/init.h> | ||
18 | |||
19 | #include <asm/mach-au1x00/au1xxx.h> | ||
20 | |||
21 | #define PORT(_base, _irq) \ | ||
22 | { \ | ||
23 | .iobase = _base, \ | ||
24 | .membase = (void __iomem *)_base,\ | ||
25 | .mapbase = CPHYSADDR(_base), \ | ||
26 | .irq = _irq, \ | ||
27 | .regshift = 2, \ | ||
28 | .iotype = UPIO_AU, \ | ||
29 | .flags = UPF_SKIP_TEST \ | ||
30 | } | ||
31 | |||
32 | static struct plat_serial8250_port au1x00_uart_data[] = { | ||
33 | #if defined(CONFIG_SERIAL_8250_AU1X00) | ||
34 | #if defined(CONFIG_SOC_AU1000) | ||
35 | PORT(UART0_ADDR, AU1000_UART0_INT), | ||
36 | PORT(UART1_ADDR, AU1000_UART1_INT), | ||
37 | PORT(UART2_ADDR, AU1000_UART2_INT), | ||
38 | PORT(UART3_ADDR, AU1000_UART3_INT), | ||
39 | #elif defined(CONFIG_SOC_AU1500) | ||
40 | PORT(UART0_ADDR, AU1500_UART0_INT), | ||
41 | PORT(UART3_ADDR, AU1500_UART3_INT), | ||
42 | #elif defined(CONFIG_SOC_AU1100) | ||
43 | PORT(UART0_ADDR, AU1100_UART0_INT), | ||
44 | PORT(UART1_ADDR, AU1100_UART1_INT), | ||
45 | PORT(UART3_ADDR, AU1100_UART3_INT), | ||
46 | #elif defined(CONFIG_SOC_AU1550) | ||
47 | PORT(UART0_ADDR, AU1550_UART0_INT), | ||
48 | PORT(UART1_ADDR, AU1550_UART1_INT), | ||
49 | PORT(UART3_ADDR, AU1550_UART3_INT), | ||
50 | #elif defined(CONFIG_SOC_AU1200) | ||
51 | PORT(UART0_ADDR, AU1200_UART0_INT), | ||
52 | PORT(UART1_ADDR, AU1200_UART1_INT), | ||
53 | #endif | ||
54 | #endif /* CONFIG_SERIAL_8250_AU1X00 */ | ||
55 | { }, | ||
56 | }; | ||
57 | |||
58 | static struct platform_device au1xx0_uart_device = { | ||
59 | .name = "serial8250", | ||
60 | .id = PLAT8250_DEV_AU1X00, | ||
61 | .dev = { | ||
62 | .platform_data = au1x00_uart_data, | ||
63 | }, | ||
64 | }; | ||
65 | |||
66 | /* OHCI (USB full speed host controller) */ | ||
67 | static struct resource au1xxx_usb_ohci_resources[] = { | ||
68 | [0] = { | ||
69 | .start = USB_OHCI_BASE, | ||
70 | .end = USB_OHCI_BASE + USB_OHCI_LEN - 1, | ||
71 | .flags = IORESOURCE_MEM, | ||
72 | }, | ||
73 | [1] = { | ||
74 | .start = AU1000_USB_HOST_INT, | ||
75 | .end = AU1000_USB_HOST_INT, | ||
76 | .flags = IORESOURCE_IRQ, | ||
77 | }, | ||
78 | }; | ||
79 | |||
80 | /* The dmamask must be set for OHCI to work */ | ||
81 | static u64 ohci_dmamask = DMA_32BIT_MASK; | ||
82 | |||
83 | static struct platform_device au1xxx_usb_ohci_device = { | ||
84 | .name = "au1xxx-ohci", | ||
85 | .id = 0, | ||
86 | .dev = { | ||
87 | .dma_mask = &ohci_dmamask, | ||
88 | .coherent_dma_mask = DMA_32BIT_MASK, | ||
89 | }, | ||
90 | .num_resources = ARRAY_SIZE(au1xxx_usb_ohci_resources), | ||
91 | .resource = au1xxx_usb_ohci_resources, | ||
92 | }; | ||
93 | |||
94 | /*** AU1100 LCD controller ***/ | ||
95 | |||
96 | #ifdef CONFIG_FB_AU1100 | ||
97 | static struct resource au1100_lcd_resources[] = { | ||
98 | [0] = { | ||
99 | .start = LCD_PHYS_ADDR, | ||
100 | .end = LCD_PHYS_ADDR + 0x800 - 1, | ||
101 | .flags = IORESOURCE_MEM, | ||
102 | }, | ||
103 | [1] = { | ||
104 | .start = AU1100_LCD_INT, | ||
105 | .end = AU1100_LCD_INT, | ||
106 | .flags = IORESOURCE_IRQ, | ||
107 | } | ||
108 | }; | ||
109 | |||
110 | static u64 au1100_lcd_dmamask = DMA_32BIT_MASK; | ||
111 | |||
112 | static struct platform_device au1100_lcd_device = { | ||
113 | .name = "au1100-lcd", | ||
114 | .id = 0, | ||
115 | .dev = { | ||
116 | .dma_mask = &au1100_lcd_dmamask, | ||
117 | .coherent_dma_mask = DMA_32BIT_MASK, | ||
118 | }, | ||
119 | .num_resources = ARRAY_SIZE(au1100_lcd_resources), | ||
120 | .resource = au1100_lcd_resources, | ||
121 | }; | ||
122 | #endif | ||
123 | |||
124 | #ifdef CONFIG_SOC_AU1200 | ||
125 | /* EHCI (USB high speed host controller) */ | ||
126 | static struct resource au1xxx_usb_ehci_resources[] = { | ||
127 | [0] = { | ||
128 | .start = USB_EHCI_BASE, | ||
129 | .end = USB_EHCI_BASE + USB_EHCI_LEN - 1, | ||
130 | .flags = IORESOURCE_MEM, | ||
131 | }, | ||
132 | [1] = { | ||
133 | .start = AU1000_USB_HOST_INT, | ||
134 | .end = AU1000_USB_HOST_INT, | ||
135 | .flags = IORESOURCE_IRQ, | ||
136 | }, | ||
137 | }; | ||
138 | |||
139 | static u64 ehci_dmamask = DMA_32BIT_MASK; | ||
140 | |||
141 | static struct platform_device au1xxx_usb_ehci_device = { | ||
142 | .name = "au1xxx-ehci", | ||
143 | .id = 0, | ||
144 | .dev = { | ||
145 | .dma_mask = &ehci_dmamask, | ||
146 | .coherent_dma_mask = DMA_32BIT_MASK, | ||
147 | }, | ||
148 | .num_resources = ARRAY_SIZE(au1xxx_usb_ehci_resources), | ||
149 | .resource = au1xxx_usb_ehci_resources, | ||
150 | }; | ||
151 | |||
152 | /* Au1200 UDC (USB gadget controller) */ | ||
153 | static struct resource au1xxx_usb_gdt_resources[] = { | ||
154 | [0] = { | ||
155 | .start = USB_UDC_BASE, | ||
156 | .end = USB_UDC_BASE + USB_UDC_LEN - 1, | ||
157 | .flags = IORESOURCE_MEM, | ||
158 | }, | ||
159 | [1] = { | ||
160 | .start = AU1200_USB_INT, | ||
161 | .end = AU1200_USB_INT, | ||
162 | .flags = IORESOURCE_IRQ, | ||
163 | }, | ||
164 | }; | ||
165 | |||
166 | static struct resource au1xxx_mmc_resources[] = { | ||
167 | [0] = { | ||
168 | .start = SD0_PHYS_ADDR, | ||
169 | .end = SD0_PHYS_ADDR + 0x7ffff, | ||
170 | .flags = IORESOURCE_MEM, | ||
171 | }, | ||
172 | [1] = { | ||
173 | .start = SD1_PHYS_ADDR, | ||
174 | .end = SD1_PHYS_ADDR + 0x7ffff, | ||
175 | .flags = IORESOURCE_MEM, | ||
176 | }, | ||
177 | [2] = { | ||
178 | .start = AU1200_SD_INT, | ||
179 | .end = AU1200_SD_INT, | ||
180 | .flags = IORESOURCE_IRQ, | ||
181 | } | ||
182 | }; | ||
183 | |||
184 | static u64 udc_dmamask = DMA_32BIT_MASK; | ||
185 | |||
186 | static struct platform_device au1xxx_usb_gdt_device = { | ||
187 | .name = "au1xxx-udc", | ||
188 | .id = 0, | ||
189 | .dev = { | ||
190 | .dma_mask = &udc_dmamask, | ||
191 | .coherent_dma_mask = DMA_32BIT_MASK, | ||
192 | }, | ||
193 | .num_resources = ARRAY_SIZE(au1xxx_usb_gdt_resources), | ||
194 | .resource = au1xxx_usb_gdt_resources, | ||
195 | }; | ||
196 | |||
197 | /* Au1200 UOC (USB OTG controller) */ | ||
198 | static struct resource au1xxx_usb_otg_resources[] = { | ||
199 | [0] = { | ||
200 | .start = USB_UOC_BASE, | ||
201 | .end = USB_UOC_BASE + USB_UOC_LEN - 1, | ||
202 | .flags = IORESOURCE_MEM, | ||
203 | }, | ||
204 | [1] = { | ||
205 | .start = AU1200_USB_INT, | ||
206 | .end = AU1200_USB_INT, | ||
207 | .flags = IORESOURCE_IRQ, | ||
208 | }, | ||
209 | }; | ||
210 | |||
211 | static u64 uoc_dmamask = DMA_32BIT_MASK; | ||
212 | |||
213 | static struct platform_device au1xxx_usb_otg_device = { | ||
214 | .name = "au1xxx-uoc", | ||
215 | .id = 0, | ||
216 | .dev = { | ||
217 | .dma_mask = &uoc_dmamask, | ||
218 | .coherent_dma_mask = DMA_32BIT_MASK, | ||
219 | }, | ||
220 | .num_resources = ARRAY_SIZE(au1xxx_usb_otg_resources), | ||
221 | .resource = au1xxx_usb_otg_resources, | ||
222 | }; | ||
223 | |||
224 | static struct resource au1200_lcd_resources[] = { | ||
225 | [0] = { | ||
226 | .start = LCD_PHYS_ADDR, | ||
227 | .end = LCD_PHYS_ADDR + 0x800 - 1, | ||
228 | .flags = IORESOURCE_MEM, | ||
229 | }, | ||
230 | [1] = { | ||
231 | .start = AU1200_LCD_INT, | ||
232 | .end = AU1200_LCD_INT, | ||
233 | .flags = IORESOURCE_IRQ, | ||
234 | } | ||
235 | }; | ||
236 | |||
237 | static u64 au1200_lcd_dmamask = DMA_32BIT_MASK; | ||
238 | |||
239 | static struct platform_device au1200_lcd_device = { | ||
240 | .name = "au1200-lcd", | ||
241 | .id = 0, | ||
242 | .dev = { | ||
243 | .dma_mask = &au1200_lcd_dmamask, | ||
244 | .coherent_dma_mask = DMA_32BIT_MASK, | ||
245 | }, | ||
246 | .num_resources = ARRAY_SIZE(au1200_lcd_resources), | ||
247 | .resource = au1200_lcd_resources, | ||
248 | }; | ||
249 | |||
250 | static u64 au1xxx_mmc_dmamask = DMA_32BIT_MASK; | ||
251 | |||
252 | static struct platform_device au1xxx_mmc_device = { | ||
253 | .name = "au1xxx-mmc", | ||
254 | .id = 0, | ||
255 | .dev = { | ||
256 | .dma_mask = &au1xxx_mmc_dmamask, | ||
257 | .coherent_dma_mask = DMA_32BIT_MASK, | ||
258 | }, | ||
259 | .num_resources = ARRAY_SIZE(au1xxx_mmc_resources), | ||
260 | .resource = au1xxx_mmc_resources, | ||
261 | }; | ||
262 | #endif /* #ifdef CONFIG_SOC_AU1200 */ | ||
263 | |||
264 | static struct platform_device au1x00_pcmcia_device = { | ||
265 | .name = "au1x00-pcmcia", | ||
266 | .id = 0, | ||
267 | }; | ||
268 | |||
269 | /* All Alchemy demoboards with I2C have this #define in their headers */ | ||
270 | #ifdef SMBUS_PSC_BASE | ||
271 | static struct resource pbdb_smbus_resources[] = { | ||
272 | { | ||
273 | .start = CPHYSADDR(SMBUS_PSC_BASE), | ||
274 | .end = CPHYSADDR(SMBUS_PSC_BASE + 0xfffff), | ||
275 | .flags = IORESOURCE_MEM, | ||
276 | }, | ||
277 | }; | ||
278 | |||
279 | static struct platform_device pbdb_smbus_device = { | ||
280 | .name = "au1xpsc_smbus", | ||
281 | .id = 0, /* bus number */ | ||
282 | .num_resources = ARRAY_SIZE(pbdb_smbus_resources), | ||
283 | .resource = pbdb_smbus_resources, | ||
284 | }; | ||
285 | #endif | ||
286 | |||
287 | static struct platform_device *au1xxx_platform_devices[] __initdata = { | ||
288 | &au1xx0_uart_device, | ||
289 | &au1xxx_usb_ohci_device, | ||
290 | &au1x00_pcmcia_device, | ||
291 | #ifdef CONFIG_FB_AU1100 | ||
292 | &au1100_lcd_device, | ||
293 | #endif | ||
294 | #ifdef CONFIG_SOC_AU1200 | ||
295 | &au1xxx_usb_ehci_device, | ||
296 | &au1xxx_usb_gdt_device, | ||
297 | &au1xxx_usb_otg_device, | ||
298 | &au1200_lcd_device, | ||
299 | &au1xxx_mmc_device, | ||
300 | #endif | ||
301 | #ifdef SMBUS_PSC_BASE | ||
302 | &pbdb_smbus_device, | ||
303 | #endif | ||
304 | }; | ||
305 | |||
306 | static int __init au1xxx_platform_init(void) | ||
307 | { | ||
308 | unsigned int uartclk = get_au1x00_uart_baud_base() * 16; | ||
309 | int i; | ||
310 | |||
311 | /* Fill up uartclk. */ | ||
312 | for (i = 0; au1x00_uart_data[i].flags; i++) | ||
313 | au1x00_uart_data[i].uartclk = uartclk; | ||
314 | |||
315 | return platform_add_devices(au1xxx_platform_devices, | ||
316 | ARRAY_SIZE(au1xxx_platform_devices)); | ||
317 | } | ||
318 | |||
319 | arch_initcall(au1xxx_platform_init); | ||
diff --git a/arch/mips/alchemy/common/power.c b/arch/mips/alchemy/common/power.c new file mode 100644 index 000000000000..bd854a6d1d89 --- /dev/null +++ b/arch/mips/alchemy/common/power.c | |||
@@ -0,0 +1,465 @@ | |||
1 | /* | ||
2 | * BRIEF MODULE DESCRIPTION | ||
3 | * Au1xx0 Power Management routines. | ||
4 | * | ||
5 | * Copyright 2001, 2008 MontaVista Software Inc. | ||
6 | * Author: MontaVista Software, Inc. <source@mvista.com> | ||
7 | * | ||
8 | * Some of the routines are right out of init/main.c, whose | ||
9 | * copyrights apply here. | ||
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 as published by the | ||
13 | * Free Software Foundation; either version 2 of the License, or (at your | ||
14 | * option) any later version. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
17 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
18 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
19 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
21 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
22 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
23 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | * | ||
27 | * You should have received a copy of the GNU General Public License along | ||
28 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
29 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
30 | */ | ||
31 | |||
32 | #include <linux/init.h> | ||
33 | #include <linux/pm.h> | ||
34 | #include <linux/sysctl.h> | ||
35 | #include <linux/jiffies.h> | ||
36 | |||
37 | #include <asm/uaccess.h> | ||
38 | #include <asm/cacheflush.h> | ||
39 | #include <asm/mach-au1x00/au1000.h> | ||
40 | |||
41 | #ifdef CONFIG_PM | ||
42 | |||
43 | #define DEBUG 1 | ||
44 | #ifdef DEBUG | ||
45 | #define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__, ## args) | ||
46 | #else | ||
47 | #define DPRINTK(fmt, args...) | ||
48 | #endif | ||
49 | |||
50 | static void au1000_calibrate_delay(void); | ||
51 | |||
52 | extern unsigned long save_local_and_disable(int controller); | ||
53 | extern void restore_local_and_enable(int controller, unsigned long mask); | ||
54 | extern void local_enable_irq(unsigned int irq_nr); | ||
55 | |||
56 | static DEFINE_SPINLOCK(pm_lock); | ||
57 | |||
58 | /* | ||
59 | * We need to save/restore a bunch of core registers that are | ||
60 | * either volatile or reset to some state across a processor sleep. | ||
61 | * If reading a register doesn't provide a proper result for a | ||
62 | * later restore, we have to provide a function for loading that | ||
63 | * register and save a copy. | ||
64 | * | ||
65 | * We only have to save/restore registers that aren't otherwise | ||
66 | * done as part of a driver pm_* function. | ||
67 | */ | ||
68 | static unsigned int sleep_aux_pll_cntrl; | ||
69 | static unsigned int sleep_cpu_pll_cntrl; | ||
70 | static unsigned int sleep_pin_function; | ||
71 | static unsigned int sleep_uart0_inten; | ||
72 | static unsigned int sleep_uart0_fifoctl; | ||
73 | static unsigned int sleep_uart0_linectl; | ||
74 | static unsigned int sleep_uart0_clkdiv; | ||
75 | static unsigned int sleep_uart0_enable; | ||
76 | static unsigned int sleep_usbhost_enable; | ||
77 | static unsigned int sleep_usbdev_enable; | ||
78 | static unsigned int sleep_static_memctlr[4][3]; | ||
79 | |||
80 | /* | ||
81 | * Define this to cause the value you write to /proc/sys/pm/sleep to | ||
82 | * set the TOY timer for the amount of time you want to sleep. | ||
83 | * This is done mainly for testing, but may be useful in other cases. | ||
84 | * The value is number of 32KHz ticks to sleep. | ||
85 | */ | ||
86 | #define SLEEP_TEST_TIMEOUT 1 | ||
87 | #ifdef SLEEP_TEST_TIMEOUT | ||
88 | static int sleep_ticks; | ||
89 | void wakeup_counter0_set(int ticks); | ||
90 | #endif | ||
91 | |||
92 | static void save_core_regs(void) | ||
93 | { | ||
94 | extern void save_au1xxx_intctl(void); | ||
95 | extern void pm_eth0_shutdown(void); | ||
96 | |||
97 | /* | ||
98 | * Do the serial ports.....these really should be a pm_* | ||
99 | * registered function by the driver......but of course the | ||
100 | * standard serial driver doesn't understand our Au1xxx | ||
101 | * unique registers. | ||
102 | */ | ||
103 | sleep_uart0_inten = au_readl(UART0_ADDR + UART_IER); | ||
104 | sleep_uart0_fifoctl = au_readl(UART0_ADDR + UART_FCR); | ||
105 | sleep_uart0_linectl = au_readl(UART0_ADDR + UART_LCR); | ||
106 | sleep_uart0_clkdiv = au_readl(UART0_ADDR + UART_CLK); | ||
107 | sleep_uart0_enable = au_readl(UART0_ADDR + UART_MOD_CNTRL); | ||
108 | |||
109 | /* Shutdown USB host/device. */ | ||
110 | sleep_usbhost_enable = au_readl(USB_HOST_CONFIG); | ||
111 | |||
112 | /* There appears to be some undocumented reset register.... */ | ||
113 | au_writel(0, 0xb0100004); au_sync(); | ||
114 | au_writel(0, USB_HOST_CONFIG); au_sync(); | ||
115 | |||
116 | sleep_usbdev_enable = au_readl(USBD_ENABLE); | ||
117 | au_writel(0, USBD_ENABLE); au_sync(); | ||
118 | |||
119 | /* Save interrupt controller state. */ | ||
120 | save_au1xxx_intctl(); | ||
121 | |||
122 | /* Clocks and PLLs. */ | ||
123 | sleep_aux_pll_cntrl = au_readl(SYS_AUXPLL); | ||
124 | |||
125 | /* | ||
126 | * We don't really need to do this one, but unless we | ||
127 | * write it again it won't have a valid value if we | ||
128 | * happen to read it. | ||
129 | */ | ||
130 | sleep_cpu_pll_cntrl = au_readl(SYS_CPUPLL); | ||
131 | |||
132 | sleep_pin_function = au_readl(SYS_PINFUNC); | ||
133 | |||
134 | /* Save the static memory controller configuration. */ | ||
135 | sleep_static_memctlr[0][0] = au_readl(MEM_STCFG0); | ||
136 | sleep_static_memctlr[0][1] = au_readl(MEM_STTIME0); | ||
137 | sleep_static_memctlr[0][2] = au_readl(MEM_STADDR0); | ||
138 | sleep_static_memctlr[1][0] = au_readl(MEM_STCFG1); | ||
139 | sleep_static_memctlr[1][1] = au_readl(MEM_STTIME1); | ||
140 | sleep_static_memctlr[1][2] = au_readl(MEM_STADDR1); | ||
141 | sleep_static_memctlr[2][0] = au_readl(MEM_STCFG2); | ||
142 | sleep_static_memctlr[2][1] = au_readl(MEM_STTIME2); | ||
143 | sleep_static_memctlr[2][2] = au_readl(MEM_STADDR2); | ||
144 | sleep_static_memctlr[3][0] = au_readl(MEM_STCFG3); | ||
145 | sleep_static_memctlr[3][1] = au_readl(MEM_STTIME3); | ||
146 | sleep_static_memctlr[3][2] = au_readl(MEM_STADDR3); | ||
147 | } | ||
148 | |||
149 | static void restore_core_regs(void) | ||
150 | { | ||
151 | extern void restore_au1xxx_intctl(void); | ||
152 | extern void wakeup_counter0_adjust(void); | ||
153 | |||
154 | au_writel(sleep_aux_pll_cntrl, SYS_AUXPLL); au_sync(); | ||
155 | au_writel(sleep_cpu_pll_cntrl, SYS_CPUPLL); au_sync(); | ||
156 | au_writel(sleep_pin_function, SYS_PINFUNC); au_sync(); | ||
157 | |||
158 | /* Restore the static memory controller configuration. */ | ||
159 | au_writel(sleep_static_memctlr[0][0], MEM_STCFG0); | ||
160 | au_writel(sleep_static_memctlr[0][1], MEM_STTIME0); | ||
161 | au_writel(sleep_static_memctlr[0][2], MEM_STADDR0); | ||
162 | au_writel(sleep_static_memctlr[1][0], MEM_STCFG1); | ||
163 | au_writel(sleep_static_memctlr[1][1], MEM_STTIME1); | ||
164 | au_writel(sleep_static_memctlr[1][2], MEM_STADDR1); | ||
165 | au_writel(sleep_static_memctlr[2][0], MEM_STCFG2); | ||
166 | au_writel(sleep_static_memctlr[2][1], MEM_STTIME2); | ||
167 | au_writel(sleep_static_memctlr[2][2], MEM_STADDR2); | ||
168 | au_writel(sleep_static_memctlr[3][0], MEM_STCFG3); | ||
169 | au_writel(sleep_static_memctlr[3][1], MEM_STTIME3); | ||
170 | au_writel(sleep_static_memctlr[3][2], MEM_STADDR3); | ||
171 | |||
172 | /* | ||
173 | * Enable the UART if it was enabled before sleep. | ||
174 | * I guess I should define module control bits........ | ||
175 | */ | ||
176 | if (sleep_uart0_enable & 0x02) { | ||
177 | au_writel(0, UART0_ADDR + UART_MOD_CNTRL); au_sync(); | ||
178 | au_writel(1, UART0_ADDR + UART_MOD_CNTRL); au_sync(); | ||
179 | au_writel(3, UART0_ADDR + UART_MOD_CNTRL); au_sync(); | ||
180 | au_writel(sleep_uart0_inten, UART0_ADDR + UART_IER); au_sync(); | ||
181 | au_writel(sleep_uart0_fifoctl, UART0_ADDR + UART_FCR); au_sync(); | ||
182 | au_writel(sleep_uart0_linectl, UART0_ADDR + UART_LCR); au_sync(); | ||
183 | au_writel(sleep_uart0_clkdiv, UART0_ADDR + UART_CLK); au_sync(); | ||
184 | } | ||
185 | |||
186 | restore_au1xxx_intctl(); | ||
187 | wakeup_counter0_adjust(); | ||
188 | } | ||
189 | |||
190 | unsigned long suspend_mode; | ||
191 | |||
192 | void wakeup_from_suspend(void) | ||
193 | { | ||
194 | suspend_mode = 0; | ||
195 | } | ||
196 | |||
197 | int au_sleep(void) | ||
198 | { | ||
199 | unsigned long wakeup, flags; | ||
200 | extern void save_and_sleep(void); | ||
201 | |||
202 | spin_lock_irqsave(&pm_lock, flags); | ||
203 | |||
204 | save_core_regs(); | ||
205 | |||
206 | flush_cache_all(); | ||
207 | |||
208 | /** | ||
209 | ** The code below is all system dependent and we should probably | ||
210 | ** have a function call out of here to set this up. You need | ||
211 | ** to configure the GPIO or timer interrupts that will bring | ||
212 | ** you out of sleep. | ||
213 | ** For testing, the TOY counter wakeup is useful. | ||
214 | **/ | ||
215 | #if 0 | ||
216 | au_writel(au_readl(SYS_PINSTATERD) & ~(1 << 11), SYS_PINSTATERD); | ||
217 | |||
218 | /* GPIO 6 can cause a wake up event */ | ||
219 | wakeup = au_readl(SYS_WAKEMSK); | ||
220 | wakeup &= ~(1 << 8); /* turn off match20 wakeup */ | ||
221 | wakeup |= 1 << 6; /* turn on GPIO 6 wakeup */ | ||
222 | #else | ||
223 | /* For testing, allow match20 to wake us up. */ | ||
224 | #ifdef SLEEP_TEST_TIMEOUT | ||
225 | wakeup_counter0_set(sleep_ticks); | ||
226 | #endif | ||
227 | wakeup = 1 << 8; /* turn on match20 wakeup */ | ||
228 | wakeup = 0; | ||
229 | #endif | ||
230 | au_writel(1, SYS_WAKESRC); /* clear cause */ | ||
231 | au_sync(); | ||
232 | au_writel(wakeup, SYS_WAKEMSK); | ||
233 | au_sync(); | ||
234 | |||
235 | save_and_sleep(); | ||
236 | |||
237 | /* | ||
238 | * After a wakeup, the cpu vectors back to 0x1fc00000, so | ||
239 | * it's up to the boot code to get us back here. | ||
240 | */ | ||
241 | restore_core_regs(); | ||
242 | spin_unlock_irqrestore(&pm_lock, flags); | ||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | static int pm_do_sleep(ctl_table *ctl, int write, struct file *file, | ||
247 | void __user *buffer, size_t *len, loff_t *ppos) | ||
248 | { | ||
249 | #ifdef SLEEP_TEST_TIMEOUT | ||
250 | #define TMPBUFLEN2 16 | ||
251 | char buf[TMPBUFLEN2], *p; | ||
252 | #endif | ||
253 | |||
254 | if (!write) | ||
255 | *len = 0; | ||
256 | else { | ||
257 | #ifdef SLEEP_TEST_TIMEOUT | ||
258 | if (*len > TMPBUFLEN2 - 1) | ||
259 | return -EFAULT; | ||
260 | if (copy_from_user(buf, buffer, *len)) | ||
261 | return -EFAULT; | ||
262 | buf[*len] = 0; | ||
263 | p = buf; | ||
264 | sleep_ticks = simple_strtoul(p, &p, 0); | ||
265 | #endif | ||
266 | |||
267 | au_sleep(); | ||
268 | } | ||
269 | return 0; | ||
270 | } | ||
271 | |||
272 | static int pm_do_freq(ctl_table *ctl, int write, struct file *file, | ||
273 | void __user *buffer, size_t *len, loff_t *ppos) | ||
274 | { | ||
275 | int retval = 0, i; | ||
276 | unsigned long val, pll; | ||
277 | #define TMPBUFLEN 64 | ||
278 | #define MAX_CPU_FREQ 396 | ||
279 | char buf[TMPBUFLEN], *p; | ||
280 | unsigned long flags, intc0_mask, intc1_mask; | ||
281 | unsigned long old_baud_base, old_cpu_freq, old_clk, old_refresh; | ||
282 | unsigned long new_baud_base, new_cpu_freq, new_clk, new_refresh; | ||
283 | unsigned long baud_rate; | ||
284 | |||
285 | spin_lock_irqsave(&pm_lock, flags); | ||
286 | if (!write) | ||
287 | *len = 0; | ||
288 | else { | ||
289 | /* Parse the new frequency */ | ||
290 | if (*len > TMPBUFLEN - 1) { | ||
291 | spin_unlock_irqrestore(&pm_lock, flags); | ||
292 | return -EFAULT; | ||
293 | } | ||
294 | if (copy_from_user(buf, buffer, *len)) { | ||
295 | spin_unlock_irqrestore(&pm_lock, flags); | ||
296 | return -EFAULT; | ||
297 | } | ||
298 | buf[*len] = 0; | ||
299 | p = buf; | ||
300 | val = simple_strtoul(p, &p, 0); | ||
301 | if (val > MAX_CPU_FREQ) { | ||
302 | spin_unlock_irqrestore(&pm_lock, flags); | ||
303 | return -EFAULT; | ||
304 | } | ||
305 | |||
306 | pll = val / 12; | ||
307 | if ((pll > 33) || (pll < 7)) { /* 396 MHz max, 84 MHz min */ | ||
308 | /* Revisit this for higher speed CPUs */ | ||
309 | spin_unlock_irqrestore(&pm_lock, flags); | ||
310 | return -EFAULT; | ||
311 | } | ||
312 | |||
313 | old_baud_base = get_au1x00_uart_baud_base(); | ||
314 | old_cpu_freq = get_au1x00_speed(); | ||
315 | |||
316 | new_cpu_freq = pll * 12 * 1000000; | ||
317 | new_baud_base = (new_cpu_freq / (2 * ((int)(au_readl(SYS_POWERCTRL) | ||
318 | & 0x03) + 2) * 16)); | ||
319 | set_au1x00_speed(new_cpu_freq); | ||
320 | set_au1x00_uart_baud_base(new_baud_base); | ||
321 | |||
322 | old_refresh = au_readl(MEM_SDREFCFG) & 0x1ffffff; | ||
323 | new_refresh = ((old_refresh * new_cpu_freq) / old_cpu_freq) | | ||
324 | (au_readl(MEM_SDREFCFG) & ~0x1ffffff); | ||
325 | |||
326 | au_writel(pll, SYS_CPUPLL); | ||
327 | au_sync_delay(1); | ||
328 | au_writel(new_refresh, MEM_SDREFCFG); | ||
329 | au_sync_delay(1); | ||
330 | |||
331 | for (i = 0; i < 4; i++) | ||
332 | if (au_readl(UART_BASE + UART_MOD_CNTRL + | ||
333 | i * 0x00100000) == 3) { | ||
334 | old_clk = au_readl(UART_BASE + UART_CLK + | ||
335 | i * 0x00100000); | ||
336 | baud_rate = old_baud_base / old_clk; | ||
337 | /* | ||
338 | * We won't get an exact baud rate and the error | ||
339 | * could be significant enough that our new | ||
340 | * calculation will result in a clock that will | ||
341 | * give us a baud rate that's too far off from | ||
342 | * what we really want. | ||
343 | */ | ||
344 | if (baud_rate > 100000) | ||
345 | baud_rate = 115200; | ||
346 | else if (baud_rate > 50000) | ||
347 | baud_rate = 57600; | ||
348 | else if (baud_rate > 30000) | ||
349 | baud_rate = 38400; | ||
350 | else if (baud_rate > 17000) | ||
351 | baud_rate = 19200; | ||
352 | else | ||
353 | baud_rate = 9600; | ||
354 | new_clk = new_baud_base / baud_rate; | ||
355 | au_writel(new_clk, UART_BASE + UART_CLK + | ||
356 | i * 0x00100000); | ||
357 | au_sync_delay(10); | ||
358 | } | ||
359 | } | ||
360 | |||
361 | /* | ||
362 | * We don't want _any_ interrupts other than match20. Otherwise our | ||
363 | * au1000_calibrate_delay() calculation will be off, potentially a lot. | ||
364 | */ | ||
365 | intc0_mask = save_local_and_disable(0); | ||
366 | intc1_mask = save_local_and_disable(1); | ||
367 | local_enable_irq(AU1000_TOY_MATCH2_INT); | ||
368 | spin_unlock_irqrestore(&pm_lock, flags); | ||
369 | au1000_calibrate_delay(); | ||
370 | restore_local_and_enable(0, intc0_mask); | ||
371 | restore_local_and_enable(1, intc1_mask); | ||
372 | |||
373 | return retval; | ||
374 | } | ||
375 | |||
376 | |||
377 | static struct ctl_table pm_table[] = { | ||
378 | { | ||
379 | .ctl_name = CTL_UNNUMBERED, | ||
380 | .procname = "sleep", | ||
381 | .data = NULL, | ||
382 | .maxlen = 0, | ||
383 | .mode = 0600, | ||
384 | .proc_handler = &pm_do_sleep | ||
385 | }, | ||
386 | { | ||
387 | .ctl_name = CTL_UNNUMBERED, | ||
388 | .procname = "freq", | ||
389 | .data = NULL, | ||
390 | .maxlen = 0, | ||
391 | .mode = 0600, | ||
392 | .proc_handler = &pm_do_freq | ||
393 | }, | ||
394 | {} | ||
395 | }; | ||
396 | |||
397 | static struct ctl_table pm_dir_table[] = { | ||
398 | { | ||
399 | .ctl_name = CTL_UNNUMBERED, | ||
400 | .procname = "pm", | ||
401 | .mode = 0555, | ||
402 | .child = pm_table | ||
403 | }, | ||
404 | {} | ||
405 | }; | ||
406 | |||
407 | /* | ||
408 | * Initialize power interface | ||
409 | */ | ||
410 | static int __init pm_init(void) | ||
411 | { | ||
412 | register_sysctl_table(pm_dir_table); | ||
413 | return 0; | ||
414 | } | ||
415 | |||
416 | __initcall(pm_init); | ||
417 | |||
418 | /* | ||
419 | * This is right out of init/main.c | ||
420 | */ | ||
421 | |||
422 | /* | ||
423 | * This is the number of bits of precision for the loops_per_jiffy. | ||
424 | * Each bit takes on average 1.5/HZ seconds. This (like the original) | ||
425 | * is a little better than 1%. | ||
426 | */ | ||
427 | #define LPS_PREC 8 | ||
428 | |||
429 | static void au1000_calibrate_delay(void) | ||
430 | { | ||
431 | unsigned long ticks, loopbit; | ||
432 | int lps_precision = LPS_PREC; | ||
433 | |||
434 | loops_per_jiffy = 1 << 12; | ||
435 | |||
436 | while (loops_per_jiffy <<= 1) { | ||
437 | /* Wait for "start of" clock tick */ | ||
438 | ticks = jiffies; | ||
439 | while (ticks == jiffies) | ||
440 | /* nothing */ ; | ||
441 | /* Go ... */ | ||
442 | ticks = jiffies; | ||
443 | __delay(loops_per_jiffy); | ||
444 | ticks = jiffies - ticks; | ||
445 | if (ticks) | ||
446 | break; | ||
447 | } | ||
448 | |||
449 | /* | ||
450 | * Do a binary approximation to get loops_per_jiffy set to be equal | ||
451 | * one clock (up to lps_precision bits) | ||
452 | */ | ||
453 | loops_per_jiffy >>= 1; | ||
454 | loopbit = loops_per_jiffy; | ||
455 | while (lps_precision-- && (loopbit >>= 1)) { | ||
456 | loops_per_jiffy |= loopbit; | ||
457 | ticks = jiffies; | ||
458 | while (ticks == jiffies); | ||
459 | ticks = jiffies; | ||
460 | __delay(loops_per_jiffy); | ||
461 | if (jiffies != ticks) /* longer than 1 tick */ | ||
462 | loops_per_jiffy &= ~loopbit; | ||
463 | } | ||
464 | } | ||
465 | #endif /* CONFIG_PM */ | ||
diff --git a/arch/mips/alchemy/common/prom.c b/arch/mips/alchemy/common/prom.c new file mode 100644 index 000000000000..18b310b475ca --- /dev/null +++ b/arch/mips/alchemy/common/prom.c | |||
@@ -0,0 +1,146 @@ | |||
1 | /* | ||
2 | * | ||
3 | * BRIEF MODULE DESCRIPTION | ||
4 | * PROM library initialisation code, supports YAMON and U-Boot. | ||
5 | * | ||
6 | * Copyright 2000-2001, 2006, 2008 MontaVista Software Inc. | ||
7 | * Author: MontaVista Software, Inc. <source@mvista.com> | ||
8 | * | ||
9 | * This file was derived from Carsten Langgaard's | ||
10 | * arch/mips/mips-boards/xx files. | ||
11 | * | ||
12 | * Carsten Langgaard, carstenl@mips.com | ||
13 | * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or modify it | ||
16 | * under the terms of the GNU General Public License as published by the | ||
17 | * Free Software Foundation; either version 2 of the License, or (at your | ||
18 | * option) any later version. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
21 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
22 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
23 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
24 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
25 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
26 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
27 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
29 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
30 | * | ||
31 | * You should have received a copy of the GNU General Public License along | ||
32 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
33 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
34 | */ | ||
35 | |||
36 | #include <linux/module.h> | ||
37 | #include <linux/init.h> | ||
38 | #include <linux/string.h> | ||
39 | |||
40 | #include <asm/bootinfo.h> | ||
41 | |||
42 | int prom_argc; | ||
43 | char **prom_argv; | ||
44 | char **prom_envp; | ||
45 | |||
46 | char * __init_or_module prom_getcmdline(void) | ||
47 | { | ||
48 | return &(arcs_cmdline[0]); | ||
49 | } | ||
50 | |||
51 | void prom_init_cmdline(void) | ||
52 | { | ||
53 | char *cp; | ||
54 | int actr; | ||
55 | |||
56 | actr = 1; /* Always ignore argv[0] */ | ||
57 | |||
58 | cp = &(arcs_cmdline[0]); | ||
59 | while (actr < prom_argc) { | ||
60 | strcpy(cp, prom_argv[actr]); | ||
61 | cp += strlen(prom_argv[actr]); | ||
62 | *cp++ = ' '; | ||
63 | actr++; | ||
64 | } | ||
65 | if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */ | ||
66 | --cp; | ||
67 | if (prom_argc > 1) | ||
68 | *cp = '\0'; | ||
69 | } | ||
70 | |||
71 | char *prom_getenv(char *envname) | ||
72 | { | ||
73 | /* | ||
74 | * Return a pointer to the given environment variable. | ||
75 | * YAMON uses "name", "value" pairs, while U-Boot uses "name=value". | ||
76 | */ | ||
77 | |||
78 | char **env = prom_envp; | ||
79 | int i = strlen(envname); | ||
80 | int yamon = (*env && strchr(*env, '=') == NULL); | ||
81 | |||
82 | while (*env) { | ||
83 | if (yamon) { | ||
84 | if (strcmp(envname, *env++) == 0) | ||
85 | return *env; | ||
86 | } else if (strncmp(envname, *env, i) == 0 && (*env)[i] == '=') | ||
87 | return *env + i + 1; | ||
88 | env++; | ||
89 | } | ||
90 | |||
91 | return NULL; | ||
92 | } | ||
93 | |||
94 | static inline unsigned char str2hexnum(unsigned char c) | ||
95 | { | ||
96 | if (c >= '0' && c <= '9') | ||
97 | return c - '0'; | ||
98 | if (c >= 'a' && c <= 'f') | ||
99 | return c - 'a' + 10; | ||
100 | if (c >= 'A' && c <= 'F') | ||
101 | return c - 'A' + 10; | ||
102 | |||
103 | return 0; /* foo */ | ||
104 | } | ||
105 | |||
106 | static inline void str2eaddr(unsigned char *ea, unsigned char *str) | ||
107 | { | ||
108 | int i; | ||
109 | |||
110 | for (i = 0; i < 6; i++) { | ||
111 | unsigned char num; | ||
112 | |||
113 | if ((*str == '.') || (*str == ':')) | ||
114 | str++; | ||
115 | num = str2hexnum(*str++) << 4; | ||
116 | num |= str2hexnum(*str++); | ||
117 | ea[i] = num; | ||
118 | } | ||
119 | } | ||
120 | |||
121 | int prom_get_ethernet_addr(char *ethernet_addr) | ||
122 | { | ||
123 | char *ethaddr_str; | ||
124 | char *argptr; | ||
125 | |||
126 | /* Check the environment variables first */ | ||
127 | ethaddr_str = prom_getenv("ethaddr"); | ||
128 | if (!ethaddr_str) { | ||
129 | /* Check command line */ | ||
130 | argptr = prom_getcmdline(); | ||
131 | ethaddr_str = strstr(argptr, "ethaddr="); | ||
132 | if (!ethaddr_str) | ||
133 | return -1; | ||
134 | |||
135 | ethaddr_str += strlen("ethaddr="); | ||
136 | } | ||
137 | |||
138 | str2eaddr(ethernet_addr, ethaddr_str); | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | EXPORT_SYMBOL(prom_get_ethernet_addr); | ||
143 | |||
144 | void __init prom_free_prom_memory(void) | ||
145 | { | ||
146 | } | ||
diff --git a/arch/mips/alchemy/common/puts.c b/arch/mips/alchemy/common/puts.c new file mode 100644 index 000000000000..55bbe24d45b6 --- /dev/null +++ b/arch/mips/alchemy/common/puts.c | |||
@@ -0,0 +1,68 @@ | |||
1 | /* | ||
2 | * | ||
3 | * BRIEF MODULE DESCRIPTION | ||
4 | * Low level UART routines to directly access Alchemy UART. | ||
5 | * | ||
6 | * Copyright 2001, 2008 MontaVista Software Inc. | ||
7 | * Author: MontaVista Software, Inc. <source@mvista.com> | ||
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 as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | * | ||
14 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
15 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
16 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
17 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
18 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
19 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
20 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
21 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
23 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License along | ||
26 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
27 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
28 | */ | ||
29 | |||
30 | #include <asm/mach-au1x00/au1000.h> | ||
31 | |||
32 | #define SERIAL_BASE UART_BASE | ||
33 | #define SER_CMD 0x7 | ||
34 | #define SER_DATA 0x1 | ||
35 | #define TX_BUSY 0x20 | ||
36 | |||
37 | #define TIMEOUT 0xffffff | ||
38 | #define SLOW_DOWN | ||
39 | |||
40 | static volatile unsigned long * const com1 = (unsigned long *)SERIAL_BASE; | ||
41 | |||
42 | #ifdef SLOW_DOWN | ||
43 | static inline void slow_down(void) | ||
44 | { | ||
45 | int k; | ||
46 | |||
47 | for (k = 0; k < 10000; k++); | ||
48 | } | ||
49 | #else | ||
50 | #define slow_down() | ||
51 | #endif | ||
52 | |||
53 | void | ||
54 | prom_putchar(const unsigned char c) | ||
55 | { | ||
56 | unsigned char ch; | ||
57 | int i = 0; | ||
58 | |||
59 | do { | ||
60 | ch = com1[SER_CMD]; | ||
61 | slow_down(); | ||
62 | i++; | ||
63 | if (i > TIMEOUT) | ||
64 | break; | ||
65 | } while (0 == (ch & TX_BUSY)); | ||
66 | |||
67 | com1[SER_DATA] = c; | ||
68 | } | ||
diff --git a/arch/mips/alchemy/common/reset.c b/arch/mips/alchemy/common/reset.c new file mode 100644 index 000000000000..d555429c8d6f --- /dev/null +++ b/arch/mips/alchemy/common/reset.c | |||
@@ -0,0 +1,189 @@ | |||
1 | /* | ||
2 | * | ||
3 | * BRIEF MODULE DESCRIPTION | ||
4 | * Au1xx0 reset routines. | ||
5 | * | ||
6 | * Copyright 2001, 2006, 2008 MontaVista Software Inc. | ||
7 | * Author: MontaVista Software, Inc. <source@mvista.com> | ||
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 as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | * | ||
14 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
15 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
16 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
17 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
18 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
19 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
20 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
21 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
23 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License along | ||
26 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
27 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
28 | */ | ||
29 | |||
30 | #include <asm/cacheflush.h> | ||
31 | |||
32 | #include <asm/mach-au1x00/au1000.h> | ||
33 | |||
34 | extern int au_sleep(void); | ||
35 | |||
36 | void au1000_restart(char *command) | ||
37 | { | ||
38 | /* Set all integrated peripherals to disabled states */ | ||
39 | extern void board_reset(void); | ||
40 | u32 prid = read_c0_prid(); | ||
41 | |||
42 | printk(KERN_NOTICE "\n** Resetting Integrated Peripherals\n"); | ||
43 | |||
44 | switch (prid & 0xFF000000) { | ||
45 | case 0x00000000: /* Au1000 */ | ||
46 | au_writel(0x02, 0xb0000010); /* ac97_enable */ | ||
47 | au_writel(0x08, 0xb017fffc); /* usbh_enable - early errata */ | ||
48 | asm("sync"); | ||
49 | au_writel(0x00, 0xb017fffc); /* usbh_enable */ | ||
50 | au_writel(0x00, 0xb0200058); /* usbd_enable */ | ||
51 | au_writel(0x00, 0xb0300040); /* ir_enable */ | ||
52 | au_writel(0x00, 0xb4004104); /* mac dma */ | ||
53 | au_writel(0x00, 0xb4004114); /* mac dma */ | ||
54 | au_writel(0x00, 0xb4004124); /* mac dma */ | ||
55 | au_writel(0x00, 0xb4004134); /* mac dma */ | ||
56 | au_writel(0x00, 0xb0520000); /* macen0 */ | ||
57 | au_writel(0x00, 0xb0520004); /* macen1 */ | ||
58 | au_writel(0x00, 0xb1000008); /* i2s_enable */ | ||
59 | au_writel(0x00, 0xb1100100); /* uart0_enable */ | ||
60 | au_writel(0x00, 0xb1200100); /* uart1_enable */ | ||
61 | au_writel(0x00, 0xb1300100); /* uart2_enable */ | ||
62 | au_writel(0x00, 0xb1400100); /* uart3_enable */ | ||
63 | au_writel(0x02, 0xb1600100); /* ssi0_enable */ | ||
64 | au_writel(0x02, 0xb1680100); /* ssi1_enable */ | ||
65 | au_writel(0x00, 0xb1900020); /* sys_freqctrl0 */ | ||
66 | au_writel(0x00, 0xb1900024); /* sys_freqctrl1 */ | ||
67 | au_writel(0x00, 0xb1900028); /* sys_clksrc */ | ||
68 | au_writel(0x10, 0xb1900060); /* sys_cpupll */ | ||
69 | au_writel(0x00, 0xb1900064); /* sys_auxpll */ | ||
70 | au_writel(0x00, 0xb1900100); /* sys_pininputen */ | ||
71 | break; | ||
72 | case 0x01000000: /* Au1500 */ | ||
73 | au_writel(0x02, 0xb0000010); /* ac97_enable */ | ||
74 | au_writel(0x08, 0xb017fffc); /* usbh_enable - early errata */ | ||
75 | asm("sync"); | ||
76 | au_writel(0x00, 0xb017fffc); /* usbh_enable */ | ||
77 | au_writel(0x00, 0xb0200058); /* usbd_enable */ | ||
78 | au_writel(0x00, 0xb4004104); /* mac dma */ | ||
79 | au_writel(0x00, 0xb4004114); /* mac dma */ | ||
80 | au_writel(0x00, 0xb4004124); /* mac dma */ | ||
81 | au_writel(0x00, 0xb4004134); /* mac dma */ | ||
82 | au_writel(0x00, 0xb1520000); /* macen0 */ | ||
83 | au_writel(0x00, 0xb1520004); /* macen1 */ | ||
84 | au_writel(0x00, 0xb1100100); /* uart0_enable */ | ||
85 | au_writel(0x00, 0xb1400100); /* uart3_enable */ | ||
86 | au_writel(0x00, 0xb1900020); /* sys_freqctrl0 */ | ||
87 | au_writel(0x00, 0xb1900024); /* sys_freqctrl1 */ | ||
88 | au_writel(0x00, 0xb1900028); /* sys_clksrc */ | ||
89 | au_writel(0x10, 0xb1900060); /* sys_cpupll */ | ||
90 | au_writel(0x00, 0xb1900064); /* sys_auxpll */ | ||
91 | au_writel(0x00, 0xb1900100); /* sys_pininputen */ | ||
92 | break; | ||
93 | case 0x02000000: /* Au1100 */ | ||
94 | au_writel(0x02, 0xb0000010); /* ac97_enable */ | ||
95 | au_writel(0x08, 0xb017fffc); /* usbh_enable - early errata */ | ||
96 | asm("sync"); | ||
97 | au_writel(0x00, 0xb017fffc); /* usbh_enable */ | ||
98 | au_writel(0x00, 0xb0200058); /* usbd_enable */ | ||
99 | au_writel(0x00, 0xb0300040); /* ir_enable */ | ||
100 | au_writel(0x00, 0xb4004104); /* mac dma */ | ||
101 | au_writel(0x00, 0xb4004114); /* mac dma */ | ||
102 | au_writel(0x00, 0xb4004124); /* mac dma */ | ||
103 | au_writel(0x00, 0xb4004134); /* mac dma */ | ||
104 | au_writel(0x00, 0xb0520000); /* macen0 */ | ||
105 | au_writel(0x00, 0xb1000008); /* i2s_enable */ | ||
106 | au_writel(0x00, 0xb1100100); /* uart0_enable */ | ||
107 | au_writel(0x00, 0xb1200100); /* uart1_enable */ | ||
108 | au_writel(0x00, 0xb1400100); /* uart3_enable */ | ||
109 | au_writel(0x02, 0xb1600100); /* ssi0_enable */ | ||
110 | au_writel(0x02, 0xb1680100); /* ssi1_enable */ | ||
111 | au_writel(0x00, 0xb1900020); /* sys_freqctrl0 */ | ||
112 | au_writel(0x00, 0xb1900024); /* sys_freqctrl1 */ | ||
113 | au_writel(0x00, 0xb1900028); /* sys_clksrc */ | ||
114 | au_writel(0x10, 0xb1900060); /* sys_cpupll */ | ||
115 | au_writel(0x00, 0xb1900064); /* sys_auxpll */ | ||
116 | au_writel(0x00, 0xb1900100); /* sys_pininputen */ | ||
117 | break; | ||
118 | case 0x03000000: /* Au1550 */ | ||
119 | au_writel(0x00, 0xb1a00004); /* psc 0 */ | ||
120 | au_writel(0x00, 0xb1b00004); /* psc 1 */ | ||
121 | au_writel(0x00, 0xb0a00004); /* psc 2 */ | ||
122 | au_writel(0x00, 0xb0b00004); /* psc 3 */ | ||
123 | au_writel(0x00, 0xb017fffc); /* usbh_enable */ | ||
124 | au_writel(0x00, 0xb0200058); /* usbd_enable */ | ||
125 | au_writel(0x00, 0xb4004104); /* mac dma */ | ||
126 | au_writel(0x00, 0xb4004114); /* mac dma */ | ||
127 | au_writel(0x00, 0xb4004124); /* mac dma */ | ||
128 | au_writel(0x00, 0xb4004134); /* mac dma */ | ||
129 | au_writel(0x00, 0xb1520000); /* macen0 */ | ||
130 | au_writel(0x00, 0xb1520004); /* macen1 */ | ||
131 | au_writel(0x00, 0xb1100100); /* uart0_enable */ | ||
132 | au_writel(0x00, 0xb1200100); /* uart1_enable */ | ||
133 | au_writel(0x00, 0xb1400100); /* uart3_enable */ | ||
134 | au_writel(0x00, 0xb1900020); /* sys_freqctrl0 */ | ||
135 | au_writel(0x00, 0xb1900024); /* sys_freqctrl1 */ | ||
136 | au_writel(0x00, 0xb1900028); /* sys_clksrc */ | ||
137 | au_writel(0x10, 0xb1900060); /* sys_cpupll */ | ||
138 | au_writel(0x00, 0xb1900064); /* sys_auxpll */ | ||
139 | au_writel(0x00, 0xb1900100); /* sys_pininputen */ | ||
140 | break; | ||
141 | } | ||
142 | |||
143 | set_c0_status(ST0_BEV | ST0_ERL); | ||
144 | change_c0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); | ||
145 | flush_cache_all(); | ||
146 | write_c0_wired(0); | ||
147 | |||
148 | /* Give board a chance to do a hardware reset */ | ||
149 | board_reset(); | ||
150 | |||
151 | /* Jump to the beggining in case board_reset() is empty */ | ||
152 | __asm__ __volatile__("jr\t%0"::"r"(0xbfc00000)); | ||
153 | } | ||
154 | |||
155 | void au1000_halt(void) | ||
156 | { | ||
157 | #if defined(CONFIG_MIPS_PB1550) || defined(CONFIG_MIPS_DB1550) | ||
158 | /* Power off system */ | ||
159 | printk(KERN_NOTICE "\n** Powering off...\n"); | ||
160 | au_writew(au_readw(0xAF00001C) | (3 << 14), 0xAF00001C); | ||
161 | au_sync(); | ||
162 | while (1); /* should not get here */ | ||
163 | #else | ||
164 | printk(KERN_NOTICE "\n** You can safely turn off the power\n"); | ||
165 | #ifdef CONFIG_MIPS_MIRAGE | ||
166 | au_writel((1 << 26) | (1 << 10), GPIO2_OUTPUT); | ||
167 | #endif | ||
168 | #ifdef CONFIG_MIPS_DB1200 | ||
169 | au_writew(au_readw(0xB980001C) | (1 << 14), 0xB980001C); | ||
170 | #endif | ||
171 | #ifdef CONFIG_PM | ||
172 | au_sleep(); | ||
173 | |||
174 | /* Should not get here */ | ||
175 | printk(KERN_ERR "Unable to put CPU in sleep mode\n"); | ||
176 | while (1); | ||
177 | #else | ||
178 | while (1) | ||
179 | __asm__(".set\tmips3\n\t" | ||
180 | "wait\n\t" | ||
181 | ".set\tmips0"); | ||
182 | #endif | ||
183 | #endif /* defined(CONFIG_MIPS_PB1550) || defined(CONFIG_MIPS_DB1550) */ | ||
184 | } | ||
185 | |||
186 | void au1000_power_off(void) | ||
187 | { | ||
188 | au1000_halt(); | ||
189 | } | ||
diff --git a/arch/mips/alchemy/common/setup.c b/arch/mips/alchemy/common/setup.c new file mode 100644 index 000000000000..1ac6b06f42a3 --- /dev/null +++ b/arch/mips/alchemy/common/setup.c | |||
@@ -0,0 +1,160 @@ | |||
1 | /* | ||
2 | * Copyright 2000, 2007-2008 MontaVista Software Inc. | ||
3 | * Author: MontaVista Software, Inc. <source@mvista.com | ||
4 | * | ||
5 | * Updates to 2.6, Pete Popov, Embedded Alley Solutions, Inc. | ||
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 as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
13 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
14 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
15 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
16 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
17 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
18 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
19 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
20 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
21 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License along | ||
24 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
25 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
26 | */ | ||
27 | |||
28 | #include <linux/init.h> | ||
29 | #include <linux/ioport.h> | ||
30 | #include <linux/module.h> | ||
31 | #include <linux/pm.h> | ||
32 | |||
33 | #include <asm/mipsregs.h> | ||
34 | #include <asm/reboot.h> | ||
35 | #include <asm/time.h> | ||
36 | |||
37 | #include <au1000.h> | ||
38 | #include <prom.h> | ||
39 | |||
40 | extern void __init board_setup(void); | ||
41 | extern void au1000_restart(char *); | ||
42 | extern void au1000_halt(void); | ||
43 | extern void au1000_power_off(void); | ||
44 | extern void set_cpuspec(void); | ||
45 | |||
46 | void __init plat_mem_setup(void) | ||
47 | { | ||
48 | struct cpu_spec *sp; | ||
49 | char *argptr; | ||
50 | unsigned long prid, cpufreq, bclk; | ||
51 | |||
52 | set_cpuspec(); | ||
53 | sp = cur_cpu_spec[0]; | ||
54 | |||
55 | board_setup(); /* board specific setup */ | ||
56 | |||
57 | prid = read_c0_prid(); | ||
58 | if (sp->cpu_pll_wo) | ||
59 | #ifdef CONFIG_SOC_AU1000_FREQUENCY | ||
60 | cpufreq = CONFIG_SOC_AU1000_FREQUENCY / 1000000; | ||
61 | #else | ||
62 | cpufreq = 396; | ||
63 | #endif | ||
64 | else | ||
65 | cpufreq = (au_readl(SYS_CPUPLL) & 0x3F) * 12; | ||
66 | printk(KERN_INFO "(PRID %08lx) @ %ld MHz\n", prid, cpufreq); | ||
67 | |||
68 | if (sp->cpu_bclk) { | ||
69 | /* Enable BCLK switching */ | ||
70 | bclk = au_readl(SYS_POWERCTRL); | ||
71 | au_writel(bclk | 0x60, SYS_POWERCTRL); | ||
72 | printk(KERN_INFO "BCLK switching enabled!\n"); | ||
73 | } | ||
74 | |||
75 | if (sp->cpu_od) | ||
76 | /* Various early Au1xx0 errata corrected by this */ | ||
77 | set_c0_config(1 << 19); /* Set Config[OD] */ | ||
78 | else | ||
79 | /* Clear to obtain best system bus performance */ | ||
80 | clear_c0_config(1 << 19); /* Clear Config[OD] */ | ||
81 | |||
82 | argptr = prom_getcmdline(); | ||
83 | |||
84 | #ifdef CONFIG_SERIAL_8250_CONSOLE | ||
85 | argptr = strstr(argptr, "console="); | ||
86 | if (argptr == NULL) { | ||
87 | argptr = prom_getcmdline(); | ||
88 | strcat(argptr, " console=ttyS0,115200"); | ||
89 | } | ||
90 | #endif | ||
91 | |||
92 | #ifdef CONFIG_FB_AU1100 | ||
93 | argptr = strstr(argptr, "video="); | ||
94 | if (argptr == NULL) { | ||
95 | argptr = prom_getcmdline(); | ||
96 | /* default panel */ | ||
97 | /*strcat(argptr, " video=au1100fb:panel:Sharp_320x240_16");*/ | ||
98 | } | ||
99 | #endif | ||
100 | |||
101 | #if defined(CONFIG_SOUND_AU1X00) && !defined(CONFIG_SOC_AU1000) | ||
102 | /* au1000 does not support vra, au1500 and au1100 do */ | ||
103 | strcat(argptr, " au1000_audio=vra"); | ||
104 | argptr = prom_getcmdline(); | ||
105 | #endif | ||
106 | _machine_restart = au1000_restart; | ||
107 | _machine_halt = au1000_halt; | ||
108 | pm_power_off = au1000_power_off; | ||
109 | |||
110 | /* IO/MEM resources. */ | ||
111 | set_io_port_base(0); | ||
112 | ioport_resource.start = IOPORT_RESOURCE_START; | ||
113 | ioport_resource.end = IOPORT_RESOURCE_END; | ||
114 | iomem_resource.start = IOMEM_RESOURCE_START; | ||
115 | iomem_resource.end = IOMEM_RESOURCE_END; | ||
116 | |||
117 | while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_E0S); | ||
118 | au_writel(SYS_CNTRL_E0 | SYS_CNTRL_EN0, SYS_COUNTER_CNTRL); | ||
119 | au_sync(); | ||
120 | while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T0S); | ||
121 | au_writel(0, SYS_TOYTRIM); | ||
122 | } | ||
123 | |||
124 | #if defined(CONFIG_64BIT_PHYS_ADDR) | ||
125 | /* This routine should be valid for all Au1x based boards */ | ||
126 | phys_t __fixup_bigphys_addr(phys_t phys_addr, phys_t size) | ||
127 | { | ||
128 | /* Don't fixup 36-bit addresses */ | ||
129 | if ((phys_addr >> 32) != 0) | ||
130 | return phys_addr; | ||
131 | |||
132 | #ifdef CONFIG_PCI | ||
133 | { | ||
134 | u32 start = (u32)Au1500_PCI_MEM_START; | ||
135 | u32 end = (u32)Au1500_PCI_MEM_END; | ||
136 | |||
137 | /* Check for PCI memory window */ | ||
138 | if (phys_addr >= start && (phys_addr + size - 1) <= end) | ||
139 | return (phys_t) | ||
140 | ((phys_addr - start) + Au1500_PCI_MEM_START); | ||
141 | } | ||
142 | #endif | ||
143 | |||
144 | /* | ||
145 | * All Au1xx0 SOCs have a PCMCIA controller. | ||
146 | * We setup our 32-bit pseudo addresses to be equal to the | ||
147 | * 36-bit addr >> 4, to make it easier to check the address | ||
148 | * and fix it. | ||
149 | * The PCMCIA socket 0 physical attribute address is 0xF 4000 0000. | ||
150 | * The pseudo address we use is 0xF400 0000. Any address over | ||
151 | * 0xF400 0000 is a PCMCIA pseudo address. | ||
152 | */ | ||
153 | if ((phys_addr >= 0xF4000000) && (phys_addr < 0xFFFFFFFF)) | ||
154 | return (phys_t)(phys_addr << 4); | ||
155 | |||
156 | /* default nop */ | ||
157 | return phys_addr; | ||
158 | } | ||
159 | EXPORT_SYMBOL(__fixup_bigphys_addr); | ||
160 | #endif | ||
diff --git a/arch/mips/alchemy/common/sleeper.S b/arch/mips/alchemy/common/sleeper.S new file mode 100644 index 000000000000..3006e270c8bc --- /dev/null +++ b/arch/mips/alchemy/common/sleeper.S | |||
@@ -0,0 +1,154 @@ | |||
1 | /* | ||
2 | * Copyright 2002 Embedded Edge, LLC | ||
3 | * Author: dan@embeddededge.com | ||
4 | * | ||
5 | * Sleep helper for Au1xxx sleep mode. | ||
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 as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <asm/asm.h> | ||
14 | #include <asm/mipsregs.h> | ||
15 | #include <asm/regdef.h> | ||
16 | #include <asm/stackframe.h> | ||
17 | |||
18 | .text | ||
19 | .set macro | ||
20 | .set noat | ||
21 | .align 5 | ||
22 | |||
23 | /* Save all of the processor general registers and go to sleep. | ||
24 | * A wakeup condition will get us back here to restore the registers. | ||
25 | */ | ||
26 | LEAF(save_and_sleep) | ||
27 | |||
28 | subu sp, PT_SIZE | ||
29 | sw $1, PT_R1(sp) | ||
30 | sw $2, PT_R2(sp) | ||
31 | sw $3, PT_R3(sp) | ||
32 | sw $4, PT_R4(sp) | ||
33 | sw $5, PT_R5(sp) | ||
34 | sw $6, PT_R6(sp) | ||
35 | sw $7, PT_R7(sp) | ||
36 | sw $8, PT_R8(sp) | ||
37 | sw $9, PT_R9(sp) | ||
38 | sw $10, PT_R10(sp) | ||
39 | sw $11, PT_R11(sp) | ||
40 | sw $12, PT_R12(sp) | ||
41 | sw $13, PT_R13(sp) | ||
42 | sw $14, PT_R14(sp) | ||
43 | sw $15, PT_R15(sp) | ||
44 | sw $16, PT_R16(sp) | ||
45 | sw $17, PT_R17(sp) | ||
46 | sw $18, PT_R18(sp) | ||
47 | sw $19, PT_R19(sp) | ||
48 | sw $20, PT_R20(sp) | ||
49 | sw $21, PT_R21(sp) | ||
50 | sw $22, PT_R22(sp) | ||
51 | sw $23, PT_R23(sp) | ||
52 | sw $24, PT_R24(sp) | ||
53 | sw $25, PT_R25(sp) | ||
54 | sw $26, PT_R26(sp) | ||
55 | sw $27, PT_R27(sp) | ||
56 | sw $28, PT_R28(sp) | ||
57 | sw $29, PT_R29(sp) | ||
58 | sw $30, PT_R30(sp) | ||
59 | sw $31, PT_R31(sp) | ||
60 | mfc0 k0, CP0_STATUS | ||
61 | sw k0, 0x20(sp) | ||
62 | mfc0 k0, CP0_CONTEXT | ||
63 | sw k0, 0x1c(sp) | ||
64 | mfc0 k0, CP0_PAGEMASK | ||
65 | sw k0, 0x18(sp) | ||
66 | mfc0 k0, CP0_CONFIG | ||
67 | sw k0, 0x14(sp) | ||
68 | |||
69 | /* Now set up the scratch registers so the boot rom will | ||
70 | * return to this point upon wakeup. | ||
71 | */ | ||
72 | la k0, 1f | ||
73 | lui k1, 0xb190 | ||
74 | ori k1, 0x18 | ||
75 | sw sp, 0(k1) | ||
76 | ori k1, 0x1c | ||
77 | sw k0, 0(k1) | ||
78 | |||
79 | /* Put SDRAM into self refresh. Preload instructions into cache, | ||
80 | * issue a precharge, then auto refresh, then sleep commands to it. | ||
81 | */ | ||
82 | la t0, sdsleep | ||
83 | .set mips3 | ||
84 | cache 0x14, 0(t0) | ||
85 | cache 0x14, 32(t0) | ||
86 | cache 0x14, 64(t0) | ||
87 | cache 0x14, 96(t0) | ||
88 | .set mips0 | ||
89 | |||
90 | sdsleep: | ||
91 | lui k0, 0xb400 | ||
92 | sw zero, 0x001c(k0) /* Precharge */ | ||
93 | sw zero, 0x0020(k0) /* Auto refresh */ | ||
94 | sw zero, 0x0030(k0) /* SDRAM sleep */ | ||
95 | sync | ||
96 | |||
97 | lui k1, 0xb190 | ||
98 | sw zero, 0x0078(k1) /* get ready to sleep */ | ||
99 | sync | ||
100 | sw zero, 0x007c(k1) /* Put processor to sleep */ | ||
101 | sync | ||
102 | |||
103 | /* This is where we return upon wakeup. | ||
104 | * Reload all of the registers and return. | ||
105 | */ | ||
106 | 1: nop | ||
107 | lw k0, 0x20(sp) | ||
108 | mtc0 k0, CP0_STATUS | ||
109 | lw k0, 0x1c(sp) | ||
110 | mtc0 k0, CP0_CONTEXT | ||
111 | lw k0, 0x18(sp) | ||
112 | mtc0 k0, CP0_PAGEMASK | ||
113 | lw k0, 0x14(sp) | ||
114 | mtc0 k0, CP0_CONFIG | ||
115 | |||
116 | /* We need to catch the ealry Alchemy SOCs with | ||
117 | * the write-only Config[OD] bit and set it back to one... | ||
118 | */ | ||
119 | jal au1x00_fixup_config_od | ||
120 | lw $1, PT_R1(sp) | ||
121 | lw $2, PT_R2(sp) | ||
122 | lw $3, PT_R3(sp) | ||
123 | lw $4, PT_R4(sp) | ||
124 | lw $5, PT_R5(sp) | ||
125 | lw $6, PT_R6(sp) | ||
126 | lw $7, PT_R7(sp) | ||
127 | lw $8, PT_R8(sp) | ||
128 | lw $9, PT_R9(sp) | ||
129 | lw $10, PT_R10(sp) | ||
130 | lw $11, PT_R11(sp) | ||
131 | lw $12, PT_R12(sp) | ||
132 | lw $13, PT_R13(sp) | ||
133 | lw $14, PT_R14(sp) | ||
134 | lw $15, PT_R15(sp) | ||
135 | lw $16, PT_R16(sp) | ||
136 | lw $17, PT_R17(sp) | ||
137 | lw $18, PT_R18(sp) | ||
138 | lw $19, PT_R19(sp) | ||
139 | lw $20, PT_R20(sp) | ||
140 | lw $21, PT_R21(sp) | ||
141 | lw $22, PT_R22(sp) | ||
142 | lw $23, PT_R23(sp) | ||
143 | lw $24, PT_R24(sp) | ||
144 | lw $25, PT_R25(sp) | ||
145 | lw $26, PT_R26(sp) | ||
146 | lw $27, PT_R27(sp) | ||
147 | lw $28, PT_R28(sp) | ||
148 | lw $29, PT_R29(sp) | ||
149 | lw $30, PT_R30(sp) | ||
150 | lw $31, PT_R31(sp) | ||
151 | addiu sp, PT_SIZE | ||
152 | |||
153 | jr ra | ||
154 | END(save_and_sleep) | ||
diff --git a/arch/mips/alchemy/common/time.c b/arch/mips/alchemy/common/time.c new file mode 100644 index 000000000000..563d9390a872 --- /dev/null +++ b/arch/mips/alchemy/common/time.c | |||
@@ -0,0 +1,266 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright (C) 2001, 2006, 2008 MontaVista Software, <source@mvista.com> | ||
4 | * Copied and modified Carsten Langgaard's time.c | ||
5 | * | ||
6 | * Carsten Langgaard, carstenl@mips.com | ||
7 | * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. | ||
8 | * | ||
9 | * ######################################################################## | ||
10 | * | ||
11 | * This program is free software; you can distribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License (Version 2) as | ||
13 | * published by the Free Software Foundation. | ||
14 | * | ||
15 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
16 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
18 | * for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License along | ||
21 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
22 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
23 | * | ||
24 | * ######################################################################## | ||
25 | * | ||
26 | * Setting up the clock on the MIPS boards. | ||
27 | * | ||
28 | * We provide the clock interrupt processing and the timer offset compute | ||
29 | * functions. If CONFIG_PM is selected, we also ensure the 32KHz timer is | ||
30 | * available. -- Dan | ||
31 | */ | ||
32 | |||
33 | #include <linux/types.h> | ||
34 | #include <linux/init.h> | ||
35 | #include <linux/spinlock.h> | ||
36 | |||
37 | #include <asm/mipsregs.h> | ||
38 | #include <asm/time.h> | ||
39 | #include <asm/mach-au1x00/au1000.h> | ||
40 | |||
41 | static int no_au1xxx_32khz; | ||
42 | extern int allow_au1k_wait; /* default off for CP0 Counter */ | ||
43 | |||
44 | #ifdef CONFIG_PM | ||
45 | #if HZ < 100 || HZ > 1000 | ||
46 | #error "unsupported HZ value! Must be in [100,1000]" | ||
47 | #endif | ||
48 | #define MATCH20_INC (328 * 100 / HZ) /* magic number 328 is for HZ=100... */ | ||
49 | static unsigned long last_pc0, last_match20; | ||
50 | #endif | ||
51 | |||
52 | static DEFINE_SPINLOCK(time_lock); | ||
53 | |||
54 | unsigned long wtimer; | ||
55 | |||
56 | #ifdef CONFIG_PM | ||
57 | static irqreturn_t counter0_irq(int irq, void *dev_id) | ||
58 | { | ||
59 | unsigned long pc0; | ||
60 | int time_elapsed; | ||
61 | static int jiffie_drift; | ||
62 | |||
63 | if (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20) { | ||
64 | /* should never happen! */ | ||
65 | printk(KERN_WARNING "counter 0 w status error\n"); | ||
66 | return IRQ_NONE; | ||
67 | } | ||
68 | |||
69 | pc0 = au_readl(SYS_TOYREAD); | ||
70 | if (pc0 < last_match20) | ||
71 | /* counter overflowed */ | ||
72 | time_elapsed = (0xffffffff - last_match20) + pc0; | ||
73 | else | ||
74 | time_elapsed = pc0 - last_match20; | ||
75 | |||
76 | while (time_elapsed > 0) { | ||
77 | do_timer(1); | ||
78 | #ifndef CONFIG_SMP | ||
79 | update_process_times(user_mode(get_irq_regs())); | ||
80 | #endif | ||
81 | time_elapsed -= MATCH20_INC; | ||
82 | last_match20 += MATCH20_INC; | ||
83 | jiffie_drift++; | ||
84 | } | ||
85 | |||
86 | last_pc0 = pc0; | ||
87 | au_writel(last_match20 + MATCH20_INC, SYS_TOYMATCH2); | ||
88 | au_sync(); | ||
89 | |||
90 | /* | ||
91 | * Our counter ticks at 10.009765625 ms/tick, we we're running | ||
92 | * almost 10 uS too slow per tick. | ||
93 | */ | ||
94 | |||
95 | if (jiffie_drift >= 999) { | ||
96 | jiffie_drift -= 999; | ||
97 | do_timer(1); /* increment jiffies by one */ | ||
98 | #ifndef CONFIG_SMP | ||
99 | update_process_times(user_mode(get_irq_regs())); | ||
100 | #endif | ||
101 | } | ||
102 | |||
103 | return IRQ_HANDLED; | ||
104 | } | ||
105 | |||
106 | struct irqaction counter0_action = { | ||
107 | .handler = counter0_irq, | ||
108 | .flags = IRQF_DISABLED, | ||
109 | .name = "alchemy-toy", | ||
110 | .dev_id = NULL, | ||
111 | }; | ||
112 | |||
113 | /* When we wakeup from sleep, we have to "catch up" on all of the | ||
114 | * timer ticks we have missed. | ||
115 | */ | ||
116 | void wakeup_counter0_adjust(void) | ||
117 | { | ||
118 | unsigned long pc0; | ||
119 | int time_elapsed; | ||
120 | |||
121 | pc0 = au_readl(SYS_TOYREAD); | ||
122 | if (pc0 < last_match20) | ||
123 | /* counter overflowed */ | ||
124 | time_elapsed = (0xffffffff - last_match20) + pc0; | ||
125 | else | ||
126 | time_elapsed = pc0 - last_match20; | ||
127 | |||
128 | while (time_elapsed > 0) { | ||
129 | time_elapsed -= MATCH20_INC; | ||
130 | last_match20 += MATCH20_INC; | ||
131 | } | ||
132 | |||
133 | last_pc0 = pc0; | ||
134 | au_writel(last_match20 + MATCH20_INC, SYS_TOYMATCH2); | ||
135 | au_sync(); | ||
136 | |||
137 | } | ||
138 | |||
139 | /* This is just for debugging to set the timer for a sleep delay. */ | ||
140 | void wakeup_counter0_set(int ticks) | ||
141 | { | ||
142 | unsigned long pc0; | ||
143 | |||
144 | pc0 = au_readl(SYS_TOYREAD); | ||
145 | last_pc0 = pc0; | ||
146 | au_writel(last_match20 + (MATCH20_INC * ticks), SYS_TOYMATCH2); | ||
147 | au_sync(); | ||
148 | } | ||
149 | #endif | ||
150 | |||
151 | /* | ||
152 | * I haven't found anyone that doesn't use a 12 MHz source clock, | ||
153 | * but just in case..... | ||
154 | */ | ||
155 | #define AU1000_SRC_CLK 12000000 | ||
156 | |||
157 | /* | ||
158 | * We read the real processor speed from the PLL. This is important | ||
159 | * because it is more accurate than computing it from the 32 KHz | ||
160 | * counter, if it exists. If we don't have an accurate processor | ||
161 | * speed, all of the peripherals that derive their clocks based on | ||
162 | * this advertised speed will introduce error and sometimes not work | ||
163 | * properly. This function is futher convoluted to still allow configurations | ||
164 | * to do that in case they have really, really old silicon with a | ||
165 | * write-only PLL register, that we need the 32 KHz when power management | ||
166 | * "wait" is enabled, and we need to detect if the 32 KHz isn't present | ||
167 | * but requested......got it? :-) -- Dan | ||
168 | */ | ||
169 | unsigned long calc_clock(void) | ||
170 | { | ||
171 | unsigned long cpu_speed; | ||
172 | unsigned long flags; | ||
173 | unsigned long counter; | ||
174 | |||
175 | spin_lock_irqsave(&time_lock, flags); | ||
176 | |||
177 | /* Power management cares if we don't have a 32 KHz counter. */ | ||
178 | no_au1xxx_32khz = 0; | ||
179 | counter = au_readl(SYS_COUNTER_CNTRL); | ||
180 | if (counter & SYS_CNTRL_E0) { | ||
181 | int trim_divide = 16; | ||
182 | |||
183 | au_writel(counter | SYS_CNTRL_EN1, SYS_COUNTER_CNTRL); | ||
184 | |||
185 | while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T1S); | ||
186 | /* RTC now ticks at 32.768/16 kHz */ | ||
187 | au_writel(trim_divide - 1, SYS_RTCTRIM); | ||
188 | while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T1S); | ||
189 | |||
190 | while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S); | ||
191 | au_writel(0, SYS_TOYWRITE); | ||
192 | while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S); | ||
193 | } else | ||
194 | no_au1xxx_32khz = 1; | ||
195 | |||
196 | /* | ||
197 | * On early Au1000, sys_cpupll was write-only. Since these | ||
198 | * silicon versions of Au1000 are not sold by AMD, we don't bend | ||
199 | * over backwards trying to determine the frequency. | ||
200 | */ | ||
201 | if (cur_cpu_spec[0]->cpu_pll_wo) | ||
202 | #ifdef CONFIG_SOC_AU1000_FREQUENCY | ||
203 | cpu_speed = CONFIG_SOC_AU1000_FREQUENCY; | ||
204 | #else | ||
205 | cpu_speed = 396000000; | ||
206 | #endif | ||
207 | else | ||
208 | cpu_speed = (au_readl(SYS_CPUPLL) & 0x0000003f) * AU1000_SRC_CLK; | ||
209 | /* On Alchemy CPU:counter ratio is 1:1 */ | ||
210 | mips_hpt_frequency = cpu_speed; | ||
211 | /* Equation: Baudrate = CPU / (SD * 2 * CLKDIV * 16) */ | ||
212 | set_au1x00_uart_baud_base(cpu_speed / (2 * ((int)(au_readl(SYS_POWERCTRL) | ||
213 | & 0x03) + 2) * 16)); | ||
214 | spin_unlock_irqrestore(&time_lock, flags); | ||
215 | return cpu_speed; | ||
216 | } | ||
217 | |||
218 | void __init plat_time_init(void) | ||
219 | { | ||
220 | unsigned int est_freq = calc_clock(); | ||
221 | |||
222 | est_freq += 5000; /* round */ | ||
223 | est_freq -= est_freq%10000; | ||
224 | printk(KERN_INFO "CPU frequency %u.%02u MHz\n", | ||
225 | est_freq / 1000000, ((est_freq % 1000000) * 100) / 1000000); | ||
226 | set_au1x00_speed(est_freq); | ||
227 | set_au1x00_lcd_clock(); /* program the LCD clock */ | ||
228 | |||
229 | #ifdef CONFIG_PM | ||
230 | /* | ||
231 | * setup counter 0, since it keeps ticking after a | ||
232 | * 'wait' instruction has been executed. The CP0 timer and | ||
233 | * counter 1 do NOT continue running after 'wait' | ||
234 | * | ||
235 | * It's too early to call request_irq() here, so we handle | ||
236 | * counter 0 interrupt as a special irq and it doesn't show | ||
237 | * up under /proc/interrupts. | ||
238 | * | ||
239 | * Check to ensure we really have a 32 KHz oscillator before | ||
240 | * we do this. | ||
241 | */ | ||
242 | if (no_au1xxx_32khz) | ||
243 | printk(KERN_WARNING "WARNING: no 32KHz clock found.\n"); | ||
244 | else { | ||
245 | while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C0S); | ||
246 | au_writel(0, SYS_TOYWRITE); | ||
247 | while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C0S); | ||
248 | |||
249 | au_writel(au_readl(SYS_WAKEMSK) | (1 << 8), SYS_WAKEMSK); | ||
250 | au_writel(~0, SYS_WAKESRC); | ||
251 | au_sync(); | ||
252 | while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20); | ||
253 | |||
254 | /* Setup match20 to interrupt once every HZ */ | ||
255 | last_pc0 = last_match20 = au_readl(SYS_TOYREAD); | ||
256 | au_writel(last_match20 + MATCH20_INC, SYS_TOYMATCH2); | ||
257 | au_sync(); | ||
258 | while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20); | ||
259 | setup_irq(AU1000_TOY_MATCH2_INT, &counter0_action); | ||
260 | |||
261 | /* We can use the real 'wait' instruction. */ | ||
262 | allow_au1k_wait = 1; | ||
263 | } | ||
264 | |||
265 | #endif | ||
266 | } | ||