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