Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / u-boot / board / mpl / common / isa.c
1 /*
2  * (C) Copyright 2001
3  * Denis Peter, MPL AG Switzerland
4  *
5  * SPDX-License-Identifier:     GPL-2.0+
6  *
7  * TODO: clean-up
8  */
9
10 #include <common.h>
11 #include <asm/processor.h>
12 #include <stdio_dev.h>
13 #include "isa.h"
14 #include "piix4_pci.h"
15 #include "kbd.h"
16 #include "video.h"
17
18
19 #undef  ISA_DEBUG
20
21 #ifdef  ISA_DEBUG
22 #define PRINTF(fmt,args...)     printf (fmt ,##args)
23 #else
24 #define PRINTF(fmt,args...)
25 #endif
26
27 #if defined(CONFIG_PIP405)
28
29 extern int drv_isa_kbd_init (void);
30
31 /* fdc (logical device 0) */
32 const SIO_LOGDEV_TABLE sio_fdc[] = {
33         {0x60, 3},                      /* set IO to FDPort (3F0) */
34         {0x61, 0xF0},           /* set IO to FDPort (3F0) */
35         {0x70, 06},                     /* set IRQ 6 for FDPort */
36         {0x74, 02},                     /* set DMA 2 for FDPort */
37         {0xF0, 0x05},           /* set to PS2 type */
38         {0xF1, 0x00},     /* default value */
39         {0x30, 1},                      /* and activate the device */
40         {0xFF, 0}                               /* end of device table */
41 };
42 /* paralell port (logical device 3) */
43 const SIO_LOGDEV_TABLE sio_pport[] = {
44         {0x60, 3},                      /* set IO to PPort (378) */
45         {0x61, 0x78},           /* set IO to PPort (378) */
46         {0x70, 07},                     /* set IRQ 7 for PPort */
47         {0xF1, 00},                     /* set PPort to normal */
48         {0x30, 1},                      /* and activate the device */
49         {0xFF, 0}                               /* end of device table */
50 };
51 /* paralell port (logical device 3) Floppy assigned to lpt */
52 const SIO_LOGDEV_TABLE sio_pport_fdc[] = {
53         {0x60, 3},                      /* set IO to PPort (378) */
54         {0x61, 0x78},           /* set IO to PPort (378) */
55         {0x70, 07},                     /* set IRQ 7 for PPort */
56         {0xF1, 02},                     /* set PPort to Floppy */
57         {0x30, 1},                      /* and activate the device */
58         {0xFF, 0}                               /* end of device table */
59 };
60 /* uart 1 (logical device 4) */
61 const SIO_LOGDEV_TABLE sio_com1[] = {
62         {0x60, 3},                      /* set IO to COM1 (3F8) */
63         {0x61, 0xF8},           /* set IO to COM1 (3F8) */
64         {0x70, 04},                     /* set IRQ 4 for COM1 */
65         {0x30, 1},                      /* and activate the device */
66         {0xFF, 0}                               /* end of device table */
67 };
68 /* uart 2 (logical device 5) */
69 const SIO_LOGDEV_TABLE sio_com2[] = {
70         {0x60, 2},                      /* set IO to COM2 (2F8) */
71         {0x61, 0xF8},           /* set IO to COM2 (2F8) */
72         {0x70, 03},                     /* set IRQ 3 for COM2 */
73         {0x30, 1},                      /* and activate the device */
74         {0xFF, 0}                               /* end of device table */
75 };
76
77 /* keyboard controller (logical device 7) */
78 const SIO_LOGDEV_TABLE sio_keyboard[] = {
79         {0x70, 1},                      /* set IRQ 1 for keyboard */
80         {0x72, 12},                     /* set IRQ 12 for mouse */
81         {0xF0, 0},                      /* disable Port92 (this is a PowerPC!!) */
82         {0x30, 1},                      /* and activate the device */
83         {0xFF, 0}                               /* end of device table */
84 };
85
86
87 /*******************************************************************************
88 * Config SuperIO FDC37C672
89 ********************************************************************************/
90 unsigned char open_cfg_super_IO(int address)
91 {
92         out8(CONFIG_SYS_ISA_IO_BASE_ADDRESS | address,0x55); /* open config */
93         out8(CONFIG_SYS_ISA_IO_BASE_ADDRESS | address,0x20); /* set address to DEV ID */
94         if(in8(CONFIG_SYS_ISA_IO_BASE_ADDRESS | address | 0x1)==0x40) /* ok Device ID is correct */
95                 return true;
96         else
97                 return false;
98 }
99
100 void close_cfg_super_IO(int address)
101 {
102         out8(CONFIG_SYS_ISA_IO_BASE_ADDRESS | address,0xAA); /* close config */
103 }
104
105
106 unsigned char read_cfg_super_IO(int address, unsigned char function, unsigned char regaddr)
107 {
108         /* assuming config reg is open */
109         out8(CONFIG_SYS_ISA_IO_BASE_ADDRESS | address,0x7); /* points to the function reg */
110         out8(CONFIG_SYS_ISA_IO_BASE_ADDRESS | address | 1,function); /* set the function no */
111         out8(CONFIG_SYS_ISA_IO_BASE_ADDRESS | address,regaddr); /* sets the address in the function */
112         return in8(CONFIG_SYS_ISA_IO_BASE_ADDRESS | address | 1);
113 }
114
115 void write_cfg_super_IO(int address, unsigned char function, unsigned char regaddr, unsigned char data)
116 {
117         /* assuming config reg is open */
118         out8(CONFIG_SYS_ISA_IO_BASE_ADDRESS | address,0x7); /* points to the function reg */
119         out8(CONFIG_SYS_ISA_IO_BASE_ADDRESS | address | 1,function); /* set the function no */
120         out8(CONFIG_SYS_ISA_IO_BASE_ADDRESS | address,regaddr); /* sets the address in the function */
121         out8(CONFIG_SYS_ISA_IO_BASE_ADDRESS | address | 1,data); /* writes the data */
122 }
123
124 void isa_write_table(SIO_LOGDEV_TABLE *ldt,unsigned char ldev)
125 {
126         while (ldt->index != 0xFF) {
127                 write_cfg_super_IO(SIO_CFG_PORT, ldev, ldt->index, ldt->val);
128                 ldt++;
129         } /* endwhile */
130 }
131
132 void isa_sio_loadtable(void)
133 {
134         char *s = getenv("floppy");
135         /* setup Floppy device 0*/
136         isa_write_table((SIO_LOGDEV_TABLE *)&sio_fdc,0);
137         /* setup parallel port device 3 */
138         if(s && !strncmp(s, "lpt", 3)) {
139                 printf("SIO:   Floppy assigned to LPT\n");
140                 /* floppy is assigned to the LPT */
141                 isa_write_table((SIO_LOGDEV_TABLE *)&sio_pport_fdc,3);
142         }
143         else {
144                 /*printf("Floppy assigned to internal port\n");*/
145                 isa_write_table((SIO_LOGDEV_TABLE *)&sio_pport,3);
146         }
147         /* setup Com1 port device 4 */
148         isa_write_table((SIO_LOGDEV_TABLE *)&sio_com1,4);
149         /* setup Com2 port device 5 */
150         isa_write_table((SIO_LOGDEV_TABLE *)&sio_com2,5);
151         /* setup keyboards device 7 */
152         isa_write_table((SIO_LOGDEV_TABLE *)&sio_keyboard,7);
153 }
154
155
156 void isa_sio_setup(void)
157 {
158         if (open_cfg_super_IO(SIO_CFG_PORT) == true)
159         {
160                 isa_sio_loadtable();
161                 close_cfg_super_IO(0x3F0);
162         }
163 }
164 #endif
165
166 /******************************************************************************
167  * IRQ Controller
168  * we use the Vector mode
169  */
170
171 struct  isa_irq_action {
172          interrupt_handler_t *handler;
173          void *arg;
174          int count;
175 };
176
177 static struct isa_irq_action isa_irqs[16];
178
179
180 /*
181  * This contains the irq mask for both 8259A irq controllers,
182  */
183 static unsigned int cached_irq_mask = 0xfff9;
184
185 #define cached_imr1     (unsigned char)cached_irq_mask
186 #define cached_imr2     (unsigned char)(cached_irq_mask>>8)
187 #define IMR_1           CONFIG_SYS_ISA_IO_BASE_ADDRESS + PIIX4_ISA_INT1_OCW1
188 #define IMR_2           CONFIG_SYS_ISA_IO_BASE_ADDRESS + PIIX4_ISA_INT2_OCW1
189 #define ICW1_1  CONFIG_SYS_ISA_IO_BASE_ADDRESS + PIIX4_ISA_INT1_ICW1
190 #define ICW1_2  CONFIG_SYS_ISA_IO_BASE_ADDRESS + PIIX4_ISA_INT2_ICW1
191 #define ICW2_1  CONFIG_SYS_ISA_IO_BASE_ADDRESS + PIIX4_ISA_INT1_ICW2
192 #define ICW2_2  CONFIG_SYS_ISA_IO_BASE_ADDRESS + PIIX4_ISA_INT2_ICW2
193 #define ICW3_1  ICW2_1
194 #define ICW3_2  ICW2_2
195 #define ICW4_1  ICW2_1
196 #define ICW4_2  ICW2_2
197 #define ISR_1           ICW1_1
198 #define ISR_2           ICW1_2
199
200
201 void disable_8259A_irq(unsigned int irq)
202 {
203         unsigned int mask = 1 << irq;
204
205         cached_irq_mask |= mask;
206         if (irq & 8)
207                 out8(IMR_2,cached_imr2);
208         else
209                 out8(IMR_1,cached_imr1);
210 }
211
212 void enable_8259A_irq(unsigned int irq)
213 {
214         unsigned int mask = ~(1 << irq);
215
216         cached_irq_mask &= mask;
217         if (irq & 8)
218                 out8(IMR_2,cached_imr2);
219         else
220                 out8(IMR_1,cached_imr1);
221 }
222 /*
223 int i8259A_irq_pending(unsigned int irq)
224 {
225         unsigned int mask = 1<<irq;
226         int ret;
227
228         if (irq < 8)
229                 ret = inb(0x20) & mask;
230         else
231                 ret = inb(0xA0) & (mask >> 8);
232         spin_unlock_irqrestore(&i8259A_lock, flags);
233
234         return ret;
235 }
236 */
237
238 /*
239  * This function assumes to be called rarely. Switching between
240  * 8259A registers is slow.
241  */
242 int i8259A_irq_real(unsigned int irq)
243 {
244         int value;
245         int irqmask = 1<<irq;
246
247         if (irq < 8) {
248                 out8(ISR_1,0x0B);               /* ISR register */
249                 value = in8(ISR_1) & irqmask;
250                 out8(ISR_1,0x0A);               /* back to the IRR register */
251                 return value;
252         }
253         out8(ISR_2,0x0B);               /* ISR register */
254         value = in8(ISR_2) & (irqmask >> 8);
255         out8(ISR_2,0x0A);               /* back to the IRR register */
256         return value;
257 }
258
259 /*
260  * Careful! The 8259A is a fragile beast, it pretty
261  * much _has_ to be done exactly like this (mask it
262  * first, _then_ send the EOI, and the order of EOI
263  * to the two 8259s is important!
264  */
265 void mask_and_ack_8259A(unsigned int irq)
266 {
267         unsigned int irqmask = 1 << irq;
268         unsigned int temp_irqmask = cached_irq_mask;
269         /*
270          * Lightweight spurious IRQ detection. We do not want
271          * to overdo spurious IRQ handling - it's usually a sign
272          * of hardware problems, so we only do the checks we can
273          * do without slowing down good hardware unnecesserily.
274          *
275          * Note that IRQ7 and IRQ15 (the two spurious IRQs
276          * usually resulting from the 8259A-1|2 PICs) occur
277          * even if the IRQ is masked in the 8259A. Thus we
278          * can check spurious 8259A IRQs without doing the
279          * quite slow i8259A_irq_real() call for every IRQ.
280          * This does not cover 100% of spurious interrupts,
281          * but should be enough to warn the user that there
282          * is something bad going on ...
283          */
284         if (temp_irqmask & irqmask)
285                 goto spurious_8259A_irq;
286         temp_irqmask |= irqmask;
287
288 handle_real_irq:
289         if (irq & 8) {
290                 in8(IMR_2);             /* DUMMY - (do we need this?) */
291                 out8(IMR_2,(unsigned char)(temp_irqmask>>8));
292                 out8(ISR_2,0x60+(irq&7));/* 'Specific EOI' to slave */
293                 out8(ISR_1,0x62);       /* 'Specific EOI' to master-IRQ2 */
294                 out8(IMR_2,cached_imr2); /* turn it on again */
295         } else {
296                 in8(IMR_1);             /* DUMMY - (do we need this?) */
297                 out8(IMR_1,(unsigned char)temp_irqmask);
298                 out8(ISR_1,0x60+irq);   /* 'Specific EOI' to master */
299                 out8(IMR_1,cached_imr1); /* turn it on again */
300         }
301
302         return;
303
304 spurious_8259A_irq:
305         /*
306          * this is the slow path - should happen rarely.
307          */
308         if (i8259A_irq_real(irq))
309                 /*
310                  * oops, the IRQ _is_ in service according to the
311                  * 8259A - not spurious, go handle it.
312                  */
313                 goto handle_real_irq;
314
315         {
316                 static int spurious_irq_mask;
317                 /*
318                  * At this point we can be sure the IRQ is spurious,
319                  * lets ACK and report it. [once per IRQ]
320                  */
321                 if (!(spurious_irq_mask & irqmask)) {
322                         PRINTF("spurious 8259A interrupt: IRQ%d.\n", irq);
323                         spurious_irq_mask |= irqmask;
324                 }
325                 /* irq_err_count++; */
326                 /*
327                  * Theoretically we do not have to handle this IRQ,
328                  * but in Linux this does not cause problems and is
329                  * simpler for us.
330                  */
331                 goto handle_real_irq;
332         }
333 }
334
335 void init_8259A(void)
336 {
337         out8(IMR_1,0xff);       /* mask all of 8259A-1 */
338         out8(IMR_2,0xff);       /* mask all of 8259A-2 */
339
340         out8(ICW1_1,0x11);      /* ICW1: select 8259A-1 init */
341         out8(ICW2_1,0x20 + 0);  /* ICW2: 8259A-1 IR0-7 mapped to 0x20-0x27 */
342         out8(ICW3_1,0x04);      /* 8259A-1 (the master) has a slave on IR2 */
343         out8(ICW4_1,0x01);      /* master expects normal EOI */
344         out8(ICW1_2,0x11);      /* ICW2: select 8259A-2 init */
345         out8(ICW2_2,0x20 + 8);  /* ICW2: 8259A-2 IR0-7 mapped to 0x28-0x2f */
346         out8(ICW3_2,0x02);      /* 8259A-2 is a slave on master's IR2 */
347         out8(ICW4_2,0x01);      /* (slave's support for AEOI in flat mode
348                                     is to be investigated) */
349         udelay(10000);          /* wait for 8259A to initialize */
350         out8(IMR_1,cached_imr1);        /* restore master IRQ mask */
351         udelay(10000);          /* wait for 8259A to initialize */
352         out8(IMR_2,cached_imr2);        /* restore slave IRQ mask */
353 }
354
355
356 #define PCI_INT_ACK_ADDR 0xEED00000
357
358 int handle_isa_int(void)
359 {
360         unsigned long irqack;
361         unsigned char irq;
362         /* first we acknokledge the int via the PCI bus */
363         irqack=in32(PCI_INT_ACK_ADDR);
364         /* now we get the ISRs */
365         in8(ISR_2);
366         in8(ISR_1);
367         irq=(unsigned char)irqack;
368         irq-=32;
369 /*      if((irq==7)&&((isr1&0x80)==0)) {
370                 PRINTF("IRQ7 detected but not in ISR\n");
371         }
372         else {
373 */              /* we should handle cascaded interrupts here also */
374         {
375 /*              printf("ISA Irq %d\n",irq); */
376                 isa_irqs[irq].count++;
377                 if(irq!=2) { /* just swallow the cascade irq 2 */
378                         if (isa_irqs[irq].handler != NULL)
379                                 (*isa_irqs[irq].handler)(isa_irqs[irq].arg);      /* call isr */
380                         else {
381                                 PRINTF ("bogus interrupt vector 0x%x\n", irq);
382                         }
383                 }
384         }
385         /* issue EOI instruction to clear the IRQ */
386         mask_and_ack_8259A(irq);
387         return 0;
388 }
389
390
391 /******************************************************************
392  * Install and free an ISA interrupt handler.
393  */
394
395 void isa_irq_install_handler(int vec, interrupt_handler_t *handler, void *arg)
396 {
397         if (isa_irqs[vec].handler != NULL) {
398                 printf ("ISA Interrupt vector %d: handler 0x%x replacing 0x%x\n",
399                         vec, (uint)handler, (uint)isa_irqs[vec].handler);
400         }
401         isa_irqs[vec].handler = handler;
402         isa_irqs[vec].arg     = arg;
403         enable_8259A_irq(vec);
404         PRINTF ("Install ISA IRQ %d ==> %p, @ %p mask=%04x\n", vec, handler, &isa_irqs[vec].handler,cached_irq_mask);
405
406 }
407
408 void isa_irq_free_handler(int vec)
409 {
410         disable_8259A_irq(vec);
411         isa_irqs[vec].handler = NULL;
412         isa_irqs[vec].arg     = NULL;
413         PRINTF ("Free ISA IRQ %d mask=%04x\n", vec, cached_irq_mask);
414
415 }
416
417 /****************************************************************************/
418 void isa_init_irq_contr(void)
419 {
420         int i;
421         /* disable all Interrupts */
422         /* first write icws controller 1 */
423         for(i=0;i<16;i++)
424         {
425                 isa_irqs[i].handler=NULL;
426                 isa_irqs[i].arg=NULL;
427                 isa_irqs[i].count=0;
428         }
429         init_8259A();
430         out8(IMR_2,0xFF);
431 }
432 /*************************************************************************/
433
434 void isa_show_irq(void)
435 {
436         int vec;
437
438         printf ("\nISA Interrupt-Information:\n");
439         printf ("Nr  Routine   Arg       Count\n");
440
441         for (vec=0; vec<16; vec++) {
442                 if (isa_irqs[vec].handler != NULL) {
443                         printf ("%02d  %08lx  %08lx  %d\n",
444                                 vec,
445                                 (ulong)isa_irqs[vec].handler,
446                                 (ulong)isa_irqs[vec].arg,
447                                 isa_irqs[vec].count);
448                 }
449         }
450 }
451
452 int isa_irq_get_count(int vec)
453 {
454         return(isa_irqs[vec].count);
455 }
456
457 /******************************************************************
458  * Init the ISA bus and devices.
459  */
460
461 #if defined(CONFIG_PIP405)
462
463 int isa_init(void)
464 {
465         isa_sio_setup();
466         isa_init_irq_contr();
467         drv_isa_kbd_init();
468         return 0;
469 }
470 #endif