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