isa_shark_machdep.c revision 1.1.14.2 1 /* $NetBSD: isa_shark_machdep.c,v 1.1.14.2 2002/06/23 17:41:22 jdolecek Exp $ */
2
3 /*
4 * Copyright 1997
5 * Digital Equipment Corporation. All rights reserved.
6 *
7 * This software is furnished under license and may be used and
8 * copied only in accordance with the following terms and conditions.
9 * Subject to these conditions, you may download, copy, install,
10 * use, modify and distribute this software in source and/or binary
11 * form. No title or ownership is transferred hereby.
12 *
13 * 1) Any source code used, modified or distributed must reproduce
14 * and retain this copyright notice and list of conditions as
15 * they appear in the source file.
16 *
17 * 2) No right is granted to use any trade name, trademark, or logo of
18 * Digital Equipment Corporation. Neither the "Digital Equipment
19 * Corporation" name nor any trademark or logo of Digital Equipment
20 * Corporation may be used to endorse or promote products derived
21 * from this software without the prior written permission of
22 * Digital Equipment Corporation.
23 *
24 * 3) This software is provided "AS-IS" and any express or implied
25 * warranties, including but not limited to, any implied warranties
26 * of merchantability, fitness for a particular purpose, or
27 * non-infringement are disclaimed. In no event shall DIGITAL be
28 * liable for any damages whatsoever, and in particular, DIGITAL
29 * shall not be liable for special, indirect, consequential, or
30 * incidental damages or damages for lost profits, loss of
31 * revenue or loss of use, whether such damages arise in contract,
32 * negligence, tort, under statute, in equity, at law or otherwise,
33 * even if advised of the possibility of such damage.
34 */
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/syslog.h>
40 #include <sys/device.h>
41 #include <sys/malloc.h>
42
43 #include <machine/intr.h>
44 #include <machine/pio.h>
45
46 #include <dev/isa/isareg.h>
47 #include <dev/isa/isavar.h>
48 #include <dev/isa/isadmavar.h>
49 #include <shark/isa/icu.h>
50
51 #include <machine/ofw.h>
52
53 struct arm32_isa_chipset isa_chipset_tag;
54
55 unsigned i8259_mask;
56
57 /* Notes on the interaction of StrongARM and ISA. A lot of the nastiness
58 is caused by consciously prostituting shark to a low bill of materials.
59
60 It takes on the order of 700ns (about 150 instruction cycles at
61 233 MHz) to access the ISA bus, so it is important to minimize the number
62 of ISA accesses, in particular to the 8259 interrupt controllers.
63
64 To reduce the number of accesses, the 8259's are NOT run in the
65 same mode as on a typical Intel (IBM AT) system, which requires
66 an interrupt acknowledge sequence (INTA) for every interrupt.
67 Instead, the 8259's are used as big OR gates with interrupt masks
68 on the front. The code in irq.S takes particular care to cache
69 the state of the interrupt masks and only update them when absolutely
70 necessary.
71
72 Unfortunately, resetting the 8259 edge detectors without a real
73 INTA sequence is problematic at best. To complicate matters further,
74 (unlike EISA components) the 8259s on the Sequoia core logic do
75 not allow configuration of edge vs. level on an IRQ-by-IRQ basis.
76 Thus, all interrupts must be either edge-triggered or level-triggered.
77 To preserve the sanity of the system, this code chooses the
78 level-triggered configuration.
79
80 None of the possible operation modes of the 8254 interval timers can
81 be used to generate a periodic, level-triggered, clearable clock
82 interrupt. This restriction means that TIMER0 -- hardwired to IRQ0 --
83 may not be used as the heartbeat timer, as it is on Intel-based PCs.
84 Instead, the real-time clock (RTC) interrupt -- connected to
85 IRQ8 -- has the right properties and is used for the heartbeat interrupt.
86 TIMER0 may still be used to implement a microsecond timer.
87 See clock.c for details.
88
89 As on most PC systems, 8254 TIMER1 is used for the ISA refresh signal.
90
91 Unlike most PC systems, 8254 TIMER2 is not used for cheap tone
92 generation. Instead, it is used to create a high-availability interrupt
93 for bit-bashing functions (e.g. for SmartCard access). TIMER2 output,
94 called "SPKR" on Sequoia 2, is routed back into the SWTCH input on
95 Sequoia 1. This input eventually reemerges from Sequoia 1 on the SMI pin,
96 which is then converted into the StrongARM FIQ (fast interrupt request).
97 To clear this interrupt, the StrongARM clears the SMI.
98 See .../shark/fiq.S for details.
99
100 One more complication: ISA devices can be rather nasty with respect
101 to ISA bus usage. For example, the CS8900 ethernet chip will occupy
102 the bus for very long DMA streams. It is possible to configure the
103 chip so it relinquishes the ISA bus every 28 usec or so
104 (about every 6500 instructions). This causes problems when trying
105 to run the TIMER2/SMI/FIQ at 50 kHz, which is required to detect the
106 baud rate of the SmartCard. A modification to .../dev/isa/isadma.c
107 allows the processor to freeze DMA during critial periods of time.
108 This is a working -- but not very satisfactory -- solution to the problem.
109 */
110
111 /*
112 * Initialize the interrupt controllers.
113 */
114 void
115 isa_init8259s()
116 {
117 /* initialize 8259's */
118 outb(IO_ICU1, 0x19); /* reset; four bytes, level triggered */
119 outb(IO_ICU1+1, ICU_OFFSET); /* int base: not used */
120 outb(IO_ICU1+1, 1 << IRQ_SLAVE); /* slave on line 2 */
121 outb(IO_ICU1+1, 2 | 1); /* auto EOI, 8086 mode */
122 outb(IO_ICU1+1, 0xff); /* disable all interrupts */
123 outb(IO_ICU1, 0x68); /* special mask mode (if available) */
124 outb(IO_ICU1, 0x0a); /* Read IRR, not ISR */
125
126 outb(IO_ICU2, 0x19); /* reset; four bytes, level triggered */
127 outb(IO_ICU2+1, ICU_OFFSET+8); /* int base + offset for master: not used */
128 outb(IO_ICU2+1, IRQ_SLAVE); /* who ami i? */
129 outb(IO_ICU2+1, 2 | 1); /* auto EOI, 8086 mode */
130 outb(IO_ICU2+1, 0xff); /* disable all interrupts */
131 outb(IO_ICU2, 0x68); /* special mask mode (if available) */
132 outb(IO_ICU2, 0x0a); /* Read IRR by default. */
133
134 i8259_mask = 0x0000ffff; /* everything disabled */
135 }
136
137 #define LEGAL_IRQ(x) ((x) >= 0 && (x) < ICU_LEN && (x) != 2)
138
139 const struct evcnt *
140 isa_intr_evcnt(isa_chipset_tag_t ic, int irq)
141 {
142
143 /* XXX for now, no evcnt parent reported */
144 return NULL;
145 }
146
147 /*
148 * Set up an interrupt handler to start being called.
149 */
150 void *
151 isa_intr_establish(ic, irq, type, level, ih_fun, ih_arg)
152 isa_chipset_tag_t ic;
153 int irq;
154 int type;
155 int level;
156 int (*ih_fun) __P((void *));
157 void *ih_arg;
158 {
159 irqhandler_t *ih;
160
161 /* no point in sleeping unless someone can free memory. */
162 ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
163 if (ih == NULL)
164 panic("isa_intr_establish: can't malloc handler info");
165
166 if (!LEGAL_IRQ(irq) || type == IST_NONE)
167 panic("intr_establish: bogus irq or type");
168
169 /* Note: sequoia doesn't allow configuration of edge vs. level
170 on an IRQ-by-IRQ basis. */
171 if (type != IST_LEVEL)
172 printf("WARNING: irq %d not level triggered\n", irq);
173
174 memset(ih, 0, sizeof *ih);
175 ih->ih_func = ih_fun;
176 ih->ih_arg = ih_arg;
177 ih->ih_level = level;
178 ih->ih_name = "isa intr";
179
180 if (irq_claim(irq, ih) == -1)
181 panic("isa_intr_establish: can't install handler");
182
183 return (ih);
184 }
185
186
187 /*
188 * Deregister an interrupt handler.
189 */
190 void
191 isa_intr_disestablish(ic, arg)
192 isa_chipset_tag_t ic;
193 void *arg;
194 {
195 panic("isa_intr_disestablish");
196 }
197
198 /* isa_init() might eventually become the ISA attach routine */
199 void
200 isa_init(vm_offset_t isa_io_addr, vm_offset_t isa_mem_addr)
201 {
202 /* initialize the bus space functions */
203 isa_io_init(isa_io_addr, isa_mem_addr);
204
205 /* Clear the IRQ/FIQ masks */
206 isa_init8259s();
207
208 /* Initialize the ISA interrupt handling code */
209 irq_init();
210 }
211
212 void
213 isa_attach_hook(parent, self, iba)
214 struct device *parent, *self;
215 struct isabus_attach_args *iba;
216 {
217
218 /*
219 * Since we can only have one ISA bus, we just use a single
220 * statically allocated ISA chipset structure. Pass it up
221 * now.
222 */
223 iba->iba_ic = &isa_chipset_tag;
224 }
225