aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/tx4938
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2005-07-25 18:45:45 -0400
committerRalf Baechle <ralf@linux-mips.org>2005-10-29 14:31:57 -0400
commit23fbee9dd5d2a41d36af49ff8e1669fb0c29fda8 (patch)
tree4e24699269b9d4d2655d961e7a0ffb29931e9b2d /arch/mips/tx4938
parent132940401174ed04f9e8f1ae2dad6f47da26ee0a (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/Kconfig24
-rw-r--r--arch/mips/tx4938/common/Makefile11
-rw-r--r--arch/mips/tx4938/common/dbgio.c50
-rw-r--r--arch/mips/tx4938/common/irq.c424
-rw-r--r--arch/mips/tx4938/common/irq_handler.S84
-rw-r--r--arch/mips/tx4938/common/prom.c129
-rw-r--r--arch/mips/tx4938/common/rtc_rx5c348.c202
-rw-r--r--arch/mips/tx4938/common/setup.c91
-rw-r--r--arch/mips/tx4938/toshiba_rbtx4938/Makefile9
-rw-r--r--arch/mips/tx4938/toshiba_rbtx4938/irq.c244
-rw-r--r--arch/mips/tx4938/toshiba_rbtx4938/prom.c78
-rw-r--r--arch/mips/tx4938/toshiba_rbtx4938/setup.c1035
-rw-r--r--arch/mips/tx4938/toshiba_rbtx4938/spi_eeprom.c219
-rw-r--r--arch/mips/tx4938/toshiba_rbtx4938/spi_txx9.c159
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 @@
1if TOSHIBA_RBTX4938
2
3comment "Multiplex Pin Select"
4choice
5 prompt "PIO[58:61]"
6 default TOSHIBA_RBTX4938_MPLEX_PIO58_61
7
8config TOSHIBA_RBTX4938_MPLEX_PIO58_61
9 bool "PIO"
10config TOSHIBA_RBTX4938_MPLEX_NAND
11 bool "NAND"
12config TOSHIBA_RBTX4938_MPLEX_ATA
13 bool "ATA"
14
15endchoice
16
17config 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
24endif
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
9obj-y += prom.o setup.o irq.o irq_handler.o rtc_rx5c348.o
10obj-$(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
38extern u8 txx9_sio_kdbg_rd(void);
39extern int txx9_sio_kdbg_wr( u8 ch );
40
41u8 getDebugChar(void)
42{
43 return (txx9_sio_kdbg_rd());
44}
45
46int 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
39static unsigned int tx4938_irq_cp0_startup(unsigned int irq);
40static void tx4938_irq_cp0_shutdown(unsigned int irq);
41static void tx4938_irq_cp0_enable(unsigned int irq);
42static void tx4938_irq_cp0_disable(unsigned int irq);
43static void tx4938_irq_cp0_mask_and_ack(unsigned int irq);
44static void tx4938_irq_cp0_end(unsigned int irq);
45
46static unsigned int tx4938_irq_pic_startup(unsigned int irq);
47static void tx4938_irq_pic_shutdown(unsigned int irq);
48static void tx4938_irq_pic_enable(unsigned int irq);
49static void tx4938_irq_pic_disable(unsigned int irq);
50static void tx4938_irq_pic_mask_and_ack(unsigned int irq);
51static void tx4938_irq_pic_end(unsigned int irq);
52
53/**********************************************************************************/
54/* Kernel structs for all pic's */
55/**********************************************************************************/
56DEFINE_SPINLOCK(tx4938_cp0_lock);
57DEFINE_SPINLOCK(tx4938_pic_lock);
58
59#define TX4938_CP0_NAME "TX4938-CP0"
60static 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"
72static 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
83static 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
96static void __init
97tx4938_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
111static unsigned int
112tx4938_irq_cp0_startup(unsigned int irq)
113{
114 tx4938_irq_cp0_enable(irq);
115
116 return (0);
117}
118
119static void
120tx4938_irq_cp0_shutdown(unsigned int irq)
121{
122 tx4938_irq_cp0_disable(irq);
123}
124
125static void
126tx4938_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
137static void
138tx4938_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
151static void
152tx4938_irq_cp0_mask_and_ack(unsigned int irq)
153{
154 tx4938_irq_cp0_disable(irq);
155
156 return;
157}
158
159static void
160tx4938_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
173u32
174tx4938_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
233u32
234tx4938_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
284static void
285tx4938_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
299static void __init
300tx4938_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
324static unsigned int
325tx4938_irq_pic_startup(unsigned int irq)
326{
327 tx4938_irq_pic_enable(irq);
328
329 return (0);
330}
331
332static void
333tx4938_irq_pic_shutdown(unsigned int irq)
334{
335 tx4938_irq_pic_disable(irq);
336
337 return;
338}
339
340static void
341tx4938_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
355static void
356tx4938_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
370static void
371tx4938_irq_pic_mask_and_ack(unsigned int irq)
372{
373 tx4938_irq_pic_disable(irq);
374
375 return;
376}
377
378static void
379tx4938_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
392void __init
393tx4938_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
404int
405tx4938_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
54ll_ip7:
55 li a0, TX4938_IRQ_CPU_TIMER
56 move a1, sp
57 jal do_IRQ
58 j ret_from_irq
59
60
61ll_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
71goto_spurious_interrupt:
72 j ret_from_irq
73
74ll_ip1:
75 li a0, TX4938_IRQ_USER1
76 move a1, sp
77 jal do_IRQ
78 j ret_from_irq
79
80ll_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
24static unsigned int __init
25tx4938_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
112unsigned int __init
113tx4938_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
51static 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};
62static int srtc_chipid;
63static int srtc_24h;
64
65static inline int
66spi_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
93static int
94rtc_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
142static unsigned long
143rtc_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
178void __init
179rtc_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
37extern void toshiba_rbtx4938_setup(void);
38extern void rbtx4938_time_init(void);
39
40void __init tx4938_setup(void);
41void __init tx4938_time_init(void);
42void __init tx4938_timer_setup(struct irqaction *irq);
43void dump_cp0(char *key);
44
45void (*__wbflush) (void);
46
47static void
48tx4938_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
63void __init
64plat_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
72void __init
73tx4938_time_init(void)
74{
75 rbtx4938_time_init();
76}
77
78void __init
79tx4938_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
9obj-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/*
16IRQ Device
17
1816 TX4938-CP0/00 Software 0
1917 TX4938-CP0/01 Software 1
2018 TX4938-CP0/02 Cascade TX4938-CP0
2119 TX4938-CP0/03 Multiplexed -- do not use
2220 TX4938-CP0/04 Multiplexed -- do not use
2321 TX4938-CP0/05 Multiplexed -- do not use
2422 TX4938-CP0/06 Multiplexed -- do not use
2523 TX4938-CP0/07 CPU TIMER
26
2724 TX4938-PIC/00
2825 TX4938-PIC/01
2926 TX4938-PIC/02 Cascade RBTX4938-IOC
3027 TX4938-PIC/03 RBTX4938 RTL-8019AS Ethernet
3128 TX4938-PIC/04
3229 TX4938-PIC/05 TX4938 ETH1
3330 TX4938-PIC/06 TX4938 ETH0
3431 TX4938-PIC/07
3532 TX4938-PIC/08 TX4938 SIO 0
3633 TX4938-PIC/09 TX4938 SIO 1
3734 TX4938-PIC/10 TX4938 DMA0
3835 TX4938-PIC/11 TX4938 DMA1
3936 TX4938-PIC/12 TX4938 DMA2
4037 TX4938-PIC/13 TX4938 DMA3
4138 TX4938-PIC/14
4239 TX4938-PIC/15
4340 TX4938-PIC/16 TX4938 PCIC
4441 TX4938-PIC/17 TX4938 TMR0
4542 TX4938-PIC/18 TX4938 TMR1
4643 TX4938-PIC/19 TX4938 TMR2
4744 TX4938-PIC/20
4845 TX4938-PIC/21
4946 TX4938-PIC/22 TX4938 PCIERR
5047 TX4938-PIC/23
5148 TX4938-PIC/24
5249 TX4938-PIC/25
5350 TX4938-PIC/26
5451 TX4938-PIC/27
5552 TX4938-PIC/28
5653 TX4938-PIC/29
5754 TX4938-PIC/30
5855 TX4938-PIC/31 TX4938 SPI
59
6056 RBTX4938-IOC/00 PCI-D
6157 RBTX4938-IOC/01 PCI-C
6258 RBTX4938-IOC/02 PCI-B
6359 RBTX4938-IOC/03 PCI-A
6460 RBTX4938-IOC/04 RTC
6561 RBTX4938-IOC/05 ATA
6662 RBTX4938-IOC/06 MODEM
6763 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
91static unsigned int toshiba_rbtx4938_irq_ioc_startup(unsigned int irq);
92static void toshiba_rbtx4938_irq_ioc_shutdown(unsigned int irq);
93static void toshiba_rbtx4938_irq_ioc_enable(unsigned int irq);
94static void toshiba_rbtx4938_irq_ioc_disable(unsigned int irq);
95static void toshiba_rbtx4938_irq_ioc_mask_and_ack(unsigned int irq);
96static void toshiba_rbtx4938_irq_ioc_end(unsigned int irq);
97
98DEFINE_SPINLOCK(toshiba_rbtx4938_ioc_lock);
99
100#define TOSHIBA_RBTX4938_IOC_NAME "RBTX4938-IOC"
101static 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
115int
116toshiba_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
130static 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/**********************************************************************************/
140static void __init
141toshiba_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
157static unsigned int
158toshiba_rbtx4938_irq_ioc_startup(unsigned int irq)
159{
160 toshiba_rbtx4938_irq_ioc_enable(irq);
161
162 return 0;
163}
164
165static void
166toshiba_rbtx4938_irq_ioc_shutdown(unsigned int irq)
167{
168 toshiba_rbtx4938_irq_ioc_disable(irq);
169}
170
171static void
172toshiba_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
188static void
189toshiba_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
205static void
206toshiba_rbtx4938_irq_ioc_mask_and_ack(unsigned int irq)
207{
208 toshiba_rbtx4938_irq_ioc_disable(irq);
209}
210
211static void
212toshiba_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
219extern void __init txx9_spi_irqinit(int irc_irq);
220
221void __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
25void __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
44void __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
60unsigned long __init prom_free_prom_memory(void)
61{
62 return 0;
63}
64
65void __init prom_fixup_mem_map(unsigned long start, unsigned long end)
66{
67 return;
68}
69
70const char *get_system_type(void)
71{
72 return "Toshiba RBTX4938";
73}
74
75char * __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
37extern void rbtx4938_time_init(void) __init;
38extern char * __init prom_getcmdline(void);
39static inline void tx4938_report_pcic_status1(struct tx4938_pcic_reg *pcicptr);
40
41/* These functions are used for rebooting or halting the machine*/
42extern void rbtx4938_machine_restart(char *command);
43extern void rbtx4938_machine_halt(void);
44extern void rbtx4938_machine_power_off(void);
45
46/* clocks */
47unsigned int txx9_master_clock;
48unsigned int txx9_cpu_clock;
49unsigned int txx9_gbus_clock;
50
51unsigned long rbtx4938_ce_base[8];
52unsigned long rbtx4938_ce_size[8];
53int txboard_pci66_mode;
54static int tx4938_pcic_trdyto; /* default: disabled */
55static int tx4938_pcic_retryto; /* default: disabled */
56static int tx4938_ccfg_toeon = 1;
57
58struct tx4938_pcic_reg *pcicptrs[4] = {
59 tx4938_pcicptr /* default setting for TX4938 */
60};
61
62static struct {
63 unsigned long base;
64 unsigned long size;
65} phys_regions[16] __initdata;
66static int num_phys_regions __initdata;
67
68#define PHYS_REGION_MINSIZE 0x10000
69
70void 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
81void rbtx4938_machine_power_off(void)
82{
83 rbtx4938_machine_halt();
84 /* no return */
85}
86
87void 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
100void __init
101txboard_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}
111unsigned long __init
112txboard_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}
130unsigned long __init
131txboard_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}
144unsigned long __init
145txboard_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}
154unsigned long __init
155txboard_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}
164unsigned long __init
165txboard_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
176void __init
177tx4938_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
297int __init
298tx4938_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
334void __init set_tx4938_pcicptr(int ch, struct tx4938_pcic_reg *pcicptr)
335{
336 pcicptrs[ch] = pcicptr;
337}
338
339struct tx4938_pcic_reg *get_tx4938_pcicptr(int ch)
340{
341 return pcicptrs[ch];
342}
343
344static 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) \
361static 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
369EARLY_PCI_OP(read, word, u16 *)
370
371int 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
405int __init
406tx4938_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
450extern struct pci_controller tx4938_pci_controller[];
451static 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
563arch_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
575static 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
606extern int spi_eeprom_read(int chipid, int address, unsigned char *buf, int len);
607
608int 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
650extern void __init txx9_spi_init(unsigned long base, int (*cs_func)(int chipid, int on));
651static 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
661static struct resource rbtx4938_fpga_resource;
662
663static char pcode_str[8];
664static struct resource tx4938_reg_resource = {
665 pcode_str, TX4938_REG_BASE, TX4938_REG_BASE+TX4938_REG_SIZE, IORESOURCE_MEM
666};
667
668void __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
836static 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
881void 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
894extern void __init rtc_rx5c348_init(int chipid);
895void __init rbtx4938_time_init(void)
896{
897 rtc_rx5c348_init(RBTX4938_SRTC_CHIPID);
898 mips_hpt_frequency = txx9_cpu_clock / 2;
899}
900
901void __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
1015extern void spi_eeprom_proc_create(struct proc_dir_entry *dir, int chipid);
1016static 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
33DEFINE_SPINLOCK(spi_eeprom_lock);
34
35static 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};
45static inline int
46spi_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
54int 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
71static 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
91int 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
101int 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
125int 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 */
176static 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
185static 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
23static int (*txx9_spi_cs_func)(int chipid, int on);
24static DEFINE_SPINLOCK(txx9_spi_lock);
25
26extern unsigned int txx9_gbus_clock;
27
28#define SPI_FIFO_SIZE 4
29
30void __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
37static DECLARE_WAIT_QUEUE_HEAD(txx9_spi_wait);
38static 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}
44static struct irqaction txx9_spi_action = {
45 txx9_spi_interrupt, 0, 0, "spi", NULL, NULL,
46};
47
48void __init txx9_spi_irqinit(int irc_irq)
49{
50 setup_irq(irc_irq, &txx9_spi_action);
51}
52
53int 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}