Linux-2.6.12-rc2
[linux-2.6.git] / arch / sh / boards / mpc1211 / setup.c
1 /*
2  * linux/arch/sh/board/mpc1211/setup.c
3  *
4  * Copyright (C) 2002  Saito.K & Jeanne,  Fujii.Y
5  *
6  */
7
8 #include <linux/config.h>
9 #include <linux/init.h>
10 #include <linux/irq.h>
11 #include <linux/hdreg.h>
12 #include <linux/ide.h>
13 #include <linux/interrupt.h>
14
15 #include <asm/io.h>
16 #include <asm/machvec.h>
17 #include <asm/mpc1211/mpc1211.h>
18 #include <asm/mpc1211/pci.h>
19 #include <asm/mpc1211/m1543c.h>
20
21
22 /* ALI15X3 SMBus address offsets */
23 #define SMBHSTSTS   (0 + 0x3100)
24 #define SMBHSTCNT   (1 + 0x3100)
25 #define SMBHSTSTART (2 + 0x3100)
26 #define SMBHSTCMD   (7 + 0x3100)
27 #define SMBHSTADD   (3 + 0x3100)
28 #define SMBHSTDAT0  (4 + 0x3100)
29 #define SMBHSTDAT1  (5 + 0x3100)
30 #define SMBBLKDAT   (6 + 0x3100)
31
32 /* Other settings */
33 #define MAX_TIMEOUT 500         /* times 1/100 sec */
34
35 /* ALI15X3 command constants */
36 #define ALI15X3_ABORT      0x04
37 #define ALI15X3_T_OUT      0x08
38 #define ALI15X3_QUICK      0x00
39 #define ALI15X3_BYTE       0x10
40 #define ALI15X3_BYTE_DATA  0x20
41 #define ALI15X3_WORD_DATA  0x30
42 #define ALI15X3_BLOCK_DATA 0x40
43 #define ALI15X3_BLOCK_CLR  0x80
44
45 /* ALI15X3 status register bits */
46 #define ALI15X3_STS_IDLE        0x04
47 #define ALI15X3_STS_BUSY        0x08
48 #define ALI15X3_STS_DONE        0x10
49 #define ALI15X3_STS_DEV         0x20    /* device error */
50 #define ALI15X3_STS_COLL        0x40    /* collision or no response */
51 #define ALI15X3_STS_TERM        0x80    /* terminated by abort */
52 #define ALI15X3_STS_ERR         0xE0    /* all the bad error bits */
53
54 const char *get_system_type(void)
55 {
56         return "Interface MPC-1211(CTP/PCI/MPC-SH02)";
57 }
58
59 static void __init pci_write_config(unsigned long busNo,
60                                     unsigned long devNo,
61                                     unsigned long fncNo,
62                                     unsigned long cnfAdd,
63                                     unsigned long cnfData)
64 {
65         ctrl_outl((0x80000000 
66                 + ((busNo & 0xff) << 16) 
67                 + ((devNo & 0x1f) << 11) 
68                 + ((fncNo & 0x07) <<  8) 
69                 + (cnfAdd & 0xfc)), PCIPAR);
70
71         ctrl_outl(cnfData, PCIPDR);
72 }
73
74 /*
75   Initialize IRQ setting
76 */
77
78 static unsigned char m_irq_mask = 0xfb;
79 static unsigned char s_irq_mask = 0xff;
80 volatile unsigned long irq_err_count;
81
82 static void disable_mpc1211_irq(unsigned int irq)
83 {
84         unsigned long flags;
85
86         save_and_cli(flags);
87         if( irq < 8) {
88                 m_irq_mask |= (1 << irq);
89                 outb(m_irq_mask,I8259_M_MR);
90         } else {
91                 s_irq_mask |= (1 << (irq - 8));
92                 outb(s_irq_mask,I8259_S_MR);
93         }
94         restore_flags(flags);
95
96 }
97
98 static void enable_mpc1211_irq(unsigned int irq)
99 {
100         unsigned long flags;
101
102         save_and_cli(flags);
103
104         if( irq < 8) {
105                 m_irq_mask &= ~(1 << irq);
106                 outb(m_irq_mask,I8259_M_MR);
107         } else {
108                 s_irq_mask &= ~(1 << (irq - 8));
109                 outb(s_irq_mask,I8259_S_MR);
110         }
111         restore_flags(flags);
112 }
113
114 static inline int mpc1211_irq_real(unsigned int irq)
115 {
116         int value;
117         int irqmask;
118
119         if ( irq < 8) {
120                 irqmask = 1<<irq;
121                 outb(0x0b,I8259_M_CR);          /* ISR register */
122                 value = inb(I8259_M_CR) & irqmask;
123                 outb(0x0a,I8259_M_CR);          /* back ro the IPR reg */
124                 return value;
125         }
126         irqmask = 1<<(irq - 8);
127         outb(0x0b,I8259_S_CR);          /* ISR register */
128         value = inb(I8259_S_CR) & irqmask;
129         outb(0x0a,I8259_S_CR);          /* back ro the IPR reg */
130         return value;
131 }
132
133 static void mask_and_ack_mpc1211(unsigned int irq)
134 {
135         unsigned long flags;
136
137         save_and_cli(flags);
138
139         if(irq < 8) {
140                 if(m_irq_mask & (1<<irq)){
141                   if(!mpc1211_irq_real(irq)){
142                     irq_err_count++;
143                     printk("spurious 8259A interrupt: IRQ %x\n",irq);
144                    }
145                 } else {
146                         m_irq_mask |= (1<<irq);
147                 }
148                 inb(I8259_M_MR);                /* DUMMY */
149                 outb(m_irq_mask,I8259_M_MR);    /* disable */
150                 outb(0x60+irq,I8259_M_CR);      /* EOI */
151                 
152         } else {
153                 if(s_irq_mask & (1<<(irq - 8))){
154                   if(!mpc1211_irq_real(irq)){
155                     irq_err_count++;
156                     printk("spurious 8259A interrupt: IRQ %x\n",irq);
157                   }
158                 } else {
159                         s_irq_mask |= (1<<(irq - 8));
160                 }
161                 inb(I8259_S_MR);                /* DUMMY */
162                 outb(s_irq_mask,I8259_S_MR);    /* disable */
163                 outb(0x60+(irq-8),I8259_S_CR);  /* EOI */
164                 outb(0x60+2,I8259_M_CR);
165         }
166         restore_flags(flags);
167 }
168
169 static void end_mpc1211_irq(unsigned int irq)
170 {
171         enable_mpc1211_irq(irq);
172 }
173
174 static unsigned int startup_mpc1211_irq(unsigned int irq)
175 {
176         enable_mpc1211_irq(irq);
177         return 0;
178 }
179
180 static void shutdown_mpc1211_irq(unsigned int irq)
181 {
182         disable_mpc1211_irq(irq);
183 }
184
185 static struct hw_interrupt_type mpc1211_irq_type = {
186         .typename       = "MPC1211-IRQ",
187         .startup        = startup_mpc1211_irq,
188         .shutdown       = shutdown_mpc1211_irq,
189         .enable         = enable_mpc1211_irq,
190         .disable        = disable_mpc1211_irq,
191         .ack            = mask_and_ack_mpc1211,
192         .end            = end_mpc1211_irq
193 };
194
195 static void make_mpc1211_irq(unsigned int irq)
196 {
197         irq_desc[irq].handler = &mpc1211_irq_type;
198         irq_desc[irq].status  = IRQ_DISABLED;
199         irq_desc[irq].action  = 0;
200         irq_desc[irq].depth   = 1;
201         disable_mpc1211_irq(irq);
202 }
203
204 int mpc1211_irq_demux(int irq)
205 {
206         unsigned int poll;
207
208         if( irq == 2 ) {
209                 outb(0x0c,I8259_M_CR);
210                 poll = inb(I8259_M_CR);
211                 if(poll & 0x80) {
212                         irq = (poll & 0x07);
213                 }
214                 if( irq == 2) {
215                         outb(0x0c,I8259_S_CR);
216                         poll = inb(I8259_S_CR);
217                         irq = (poll & 0x07) + 8;
218                 }
219         }
220         return irq;
221 }
222
223 void __init init_mpc1211_IRQ(void)
224 {
225         int i;
226         /*
227          * Super I/O (Just mimic PC):
228          *  1: keyboard
229          *  3: serial 1
230          *  4: serial 0
231          *  5: printer
232          *  6: floppy
233          *  8: rtc
234          * 10: lan
235          * 12: mouse
236          * 14: ide0
237          * 15: ide1
238          */
239
240         pci_write_config(0,0,0,0x54, 0xb0b0002d);
241         outb(0x11, I8259_M_CR);         /* mater icw1 edge trigger  */
242         outb(0x11, I8259_S_CR);         /* slave icw1 edge trigger  */
243         outb(0x20, I8259_M_MR);         /* m icw2 base vec 0x08     */
244         outb(0x28, I8259_S_MR);         /* s icw2 base vec 0x70     */
245         outb(0x04, I8259_M_MR);         /* m icw3 slave irq2        */
246         outb(0x02, I8259_S_MR);         /* s icw3 slave id          */
247         outb(0x01, I8259_M_MR);         /* m icw4 non buf normal eoi*/
248         outb(0x01, I8259_S_MR);         /* s icw4 non buf normal eo1*/
249         outb(0xfb, I8259_M_MR);         /* disable irq0--irq7  */
250         outb(0xff, I8259_S_MR);         /* disable irq8--irq15 */
251
252         for ( i=0; i < 16; i++) {
253                 if(i != 2) {
254                         make_mpc1211_irq(i);
255                 }
256         }
257 }
258
259 /*
260   Initialize the board
261 */
262
263
264 static void delay (void)
265 {
266         volatile unsigned short tmp;
267         tmp = *(volatile unsigned short *) 0xa0000000;
268 }
269
270 static void delay1000 (void)
271 {
272         int i;
273
274         for (i=0; i<1000; i++)
275                 delay ();
276 }
277
278 static int put_smb_blk(unsigned char *p, int address, int command, int no)
279 {
280         int temp;
281         int timeout;
282         int i;
283
284         outb(0xff, SMBHSTSTS);
285         temp = inb(SMBHSTSTS);
286         for (timeout = 0; (timeout < MAX_TIMEOUT) && !(temp & ALI15X3_STS_IDLE); timeout++) {
287                 delay1000();
288                 temp = inb(SMBHSTSTS);
289         }
290         if (timeout >= MAX_TIMEOUT){
291                 return -1;
292         }
293
294         outb(((address & 0x7f) << 1), SMBHSTADD);
295         outb(0xc0, SMBHSTCNT);
296         outb(command & 0xff, SMBHSTCMD);
297         outb(no & 0x1f, SMBHSTDAT0);
298
299         for(i = 1; i <= no; i++) {
300                 outb(*p++, SMBBLKDAT);
301         }
302         outb(0xff, SMBHSTSTART);
303
304         temp = inb(SMBHSTSTS);
305         for (timeout = 0; (timeout < MAX_TIMEOUT) && !(temp & (ALI15X3_STS_ERR | ALI15X3_STS_DONE)); timeout++) {
306                 delay1000();
307                 temp = inb(SMBHSTSTS);
308         }
309         if (timeout >= MAX_TIMEOUT) {
310                 return -2;
311         }
312         if ( temp & ALI15X3_STS_ERR ){
313                 return -3;
314         }
315         return 0;
316 }
317
318 /*
319  * The Machine Vector
320  */
321
322 struct sh_machine_vector mv_mpc1211 __initmv = {
323         .mv_nr_irqs             = 48,
324         .mv_irq_demux           = mpc1211_irq_demux,
325         .mv_init_irq            = init_mpc1211_IRQ,
326
327 #ifdef CONFIG_HEARTBEAT
328         .mv_heartbeat           = heartbeat_mpc1211,
329 #endif
330 };
331
332 ALIAS_MV(mpc1211)
333
334 /* arch/sh/boards/mpc1211/rtc.c */
335 void mpc1211_time_init(void);
336
337 int __init platform_setup(void)
338 {
339         unsigned char spd_buf[128];
340
341         __set_io_port_base(PA_PCI_IO);
342
343         pci_write_config(0,0,0,0x54, 0xb0b00000);
344
345         do {
346                 outb(ALI15X3_ABORT, SMBHSTCNT);
347                 spd_buf[0] = 0x0c;
348                 spd_buf[1] = 0x43;
349                 spd_buf[2] = 0x7f;
350                 spd_buf[3] = 0x03;
351                 spd_buf[4] = 0x00;
352                 spd_buf[5] = 0x03;
353                 spd_buf[6] = 0x00;
354         } while (put_smb_blk(spd_buf, 0x69, 0, 7) < 0);
355
356         board_time_init = mpc1211_time_init;
357
358         return 0;
359 }
360