diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2005-07-25 18:45:45 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2005-10-29 14:31:57 -0400 |
commit | 23fbee9dd5d2a41d36af49ff8e1669fb0c29fda8 (patch) | |
tree | 4e24699269b9d4d2655d961e7a0ffb29931e9b2d /arch/mips/tx4938 | |
parent | 132940401174ed04f9e8f1ae2dad6f47da26ee0a (diff) |
Support for Toshiba's RBHMA4500 eval board for the TX4938.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/tx4938')
-rw-r--r-- | arch/mips/tx4938/Kconfig | 24 | ||||
-rw-r--r-- | arch/mips/tx4938/common/Makefile | 11 | ||||
-rw-r--r-- | arch/mips/tx4938/common/dbgio.c | 50 | ||||
-rw-r--r-- | arch/mips/tx4938/common/irq.c | 424 | ||||
-rw-r--r-- | arch/mips/tx4938/common/irq_handler.S | 84 | ||||
-rw-r--r-- | arch/mips/tx4938/common/prom.c | 129 | ||||
-rw-r--r-- | arch/mips/tx4938/common/rtc_rx5c348.c | 202 | ||||
-rw-r--r-- | arch/mips/tx4938/common/setup.c | 91 | ||||
-rw-r--r-- | arch/mips/tx4938/toshiba_rbtx4938/Makefile | 9 | ||||
-rw-r--r-- | arch/mips/tx4938/toshiba_rbtx4938/irq.c | 244 | ||||
-rw-r--r-- | arch/mips/tx4938/toshiba_rbtx4938/prom.c | 78 | ||||
-rw-r--r-- | arch/mips/tx4938/toshiba_rbtx4938/setup.c | 1035 | ||||
-rw-r--r-- | arch/mips/tx4938/toshiba_rbtx4938/spi_eeprom.c | 219 | ||||
-rw-r--r-- | arch/mips/tx4938/toshiba_rbtx4938/spi_txx9.c | 159 |
14 files changed, 2759 insertions, 0 deletions
diff --git a/arch/mips/tx4938/Kconfig b/arch/mips/tx4938/Kconfig new file mode 100644 index 000000000000..d90e9cd85138 --- /dev/null +++ b/arch/mips/tx4938/Kconfig | |||
@@ -0,0 +1,24 @@ | |||
1 | if TOSHIBA_RBTX4938 | ||
2 | |||
3 | comment "Multiplex Pin Select" | ||
4 | choice | ||
5 | prompt "PIO[58:61]" | ||
6 | default TOSHIBA_RBTX4938_MPLEX_PIO58_61 | ||
7 | |||
8 | config TOSHIBA_RBTX4938_MPLEX_PIO58_61 | ||
9 | bool "PIO" | ||
10 | config TOSHIBA_RBTX4938_MPLEX_NAND | ||
11 | bool "NAND" | ||
12 | config TOSHIBA_RBTX4938_MPLEX_ATA | ||
13 | bool "ATA" | ||
14 | |||
15 | endchoice | ||
16 | |||
17 | config TX4938_NAND_BOOT | ||
18 | depends on EXPERIMENTAL && TOSHIBA_RBTX4938_MPLEX_NAND | ||
19 | bool "NAND Boot Support (EXPERIMENTAL)" | ||
20 | help | ||
21 | This is only for Toshiba RBTX4938 reference board, which has NAND IPL. | ||
22 | Select this option if you need to use NAND boot. | ||
23 | |||
24 | endif | ||
diff --git a/arch/mips/tx4938/common/Makefile b/arch/mips/tx4938/common/Makefile new file mode 100644 index 000000000000..74c95c5bcdbf --- /dev/null +++ b/arch/mips/tx4938/common/Makefile | |||
@@ -0,0 +1,11 @@ | |||
1 | # | ||
2 | # Makefile for common code for Toshiba TX4927 based systems | ||
3 | # | ||
4 | # Note! Dependencies are done automagically by 'make dep', which also | ||
5 | # removes any old dependencies. DON'T put your own dependencies here | ||
6 | # unless it's something special (ie not a .c file). | ||
7 | # | ||
8 | |||
9 | obj-y += prom.o setup.o irq.o irq_handler.o rtc_rx5c348.o | ||
10 | obj-$(CONFIG_KGDB) += dbgio.o | ||
11 | |||
diff --git a/arch/mips/tx4938/common/dbgio.c b/arch/mips/tx4938/common/dbgio.c new file mode 100644 index 000000000000..bea59ff1842a --- /dev/null +++ b/arch/mips/tx4938/common/dbgio.c | |||
@@ -0,0 +1,50 @@ | |||
1 | /* | ||
2 | * linux/arch/mips/tx4938/common/dbgio.c | ||
3 | * | ||
4 | * kgdb interface for gdb | ||
5 | * | ||
6 | * Author: MontaVista Software, Inc. | ||
7 | * source@mvista.com | ||
8 | * | ||
9 | * Copyright 2005 MontaVista Software Inc. | ||
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. | ||
19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | ||
21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS | ||
22 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR | ||
24 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE | ||
25 | * USE OF 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 | * Support for TX4938 in 2.6 - Hiroshi DOYU <Hiroshi_DOYU@montavista.co.jp> | ||
32 | */ | ||
33 | |||
34 | #include <asm/mipsregs.h> | ||
35 | #include <asm/system.h> | ||
36 | #include <asm/tx4938/tx4938_mips.h> | ||
37 | |||
38 | extern u8 txx9_sio_kdbg_rd(void); | ||
39 | extern int txx9_sio_kdbg_wr( u8 ch ); | ||
40 | |||
41 | u8 getDebugChar(void) | ||
42 | { | ||
43 | return (txx9_sio_kdbg_rd()); | ||
44 | } | ||
45 | |||
46 | int putDebugChar(u8 byte) | ||
47 | { | ||
48 | return (txx9_sio_kdbg_wr(byte)); | ||
49 | } | ||
50 | |||
diff --git a/arch/mips/tx4938/common/irq.c b/arch/mips/tx4938/common/irq.c new file mode 100644 index 000000000000..4f90d7faf634 --- /dev/null +++ b/arch/mips/tx4938/common/irq.c | |||
@@ -0,0 +1,424 @@ | |||
1 | /* | ||
2 | * linux/arch/mps/tx4938/common/irq.c | ||
3 | * | ||
4 | * Common tx4938 irq handler | ||
5 | * Copyright (C) 2000-2001 Toshiba Corporation | ||
6 | * | ||
7 | * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the | ||
8 | * terms of the GNU General Public License version 2. This program is | ||
9 | * licensed "as is" without any warranty of any kind, whether express | ||
10 | * or implied. | ||
11 | * | ||
12 | * Support for TX4938 in 2.6 - Manish Lachwani (mlachwani@mvista.com) | ||
13 | */ | ||
14 | #include <linux/errno.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/kernel_stat.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/signal.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/types.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/ioport.h> | ||
23 | #include <linux/timex.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/random.h> | ||
26 | #include <linux/irq.h> | ||
27 | #include <asm/bitops.h> | ||
28 | #include <asm/bootinfo.h> | ||
29 | #include <asm/io.h> | ||
30 | #include <asm/irq.h> | ||
31 | #include <asm/mipsregs.h> | ||
32 | #include <asm/system.h> | ||
33 | #include <asm/tx4938/rbtx4938.h> | ||
34 | |||
35 | /**********************************************************************************/ | ||
36 | /* Forwad definitions for all pic's */ | ||
37 | /**********************************************************************************/ | ||
38 | |||
39 | static unsigned int tx4938_irq_cp0_startup(unsigned int irq); | ||
40 | static void tx4938_irq_cp0_shutdown(unsigned int irq); | ||
41 | static void tx4938_irq_cp0_enable(unsigned int irq); | ||
42 | static void tx4938_irq_cp0_disable(unsigned int irq); | ||
43 | static void tx4938_irq_cp0_mask_and_ack(unsigned int irq); | ||
44 | static void tx4938_irq_cp0_end(unsigned int irq); | ||
45 | |||
46 | static unsigned int tx4938_irq_pic_startup(unsigned int irq); | ||
47 | static void tx4938_irq_pic_shutdown(unsigned int irq); | ||
48 | static void tx4938_irq_pic_enable(unsigned int irq); | ||
49 | static void tx4938_irq_pic_disable(unsigned int irq); | ||
50 | static void tx4938_irq_pic_mask_and_ack(unsigned int irq); | ||
51 | static void tx4938_irq_pic_end(unsigned int irq); | ||
52 | |||
53 | /**********************************************************************************/ | ||
54 | /* Kernel structs for all pic's */ | ||
55 | /**********************************************************************************/ | ||
56 | DEFINE_SPINLOCK(tx4938_cp0_lock); | ||
57 | DEFINE_SPINLOCK(tx4938_pic_lock); | ||
58 | |||
59 | #define TX4938_CP0_NAME "TX4938-CP0" | ||
60 | static struct hw_interrupt_type tx4938_irq_cp0_type = { | ||
61 | .typename = TX4938_CP0_NAME, | ||
62 | .startup = tx4938_irq_cp0_startup, | ||
63 | .shutdown = tx4938_irq_cp0_shutdown, | ||
64 | .enable = tx4938_irq_cp0_enable, | ||
65 | .disable = tx4938_irq_cp0_disable, | ||
66 | .ack = tx4938_irq_cp0_mask_and_ack, | ||
67 | .end = tx4938_irq_cp0_end, | ||
68 | .set_affinity = NULL | ||
69 | }; | ||
70 | |||
71 | #define TX4938_PIC_NAME "TX4938-PIC" | ||
72 | static struct hw_interrupt_type tx4938_irq_pic_type = { | ||
73 | .typename = TX4938_PIC_NAME, | ||
74 | .startup = tx4938_irq_pic_startup, | ||
75 | .shutdown = tx4938_irq_pic_shutdown, | ||
76 | .enable = tx4938_irq_pic_enable, | ||
77 | .disable = tx4938_irq_pic_disable, | ||
78 | .ack = tx4938_irq_pic_mask_and_ack, | ||
79 | .end = tx4938_irq_pic_end, | ||
80 | .set_affinity = NULL | ||
81 | }; | ||
82 | |||
83 | static struct irqaction tx4938_irq_pic_action = { | ||
84 | .handler = no_action, | ||
85 | .flags = 0, | ||
86 | .mask = CPU_MASK_NONE, | ||
87 | .name = TX4938_PIC_NAME | ||
88 | }; | ||
89 | |||
90 | /**********************************************************************************/ | ||
91 | /* Functions for cp0 */ | ||
92 | /**********************************************************************************/ | ||
93 | |||
94 | #define tx4938_irq_cp0_mask(irq) ( 1 << ( irq-TX4938_IRQ_CP0_BEG+8 ) ) | ||
95 | |||
96 | static void __init | ||
97 | tx4938_irq_cp0_init(void) | ||
98 | { | ||
99 | int i; | ||
100 | |||
101 | for (i = TX4938_IRQ_CP0_BEG; i <= TX4938_IRQ_CP0_END; i++) { | ||
102 | irq_desc[i].status = IRQ_DISABLED; | ||
103 | irq_desc[i].action = 0; | ||
104 | irq_desc[i].depth = 1; | ||
105 | irq_desc[i].handler = &tx4938_irq_cp0_type; | ||
106 | } | ||
107 | |||
108 | return; | ||
109 | } | ||
110 | |||
111 | static unsigned int | ||
112 | tx4938_irq_cp0_startup(unsigned int irq) | ||
113 | { | ||
114 | tx4938_irq_cp0_enable(irq); | ||
115 | |||
116 | return (0); | ||
117 | } | ||
118 | |||
119 | static void | ||
120 | tx4938_irq_cp0_shutdown(unsigned int irq) | ||
121 | { | ||
122 | tx4938_irq_cp0_disable(irq); | ||
123 | } | ||
124 | |||
125 | static void | ||
126 | tx4938_irq_cp0_enable(unsigned int irq) | ||
127 | { | ||
128 | unsigned long flags; | ||
129 | |||
130 | spin_lock_irqsave(&tx4938_cp0_lock, flags); | ||
131 | |||
132 | set_c0_status(tx4938_irq_cp0_mask(irq)); | ||
133 | |||
134 | spin_unlock_irqrestore(&tx4938_cp0_lock, flags); | ||
135 | } | ||
136 | |||
137 | static void | ||
138 | tx4938_irq_cp0_disable(unsigned int irq) | ||
139 | { | ||
140 | unsigned long flags; | ||
141 | |||
142 | spin_lock_irqsave(&tx4938_cp0_lock, flags); | ||
143 | |||
144 | clear_c0_status(tx4938_irq_cp0_mask(irq)); | ||
145 | |||
146 | spin_unlock_irqrestore(&tx4938_cp0_lock, flags); | ||
147 | |||
148 | return; | ||
149 | } | ||
150 | |||
151 | static void | ||
152 | tx4938_irq_cp0_mask_and_ack(unsigned int irq) | ||
153 | { | ||
154 | tx4938_irq_cp0_disable(irq); | ||
155 | |||
156 | return; | ||
157 | } | ||
158 | |||
159 | static void | ||
160 | tx4938_irq_cp0_end(unsigned int irq) | ||
161 | { | ||
162 | if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) { | ||
163 | tx4938_irq_cp0_enable(irq); | ||
164 | } | ||
165 | |||
166 | return; | ||
167 | } | ||
168 | |||
169 | /**********************************************************************************/ | ||
170 | /* Functions for pic */ | ||
171 | /**********************************************************************************/ | ||
172 | |||
173 | u32 | ||
174 | tx4938_irq_pic_addr(int irq) | ||
175 | { | ||
176 | /* MVMCP -- need to formulize this */ | ||
177 | irq -= TX4938_IRQ_PIC_BEG; | ||
178 | |||
179 | switch (irq) { | ||
180 | case 17: | ||
181 | case 16: | ||
182 | case 1: | ||
183 | case 0:{ | ||
184 | return (TX4938_MKA(TX4938_IRC_IRLVL0)); | ||
185 | } | ||
186 | case 19: | ||
187 | case 18: | ||
188 | case 3: | ||
189 | case 2:{ | ||
190 | return (TX4938_MKA(TX4938_IRC_IRLVL1)); | ||
191 | } | ||
192 | case 21: | ||
193 | case 20: | ||
194 | case 5: | ||
195 | case 4:{ | ||
196 | return (TX4938_MKA(TX4938_IRC_IRLVL2)); | ||
197 | } | ||
198 | case 23: | ||
199 | case 22: | ||
200 | case 7: | ||
201 | case 6:{ | ||
202 | return (TX4938_MKA(TX4938_IRC_IRLVL3)); | ||
203 | } | ||
204 | case 25: | ||
205 | case 24: | ||
206 | case 9: | ||
207 | case 8:{ | ||
208 | return (TX4938_MKA(TX4938_IRC_IRLVL4)); | ||
209 | } | ||
210 | case 27: | ||
211 | case 26: | ||
212 | case 11: | ||
213 | case 10:{ | ||
214 | return (TX4938_MKA(TX4938_IRC_IRLVL5)); | ||
215 | } | ||
216 | case 29: | ||
217 | case 28: | ||
218 | case 13: | ||
219 | case 12:{ | ||
220 | return (TX4938_MKA(TX4938_IRC_IRLVL6)); | ||
221 | } | ||
222 | case 31: | ||
223 | case 30: | ||
224 | case 15: | ||
225 | case 14:{ | ||
226 | return (TX4938_MKA(TX4938_IRC_IRLVL7)); | ||
227 | } | ||
228 | } | ||
229 | |||
230 | return (0); | ||
231 | } | ||
232 | |||
233 | u32 | ||
234 | tx4938_irq_pic_mask(int irq) | ||
235 | { | ||
236 | /* MVMCP -- need to formulize this */ | ||
237 | irq -= TX4938_IRQ_PIC_BEG; | ||
238 | |||
239 | switch (irq) { | ||
240 | case 31: | ||
241 | case 29: | ||
242 | case 27: | ||
243 | case 25: | ||
244 | case 23: | ||
245 | case 21: | ||
246 | case 19: | ||
247 | case 17:{ | ||
248 | return (0x07000000); | ||
249 | } | ||
250 | case 30: | ||
251 | case 28: | ||
252 | case 26: | ||
253 | case 24: | ||
254 | case 22: | ||
255 | case 20: | ||
256 | case 18: | ||
257 | case 16:{ | ||
258 | return (0x00070000); | ||
259 | } | ||
260 | case 15: | ||
261 | case 13: | ||
262 | case 11: | ||
263 | case 9: | ||
264 | case 7: | ||
265 | case 5: | ||
266 | case 3: | ||
267 | case 1:{ | ||
268 | return (0x00000700); | ||
269 | } | ||
270 | case 14: | ||
271 | case 12: | ||
272 | case 10: | ||
273 | case 8: | ||
274 | case 6: | ||
275 | case 4: | ||
276 | case 2: | ||
277 | case 0:{ | ||
278 | return (0x00000007); | ||
279 | } | ||
280 | } | ||
281 | return (0x00000000); | ||
282 | } | ||
283 | |||
284 | static void | ||
285 | tx4938_irq_pic_modify(unsigned pic_reg, unsigned clr_bits, unsigned set_bits) | ||
286 | { | ||
287 | unsigned long val = 0; | ||
288 | |||
289 | val = TX4938_RD(pic_reg); | ||
290 | val &= (~clr_bits); | ||
291 | val |= (set_bits); | ||
292 | TX4938_WR(pic_reg, val); | ||
293 | mmiowb(); | ||
294 | TX4938_RD(pic_reg); | ||
295 | |||
296 | return; | ||
297 | } | ||
298 | |||
299 | static void __init | ||
300 | tx4938_irq_pic_init(void) | ||
301 | { | ||
302 | unsigned long flags; | ||
303 | int i; | ||
304 | |||
305 | for (i = TX4938_IRQ_PIC_BEG; i <= TX4938_IRQ_PIC_END; i++) { | ||
306 | irq_desc[i].status = IRQ_DISABLED; | ||
307 | irq_desc[i].action = 0; | ||
308 | irq_desc[i].depth = 2; | ||
309 | irq_desc[i].handler = &tx4938_irq_pic_type; | ||
310 | } | ||
311 | |||
312 | setup_irq(TX4938_IRQ_NEST_PIC_ON_CP0, &tx4938_irq_pic_action); | ||
313 | |||
314 | spin_lock_irqsave(&tx4938_pic_lock, flags); | ||
315 | |||
316 | TX4938_WR(0xff1ff640, 0x6); /* irq level mask -- only accept hightest */ | ||
317 | TX4938_WR(0xff1ff600, TX4938_RD(0xff1ff600) | 0x1); /* irq enable */ | ||
318 | |||
319 | spin_unlock_irqrestore(&tx4938_pic_lock, flags); | ||
320 | |||
321 | return; | ||
322 | } | ||
323 | |||
324 | static unsigned int | ||
325 | tx4938_irq_pic_startup(unsigned int irq) | ||
326 | { | ||
327 | tx4938_irq_pic_enable(irq); | ||
328 | |||
329 | return (0); | ||
330 | } | ||
331 | |||
332 | static void | ||
333 | tx4938_irq_pic_shutdown(unsigned int irq) | ||
334 | { | ||
335 | tx4938_irq_pic_disable(irq); | ||
336 | |||
337 | return; | ||
338 | } | ||
339 | |||
340 | static void | ||
341 | tx4938_irq_pic_enable(unsigned int irq) | ||
342 | { | ||
343 | unsigned long flags; | ||
344 | |||
345 | spin_lock_irqsave(&tx4938_pic_lock, flags); | ||
346 | |||
347 | tx4938_irq_pic_modify(tx4938_irq_pic_addr(irq), 0, | ||
348 | tx4938_irq_pic_mask(irq)); | ||
349 | |||
350 | spin_unlock_irqrestore(&tx4938_pic_lock, flags); | ||
351 | |||
352 | return; | ||
353 | } | ||
354 | |||
355 | static void | ||
356 | tx4938_irq_pic_disable(unsigned int irq) | ||
357 | { | ||
358 | unsigned long flags; | ||
359 | |||
360 | spin_lock_irqsave(&tx4938_pic_lock, flags); | ||
361 | |||
362 | tx4938_irq_pic_modify(tx4938_irq_pic_addr(irq), | ||
363 | tx4938_irq_pic_mask(irq), 0); | ||
364 | |||
365 | spin_unlock_irqrestore(&tx4938_pic_lock, flags); | ||
366 | |||
367 | return; | ||
368 | } | ||
369 | |||
370 | static void | ||
371 | tx4938_irq_pic_mask_and_ack(unsigned int irq) | ||
372 | { | ||
373 | tx4938_irq_pic_disable(irq); | ||
374 | |||
375 | return; | ||
376 | } | ||
377 | |||
378 | static void | ||
379 | tx4938_irq_pic_end(unsigned int irq) | ||
380 | { | ||
381 | if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) { | ||
382 | tx4938_irq_pic_enable(irq); | ||
383 | } | ||
384 | |||
385 | return; | ||
386 | } | ||
387 | |||
388 | /**********************************************************************************/ | ||
389 | /* Main init functions */ | ||
390 | /**********************************************************************************/ | ||
391 | |||
392 | void __init | ||
393 | tx4938_irq_init(void) | ||
394 | { | ||
395 | extern asmlinkage void tx4938_irq_handler(void); | ||
396 | |||
397 | tx4938_irq_cp0_init(); | ||
398 | tx4938_irq_pic_init(); | ||
399 | set_except_vector(0, tx4938_irq_handler); | ||
400 | |||
401 | return; | ||
402 | } | ||
403 | |||
404 | int | ||
405 | tx4938_irq_nested(void) | ||
406 | { | ||
407 | int sw_irq = 0; | ||
408 | u32 level2; | ||
409 | |||
410 | level2 = TX4938_RD(0xff1ff6a0); | ||
411 | if ((level2 & 0x10000) == 0) { | ||
412 | level2 &= 0x1f; | ||
413 | sw_irq = TX4938_IRQ_PIC_BEG + level2; | ||
414 | if (sw_irq == 26) { | ||
415 | { | ||
416 | extern int toshiba_rbtx4938_irq_nested(int sw_irq); | ||
417 | sw_irq = toshiba_rbtx4938_irq_nested(sw_irq); | ||
418 | } | ||
419 | } | ||
420 | } | ||
421 | |||
422 | wbflush(); | ||
423 | return (sw_irq); | ||
424 | } | ||
diff --git a/arch/mips/tx4938/common/irq_handler.S b/arch/mips/tx4938/common/irq_handler.S new file mode 100644 index 000000000000..1b2f72bac42d --- /dev/null +++ b/arch/mips/tx4938/common/irq_handler.S | |||
@@ -0,0 +1,84 @@ | |||
1 | /* | ||
2 | * linux/arch/mips/tx4938/common/handler.S | ||
3 | * | ||
4 | * Primary interrupt handler for tx4938 based systems | ||
5 | * Copyright (C) 2000-2001 Toshiba Corporation | ||
6 | * | ||
7 | * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the | ||
8 | * terms of the GNU General Public License version 2. This program is | ||
9 | * licensed "as is" without any warranty of any kind, whether express | ||
10 | * or implied. | ||
11 | * | ||
12 | * Support for TX4938 in 2.6 - Manish Lachwani (mlachwani@mvista.com) | ||
13 | */ | ||
14 | #include <asm/asm.h> | ||
15 | #include <asm/mipsregs.h> | ||
16 | #include <asm/addrspace.h> | ||
17 | #include <asm/regdef.h> | ||
18 | #include <asm/stackframe.h> | ||
19 | #include <asm/tx4938/rbtx4938.h> | ||
20 | |||
21 | |||
22 | .align 5 | ||
23 | NESTED(tx4938_irq_handler, PT_SIZE, sp) | ||
24 | SAVE_ALL | ||
25 | CLI | ||
26 | .set at | ||
27 | |||
28 | mfc0 t0, CP0_CAUSE | ||
29 | mfc0 t1, CP0_STATUS | ||
30 | and t0, t1 | ||
31 | |||
32 | andi t1, t0, STATUSF_IP7 /* cpu timer */ | ||
33 | bnez t1, ll_ip7 | ||
34 | |||
35 | /* IP6..IP3 multiplexed -- do not use */ | ||
36 | |||
37 | andi t1, t0, STATUSF_IP2 /* tx4938 pic */ | ||
38 | bnez t1, ll_ip2 | ||
39 | |||
40 | andi t1, t0, STATUSF_IP1 /* user line 1 */ | ||
41 | bnez t1, ll_ip1 | ||
42 | |||
43 | andi t1, t0, STATUSF_IP0 /* user line 0 */ | ||
44 | bnez t1, ll_ip0 | ||
45 | |||
46 | .set reorder | ||
47 | |||
48 | nop | ||
49 | END(tx4938_irq_handler) | ||
50 | |||
51 | .align 5 | ||
52 | |||
53 | |||
54 | ll_ip7: | ||
55 | li a0, TX4938_IRQ_CPU_TIMER | ||
56 | move a1, sp | ||
57 | jal do_IRQ | ||
58 | j ret_from_irq | ||
59 | |||
60 | |||
61 | ll_ip2: | ||
62 | jal tx4938_irq_nested | ||
63 | nop | ||
64 | beqz v0, goto_spurious_interrupt | ||
65 | nop | ||
66 | move a0, v0 | ||
67 | move a1, sp | ||
68 | jal do_IRQ | ||
69 | j ret_from_irq | ||
70 | |||
71 | goto_spurious_interrupt: | ||
72 | j ret_from_irq | ||
73 | |||
74 | ll_ip1: | ||
75 | li a0, TX4938_IRQ_USER1 | ||
76 | move a1, sp | ||
77 | jal do_IRQ | ||
78 | j ret_from_irq | ||
79 | |||
80 | ll_ip0: | ||
81 | li a0, TX4938_IRQ_USER0 | ||
82 | move a1, sp | ||
83 | jal do_IRQ | ||
84 | j ret_from_irq | ||
diff --git a/arch/mips/tx4938/common/prom.c b/arch/mips/tx4938/common/prom.c new file mode 100644 index 000000000000..3189a65f7d7e --- /dev/null +++ b/arch/mips/tx4938/common/prom.c | |||
@@ -0,0 +1,129 @@ | |||
1 | /* | ||
2 | * linux/arch/mips/tx4938/common/prom.c | ||
3 | * | ||
4 | * common tx4938 memory interface | ||
5 | * Copyright (C) 2000-2001 Toshiba Corporation | ||
6 | * | ||
7 | * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the | ||
8 | * terms of the GNU General Public License version 2. This program is | ||
9 | * licensed "as is" without any warranty of any kind, whether express | ||
10 | * or implied. | ||
11 | * | ||
12 | * Support for TX4938 in 2.6 - Manish Lachwani (mlachwani@mvista.com) | ||
13 | */ | ||
14 | |||
15 | #include <linux/init.h> | ||
16 | #include <linux/mm.h> | ||
17 | #include <linux/sched.h> | ||
18 | #include <linux/bootmem.h> | ||
19 | |||
20 | #include <asm/addrspace.h> | ||
21 | #include <asm/bootinfo.h> | ||
22 | #include <asm/tx4938/tx4938.h> | ||
23 | |||
24 | static unsigned int __init | ||
25 | tx4938_process_sdccr(u64 * addr) | ||
26 | { | ||
27 | u64 val; | ||
28 | unsigned int sdccr_ce; | ||
29 | unsigned int sdccr_rs; | ||
30 | unsigned int sdccr_cs; | ||
31 | unsigned int sdccr_mw; | ||
32 | unsigned int rs = 0; | ||
33 | unsigned int cs = 0; | ||
34 | unsigned int mw = 0; | ||
35 | unsigned int bc = 4; | ||
36 | unsigned int msize = 0; | ||
37 | |||
38 | val = (*((vu64 *) (addr))); | ||
39 | |||
40 | /* MVMCP -- need #defs for these bits masks */ | ||
41 | sdccr_ce = ((val & (1 << 10)) >> 10); | ||
42 | sdccr_rs = ((val & (3 << 5)) >> 5); | ||
43 | sdccr_cs = ((val & (7 << 2)) >> 2); | ||
44 | sdccr_mw = ((val & (1 << 0)) >> 0); | ||
45 | |||
46 | if (sdccr_ce) { | ||
47 | switch (sdccr_rs) { | ||
48 | case 0:{ | ||
49 | rs = 2048; | ||
50 | break; | ||
51 | } | ||
52 | case 1:{ | ||
53 | rs = 4096; | ||
54 | break; | ||
55 | } | ||
56 | case 2:{ | ||
57 | rs = 8192; | ||
58 | break; | ||
59 | } | ||
60 | default:{ | ||
61 | rs = 0; | ||
62 | break; | ||
63 | } | ||
64 | } | ||
65 | switch (sdccr_cs) { | ||
66 | case 0:{ | ||
67 | cs = 256; | ||
68 | break; | ||
69 | } | ||
70 | case 1:{ | ||
71 | cs = 512; | ||
72 | break; | ||
73 | } | ||
74 | case 2:{ | ||
75 | cs = 1024; | ||
76 | break; | ||
77 | } | ||
78 | case 3:{ | ||
79 | cs = 2048; | ||
80 | break; | ||
81 | } | ||
82 | case 4:{ | ||
83 | cs = 4096; | ||
84 | break; | ||
85 | } | ||
86 | default:{ | ||
87 | cs = 0; | ||
88 | break; | ||
89 | } | ||
90 | } | ||
91 | switch (sdccr_mw) { | ||
92 | case 0:{ | ||
93 | mw = 8; | ||
94 | break; | ||
95 | } /* 8 bytes = 64 bits */ | ||
96 | case 1:{ | ||
97 | mw = 4; | ||
98 | break; | ||
99 | } /* 4 bytes = 32 bits */ | ||
100 | } | ||
101 | } | ||
102 | |||
103 | /* bytes per chip MB per chip bank count */ | ||
104 | msize = (((rs * cs * mw) / (1024 * 1024)) * (bc)); | ||
105 | |||
106 | /* MVMCP -- bc hard coded to 4 from table 9.3.1 */ | ||
107 | /* boad supports bc=2 but no way to detect */ | ||
108 | |||
109 | return (msize); | ||
110 | } | ||
111 | |||
112 | unsigned int __init | ||
113 | tx4938_get_mem_size(void) | ||
114 | { | ||
115 | unsigned int c0; | ||
116 | unsigned int c1; | ||
117 | unsigned int c2; | ||
118 | unsigned int c3; | ||
119 | unsigned int total; | ||
120 | |||
121 | /* MVMCP -- need #defs for these registers */ | ||
122 | c0 = tx4938_process_sdccr((u64 *) 0xff1f8000); | ||
123 | c1 = tx4938_process_sdccr((u64 *) 0xff1f8008); | ||
124 | c2 = tx4938_process_sdccr((u64 *) 0xff1f8010); | ||
125 | c3 = tx4938_process_sdccr((u64 *) 0xff1f8018); | ||
126 | total = c0 + c1 + c2 + c3; | ||
127 | |||
128 | return (total); | ||
129 | } | ||
diff --git a/arch/mips/tx4938/common/rtc_rx5c348.c b/arch/mips/tx4938/common/rtc_rx5c348.c new file mode 100644 index 000000000000..d249edbb6af4 --- /dev/null +++ b/arch/mips/tx4938/common/rtc_rx5c348.c | |||
@@ -0,0 +1,202 @@ | |||
1 | /* | ||
2 | * RTC routines for RICOH Rx5C348 SPI chip. | ||
3 | * Copyright (C) 2000-2001 Toshiba Corporation | ||
4 | * | ||
5 | * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the | ||
6 | * terms of the GNU General Public License version 2. This program is | ||
7 | * licensed "as is" without any warranty of any kind, whether express | ||
8 | * or implied. | ||
9 | * | ||
10 | * Support for TX4938 in 2.6 - Manish Lachwani (mlachwani@mvista.com) | ||
11 | */ | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/string.h> | ||
15 | #include <linux/rtc.h> | ||
16 | #include <linux/time.h> | ||
17 | #include <asm/time.h> | ||
18 | #include <asm/tx4938/spi.h> | ||
19 | |||
20 | #define EPOCH 2000 | ||
21 | |||
22 | /* registers */ | ||
23 | #define Rx5C348_REG_SECOND 0 | ||
24 | #define Rx5C348_REG_MINUTE 1 | ||
25 | #define Rx5C348_REG_HOUR 2 | ||
26 | #define Rx5C348_REG_WEEK 3 | ||
27 | #define Rx5C348_REG_DAY 4 | ||
28 | #define Rx5C348_REG_MONTH 5 | ||
29 | #define Rx5C348_REG_YEAR 6 | ||
30 | #define Rx5C348_REG_ADJUST 7 | ||
31 | #define Rx5C348_REG_ALARM_W_MIN 8 | ||
32 | #define Rx5C348_REG_ALARM_W_HOUR 9 | ||
33 | #define Rx5C348_REG_ALARM_W_WEEK 10 | ||
34 | #define Rx5C348_REG_ALARM_D_MIN 11 | ||
35 | #define Rx5C348_REG_ALARM_D_HOUR 12 | ||
36 | #define Rx5C348_REG_CTL1 14 | ||
37 | #define Rx5C348_REG_CTL2 15 | ||
38 | |||
39 | /* register bits */ | ||
40 | #define Rx5C348_BIT_PM 0x20 /* REG_HOUR */ | ||
41 | #define Rx5C348_BIT_Y2K 0x80 /* REG_MONTH */ | ||
42 | #define Rx5C348_BIT_24H 0x20 /* REG_CTL1 */ | ||
43 | #define Rx5C348_BIT_XSTP 0x10 /* REG_CTL2 */ | ||
44 | |||
45 | /* commands */ | ||
46 | #define Rx5C348_CMD_W(addr) (((addr) << 4) | 0x08) /* single write */ | ||
47 | #define Rx5C348_CMD_R(addr) (((addr) << 4) | 0x0c) /* single read */ | ||
48 | #define Rx5C348_CMD_MW(addr) (((addr) << 4) | 0x00) /* burst write */ | ||
49 | #define Rx5C348_CMD_MR(addr) (((addr) << 4) | 0x04) /* burst read */ | ||
50 | |||
51 | static struct spi_dev_desc srtc_dev_desc = { | ||
52 | .baud = 1000000, /* 1.0Mbps @ Vdd 2.0V */ | ||
53 | .tcss = 31, | ||
54 | .tcsh = 1, | ||
55 | .tcsr = 62, | ||
56 | /* 31us for Tcss (62us for Tcsr) is required for carry operation) */ | ||
57 | .byteorder = 1, /* MSB-First */ | ||
58 | .polarity = 0, /* High-Active */ | ||
59 | .phase = 1, /* Shift-Then-Sample */ | ||
60 | |||
61 | }; | ||
62 | static int srtc_chipid; | ||
63 | static int srtc_24h; | ||
64 | |||
65 | static inline int | ||
66 | spi_rtc_io(unsigned char *inbuf, unsigned char *outbuf, unsigned int count) | ||
67 | { | ||
68 | unsigned char *inbufs[1], *outbufs[1]; | ||
69 | unsigned int incounts[2], outcounts[2]; | ||
70 | inbufs[0] = inbuf; | ||
71 | incounts[0] = count; | ||
72 | incounts[1] = 0; | ||
73 | outbufs[0] = outbuf; | ||
74 | outcounts[0] = count; | ||
75 | outcounts[1] = 0; | ||
76 | return txx9_spi_io(srtc_chipid, &srtc_dev_desc, | ||
77 | inbufs, incounts, outbufs, outcounts, 0); | ||
78 | } | ||
79 | |||
80 | /* | ||
81 | * Conversion between binary and BCD. | ||
82 | */ | ||
83 | #ifndef BCD_TO_BIN | ||
84 | #define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10) | ||
85 | #endif | ||
86 | |||
87 | #ifndef BIN_TO_BCD | ||
88 | #define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10) | ||
89 | #endif | ||
90 | |||
91 | /* RTC-dependent code for time.c */ | ||
92 | |||
93 | static int | ||
94 | rtc_rx5c348_set_time(unsigned long t) | ||
95 | { | ||
96 | unsigned char inbuf[8]; | ||
97 | struct rtc_time tm; | ||
98 | u8 year, month, day, hour, minute, second, century; | ||
99 | |||
100 | /* convert */ | ||
101 | to_tm(t, &tm); | ||
102 | |||
103 | year = tm.tm_year % 100; | ||
104 | month = tm.tm_mon+1; /* tm_mon starts from 0 to 11 */ | ||
105 | day = tm.tm_mday; | ||
106 | hour = tm.tm_hour; | ||
107 | minute = tm.tm_min; | ||
108 | second = tm.tm_sec; | ||
109 | century = tm.tm_year / 100; | ||
110 | |||
111 | inbuf[0] = Rx5C348_CMD_MW(Rx5C348_REG_SECOND); | ||
112 | BIN_TO_BCD(second); | ||
113 | inbuf[1] = second; | ||
114 | BIN_TO_BCD(minute); | ||
115 | inbuf[2] = minute; | ||
116 | |||
117 | if (srtc_24h) { | ||
118 | BIN_TO_BCD(hour); | ||
119 | inbuf[3] = hour; | ||
120 | } else { | ||
121 | /* hour 0 is AM12, noon is PM12 */ | ||
122 | inbuf[3] = 0; | ||
123 | if (hour >= 12) | ||
124 | inbuf[3] = Rx5C348_BIT_PM; | ||
125 | hour = (hour + 11) % 12 + 1; | ||
126 | BIN_TO_BCD(hour); | ||
127 | inbuf[3] |= hour; | ||
128 | } | ||
129 | inbuf[4] = 0; /* ignore week */ | ||
130 | BIN_TO_BCD(day); | ||
131 | inbuf[5] = day; | ||
132 | BIN_TO_BCD(month); | ||
133 | inbuf[6] = month; | ||
134 | if (century >= 20) | ||
135 | inbuf[6] |= Rx5C348_BIT_Y2K; | ||
136 | BIN_TO_BCD(year); | ||
137 | inbuf[7] = year; | ||
138 | /* write in one transfer to avoid data inconsistency */ | ||
139 | return spi_rtc_io(inbuf, NULL, 8); | ||
140 | } | ||
141 | |||
142 | static unsigned long | ||
143 | rtc_rx5c348_get_time(void) | ||
144 | { | ||
145 | unsigned char inbuf[8], outbuf[8]; | ||
146 | unsigned int year, month, day, hour, minute, second; | ||
147 | |||
148 | inbuf[0] = Rx5C348_CMD_MR(Rx5C348_REG_SECOND); | ||
149 | memset(inbuf + 1, 0, 7); | ||
150 | /* read in one transfer to avoid data inconsistency */ | ||
151 | if (spi_rtc_io(inbuf, outbuf, 8)) | ||
152 | return 0; | ||
153 | second = outbuf[1]; | ||
154 | BCD_TO_BIN(second); | ||
155 | minute = outbuf[2]; | ||
156 | BCD_TO_BIN(minute); | ||
157 | if (srtc_24h) { | ||
158 | hour = outbuf[3]; | ||
159 | BCD_TO_BIN(hour); | ||
160 | } else { | ||
161 | hour = outbuf[3] & ~Rx5C348_BIT_PM; | ||
162 | BCD_TO_BIN(hour); | ||
163 | hour %= 12; | ||
164 | if (outbuf[3] & Rx5C348_BIT_PM) | ||
165 | hour += 12; | ||
166 | } | ||
167 | day = outbuf[5]; | ||
168 | BCD_TO_BIN(day); | ||
169 | month = outbuf[6] & ~Rx5C348_BIT_Y2K; | ||
170 | BCD_TO_BIN(month); | ||
171 | year = outbuf[7]; | ||
172 | BCD_TO_BIN(year); | ||
173 | year += EPOCH; | ||
174 | |||
175 | return mktime(year, month, day, hour, minute, second); | ||
176 | } | ||
177 | |||
178 | void __init | ||
179 | rtc_rx5c348_init(int chipid) | ||
180 | { | ||
181 | unsigned char inbuf[2], outbuf[2]; | ||
182 | srtc_chipid = chipid; | ||
183 | /* turn on RTC if it is not on */ | ||
184 | inbuf[0] = Rx5C348_CMD_R(Rx5C348_REG_CTL2); | ||
185 | inbuf[1] = 0; | ||
186 | spi_rtc_io(inbuf, outbuf, 2); | ||
187 | if (outbuf[1] & Rx5C348_BIT_XSTP) { | ||
188 | inbuf[0] = Rx5C348_CMD_W(Rx5C348_REG_CTL2); | ||
189 | inbuf[1] = 0; | ||
190 | spi_rtc_io(inbuf, NULL, 2); | ||
191 | } | ||
192 | |||
193 | inbuf[0] = Rx5C348_CMD_R(Rx5C348_REG_CTL1); | ||
194 | inbuf[1] = 0; | ||
195 | spi_rtc_io(inbuf, outbuf, 2); | ||
196 | if (outbuf[1] & Rx5C348_BIT_24H) | ||
197 | srtc_24h = 1; | ||
198 | |||
199 | /* set the function pointers */ | ||
200 | rtc_get_time = rtc_rx5c348_get_time; | ||
201 | rtc_set_time = rtc_rx5c348_set_time; | ||
202 | } | ||
diff --git a/arch/mips/tx4938/common/setup.c b/arch/mips/tx4938/common/setup.c new file mode 100644 index 000000000000..fc992953bf95 --- /dev/null +++ b/arch/mips/tx4938/common/setup.c | |||
@@ -0,0 +1,91 @@ | |||
1 | /* | ||
2 | * linux/arch/mips/tx4938/common/setup.c | ||
3 | * | ||
4 | * common tx4938 setup routines | ||
5 | * | ||
6 | * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the | ||
7 | * terms of the GNU General Public License version 2. This program is | ||
8 | * licensed "as is" without any warranty of any kind, whether express | ||
9 | * or implied. | ||
10 | * | ||
11 | * Support for TX4938 in 2.6 - Manish Lachwani (mlachwani@mvista.com) | ||
12 | */ | ||
13 | |||
14 | #include <linux/errno.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/kernel_stat.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/signal.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/types.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/ioport.h> | ||
23 | #include <linux/timex.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/random.h> | ||
26 | #include <linux/irq.h> | ||
27 | #include <asm/bitops.h> | ||
28 | #include <asm/bootinfo.h> | ||
29 | #include <asm/io.h> | ||
30 | #include <asm/irq.h> | ||
31 | #include <asm/mipsregs.h> | ||
32 | #include <asm/system.h> | ||
33 | #include <asm/time.h> | ||
34 | #include <asm/time.h> | ||
35 | #include <asm/tx4938/rbtx4938.h> | ||
36 | |||
37 | extern void toshiba_rbtx4938_setup(void); | ||
38 | extern void rbtx4938_time_init(void); | ||
39 | |||
40 | void __init tx4938_setup(void); | ||
41 | void __init tx4938_time_init(void); | ||
42 | void __init tx4938_timer_setup(struct irqaction *irq); | ||
43 | void dump_cp0(char *key); | ||
44 | |||
45 | void (*__wbflush) (void); | ||
46 | |||
47 | static void | ||
48 | tx4938_write_buffer_flush(void) | ||
49 | { | ||
50 | mmiowb(); | ||
51 | |||
52 | __asm__ __volatile__( | ||
53 | ".set push\n\t" | ||
54 | ".set noreorder\n\t" | ||
55 | "lw $0,%0\n\t" | ||
56 | "nop\n\t" | ||
57 | ".set pop" | ||
58 | : /* no output */ | ||
59 | : "m" (*(int *)KSEG1) | ||
60 | : "memory"); | ||
61 | } | ||
62 | |||
63 | void __init | ||
64 | plat_setup(void) | ||
65 | { | ||
66 | board_time_init = tx4938_time_init; | ||
67 | board_timer_setup = tx4938_timer_setup; | ||
68 | __wbflush = tx4938_write_buffer_flush; | ||
69 | toshiba_rbtx4938_setup(); | ||
70 | } | ||
71 | |||
72 | void __init | ||
73 | tx4938_time_init(void) | ||
74 | { | ||
75 | rbtx4938_time_init(); | ||
76 | } | ||
77 | |||
78 | void __init | ||
79 | tx4938_timer_setup(struct irqaction *irq) | ||
80 | { | ||
81 | u32 count; | ||
82 | u32 c1; | ||
83 | u32 c2; | ||
84 | |||
85 | setup_irq(TX4938_IRQ_CPU_TIMER, irq); | ||
86 | |||
87 | c1 = read_c0_count(); | ||
88 | count = c1 + (mips_hpt_frequency / HZ); | ||
89 | write_c0_compare(count); | ||
90 | c2 = read_c0_count(); | ||
91 | } | ||
diff --git a/arch/mips/tx4938/toshiba_rbtx4938/Makefile b/arch/mips/tx4938/toshiba_rbtx4938/Makefile new file mode 100644 index 000000000000..226941279d75 --- /dev/null +++ b/arch/mips/tx4938/toshiba_rbtx4938/Makefile | |||
@@ -0,0 +1,9 @@ | |||
1 | # | ||
2 | # Makefile for common code for Toshiba TX4927 based systems | ||
3 | # | ||
4 | # Note! Dependencies are done automagically by 'make dep', which also | ||
5 | # removes any old dependencies. DON'T put your own dependencies here | ||
6 | # unless it's something special (ie not a .c file). | ||
7 | # | ||
8 | |||
9 | obj-y += prom.o setup.o irq.o spi_eeprom.o spi_txx9.o | ||
diff --git a/arch/mips/tx4938/toshiba_rbtx4938/irq.c b/arch/mips/tx4938/toshiba_rbtx4938/irq.c new file mode 100644 index 000000000000..230f5a93c2e6 --- /dev/null +++ b/arch/mips/tx4938/toshiba_rbtx4938/irq.c | |||
@@ -0,0 +1,244 @@ | |||
1 | /* | ||
2 | * linux/arch/mips/tx4938/toshiba_rbtx4938/irq.c | ||
3 | * | ||
4 | * Toshiba RBTX4938 specific interrupt handlers | ||
5 | * Copyright (C) 2000-2001 Toshiba Corporation | ||
6 | * | ||
7 | * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the | ||
8 | * terms of the GNU General Public License version 2. This program is | ||
9 | * licensed "as is" without any warranty of any kind, whether express | ||
10 | * or implied. | ||
11 | * | ||
12 | * Support for TX4938 in 2.6 - Manish Lachwani (mlachwani@mvista.com) | ||
13 | */ | ||
14 | |||
15 | /* | ||
16 | IRQ Device | ||
17 | |||
18 | 16 TX4938-CP0/00 Software 0 | ||
19 | 17 TX4938-CP0/01 Software 1 | ||
20 | 18 TX4938-CP0/02 Cascade TX4938-CP0 | ||
21 | 19 TX4938-CP0/03 Multiplexed -- do not use | ||
22 | 20 TX4938-CP0/04 Multiplexed -- do not use | ||
23 | 21 TX4938-CP0/05 Multiplexed -- do not use | ||
24 | 22 TX4938-CP0/06 Multiplexed -- do not use | ||
25 | 23 TX4938-CP0/07 CPU TIMER | ||
26 | |||
27 | 24 TX4938-PIC/00 | ||
28 | 25 TX4938-PIC/01 | ||
29 | 26 TX4938-PIC/02 Cascade RBTX4938-IOC | ||
30 | 27 TX4938-PIC/03 RBTX4938 RTL-8019AS Ethernet | ||
31 | 28 TX4938-PIC/04 | ||
32 | 29 TX4938-PIC/05 TX4938 ETH1 | ||
33 | 30 TX4938-PIC/06 TX4938 ETH0 | ||
34 | 31 TX4938-PIC/07 | ||
35 | 32 TX4938-PIC/08 TX4938 SIO 0 | ||
36 | 33 TX4938-PIC/09 TX4938 SIO 1 | ||
37 | 34 TX4938-PIC/10 TX4938 DMA0 | ||
38 | 35 TX4938-PIC/11 TX4938 DMA1 | ||
39 | 36 TX4938-PIC/12 TX4938 DMA2 | ||
40 | 37 TX4938-PIC/13 TX4938 DMA3 | ||
41 | 38 TX4938-PIC/14 | ||
42 | 39 TX4938-PIC/15 | ||
43 | 40 TX4938-PIC/16 TX4938 PCIC | ||
44 | 41 TX4938-PIC/17 TX4938 TMR0 | ||
45 | 42 TX4938-PIC/18 TX4938 TMR1 | ||
46 | 43 TX4938-PIC/19 TX4938 TMR2 | ||
47 | 44 TX4938-PIC/20 | ||
48 | 45 TX4938-PIC/21 | ||
49 | 46 TX4938-PIC/22 TX4938 PCIERR | ||
50 | 47 TX4938-PIC/23 | ||
51 | 48 TX4938-PIC/24 | ||
52 | 49 TX4938-PIC/25 | ||
53 | 50 TX4938-PIC/26 | ||
54 | 51 TX4938-PIC/27 | ||
55 | 52 TX4938-PIC/28 | ||
56 | 53 TX4938-PIC/29 | ||
57 | 54 TX4938-PIC/30 | ||
58 | 55 TX4938-PIC/31 TX4938 SPI | ||
59 | |||
60 | 56 RBTX4938-IOC/00 PCI-D | ||
61 | 57 RBTX4938-IOC/01 PCI-C | ||
62 | 58 RBTX4938-IOC/02 PCI-B | ||
63 | 59 RBTX4938-IOC/03 PCI-A | ||
64 | 60 RBTX4938-IOC/04 RTC | ||
65 | 61 RBTX4938-IOC/05 ATA | ||
66 | 62 RBTX4938-IOC/06 MODEM | ||
67 | 63 RBTX4938-IOC/07 SWINT | ||
68 | */ | ||
69 | #include <linux/init.h> | ||
70 | #include <linux/kernel.h> | ||
71 | #include <linux/types.h> | ||
72 | #include <linux/mm.h> | ||
73 | #include <linux/swap.h> | ||
74 | #include <linux/ioport.h> | ||
75 | #include <linux/sched.h> | ||
76 | #include <linux/interrupt.h> | ||
77 | #include <linux/pci.h> | ||
78 | #include <linux/timex.h> | ||
79 | #include <asm/bootinfo.h> | ||
80 | #include <asm/page.h> | ||
81 | #include <asm/io.h> | ||
82 | #include <asm/irq.h> | ||
83 | #include <asm/processor.h> | ||
84 | #include <asm/ptrace.h> | ||
85 | #include <asm/reboot.h> | ||
86 | #include <asm/time.h> | ||
87 | #include <linux/version.h> | ||
88 | #include <linux/bootmem.h> | ||
89 | #include <asm/tx4938/rbtx4938.h> | ||
90 | |||
91 | static unsigned int toshiba_rbtx4938_irq_ioc_startup(unsigned int irq); | ||
92 | static void toshiba_rbtx4938_irq_ioc_shutdown(unsigned int irq); | ||
93 | static void toshiba_rbtx4938_irq_ioc_enable(unsigned int irq); | ||
94 | static void toshiba_rbtx4938_irq_ioc_disable(unsigned int irq); | ||
95 | static void toshiba_rbtx4938_irq_ioc_mask_and_ack(unsigned int irq); | ||
96 | static void toshiba_rbtx4938_irq_ioc_end(unsigned int irq); | ||
97 | |||
98 | DEFINE_SPINLOCK(toshiba_rbtx4938_ioc_lock); | ||
99 | |||
100 | #define TOSHIBA_RBTX4938_IOC_NAME "RBTX4938-IOC" | ||
101 | static struct hw_interrupt_type toshiba_rbtx4938_irq_ioc_type = { | ||
102 | .typename = TOSHIBA_RBTX4938_IOC_NAME, | ||
103 | .startup = toshiba_rbtx4938_irq_ioc_startup, | ||
104 | .shutdown = toshiba_rbtx4938_irq_ioc_shutdown, | ||
105 | .enable = toshiba_rbtx4938_irq_ioc_enable, | ||
106 | .disable = toshiba_rbtx4938_irq_ioc_disable, | ||
107 | .ack = toshiba_rbtx4938_irq_ioc_mask_and_ack, | ||
108 | .end = toshiba_rbtx4938_irq_ioc_end, | ||
109 | .set_affinity = NULL | ||
110 | }; | ||
111 | |||
112 | #define TOSHIBA_RBTX4938_IOC_INTR_ENAB 0xb7f02000 | ||
113 | #define TOSHIBA_RBTX4938_IOC_INTR_STAT 0xb7f0200a | ||
114 | |||
115 | int | ||
116 | toshiba_rbtx4938_irq_nested(int sw_irq) | ||
117 | { | ||
118 | u8 level3; | ||
119 | |||
120 | level3 = reg_rd08(TOSHIBA_RBTX4938_IOC_INTR_STAT) & 0xff; | ||
121 | if (level3) { | ||
122 | /* must use fls so onboard ATA has priority */ | ||
123 | sw_irq = TOSHIBA_RBTX4938_IRQ_IOC_BEG + fls(level3) - 1; | ||
124 | } | ||
125 | |||
126 | wbflush(); | ||
127 | return sw_irq; | ||
128 | } | ||
129 | |||
130 | static struct irqaction toshiba_rbtx4938_irq_ioc_action = { | ||
131 | .handler = no_action, | ||
132 | .flags = 0, | ||
133 | .mask = CPU_MASK_NONE, | ||
134 | .name = TOSHIBA_RBTX4938_IOC_NAME, | ||
135 | }; | ||
136 | |||
137 | /**********************************************************************************/ | ||
138 | /* Functions for ioc */ | ||
139 | /**********************************************************************************/ | ||
140 | static void __init | ||
141 | toshiba_rbtx4938_irq_ioc_init(void) | ||
142 | { | ||
143 | int i; | ||
144 | |||
145 | for (i = TOSHIBA_RBTX4938_IRQ_IOC_BEG; | ||
146 | i <= TOSHIBA_RBTX4938_IRQ_IOC_END; i++) { | ||
147 | irq_desc[i].status = IRQ_DISABLED; | ||
148 | irq_desc[i].action = 0; | ||
149 | irq_desc[i].depth = 3; | ||
150 | irq_desc[i].handler = &toshiba_rbtx4938_irq_ioc_type; | ||
151 | } | ||
152 | |||
153 | setup_irq(RBTX4938_IRQ_IOCINT, | ||
154 | &toshiba_rbtx4938_irq_ioc_action); | ||
155 | } | ||
156 | |||
157 | static unsigned int | ||
158 | toshiba_rbtx4938_irq_ioc_startup(unsigned int irq) | ||
159 | { | ||
160 | toshiba_rbtx4938_irq_ioc_enable(irq); | ||
161 | |||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | static void | ||
166 | toshiba_rbtx4938_irq_ioc_shutdown(unsigned int irq) | ||
167 | { | ||
168 | toshiba_rbtx4938_irq_ioc_disable(irq); | ||
169 | } | ||
170 | |||
171 | static void | ||
172 | toshiba_rbtx4938_irq_ioc_enable(unsigned int irq) | ||
173 | { | ||
174 | unsigned long flags; | ||
175 | volatile unsigned char v; | ||
176 | |||
177 | spin_lock_irqsave(&toshiba_rbtx4938_ioc_lock, flags); | ||
178 | |||
179 | v = TX4938_RD08(TOSHIBA_RBTX4938_IOC_INTR_ENAB); | ||
180 | v |= (1 << (irq - TOSHIBA_RBTX4938_IRQ_IOC_BEG)); | ||
181 | TX4938_WR08(TOSHIBA_RBTX4938_IOC_INTR_ENAB, v); | ||
182 | mmiowb(); | ||
183 | TX4938_RD08(TOSHIBA_RBTX4938_IOC_INTR_ENAB); | ||
184 | |||
185 | spin_unlock_irqrestore(&toshiba_rbtx4938_ioc_lock, flags); | ||
186 | } | ||
187 | |||
188 | static void | ||
189 | toshiba_rbtx4938_irq_ioc_disable(unsigned int irq) | ||
190 | { | ||
191 | unsigned long flags; | ||
192 | volatile unsigned char v; | ||
193 | |||
194 | spin_lock_irqsave(&toshiba_rbtx4938_ioc_lock, flags); | ||
195 | |||
196 | v = TX4938_RD08(TOSHIBA_RBTX4938_IOC_INTR_ENAB); | ||
197 | v &= ~(1 << (irq - TOSHIBA_RBTX4938_IRQ_IOC_BEG)); | ||
198 | TX4938_WR08(TOSHIBA_RBTX4938_IOC_INTR_ENAB, v); | ||
199 | mmiowb(); | ||
200 | TX4938_RD08(TOSHIBA_RBTX4938_IOC_INTR_ENAB); | ||
201 | |||
202 | spin_unlock_irqrestore(&toshiba_rbtx4938_ioc_lock, flags); | ||
203 | } | ||
204 | |||
205 | static void | ||
206 | toshiba_rbtx4938_irq_ioc_mask_and_ack(unsigned int irq) | ||
207 | { | ||
208 | toshiba_rbtx4938_irq_ioc_disable(irq); | ||
209 | } | ||
210 | |||
211 | static void | ||
212 | toshiba_rbtx4938_irq_ioc_end(unsigned int irq) | ||
213 | { | ||
214 | if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) { | ||
215 | toshiba_rbtx4938_irq_ioc_enable(irq); | ||
216 | } | ||
217 | } | ||
218 | |||
219 | extern void __init txx9_spi_irqinit(int irc_irq); | ||
220 | |||
221 | void __init arch_init_irq(void) | ||
222 | { | ||
223 | extern void tx4938_irq_init(void); | ||
224 | |||
225 | /* Now, interrupt control disabled, */ | ||
226 | /* all IRC interrupts are masked, */ | ||
227 | /* all IRC interrupt mode are Low Active. */ | ||
228 | |||
229 | /* mask all IOC interrupts */ | ||
230 | *rbtx4938_imask_ptr = 0; | ||
231 | |||
232 | /* clear SoftInt interrupts */ | ||
233 | *rbtx4938_softint_ptr = 0; | ||
234 | tx4938_irq_init(); | ||
235 | toshiba_rbtx4938_irq_ioc_init(); | ||
236 | /* Onboard 10M Ether: High Active */ | ||
237 | TX4938_WR(TX4938_MKA(TX4938_IRC_IRDM0), 0x00000040); | ||
238 | |||
239 | if (tx4938_ccfgptr->pcfg & TX4938_PCFG_SPI_SEL) { | ||
240 | txx9_spi_irqinit(RBTX4938_IRQ_IRC_SPI); | ||
241 | } | ||
242 | |||
243 | wbflush(); | ||
244 | } | ||
diff --git a/arch/mips/tx4938/toshiba_rbtx4938/prom.c b/arch/mips/tx4938/toshiba_rbtx4938/prom.c new file mode 100644 index 000000000000..7df8b32ba265 --- /dev/null +++ b/arch/mips/tx4938/toshiba_rbtx4938/prom.c | |||
@@ -0,0 +1,78 @@ | |||
1 | /* | ||
2 | * linux/arch/mips/tx4938/toshiba_rbtx4938/prom.c | ||
3 | * | ||
4 | * rbtx4938 specific prom routines | ||
5 | * Copyright (C) 2000-2001 Toshiba Corporation | ||
6 | * | ||
7 | * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the | ||
8 | * terms of the GNU General Public License version 2. This program is | ||
9 | * licensed "as is" without any warranty of any kind, whether express | ||
10 | * or implied. | ||
11 | * | ||
12 | * Support for TX4938 in 2.6 - Manish Lachwani (mlachwani@mvista.com) | ||
13 | */ | ||
14 | |||
15 | #include <linux/config.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/mm.h> | ||
18 | #include <linux/sched.h> | ||
19 | #include <linux/bootmem.h> | ||
20 | |||
21 | #include <asm/addrspace.h> | ||
22 | #include <asm/bootinfo.h> | ||
23 | #include <asm/tx4938/tx4938.h> | ||
24 | |||
25 | void __init prom_init_cmdline(void) | ||
26 | { | ||
27 | int argc = (int) fw_arg0; | ||
28 | char **argv = (char **) fw_arg1; | ||
29 | int i; | ||
30 | |||
31 | /* ignore all built-in args if any f/w args given */ | ||
32 | if (argc > 1) { | ||
33 | *arcs_cmdline = '\0'; | ||
34 | } | ||
35 | |||
36 | for (i = 1; i < argc; i++) { | ||
37 | if (i != 1) { | ||
38 | strcat(arcs_cmdline, " "); | ||
39 | } | ||
40 | strcat(arcs_cmdline, argv[i]); | ||
41 | } | ||
42 | } | ||
43 | |||
44 | void __init prom_init(void) | ||
45 | { | ||
46 | extern int tx4938_get_mem_size(void); | ||
47 | int msize; | ||
48 | #ifndef CONFIG_TX4938_NAND_BOOT | ||
49 | prom_init_cmdline(); | ||
50 | #endif | ||
51 | mips_machgroup = MACH_GROUP_TOSHIBA; | ||
52 | mips_machtype = MACH_TOSHIBA_RBTX4938; | ||
53 | |||
54 | msize = tx4938_get_mem_size(); | ||
55 | add_memory_region(0, msize << 20, BOOT_MEM_RAM); | ||
56 | |||
57 | return; | ||
58 | } | ||
59 | |||
60 | unsigned long __init prom_free_prom_memory(void) | ||
61 | { | ||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | void __init prom_fixup_mem_map(unsigned long start, unsigned long end) | ||
66 | { | ||
67 | return; | ||
68 | } | ||
69 | |||
70 | const char *get_system_type(void) | ||
71 | { | ||
72 | return "Toshiba RBTX4938"; | ||
73 | } | ||
74 | |||
75 | char * __init prom_getcmdline(void) | ||
76 | { | ||
77 | return &(arcs_cmdline[0]); | ||
78 | } | ||
diff --git a/arch/mips/tx4938/toshiba_rbtx4938/setup.c b/arch/mips/tx4938/toshiba_rbtx4938/setup.c new file mode 100644 index 000000000000..9f1dcc8ca5a3 --- /dev/null +++ b/arch/mips/tx4938/toshiba_rbtx4938/setup.c | |||
@@ -0,0 +1,1035 @@ | |||
1 | /* | ||
2 | * linux/arch/mips/tx4938/toshiba_rbtx4938/setup.c | ||
3 | * | ||
4 | * Setup pointers to hardware-dependent routines. | ||
5 | * Copyright (C) 2000-2001 Toshiba Corporation | ||
6 | * | ||
7 | * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the | ||
8 | * terms of the GNU General Public License version 2. This program is | ||
9 | * licensed "as is" without any warranty of any kind, whether express | ||
10 | * or implied. | ||
11 | * | ||
12 | * Support for TX4938 in 2.6 - Manish Lachwani (mlachwani@mvista.com) | ||
13 | */ | ||
14 | #include <linux/config.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/types.h> | ||
17 | #include <linux/ioport.h> | ||
18 | #include <linux/proc_fs.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/interrupt.h> | ||
21 | #include <linux/console.h> | ||
22 | #include <linux/pci.h> | ||
23 | #include <asm/wbflush.h> | ||
24 | #include <asm/reboot.h> | ||
25 | #include <asm/irq.h> | ||
26 | #include <asm/time.h> | ||
27 | #include <asm/uaccess.h> | ||
28 | #include <asm/io.h> | ||
29 | #include <asm/bootinfo.h> | ||
30 | #include <asm/tx4938/rbtx4938.h> | ||
31 | #ifdef CONFIG_SERIAL_TXX9 | ||
32 | #include <linux/tty.h> | ||
33 | #include <linux/serial.h> | ||
34 | #include <linux/serial_core.h> | ||
35 | #endif | ||
36 | |||
37 | extern void rbtx4938_time_init(void) __init; | ||
38 | extern char * __init prom_getcmdline(void); | ||
39 | static inline void tx4938_report_pcic_status1(struct tx4938_pcic_reg *pcicptr); | ||
40 | |||
41 | /* These functions are used for rebooting or halting the machine*/ | ||
42 | extern void rbtx4938_machine_restart(char *command); | ||
43 | extern void rbtx4938_machine_halt(void); | ||
44 | extern void rbtx4938_machine_power_off(void); | ||
45 | |||
46 | /* clocks */ | ||
47 | unsigned int txx9_master_clock; | ||
48 | unsigned int txx9_cpu_clock; | ||
49 | unsigned int txx9_gbus_clock; | ||
50 | |||
51 | unsigned long rbtx4938_ce_base[8]; | ||
52 | unsigned long rbtx4938_ce_size[8]; | ||
53 | int txboard_pci66_mode; | ||
54 | static int tx4938_pcic_trdyto; /* default: disabled */ | ||
55 | static int tx4938_pcic_retryto; /* default: disabled */ | ||
56 | static int tx4938_ccfg_toeon = 1; | ||
57 | |||
58 | struct tx4938_pcic_reg *pcicptrs[4] = { | ||
59 | tx4938_pcicptr /* default setting for TX4938 */ | ||
60 | }; | ||
61 | |||
62 | static struct { | ||
63 | unsigned long base; | ||
64 | unsigned long size; | ||
65 | } phys_regions[16] __initdata; | ||
66 | static int num_phys_regions __initdata; | ||
67 | |||
68 | #define PHYS_REGION_MINSIZE 0x10000 | ||
69 | |||
70 | void rbtx4938_machine_halt(void) | ||
71 | { | ||
72 | printk(KERN_NOTICE "System Halted\n"); | ||
73 | local_irq_disable(); | ||
74 | |||
75 | while (1) | ||
76 | __asm__(".set\tmips3\n\t" | ||
77 | "wait\n\t" | ||
78 | ".set\tmips0"); | ||
79 | } | ||
80 | |||
81 | void rbtx4938_machine_power_off(void) | ||
82 | { | ||
83 | rbtx4938_machine_halt(); | ||
84 | /* no return */ | ||
85 | } | ||
86 | |||
87 | void rbtx4938_machine_restart(char *command) | ||
88 | { | ||
89 | local_irq_disable(); | ||
90 | |||
91 | printk("Rebooting..."); | ||
92 | *rbtx4938_softresetlock_ptr = 1; | ||
93 | *rbtx4938_sfvol_ptr = 1; | ||
94 | *rbtx4938_softreset_ptr = 1; | ||
95 | wbflush(); | ||
96 | |||
97 | while(1); | ||
98 | } | ||
99 | |||
100 | void __init | ||
101 | txboard_add_phys_region(unsigned long base, unsigned long size) | ||
102 | { | ||
103 | if (num_phys_regions >= ARRAY_SIZE(phys_regions)) { | ||
104 | printk("phys_region overflow\n"); | ||
105 | return; | ||
106 | } | ||
107 | phys_regions[num_phys_regions].base = base; | ||
108 | phys_regions[num_phys_regions].size = size; | ||
109 | num_phys_regions++; | ||
110 | } | ||
111 | unsigned long __init | ||
112 | txboard_find_free_phys_region(unsigned long begin, unsigned long end, | ||
113 | unsigned long size) | ||
114 | { | ||
115 | unsigned long base; | ||
116 | int i; | ||
117 | |||
118 | for (base = begin / size * size; base < end; base += size) { | ||
119 | for (i = 0; i < num_phys_regions; i++) { | ||
120 | if (phys_regions[i].size && | ||
121 | base <= phys_regions[i].base + (phys_regions[i].size - 1) && | ||
122 | base + (size - 1) >= phys_regions[i].base) | ||
123 | break; | ||
124 | } | ||
125 | if (i == num_phys_regions) | ||
126 | return base; | ||
127 | } | ||
128 | return 0; | ||
129 | } | ||
130 | unsigned long __init | ||
131 | txboard_find_free_phys_region_shrink(unsigned long begin, unsigned long end, | ||
132 | unsigned long *size) | ||
133 | { | ||
134 | unsigned long sz, base; | ||
135 | for (sz = *size; sz >= PHYS_REGION_MINSIZE; sz /= 2) { | ||
136 | base = txboard_find_free_phys_region(begin, end, sz); | ||
137 | if (base) { | ||
138 | *size = sz; | ||
139 | return base; | ||
140 | } | ||
141 | } | ||
142 | return 0; | ||
143 | } | ||
144 | unsigned long __init | ||
145 | txboard_request_phys_region_range(unsigned long begin, unsigned long end, | ||
146 | unsigned long size) | ||
147 | { | ||
148 | unsigned long base; | ||
149 | base = txboard_find_free_phys_region(begin, end, size); | ||
150 | if (base) | ||
151 | txboard_add_phys_region(base, size); | ||
152 | return base; | ||
153 | } | ||
154 | unsigned long __init | ||
155 | txboard_request_phys_region(unsigned long size) | ||
156 | { | ||
157 | unsigned long base; | ||
158 | unsigned long begin = 0, end = 0x20000000; /* search low 512MB */ | ||
159 | base = txboard_find_free_phys_region(begin, end, size); | ||
160 | if (base) | ||
161 | txboard_add_phys_region(base, size); | ||
162 | return base; | ||
163 | } | ||
164 | unsigned long __init | ||
165 | txboard_request_phys_region_shrink(unsigned long *size) | ||
166 | { | ||
167 | unsigned long base; | ||
168 | unsigned long begin = 0, end = 0x20000000; /* search low 512MB */ | ||
169 | base = txboard_find_free_phys_region_shrink(begin, end, size); | ||
170 | if (base) | ||
171 | txboard_add_phys_region(base, *size); | ||
172 | return base; | ||
173 | } | ||
174 | |||
175 | #ifdef CONFIG_PCI | ||
176 | void __init | ||
177 | tx4938_pcic_setup(struct tx4938_pcic_reg *pcicptr, | ||
178 | struct pci_controller *channel, | ||
179 | unsigned long pci_io_base, | ||
180 | int extarb) | ||
181 | { | ||
182 | int i; | ||
183 | |||
184 | /* Disable All Initiator Space */ | ||
185 | pcicptr->pciccfg &= ~(TX4938_PCIC_PCICCFG_G2PMEN(0)| | ||
186 | TX4938_PCIC_PCICCFG_G2PMEN(1)| | ||
187 | TX4938_PCIC_PCICCFG_G2PMEN(2)| | ||
188 | TX4938_PCIC_PCICCFG_G2PIOEN); | ||
189 | |||
190 | /* GB->PCI mappings */ | ||
191 | pcicptr->g2piomask = (channel->io_resource->end - channel->io_resource->start) >> 4; | ||
192 | pcicptr->g2piogbase = pci_io_base | | ||
193 | #ifdef __BIG_ENDIAN | ||
194 | TX4938_PCIC_G2PIOGBASE_ECHG | ||
195 | #else | ||
196 | TX4938_PCIC_G2PIOGBASE_BSDIS | ||
197 | #endif | ||
198 | ; | ||
199 | pcicptr->g2piopbase = 0; | ||
200 | for (i = 0; i < 3; i++) { | ||
201 | pcicptr->g2pmmask[i] = 0; | ||
202 | pcicptr->g2pmgbase[i] = 0; | ||
203 | pcicptr->g2pmpbase[i] = 0; | ||
204 | } | ||
205 | if (channel->mem_resource->end) { | ||
206 | pcicptr->g2pmmask[0] = (channel->mem_resource->end - channel->mem_resource->start) >> 4; | ||
207 | pcicptr->g2pmgbase[0] = channel->mem_resource->start | | ||
208 | #ifdef __BIG_ENDIAN | ||
209 | TX4938_PCIC_G2PMnGBASE_ECHG | ||
210 | #else | ||
211 | TX4938_PCIC_G2PMnGBASE_BSDIS | ||
212 | #endif | ||
213 | ; | ||
214 | pcicptr->g2pmpbase[0] = channel->mem_resource->start; | ||
215 | } | ||
216 | /* PCI->GB mappings (I/O 256B) */ | ||
217 | pcicptr->p2giopbase = 0; /* 256B */ | ||
218 | pcicptr->p2giogbase = 0; | ||
219 | /* PCI->GB mappings (MEM 512MB (64MB on R1.x)) */ | ||
220 | pcicptr->p2gm0plbase = 0; | ||
221 | pcicptr->p2gm0pubase = 0; | ||
222 | pcicptr->p2gmgbase[0] = 0 | | ||
223 | TX4938_PCIC_P2GMnGBASE_TMEMEN | | ||
224 | #ifdef __BIG_ENDIAN | ||
225 | TX4938_PCIC_P2GMnGBASE_TECHG | ||
226 | #else | ||
227 | TX4938_PCIC_P2GMnGBASE_TBSDIS | ||
228 | #endif | ||
229 | ; | ||
230 | /* PCI->GB mappings (MEM 16MB) */ | ||
231 | pcicptr->p2gm1plbase = 0xffffffff; | ||
232 | pcicptr->p2gm1pubase = 0xffffffff; | ||
233 | pcicptr->p2gmgbase[1] = 0; | ||
234 | /* PCI->GB mappings (MEM 1MB) */ | ||
235 | pcicptr->p2gm2pbase = 0xffffffff; /* 1MB */ | ||
236 | pcicptr->p2gmgbase[2] = 0; | ||
237 | |||
238 | pcicptr->pciccfg &= TX4938_PCIC_PCICCFG_GBWC_MASK; | ||
239 | /* Enable Initiator Memory Space */ | ||
240 | if (channel->mem_resource->end) | ||
241 | pcicptr->pciccfg |= TX4938_PCIC_PCICCFG_G2PMEN(0); | ||
242 | /* Enable Initiator I/O Space */ | ||
243 | if (channel->io_resource->end) | ||
244 | pcicptr->pciccfg |= TX4938_PCIC_PCICCFG_G2PIOEN; | ||
245 | /* Enable Initiator Config */ | ||
246 | pcicptr->pciccfg |= | ||
247 | TX4938_PCIC_PCICCFG_ICAEN | | ||
248 | TX4938_PCIC_PCICCFG_TCAR; | ||
249 | |||
250 | /* Do not use MEMMUL, MEMINF: YMFPCI card causes M_ABORT. */ | ||
251 | pcicptr->pcicfg1 = 0; | ||
252 | |||
253 | pcicptr->g2ptocnt &= ~0xffff; | ||
254 | |||
255 | if (tx4938_pcic_trdyto >= 0) { | ||
256 | pcicptr->g2ptocnt &= ~0xff; | ||
257 | pcicptr->g2ptocnt |= (tx4938_pcic_trdyto & 0xff); | ||
258 | } | ||
259 | |||
260 | if (tx4938_pcic_retryto >= 0) { | ||
261 | pcicptr->g2ptocnt &= ~0xff00; | ||
262 | pcicptr->g2ptocnt |= ((tx4938_pcic_retryto<<8) & 0xff00); | ||
263 | } | ||
264 | |||
265 | /* Clear All Local Bus Status */ | ||
266 | pcicptr->pcicstatus = TX4938_PCIC_PCICSTATUS_ALL; | ||
267 | /* Enable All Local Bus Interrupts */ | ||
268 | pcicptr->pcicmask = TX4938_PCIC_PCICSTATUS_ALL; | ||
269 | /* Clear All Initiator Status */ | ||
270 | pcicptr->g2pstatus = TX4938_PCIC_G2PSTATUS_ALL; | ||
271 | /* Enable All Initiator Interrupts */ | ||
272 | pcicptr->g2pmask = TX4938_PCIC_G2PSTATUS_ALL; | ||
273 | /* Clear All PCI Status Error */ | ||
274 | pcicptr->pcistatus = | ||
275 | (pcicptr->pcistatus & 0x0000ffff) | | ||
276 | (TX4938_PCIC_PCISTATUS_ALL << 16); | ||
277 | /* Enable All PCI Status Error Interrupts */ | ||
278 | pcicptr->pcimask = TX4938_PCIC_PCISTATUS_ALL; | ||
279 | |||
280 | if (!extarb) { | ||
281 | /* Reset Bus Arbiter */ | ||
282 | pcicptr->pbacfg = TX4938_PCIC_PBACFG_RPBA; | ||
283 | pcicptr->pbabm = 0; | ||
284 | /* Enable Bus Arbiter */ | ||
285 | pcicptr->pbacfg = TX4938_PCIC_PBACFG_PBAEN; | ||
286 | } | ||
287 | |||
288 | /* PCIC Int => IRC IRQ16 */ | ||
289 | pcicptr->pcicfg2 = | ||
290 | (pcicptr->pcicfg2 & 0xffffff00) | TX4938_IR_PCIC; | ||
291 | |||
292 | pcicptr->pcistatus = PCI_COMMAND_MASTER | | ||
293 | PCI_COMMAND_MEMORY | | ||
294 | PCI_COMMAND_PARITY | PCI_COMMAND_SERR; | ||
295 | } | ||
296 | |||
297 | int __init | ||
298 | tx4938_report_pciclk(void) | ||
299 | { | ||
300 | unsigned long pcode = TX4938_REV_PCODE(); | ||
301 | int pciclk = 0; | ||
302 | printk("TX%lx PCIC --%s PCICLK:", | ||
303 | pcode, | ||
304 | (tx4938_ccfgptr->ccfg & TX4938_CCFG_PCI66) ? " PCI66" : ""); | ||
305 | if (tx4938_ccfgptr->pcfg & TX4938_PCFG_PCICLKEN_ALL) { | ||
306 | |||
307 | switch ((unsigned long)tx4938_ccfgptr->ccfg & TX4938_CCFG_PCIDIVMODE_MASK) { | ||
308 | case TX4938_CCFG_PCIDIVMODE_4: | ||
309 | pciclk = txx9_cpu_clock / 4; break; | ||
310 | case TX4938_CCFG_PCIDIVMODE_4_5: | ||
311 | pciclk = txx9_cpu_clock * 2 / 9; break; | ||
312 | case TX4938_CCFG_PCIDIVMODE_5: | ||
313 | pciclk = txx9_cpu_clock / 5; break; | ||
314 | case TX4938_CCFG_PCIDIVMODE_5_5: | ||
315 | pciclk = txx9_cpu_clock * 2 / 11; break; | ||
316 | case TX4938_CCFG_PCIDIVMODE_8: | ||
317 | pciclk = txx9_cpu_clock / 8; break; | ||
318 | case TX4938_CCFG_PCIDIVMODE_9: | ||
319 | pciclk = txx9_cpu_clock / 9; break; | ||
320 | case TX4938_CCFG_PCIDIVMODE_10: | ||
321 | pciclk = txx9_cpu_clock / 10; break; | ||
322 | case TX4938_CCFG_PCIDIVMODE_11: | ||
323 | pciclk = txx9_cpu_clock / 11; break; | ||
324 | } | ||
325 | printk("Internal(%dMHz)", pciclk / 1000000); | ||
326 | } else { | ||
327 | printk("External"); | ||
328 | pciclk = -1; | ||
329 | } | ||
330 | printk("\n"); | ||
331 | return pciclk; | ||
332 | } | ||
333 | |||
334 | void __init set_tx4938_pcicptr(int ch, struct tx4938_pcic_reg *pcicptr) | ||
335 | { | ||
336 | pcicptrs[ch] = pcicptr; | ||
337 | } | ||
338 | |||
339 | struct tx4938_pcic_reg *get_tx4938_pcicptr(int ch) | ||
340 | { | ||
341 | return pcicptrs[ch]; | ||
342 | } | ||
343 | |||
344 | static struct pci_dev *fake_pci_dev(struct pci_controller *hose, | ||
345 | int top_bus, int busnr, int devfn) | ||
346 | { | ||
347 | static struct pci_dev dev; | ||
348 | static struct pci_bus bus; | ||
349 | |||
350 | dev.sysdata = (void *)hose; | ||
351 | dev.devfn = devfn; | ||
352 | bus.number = busnr; | ||
353 | bus.ops = hose->pci_ops; | ||
354 | bus.parent = NULL; | ||
355 | dev.bus = &bus; | ||
356 | |||
357 | return &dev; | ||
358 | } | ||
359 | |||
360 | #define EARLY_PCI_OP(rw, size, type) \ | ||
361 | static int early_##rw##_config_##size(struct pci_controller *hose, \ | ||
362 | int top_bus, int bus, int devfn, int offset, type value) \ | ||
363 | { \ | ||
364 | return pci_##rw##_config_##size( \ | ||
365 | fake_pci_dev(hose, top_bus, bus, devfn), \ | ||
366 | offset, value); \ | ||
367 | } | ||
368 | |||
369 | EARLY_PCI_OP(read, word, u16 *) | ||
370 | |||
371 | int txboard_pci66_check(struct pci_controller *hose, int top_bus, int current_bus) | ||
372 | { | ||
373 | u32 pci_devfn; | ||
374 | unsigned short vid; | ||
375 | int devfn_start = 0; | ||
376 | int devfn_stop = 0xff; | ||
377 | int cap66 = -1; | ||
378 | u16 stat; | ||
379 | |||
380 | printk("PCI: Checking 66MHz capabilities...\n"); | ||
381 | |||
382 | for (pci_devfn=devfn_start; pci_devfn<devfn_stop; pci_devfn++) { | ||
383 | early_read_config_word(hose, top_bus, current_bus, pci_devfn, | ||
384 | PCI_VENDOR_ID, &vid); | ||
385 | |||
386 | if (vid == 0xffff) continue; | ||
387 | |||
388 | /* check 66MHz capability */ | ||
389 | if (cap66 < 0) | ||
390 | cap66 = 1; | ||
391 | if (cap66) { | ||
392 | early_read_config_word(hose, top_bus, current_bus, pci_devfn, | ||
393 | PCI_STATUS, &stat); | ||
394 | if (!(stat & PCI_STATUS_66MHZ)) { | ||
395 | printk(KERN_DEBUG "PCI: %02x:%02x not 66MHz capable.\n", | ||
396 | current_bus, pci_devfn); | ||
397 | cap66 = 0; | ||
398 | break; | ||
399 | } | ||
400 | } | ||
401 | } | ||
402 | return cap66 > 0; | ||
403 | } | ||
404 | |||
405 | int __init | ||
406 | tx4938_pciclk66_setup(void) | ||
407 | { | ||
408 | int pciclk; | ||
409 | |||
410 | /* Assert M66EN */ | ||
411 | tx4938_ccfgptr->ccfg |= TX4938_CCFG_PCI66; | ||
412 | /* Double PCICLK (if possible) */ | ||
413 | if (tx4938_ccfgptr->pcfg & TX4938_PCFG_PCICLKEN_ALL) { | ||
414 | unsigned int pcidivmode = | ||
415 | tx4938_ccfgptr->ccfg & TX4938_CCFG_PCIDIVMODE_MASK; | ||
416 | switch (pcidivmode) { | ||
417 | case TX4938_CCFG_PCIDIVMODE_8: | ||
418 | case TX4938_CCFG_PCIDIVMODE_4: | ||
419 | pcidivmode = TX4938_CCFG_PCIDIVMODE_4; | ||
420 | pciclk = txx9_cpu_clock / 4; | ||
421 | break; | ||
422 | case TX4938_CCFG_PCIDIVMODE_9: | ||
423 | case TX4938_CCFG_PCIDIVMODE_4_5: | ||
424 | pcidivmode = TX4938_CCFG_PCIDIVMODE_4_5; | ||
425 | pciclk = txx9_cpu_clock * 2 / 9; | ||
426 | break; | ||
427 | case TX4938_CCFG_PCIDIVMODE_10: | ||
428 | case TX4938_CCFG_PCIDIVMODE_5: | ||
429 | pcidivmode = TX4938_CCFG_PCIDIVMODE_5; | ||
430 | pciclk = txx9_cpu_clock / 5; | ||
431 | break; | ||
432 | case TX4938_CCFG_PCIDIVMODE_11: | ||
433 | case TX4938_CCFG_PCIDIVMODE_5_5: | ||
434 | default: | ||
435 | pcidivmode = TX4938_CCFG_PCIDIVMODE_5_5; | ||
436 | pciclk = txx9_cpu_clock * 2 / 11; | ||
437 | break; | ||
438 | } | ||
439 | tx4938_ccfgptr->ccfg = | ||
440 | (tx4938_ccfgptr->ccfg & ~TX4938_CCFG_PCIDIVMODE_MASK) | ||
441 | | pcidivmode; | ||
442 | printk(KERN_DEBUG "PCICLK: ccfg:%08lx\n", | ||
443 | (unsigned long)tx4938_ccfgptr->ccfg); | ||
444 | } else { | ||
445 | pciclk = -1; | ||
446 | } | ||
447 | return pciclk; | ||
448 | } | ||
449 | |||
450 | extern struct pci_controller tx4938_pci_controller[]; | ||
451 | static int __init tx4938_pcibios_init(void) | ||
452 | { | ||
453 | unsigned long mem_base[2]; | ||
454 | unsigned long mem_size[2] = {TX4938_PCIMEM_SIZE_0,TX4938_PCIMEM_SIZE_1}; /* MAX 128M,64K */ | ||
455 | unsigned long io_base[2]; | ||
456 | unsigned long io_size[2] = {TX4938_PCIIO_SIZE_0,TX4938_PCIIO_SIZE_1}; /* MAX 16M,64K */ | ||
457 | /* TX4938 PCIC1: 64K MEM/IO is enough for ETH0,ETH1 */ | ||
458 | int extarb = !(tx4938_ccfgptr->ccfg & TX4938_CCFG_PCIXARB); | ||
459 | |||
460 | PCIBIOS_MIN_IO = 0x00001000UL; | ||
461 | PCIBIOS_MIN_MEM = 0x01000000UL; | ||
462 | |||
463 | mem_base[0] = txboard_request_phys_region_shrink(&mem_size[0]); | ||
464 | io_base[0] = txboard_request_phys_region_shrink(&io_size[0]); | ||
465 | |||
466 | printk("TX4938 PCIC -- DID:%04x VID:%04x RID:%02x Arbiter:%s\n", | ||
467 | (unsigned short)(tx4938_pcicptr->pciid >> 16), | ||
468 | (unsigned short)(tx4938_pcicptr->pciid & 0xffff), | ||
469 | (unsigned short)(tx4938_pcicptr->pciccrev & 0xff), | ||
470 | extarb ? "External" : "Internal"); | ||
471 | |||
472 | /* setup PCI area */ | ||
473 | tx4938_pci_controller[0].io_resource->start = io_base[0]; | ||
474 | tx4938_pci_controller[0].io_resource->end = (io_base[0] + io_size[0]) - 1; | ||
475 | tx4938_pci_controller[0].mem_resource->start = mem_base[0]; | ||
476 | tx4938_pci_controller[0].mem_resource->end = mem_base[0] + mem_size[0] - 1; | ||
477 | |||
478 | set_tx4938_pcicptr(0, tx4938_pcicptr); | ||
479 | |||
480 | register_pci_controller(&tx4938_pci_controller[0]); | ||
481 | |||
482 | if (tx4938_ccfgptr->ccfg & TX4938_CCFG_PCI66) { | ||
483 | printk("TX4938_CCFG_PCI66 already configured\n"); | ||
484 | txboard_pci66_mode = -1; /* already configured */ | ||
485 | } | ||
486 | |||
487 | /* Reset PCI Bus */ | ||
488 | *rbtx4938_pcireset_ptr = 0; | ||
489 | /* Reset PCIC */ | ||
490 | tx4938_ccfgptr->clkctr |= TX4938_CLKCTR_PCIRST; | ||
491 | if (txboard_pci66_mode > 0) | ||
492 | tx4938_pciclk66_setup(); | ||
493 | mdelay(10); | ||
494 | /* clear PCIC reset */ | ||
495 | tx4938_ccfgptr->clkctr &= ~TX4938_CLKCTR_PCIRST; | ||
496 | *rbtx4938_pcireset_ptr = 1; | ||
497 | wbflush(); | ||
498 | tx4938_report_pcic_status1(tx4938_pcicptr); | ||
499 | |||
500 | tx4938_report_pciclk(); | ||
501 | tx4938_pcic_setup(tx4938_pcicptr, &tx4938_pci_controller[0], io_base[0], extarb); | ||
502 | if (txboard_pci66_mode == 0 && | ||
503 | txboard_pci66_check(&tx4938_pci_controller[0], 0, 0)) { | ||
504 | /* Reset PCI Bus */ | ||
505 | *rbtx4938_pcireset_ptr = 0; | ||
506 | /* Reset PCIC */ | ||
507 | tx4938_ccfgptr->clkctr |= TX4938_CLKCTR_PCIRST; | ||
508 | tx4938_pciclk66_setup(); | ||
509 | mdelay(10); | ||
510 | /* clear PCIC reset */ | ||
511 | tx4938_ccfgptr->clkctr &= ~TX4938_CLKCTR_PCIRST; | ||
512 | *rbtx4938_pcireset_ptr = 1; | ||
513 | wbflush(); | ||
514 | /* Reinitialize PCIC */ | ||
515 | tx4938_report_pciclk(); | ||
516 | tx4938_pcic_setup(tx4938_pcicptr, &tx4938_pci_controller[0], io_base[0], extarb); | ||
517 | } | ||
518 | |||
519 | mem_base[1] = txboard_request_phys_region_shrink(&mem_size[1]); | ||
520 | io_base[1] = txboard_request_phys_region_shrink(&io_size[1]); | ||
521 | /* Reset PCIC1 */ | ||
522 | tx4938_ccfgptr->clkctr |= TX4938_CLKCTR_PCIC1RST; | ||
523 | /* PCI1DMD==0 => PCI1CLK==GBUSCLK/2 => PCI66 */ | ||
524 | if (!(tx4938_ccfgptr->ccfg & TX4938_CCFG_PCI1DMD)) | ||
525 | tx4938_ccfgptr->ccfg |= TX4938_CCFG_PCI1_66; | ||
526 | else | ||
527 | tx4938_ccfgptr->ccfg &= ~TX4938_CCFG_PCI1_66; | ||
528 | mdelay(10); | ||
529 | /* clear PCIC1 reset */ | ||
530 | tx4938_ccfgptr->clkctr &= ~TX4938_CLKCTR_PCIC1RST; | ||
531 | tx4938_report_pcic_status1(tx4938_pcic1ptr); | ||
532 | |||
533 | printk("TX4938 PCIC1 -- DID:%04x VID:%04x RID:%02x", | ||
534 | (unsigned short)(tx4938_pcic1ptr->pciid >> 16), | ||
535 | (unsigned short)(tx4938_pcic1ptr->pciid & 0xffff), | ||
536 | (unsigned short)(tx4938_pcic1ptr->pciccrev & 0xff)); | ||
537 | printk("%s PCICLK:%dMHz\n", | ||
538 | (tx4938_ccfgptr->ccfg & TX4938_CCFG_PCI1_66) ? " PCI66" : "", | ||
539 | txx9_gbus_clock / | ||
540 | ((tx4938_ccfgptr->ccfg & TX4938_CCFG_PCI1DMD) ? 4 : 2) / | ||
541 | 1000000); | ||
542 | |||
543 | /* assumption: CPHYSADDR(mips_io_port_base) == io_base[0] */ | ||
544 | tx4938_pci_controller[1].io_resource->start = | ||
545 | io_base[1] - io_base[0]; | ||
546 | tx4938_pci_controller[1].io_resource->end = | ||
547 | io_base[1] - io_base[0] + io_size[1] - 1; | ||
548 | tx4938_pci_controller[1].mem_resource->start = mem_base[1]; | ||
549 | tx4938_pci_controller[1].mem_resource->end = | ||
550 | mem_base[1] + mem_size[1] - 1; | ||
551 | set_tx4938_pcicptr(1, tx4938_pcic1ptr); | ||
552 | |||
553 | register_pci_controller(&tx4938_pci_controller[1]); | ||
554 | |||
555 | tx4938_pcic_setup(tx4938_pcic1ptr, &tx4938_pci_controller[1], io_base[1], extarb); | ||
556 | |||
557 | /* map ioport 0 to PCI I/O space address 0 */ | ||
558 | set_io_port_base(KSEG1 + io_base[0]); | ||
559 | |||
560 | return 0; | ||
561 | } | ||
562 | |||
563 | arch_initcall(tx4938_pcibios_init); | ||
564 | |||
565 | #endif /* CONFIG_PCI */ | ||
566 | |||
567 | /* SPI support */ | ||
568 | |||
569 | /* chip select for SPI devices */ | ||
570 | #define SEEPROM1_CS 7 /* PIO7 */ | ||
571 | #define SEEPROM2_CS 0 /* IOC */ | ||
572 | #define SEEPROM3_CS 1 /* IOC */ | ||
573 | #define SRTC_CS 2 /* IOC */ | ||
574 | |||
575 | static int rbtx4938_spi_cs_func(int chipid, int on) | ||
576 | { | ||
577 | unsigned char bit; | ||
578 | switch (chipid) { | ||
579 | case RBTX4938_SEEPROM1_CHIPID: | ||
580 | if (on) | ||
581 | tx4938_pioptr->dout &= ~(1 << SEEPROM1_CS); | ||
582 | else | ||
583 | tx4938_pioptr->dout |= (1 << SEEPROM1_CS); | ||
584 | return 0; | ||
585 | break; | ||
586 | case RBTX4938_SEEPROM2_CHIPID: | ||
587 | bit = (1 << SEEPROM2_CS); | ||
588 | break; | ||
589 | case RBTX4938_SEEPROM3_CHIPID: | ||
590 | bit = (1 << SEEPROM3_CS); | ||
591 | break; | ||
592 | case RBTX4938_SRTC_CHIPID: | ||
593 | bit = (1 << SRTC_CS); | ||
594 | break; | ||
595 | default: | ||
596 | return -ENODEV; | ||
597 | } | ||
598 | /* bit1,2,4 are low active, bit3 is high active */ | ||
599 | *rbtx4938_spics_ptr = | ||
600 | (*rbtx4938_spics_ptr & ~bit) | | ||
601 | ((on ? (bit ^ 0x0b) : ~(bit ^ 0x0b)) & bit); | ||
602 | return 0; | ||
603 | } | ||
604 | |||
605 | #ifdef CONFIG_PCI | ||
606 | extern int spi_eeprom_read(int chipid, int address, unsigned char *buf, int len); | ||
607 | |||
608 | int rbtx4938_get_tx4938_ethaddr(struct pci_dev *dev, unsigned char *addr) | ||
609 | { | ||
610 | struct pci_controller *channel = (struct pci_controller *)dev->bus->sysdata; | ||
611 | static unsigned char dat[17]; | ||
612 | static int read_dat = 0; | ||
613 | int ch = 0; | ||
614 | |||
615 | if (channel != &tx4938_pci_controller[1]) | ||
616 | return -ENODEV; | ||
617 | /* TX4938 PCIC1 */ | ||
618 | switch (PCI_SLOT(dev->devfn)) { | ||
619 | case TX4938_PCIC_IDSEL_AD_TO_SLOT(31): | ||
620 | ch = 0; | ||
621 | break; | ||
622 | case TX4938_PCIC_IDSEL_AD_TO_SLOT(30): | ||
623 | ch = 1; | ||
624 | break; | ||
625 | default: | ||
626 | return -ENODEV; | ||
627 | } | ||
628 | if (!read_dat) { | ||
629 | unsigned char sum; | ||
630 | int i; | ||
631 | read_dat = 1; | ||
632 | /* 0-3: "MAC\0", 4-9:eth0, 10-15:eth1, 16:sum */ | ||
633 | if (spi_eeprom_read(RBTX4938_SEEPROM1_CHIPID, | ||
634 | 0, dat, sizeof(dat))) { | ||
635 | printk(KERN_ERR "seeprom: read error.\n"); | ||
636 | } else { | ||
637 | if (strcmp(dat, "MAC") != 0) | ||
638 | printk(KERN_WARNING "seeprom: bad signature.\n"); | ||
639 | for (i = 0, sum = 0; i < sizeof(dat); i++) | ||
640 | sum += dat[i]; | ||
641 | if (sum) | ||
642 | printk(KERN_WARNING "seeprom: bad checksum.\n"); | ||
643 | } | ||
644 | } | ||
645 | memcpy(addr, &dat[4 + 6 * ch], 6); | ||
646 | return 0; | ||
647 | } | ||
648 | #endif /* CONFIG_PCI */ | ||
649 | |||
650 | extern void __init txx9_spi_init(unsigned long base, int (*cs_func)(int chipid, int on)); | ||
651 | static void __init rbtx4938_spi_setup(void) | ||
652 | { | ||
653 | /* set SPI_SEL */ | ||
654 | tx4938_ccfgptr->pcfg |= TX4938_PCFG_SPI_SEL; | ||
655 | /* chip selects for SPI devices */ | ||
656 | tx4938_pioptr->dout |= (1 << SEEPROM1_CS); | ||
657 | tx4938_pioptr->dir |= (1 << SEEPROM1_CS); | ||
658 | txx9_spi_init(TX4938_SPI_REG, rbtx4938_spi_cs_func); | ||
659 | } | ||
660 | |||
661 | static struct resource rbtx4938_fpga_resource; | ||
662 | |||
663 | static char pcode_str[8]; | ||
664 | static struct resource tx4938_reg_resource = { | ||
665 | pcode_str, TX4938_REG_BASE, TX4938_REG_BASE+TX4938_REG_SIZE, IORESOURCE_MEM | ||
666 | }; | ||
667 | |||
668 | void __init tx4938_board_setup(void) | ||
669 | { | ||
670 | int i; | ||
671 | unsigned long divmode; | ||
672 | int cpuclk = 0; | ||
673 | unsigned long pcode = TX4938_REV_PCODE(); | ||
674 | |||
675 | ioport_resource.start = 0x1000; | ||
676 | ioport_resource.end = 0xffffffff; | ||
677 | iomem_resource.start = 0x1000; | ||
678 | iomem_resource.end = 0xffffffff; /* expand to 4GB */ | ||
679 | |||
680 | sprintf(pcode_str, "TX%lx", pcode); | ||
681 | /* SDRAMC,EBUSC are configured by PROM */ | ||
682 | for (i = 0; i < 8; i++) { | ||
683 | if (!(tx4938_ebuscptr->cr[i] & 0x8)) | ||
684 | continue; /* disabled */ | ||
685 | rbtx4938_ce_base[i] = (unsigned long)TX4938_EBUSC_BA(i); | ||
686 | txboard_add_phys_region(rbtx4938_ce_base[i], TX4938_EBUSC_SIZE(i)); | ||
687 | } | ||
688 | |||
689 | /* clocks */ | ||
690 | if (txx9_master_clock) { | ||
691 | /* calculate gbus_clock and cpu_clock from master_clock */ | ||
692 | divmode = (unsigned long)tx4938_ccfgptr->ccfg & TX4938_CCFG_DIVMODE_MASK; | ||
693 | switch (divmode) { | ||
694 | case TX4938_CCFG_DIVMODE_8: | ||
695 | case TX4938_CCFG_DIVMODE_10: | ||
696 | case TX4938_CCFG_DIVMODE_12: | ||
697 | case TX4938_CCFG_DIVMODE_16: | ||
698 | case TX4938_CCFG_DIVMODE_18: | ||
699 | txx9_gbus_clock = txx9_master_clock * 4; break; | ||
700 | default: | ||
701 | txx9_gbus_clock = txx9_master_clock; | ||
702 | } | ||
703 | switch (divmode) { | ||
704 | case TX4938_CCFG_DIVMODE_2: | ||
705 | case TX4938_CCFG_DIVMODE_8: | ||
706 | cpuclk = txx9_gbus_clock * 2; break; | ||
707 | case TX4938_CCFG_DIVMODE_2_5: | ||
708 | case TX4938_CCFG_DIVMODE_10: | ||
709 | cpuclk = txx9_gbus_clock * 5 / 2; break; | ||
710 | case TX4938_CCFG_DIVMODE_3: | ||
711 | case TX4938_CCFG_DIVMODE_12: | ||
712 | cpuclk = txx9_gbus_clock * 3; break; | ||
713 | case TX4938_CCFG_DIVMODE_4: | ||
714 | case TX4938_CCFG_DIVMODE_16: | ||
715 | cpuclk = txx9_gbus_clock * 4; break; | ||
716 | case TX4938_CCFG_DIVMODE_4_5: | ||
717 | case TX4938_CCFG_DIVMODE_18: | ||
718 | cpuclk = txx9_gbus_clock * 9 / 2; break; | ||
719 | } | ||
720 | txx9_cpu_clock = cpuclk; | ||
721 | } else { | ||
722 | if (txx9_cpu_clock == 0) { | ||
723 | txx9_cpu_clock = 300000000; /* 300MHz */ | ||
724 | } | ||
725 | /* calculate gbus_clock and master_clock from cpu_clock */ | ||
726 | cpuclk = txx9_cpu_clock; | ||
727 | divmode = (unsigned long)tx4938_ccfgptr->ccfg & TX4938_CCFG_DIVMODE_MASK; | ||
728 | switch (divmode) { | ||
729 | case TX4938_CCFG_DIVMODE_2: | ||
730 | case TX4938_CCFG_DIVMODE_8: | ||
731 | txx9_gbus_clock = cpuclk / 2; break; | ||
732 | case TX4938_CCFG_DIVMODE_2_5: | ||
733 | case TX4938_CCFG_DIVMODE_10: | ||
734 | txx9_gbus_clock = cpuclk * 2 / 5; break; | ||
735 | case TX4938_CCFG_DIVMODE_3: | ||
736 | case TX4938_CCFG_DIVMODE_12: | ||
737 | txx9_gbus_clock = cpuclk / 3; break; | ||
738 | case TX4938_CCFG_DIVMODE_4: | ||
739 | case TX4938_CCFG_DIVMODE_16: | ||
740 | txx9_gbus_clock = cpuclk / 4; break; | ||
741 | case TX4938_CCFG_DIVMODE_4_5: | ||
742 | case TX4938_CCFG_DIVMODE_18: | ||
743 | txx9_gbus_clock = cpuclk * 2 / 9; break; | ||
744 | } | ||
745 | switch (divmode) { | ||
746 | case TX4938_CCFG_DIVMODE_8: | ||
747 | case TX4938_CCFG_DIVMODE_10: | ||
748 | case TX4938_CCFG_DIVMODE_12: | ||
749 | case TX4938_CCFG_DIVMODE_16: | ||
750 | case TX4938_CCFG_DIVMODE_18: | ||
751 | txx9_master_clock = txx9_gbus_clock / 4; break; | ||
752 | default: | ||
753 | txx9_master_clock = txx9_gbus_clock; | ||
754 | } | ||
755 | } | ||
756 | /* change default value to udelay/mdelay take reasonable time */ | ||
757 | loops_per_jiffy = txx9_cpu_clock / HZ / 2; | ||
758 | |||
759 | /* CCFG */ | ||
760 | /* clear WatchDogReset,BusErrorOnWrite flag (W1C) */ | ||
761 | tx4938_ccfgptr->ccfg |= TX4938_CCFG_WDRST | TX4938_CCFG_BEOW; | ||
762 | /* clear PCIC1 reset */ | ||
763 | if (tx4938_ccfgptr->clkctr & TX4938_CLKCTR_PCIC1RST) | ||
764 | tx4938_ccfgptr->clkctr &= ~TX4938_CLKCTR_PCIC1RST; | ||
765 | |||
766 | /* enable Timeout BusError */ | ||
767 | if (tx4938_ccfg_toeon) | ||
768 | tx4938_ccfgptr->ccfg |= TX4938_CCFG_TOE; | ||
769 | |||
770 | /* DMA selection */ | ||
771 | tx4938_ccfgptr->pcfg &= ~TX4938_PCFG_DMASEL_ALL; | ||
772 | |||
773 | /* Use external clock for external arbiter */ | ||
774 | if (!(tx4938_ccfgptr->ccfg & TX4938_CCFG_PCIXARB)) | ||
775 | tx4938_ccfgptr->pcfg &= ~TX4938_PCFG_PCICLKEN_ALL; | ||
776 | |||
777 | printk("%s -- %dMHz(M%dMHz) CRIR:%08lx CCFG:%Lx PCFG:%Lx\n", | ||
778 | pcode_str, | ||
779 | cpuclk / 1000000, txx9_master_clock / 1000000, | ||
780 | (unsigned long)tx4938_ccfgptr->crir, | ||
781 | tx4938_ccfgptr->ccfg, | ||
782 | tx4938_ccfgptr->pcfg); | ||
783 | |||
784 | printk("%s SDRAMC --", pcode_str); | ||
785 | for (i = 0; i < 4; i++) { | ||
786 | unsigned long long cr = tx4938_sdramcptr->cr[i]; | ||
787 | unsigned long ram_base, ram_size; | ||
788 | if (!((unsigned long)cr & 0x00000400)) | ||
789 | continue; /* disabled */ | ||
790 | ram_base = (unsigned long)(cr >> 49) << 21; | ||
791 | ram_size = ((unsigned long)(cr >> 33) + 1) << 21; | ||
792 | if (ram_base >= 0x20000000) | ||
793 | continue; /* high memory (ignore) */ | ||
794 | printk(" CR%d:%016Lx", i, cr); | ||
795 | txboard_add_phys_region(ram_base, ram_size); | ||
796 | } | ||
797 | printk(" TR:%09Lx\n", tx4938_sdramcptr->tr); | ||
798 | |||
799 | /* SRAM */ | ||
800 | if (pcode == 0x4938 && tx4938_sramcptr->cr & 1) { | ||
801 | unsigned int size = 0x800; | ||
802 | unsigned long base = | ||
803 | (tx4938_sramcptr->cr >> (39-11)) & ~(size - 1); | ||
804 | txboard_add_phys_region(base, size); | ||
805 | } | ||
806 | |||
807 | /* IRC */ | ||
808 | /* disable interrupt control */ | ||
809 | tx4938_ircptr->cer = 0; | ||
810 | |||
811 | /* TMR */ | ||
812 | /* disable all timers */ | ||
813 | for (i = 0; i < TX4938_NR_TMR; i++) { | ||
814 | tx4938_tmrptr(i)->tcr = 0x00000020; | ||
815 | tx4938_tmrptr(i)->tisr = 0; | ||
816 | tx4938_tmrptr(i)->cpra = 0xffffffff; | ||
817 | tx4938_tmrptr(i)->itmr = 0; | ||
818 | tx4938_tmrptr(i)->ccdr = 0; | ||
819 | tx4938_tmrptr(i)->pgmr = 0; | ||
820 | } | ||
821 | |||
822 | /* enable DMA */ | ||
823 | TX4938_WR64(0xff1fb150, TX4938_DMA_MCR_MSTEN); | ||
824 | TX4938_WR64(0xff1fb950, TX4938_DMA_MCR_MSTEN); | ||
825 | |||
826 | /* PIO */ | ||
827 | tx4938_pioptr->maskcpu = 0; | ||
828 | tx4938_pioptr->maskext = 0; | ||
829 | |||
830 | /* TX4938 internal registers */ | ||
831 | if (request_resource(&iomem_resource, &tx4938_reg_resource)) | ||
832 | printk("request resource for internal registers failed\n"); | ||
833 | } | ||
834 | |||
835 | #ifdef CONFIG_PCI | ||
836 | static inline void tx4938_report_pcic_status1(struct tx4938_pcic_reg *pcicptr) | ||
837 | { | ||
838 | unsigned short pcistatus = (unsigned short)(pcicptr->pcistatus >> 16); | ||
839 | unsigned long g2pstatus = pcicptr->g2pstatus; | ||
840 | unsigned long pcicstatus = pcicptr->pcicstatus; | ||
841 | static struct { | ||
842 | unsigned long flag; | ||
843 | const char *str; | ||
844 | } pcistat_tbl[] = { | ||
845 | { PCI_STATUS_DETECTED_PARITY, "DetectedParityError" }, | ||
846 | { PCI_STATUS_SIG_SYSTEM_ERROR, "SignaledSystemError" }, | ||
847 | { PCI_STATUS_REC_MASTER_ABORT, "ReceivedMasterAbort" }, | ||
848 | { PCI_STATUS_REC_TARGET_ABORT, "ReceivedTargetAbort" }, | ||
849 | { PCI_STATUS_SIG_TARGET_ABORT, "SignaledTargetAbort" }, | ||
850 | { PCI_STATUS_PARITY, "MasterParityError" }, | ||
851 | }, g2pstat_tbl[] = { | ||
852 | { TX4938_PCIC_G2PSTATUS_TTOE, "TIOE" }, | ||
853 | { TX4938_PCIC_G2PSTATUS_RTOE, "RTOE" }, | ||
854 | }, pcicstat_tbl[] = { | ||
855 | { TX4938_PCIC_PCICSTATUS_PME, "PME" }, | ||
856 | { TX4938_PCIC_PCICSTATUS_TLB, "TLB" }, | ||
857 | { TX4938_PCIC_PCICSTATUS_NIB, "NIB" }, | ||
858 | { TX4938_PCIC_PCICSTATUS_ZIB, "ZIB" }, | ||
859 | { TX4938_PCIC_PCICSTATUS_PERR, "PERR" }, | ||
860 | { TX4938_PCIC_PCICSTATUS_SERR, "SERR" }, | ||
861 | { TX4938_PCIC_PCICSTATUS_GBE, "GBE" }, | ||
862 | { TX4938_PCIC_PCICSTATUS_IWB, "IWB" }, | ||
863 | }; | ||
864 | int i; | ||
865 | |||
866 | printk("pcistat:%04x(", pcistatus); | ||
867 | for (i = 0; i < ARRAY_SIZE(pcistat_tbl); i++) | ||
868 | if (pcistatus & pcistat_tbl[i].flag) | ||
869 | printk("%s ", pcistat_tbl[i].str); | ||
870 | printk("), g2pstatus:%08lx(", g2pstatus); | ||
871 | for (i = 0; i < ARRAY_SIZE(g2pstat_tbl); i++) | ||
872 | if (g2pstatus & g2pstat_tbl[i].flag) | ||
873 | printk("%s ", g2pstat_tbl[i].str); | ||
874 | printk("), pcicstatus:%08lx(", pcicstatus); | ||
875 | for (i = 0; i < ARRAY_SIZE(pcicstat_tbl); i++) | ||
876 | if (pcicstatus & pcicstat_tbl[i].flag) | ||
877 | printk("%s ", pcicstat_tbl[i].str); | ||
878 | printk(")\n"); | ||
879 | } | ||
880 | |||
881 | void tx4938_report_pcic_status(void) | ||
882 | { | ||
883 | int i; | ||
884 | struct tx4938_pcic_reg *pcicptr; | ||
885 | for (i = 0; (pcicptr = get_tx4938_pcicptr(i)) != NULL; i++) | ||
886 | tx4938_report_pcic_status1(pcicptr); | ||
887 | } | ||
888 | |||
889 | #endif /* CONFIG_PCI */ | ||
890 | |||
891 | /* We use onchip r4k counter or TMR timer as our system wide timer | ||
892 | * interrupt running at 100HZ. */ | ||
893 | |||
894 | extern void __init rtc_rx5c348_init(int chipid); | ||
895 | void __init rbtx4938_time_init(void) | ||
896 | { | ||
897 | rtc_rx5c348_init(RBTX4938_SRTC_CHIPID); | ||
898 | mips_hpt_frequency = txx9_cpu_clock / 2; | ||
899 | } | ||
900 | |||
901 | void __init toshiba_rbtx4938_setup(void) | ||
902 | { | ||
903 | unsigned long long pcfg; | ||
904 | char *argptr; | ||
905 | |||
906 | iomem_resource.end = 0xffffffff; /* 4GB */ | ||
907 | |||
908 | if (txx9_master_clock == 0) | ||
909 | txx9_master_clock = 25000000; /* 25MHz */ | ||
910 | tx4938_board_setup(); | ||
911 | /* setup irq stuff */ | ||
912 | TX4938_WR(TX4938_MKA(TX4938_IRC_IRDM0), 0x00000000); /* irq trigger */ | ||
913 | TX4938_WR(TX4938_MKA(TX4938_IRC_IRDM1), 0x00000000); /* irq trigger */ | ||
914 | /* setup serial stuff */ | ||
915 | TX4938_WR(0xff1ff314, 0x00000000); /* h/w flow control off */ | ||
916 | TX4938_WR(0xff1ff414, 0x00000000); /* h/w flow control off */ | ||
917 | |||
918 | #ifndef CONFIG_PCI | ||
919 | set_io_port_base(RBTX4938_ETHER_BASE); | ||
920 | #endif | ||
921 | |||
922 | #ifdef CONFIG_SERIAL_TXX9 | ||
923 | { | ||
924 | extern int early_serial_txx9_setup(struct uart_port *port); | ||
925 | int i; | ||
926 | struct uart_port req; | ||
927 | for(i = 0; i < 2; i++) { | ||
928 | memset(&req, 0, sizeof(req)); | ||
929 | req.line = i; | ||
930 | req.iotype = UPIO_MEM; | ||
931 | req.membase = (char *)(0xff1ff300 + i * 0x100); | ||
932 | req.mapbase = 0xff1ff300 + i * 0x100; | ||
933 | req.irq = 32 + i; | ||
934 | req.flags |= UPF_BUGGY_UART /*HAVE_CTS_LINE*/; | ||
935 | req.uartclk = 50000000; | ||
936 | early_serial_txx9_setup(&req); | ||
937 | } | ||
938 | } | ||
939 | #ifdef CONFIG_SERIAL_TXX9_CONSOLE | ||
940 | argptr = prom_getcmdline(); | ||
941 | if (strstr(argptr, "console=") == NULL) { | ||
942 | strcat(argptr, " console=ttyS0,38400"); | ||
943 | } | ||
944 | #endif | ||
945 | #endif | ||
946 | |||
947 | #ifdef CONFIG_TOSHIBA_RBTX4938_MPLEX_PIO58_61 | ||
948 | printk("PIOSEL: disabling both ata and nand selection\n"); | ||
949 | local_irq_disable(); | ||
950 | tx4938_ccfgptr->pcfg &= ~(TX4938_PCFG_NDF_SEL | TX4938_PCFG_ATA_SEL); | ||
951 | #endif | ||
952 | |||
953 | #ifdef CONFIG_TOSHIBA_RBTX4938_MPLEX_NAND | ||
954 | printk("PIOSEL: enabling nand selection\n"); | ||
955 | tx4938_ccfgptr->pcfg |= TX4938_PCFG_NDF_SEL; | ||
956 | tx4938_ccfgptr->pcfg &= ~TX4938_PCFG_ATA_SEL; | ||
957 | #endif | ||
958 | |||
959 | #ifdef CONFIG_TOSHIBA_RBTX4938_MPLEX_ATA | ||
960 | printk("PIOSEL: enabling ata selection\n"); | ||
961 | tx4938_ccfgptr->pcfg |= TX4938_PCFG_ATA_SEL; | ||
962 | tx4938_ccfgptr->pcfg &= ~TX4938_PCFG_NDF_SEL; | ||
963 | #endif | ||
964 | |||
965 | #ifdef CONFIG_IP_PNP | ||
966 | argptr = prom_getcmdline(); | ||
967 | if (strstr(argptr, "ip=") == NULL) { | ||
968 | strcat(argptr, " ip=any"); | ||
969 | } | ||
970 | #endif | ||
971 | |||
972 | |||
973 | #ifdef CONFIG_FB | ||
974 | { | ||
975 | conswitchp = &dummy_con; | ||
976 | } | ||
977 | #endif | ||
978 | |||
979 | rbtx4938_spi_setup(); | ||
980 | pcfg = tx4938_ccfgptr->pcfg; /* updated */ | ||
981 | /* fixup piosel */ | ||
982 | if ((pcfg & (TX4938_PCFG_ATA_SEL | TX4938_PCFG_NDF_SEL)) == | ||
983 | TX4938_PCFG_ATA_SEL) { | ||
984 | *rbtx4938_piosel_ptr = (*rbtx4938_piosel_ptr & 0x03) | 0x04; | ||
985 | } | ||
986 | else if ((pcfg & (TX4938_PCFG_ATA_SEL | TX4938_PCFG_NDF_SEL)) == | ||
987 | TX4938_PCFG_NDF_SEL) { | ||
988 | *rbtx4938_piosel_ptr = (*rbtx4938_piosel_ptr & 0x03) | 0x08; | ||
989 | } | ||
990 | else { | ||
991 | *rbtx4938_piosel_ptr &= ~(0x08 | 0x04); | ||
992 | } | ||
993 | |||
994 | rbtx4938_fpga_resource.name = "FPGA Registers"; | ||
995 | rbtx4938_fpga_resource.start = CPHYSADDR(RBTX4938_FPGA_REG_ADDR); | ||
996 | rbtx4938_fpga_resource.end = CPHYSADDR(RBTX4938_FPGA_REG_ADDR) + 0xffff; | ||
997 | rbtx4938_fpga_resource.flags = IORESOURCE_MEM | IORESOURCE_BUSY; | ||
998 | if (request_resource(&iomem_resource, &rbtx4938_fpga_resource)) | ||
999 | printk("request resource for fpga failed\n"); | ||
1000 | |||
1001 | /* disable all OnBoard I/O interrupts */ | ||
1002 | *rbtx4938_imask_ptr = 0; | ||
1003 | |||
1004 | _machine_restart = rbtx4938_machine_restart; | ||
1005 | _machine_halt = rbtx4938_machine_halt; | ||
1006 | _machine_power_off = rbtx4938_machine_power_off; | ||
1007 | |||
1008 | *rbtx4938_led_ptr = 0xff; | ||
1009 | printk("RBTX4938 --- FPGA(Rev %02x)", *rbtx4938_fpga_rev_ptr); | ||
1010 | printk(" DIPSW:%02x,%02x\n", | ||
1011 | *rbtx4938_dipsw_ptr, *rbtx4938_bdipsw_ptr); | ||
1012 | } | ||
1013 | |||
1014 | #ifdef CONFIG_PROC_FS | ||
1015 | extern void spi_eeprom_proc_create(struct proc_dir_entry *dir, int chipid); | ||
1016 | static int __init tx4938_spi_proc_setup(void) | ||
1017 | { | ||
1018 | struct proc_dir_entry *tx4938_spi_eeprom_dir; | ||
1019 | |||
1020 | tx4938_spi_eeprom_dir = proc_mkdir("spi_eeprom", 0); | ||
1021 | |||
1022 | if (!tx4938_spi_eeprom_dir) | ||
1023 | return -ENOMEM; | ||
1024 | |||
1025 | /* don't allow user access to RBTX4938_SEEPROM1_CHIPID | ||
1026 | * as it contains eth0 and eth1 MAC addresses | ||
1027 | */ | ||
1028 | spi_eeprom_proc_create(tx4938_spi_eeprom_dir, RBTX4938_SEEPROM2_CHIPID); | ||
1029 | spi_eeprom_proc_create(tx4938_spi_eeprom_dir, RBTX4938_SEEPROM3_CHIPID); | ||
1030 | |||
1031 | return 0; | ||
1032 | } | ||
1033 | |||
1034 | __initcall(tx4938_spi_proc_setup); | ||
1035 | #endif | ||
diff --git a/arch/mips/tx4938/toshiba_rbtx4938/spi_eeprom.c b/arch/mips/tx4938/toshiba_rbtx4938/spi_eeprom.c new file mode 100644 index 000000000000..951a208ee9b3 --- /dev/null +++ b/arch/mips/tx4938/toshiba_rbtx4938/spi_eeprom.c | |||
@@ -0,0 +1,219 @@ | |||
1 | /* | ||
2 | * linux/arch/mips/tx4938/toshiba_rbtx4938/spi_eeprom.c | ||
3 | * Copyright (C) 2000-2001 Toshiba Corporation | ||
4 | * | ||
5 | * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the | ||
6 | * terms of the GNU General Public License version 2. This program is | ||
7 | * licensed "as is" without any warranty of any kind, whether express | ||
8 | * or implied. | ||
9 | * | ||
10 | * Support for TX4938 in 2.6 - Manish Lachwani (mlachwani@mvista.com) | ||
11 | */ | ||
12 | #include <linux/config.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/delay.h> | ||
15 | #include <linux/proc_fs.h> | ||
16 | #include <linux/spinlock.h> | ||
17 | #include <asm/tx4938/spi.h> | ||
18 | #include <asm/tx4938/tx4938.h> | ||
19 | |||
20 | /* ATMEL 250x0 instructions */ | ||
21 | #define ATMEL_WREN 0x06 | ||
22 | #define ATMEL_WRDI 0x04 | ||
23 | #define ATMEL_RDSR 0x05 | ||
24 | #define ATMEL_WRSR 0x01 | ||
25 | #define ATMEL_READ 0x03 | ||
26 | #define ATMEL_WRITE 0x02 | ||
27 | |||
28 | #define ATMEL_SR_BSY 0x01 | ||
29 | #define ATMEL_SR_WEN 0x02 | ||
30 | #define ATMEL_SR_BP0 0x04 | ||
31 | #define ATMEL_SR_BP1 0x08 | ||
32 | |||
33 | DEFINE_SPINLOCK(spi_eeprom_lock); | ||
34 | |||
35 | static struct spi_dev_desc seeprom_dev_desc = { | ||
36 | .baud = 1500000, /* 1.5Mbps */ | ||
37 | .tcss = 1, | ||
38 | .tcsh = 1, | ||
39 | .tcsr = 1, | ||
40 | .byteorder = 1, /* MSB-First */ | ||
41 | .polarity = 0, /* High-Active */ | ||
42 | .phase = 0, /* Sample-Then-Shift */ | ||
43 | |||
44 | }; | ||
45 | static inline int | ||
46 | spi_eeprom_io(int chipid, | ||
47 | unsigned char **inbufs, unsigned int *incounts, | ||
48 | unsigned char **outbufs, unsigned int *outcounts) | ||
49 | { | ||
50 | return txx9_spi_io(chipid, &seeprom_dev_desc, | ||
51 | inbufs, incounts, outbufs, outcounts, 0); | ||
52 | } | ||
53 | |||
54 | int spi_eeprom_write_enable(int chipid, int enable) | ||
55 | { | ||
56 | unsigned char inbuf[1]; | ||
57 | unsigned char *inbufs[1]; | ||
58 | unsigned int incounts[2]; | ||
59 | unsigned long flags; | ||
60 | int stat; | ||
61 | inbuf[0] = enable ? ATMEL_WREN : ATMEL_WRDI; | ||
62 | inbufs[0] = inbuf; | ||
63 | incounts[0] = sizeof(inbuf); | ||
64 | incounts[1] = 0; | ||
65 | spin_lock_irqsave(&spi_eeprom_lock, flags); | ||
66 | stat = spi_eeprom_io(chipid, inbufs, incounts, NULL, NULL); | ||
67 | spin_unlock_irqrestore(&spi_eeprom_lock, flags); | ||
68 | return stat; | ||
69 | } | ||
70 | |||
71 | static int spi_eeprom_read_status_nolock(int chipid) | ||
72 | { | ||
73 | unsigned char inbuf[2], outbuf[2]; | ||
74 | unsigned char *inbufs[1], *outbufs[1]; | ||
75 | unsigned int incounts[2], outcounts[2]; | ||
76 | int stat; | ||
77 | inbuf[0] = ATMEL_RDSR; | ||
78 | inbuf[1] = 0; | ||
79 | inbufs[0] = inbuf; | ||
80 | incounts[0] = sizeof(inbuf); | ||
81 | incounts[1] = 0; | ||
82 | outbufs[0] = outbuf; | ||
83 | outcounts[0] = sizeof(outbuf); | ||
84 | outcounts[1] = 0; | ||
85 | stat = spi_eeprom_io(chipid, inbufs, incounts, outbufs, outcounts); | ||
86 | if (stat < 0) | ||
87 | return stat; | ||
88 | return outbuf[1]; | ||
89 | } | ||
90 | |||
91 | int spi_eeprom_read_status(int chipid) | ||
92 | { | ||
93 | unsigned long flags; | ||
94 | int stat; | ||
95 | spin_lock_irqsave(&spi_eeprom_lock, flags); | ||
96 | stat = spi_eeprom_read_status_nolock(chipid); | ||
97 | spin_unlock_irqrestore(&spi_eeprom_lock, flags); | ||
98 | return stat; | ||
99 | } | ||
100 | |||
101 | int spi_eeprom_read(int chipid, int address, unsigned char *buf, int len) | ||
102 | { | ||
103 | unsigned char inbuf[2]; | ||
104 | unsigned char *inbufs[2], *outbufs[2]; | ||
105 | unsigned int incounts[2], outcounts[3]; | ||
106 | unsigned long flags; | ||
107 | int stat; | ||
108 | inbuf[0] = ATMEL_READ; | ||
109 | inbuf[1] = address; | ||
110 | inbufs[0] = inbuf; | ||
111 | inbufs[1] = NULL; | ||
112 | incounts[0] = sizeof(inbuf); | ||
113 | incounts[1] = 0; | ||
114 | outbufs[0] = NULL; | ||
115 | outbufs[1] = buf; | ||
116 | outcounts[0] = 2; | ||
117 | outcounts[1] = len; | ||
118 | outcounts[2] = 0; | ||
119 | spin_lock_irqsave(&spi_eeprom_lock, flags); | ||
120 | stat = spi_eeprom_io(chipid, inbufs, incounts, outbufs, outcounts); | ||
121 | spin_unlock_irqrestore(&spi_eeprom_lock, flags); | ||
122 | return stat; | ||
123 | } | ||
124 | |||
125 | int spi_eeprom_write(int chipid, int address, unsigned char *buf, int len) | ||
126 | { | ||
127 | unsigned char inbuf[2]; | ||
128 | unsigned char *inbufs[2]; | ||
129 | unsigned int incounts[3]; | ||
130 | unsigned long flags; | ||
131 | int i, stat; | ||
132 | |||
133 | if (address / 8 != (address + len - 1) / 8) | ||
134 | return -EINVAL; | ||
135 | stat = spi_eeprom_write_enable(chipid, 1); | ||
136 | if (stat < 0) | ||
137 | return stat; | ||
138 | stat = spi_eeprom_read_status(chipid); | ||
139 | if (stat < 0) | ||
140 | return stat; | ||
141 | if (!(stat & ATMEL_SR_WEN)) | ||
142 | return -EPERM; | ||
143 | |||
144 | inbuf[0] = ATMEL_WRITE; | ||
145 | inbuf[1] = address; | ||
146 | inbufs[0] = inbuf; | ||
147 | inbufs[1] = buf; | ||
148 | incounts[0] = sizeof(inbuf); | ||
149 | incounts[1] = len; | ||
150 | incounts[2] = 0; | ||
151 | spin_lock_irqsave(&spi_eeprom_lock, flags); | ||
152 | stat = spi_eeprom_io(chipid, inbufs, incounts, NULL, NULL); | ||
153 | if (stat < 0) | ||
154 | goto unlock_return; | ||
155 | |||
156 | /* write start. max 10ms */ | ||
157 | for (i = 10; i > 0; i--) { | ||
158 | int stat = spi_eeprom_read_status_nolock(chipid); | ||
159 | if (stat < 0) | ||
160 | goto unlock_return; | ||
161 | if (!(stat & ATMEL_SR_BSY)) | ||
162 | break; | ||
163 | mdelay(1); | ||
164 | } | ||
165 | spin_unlock_irqrestore(&spi_eeprom_lock, flags); | ||
166 | if (i == 0) | ||
167 | return -EIO; | ||
168 | return len; | ||
169 | unlock_return: | ||
170 | spin_unlock_irqrestore(&spi_eeprom_lock, flags); | ||
171 | return stat; | ||
172 | } | ||
173 | |||
174 | #ifdef CONFIG_PROC_FS | ||
175 | #define MAX_SIZE 0x80 /* for ATMEL 25010 */ | ||
176 | static int spi_eeprom_read_proc(char *page, char **start, off_t off, | ||
177 | int count, int *eof, void *data) | ||
178 | { | ||
179 | unsigned int size = MAX_SIZE; | ||
180 | if (spi_eeprom_read((int)data, 0, (unsigned char *)page, size) < 0) | ||
181 | size = 0; | ||
182 | return size; | ||
183 | } | ||
184 | |||
185 | static int spi_eeprom_write_proc(struct file *file, const char *buffer, | ||
186 | unsigned long count, void *data) | ||
187 | { | ||
188 | unsigned int size = MAX_SIZE; | ||
189 | int i; | ||
190 | if (file->f_pos >= size) | ||
191 | return -EIO; | ||
192 | if (file->f_pos + count > size) | ||
193 | count = size - file->f_pos; | ||
194 | for (i = 0; i < count; i += 8) { | ||
195 | int len = count - i < 8 ? count - i : 8; | ||
196 | if (spi_eeprom_write((int)data, file->f_pos, | ||
197 | (unsigned char *)buffer, len) < 0) { | ||
198 | count = -EIO; | ||
199 | break; | ||
200 | } | ||
201 | buffer += len; | ||
202 | file->f_pos += len; | ||
203 | } | ||
204 | return count; | ||
205 | } | ||
206 | |||
207 | __init void spi_eeprom_proc_create(struct proc_dir_entry *dir, int chipid) | ||
208 | { | ||
209 | struct proc_dir_entry *entry; | ||
210 | char name[128]; | ||
211 | sprintf(name, "seeprom-%d", chipid); | ||
212 | entry = create_proc_entry(name, 0600, dir); | ||
213 | if (entry) { | ||
214 | entry->read_proc = spi_eeprom_read_proc; | ||
215 | entry->write_proc = spi_eeprom_write_proc; | ||
216 | entry->data = (void *)chipid; | ||
217 | } | ||
218 | } | ||
219 | #endif /* CONFIG_PROC_FS */ | ||
diff --git a/arch/mips/tx4938/toshiba_rbtx4938/spi_txx9.c b/arch/mips/tx4938/toshiba_rbtx4938/spi_txx9.c new file mode 100644 index 000000000000..fae3136f462d --- /dev/null +++ b/arch/mips/tx4938/toshiba_rbtx4938/spi_txx9.c | |||
@@ -0,0 +1,159 @@ | |||
1 | /* | ||
2 | * linux/arch/mips/tx4938/toshiba_rbtx4938/spi_txx9.c | ||
3 | * Copyright (C) 2000-2001 Toshiba Corporation | ||
4 | * | ||
5 | * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the | ||
6 | * terms of the GNU General Public License version 2. This program is | ||
7 | * licensed "as is" without any warranty of any kind, whether express | ||
8 | * or implied. | ||
9 | * | ||
10 | * Support for TX4938 in 2.6 - Manish Lachwani (mlachwani@mvista.com) | ||
11 | */ | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/delay.h> | ||
14 | #include <linux/errno.h> | ||
15 | #include <linux/interrupt.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/sched.h> | ||
18 | #include <linux/spinlock.h> | ||
19 | #include <linux/wait.h> | ||
20 | #include <asm/tx4938/spi.h> | ||
21 | #include <asm/tx4938/tx4938.h> | ||
22 | |||
23 | static int (*txx9_spi_cs_func)(int chipid, int on); | ||
24 | static DEFINE_SPINLOCK(txx9_spi_lock); | ||
25 | |||
26 | extern unsigned int txx9_gbus_clock; | ||
27 | |||
28 | #define SPI_FIFO_SIZE 4 | ||
29 | |||
30 | void __init txx9_spi_init(unsigned long base, int (*cs_func)(int chipid, int on)) | ||
31 | { | ||
32 | txx9_spi_cs_func = cs_func; | ||
33 | /* enter config mode */ | ||
34 | tx4938_spiptr->mcr = TXx9_SPMCR_CONFIG | TXx9_SPMCR_BCLR; | ||
35 | } | ||
36 | |||
37 | static DECLARE_WAIT_QUEUE_HEAD(txx9_spi_wait); | ||
38 | static void txx9_spi_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
39 | { | ||
40 | /* disable rx intr */ | ||
41 | tx4938_spiptr->cr0 &= ~TXx9_SPCR0_RBSIE; | ||
42 | wake_up(&txx9_spi_wait); | ||
43 | } | ||
44 | static struct irqaction txx9_spi_action = { | ||
45 | txx9_spi_interrupt, 0, 0, "spi", NULL, NULL, | ||
46 | }; | ||
47 | |||
48 | void __init txx9_spi_irqinit(int irc_irq) | ||
49 | { | ||
50 | setup_irq(irc_irq, &txx9_spi_action); | ||
51 | } | ||
52 | |||
53 | int txx9_spi_io(int chipid, struct spi_dev_desc *desc, | ||
54 | unsigned char **inbufs, unsigned int *incounts, | ||
55 | unsigned char **outbufs, unsigned int *outcounts, | ||
56 | int cansleep) | ||
57 | { | ||
58 | unsigned int incount, outcount; | ||
59 | unsigned char *inp, *outp; | ||
60 | int ret; | ||
61 | unsigned long flags; | ||
62 | |||
63 | spin_lock_irqsave(&txx9_spi_lock, flags); | ||
64 | if ((tx4938_spiptr->mcr & TXx9_SPMCR_OPMODE) == TXx9_SPMCR_ACTIVE) { | ||
65 | spin_unlock_irqrestore(&txx9_spi_lock, flags); | ||
66 | return -EBUSY; | ||
67 | } | ||
68 | /* enter config mode */ | ||
69 | tx4938_spiptr->mcr = TXx9_SPMCR_CONFIG | TXx9_SPMCR_BCLR; | ||
70 | tx4938_spiptr->cr0 = | ||
71 | (desc->byteorder ? TXx9_SPCR0_SBOS : 0) | | ||
72 | (desc->polarity ? TXx9_SPCR0_SPOL : 0) | | ||
73 | (desc->phase ? TXx9_SPCR0_SPHA : 0) | | ||
74 | 0x08; | ||
75 | tx4938_spiptr->cr1 = | ||
76 | (((TXX9_IMCLK + desc->baud) / (2 * desc->baud) - 1) << 8) | | ||
77 | 0x08 /* 8 bit only */; | ||
78 | /* enter active mode */ | ||
79 | tx4938_spiptr->mcr = TXx9_SPMCR_ACTIVE; | ||
80 | spin_unlock_irqrestore(&txx9_spi_lock, flags); | ||
81 | |||
82 | /* CS ON */ | ||
83 | if ((ret = txx9_spi_cs_func(chipid, 1)) < 0) { | ||
84 | spin_unlock_irqrestore(&txx9_spi_lock, flags); | ||
85 | return ret; | ||
86 | } | ||
87 | udelay(desc->tcss); | ||
88 | |||
89 | /* do scatter IO */ | ||
90 | inp = inbufs ? *inbufs : NULL; | ||
91 | outp = outbufs ? *outbufs : NULL; | ||
92 | incount = 0; | ||
93 | outcount = 0; | ||
94 | while (1) { | ||
95 | unsigned char data; | ||
96 | unsigned int count; | ||
97 | int i; | ||
98 | if (!incount) { | ||
99 | incount = incounts ? *incounts++ : 0; | ||
100 | inp = (incount && inbufs) ? *inbufs++ : NULL; | ||
101 | } | ||
102 | if (!outcount) { | ||
103 | outcount = outcounts ? *outcounts++ : 0; | ||
104 | outp = (outcount && outbufs) ? *outbufs++ : NULL; | ||
105 | } | ||
106 | if (!inp && !outp) | ||
107 | break; | ||
108 | count = SPI_FIFO_SIZE; | ||
109 | if (incount) | ||
110 | count = min(count, incount); | ||
111 | if (outcount) | ||
112 | count = min(count, outcount); | ||
113 | |||
114 | /* now tx must be idle... */ | ||
115 | while (!(tx4938_spiptr->sr & TXx9_SPSR_SIDLE)) | ||
116 | ; | ||
117 | |||
118 | tx4938_spiptr->cr0 = | ||
119 | (tx4938_spiptr->cr0 & ~TXx9_SPCR0_RXIFL_MASK) | | ||
120 | ((count - 1) << 12); | ||
121 | if (cansleep) { | ||
122 | /* enable rx intr */ | ||
123 | tx4938_spiptr->cr0 |= TXx9_SPCR0_RBSIE; | ||
124 | } | ||
125 | /* send */ | ||
126 | for (i = 0; i < count; i++) | ||
127 | tx4938_spiptr->dr = inp ? *inp++ : 0; | ||
128 | /* wait all rx data */ | ||
129 | if (cansleep) { | ||
130 | wait_event(txx9_spi_wait, | ||
131 | tx4938_spiptr->sr & TXx9_SPSR_SRRDY); | ||
132 | } else { | ||
133 | while (!(tx4938_spiptr->sr & TXx9_SPSR_RBSI)) | ||
134 | ; | ||
135 | } | ||
136 | /* receive */ | ||
137 | for (i = 0; i < count; i++) { | ||
138 | data = tx4938_spiptr->dr; | ||
139 | if (outp) | ||
140 | *outp++ = data; | ||
141 | } | ||
142 | if (incount) | ||
143 | incount -= count; | ||
144 | if (outcount) | ||
145 | outcount -= count; | ||
146 | } | ||
147 | |||
148 | /* CS OFF */ | ||
149 | udelay(desc->tcsh); | ||
150 | txx9_spi_cs_func(chipid, 0); | ||
151 | udelay(desc->tcsr); | ||
152 | |||
153 | spin_lock_irqsave(&txx9_spi_lock, flags); | ||
154 | /* enter config mode */ | ||
155 | tx4938_spiptr->mcr = TXx9_SPMCR_CONFIG | TXx9_SPMCR_BCLR; | ||
156 | spin_unlock_irqrestore(&txx9_spi_lock, flags); | ||
157 | |||
158 | return 0; | ||
159 | } | ||