xref: /netbsd/sys/arch/shark/isa/isa_shark_machdep.c (revision bf9ec67e)
1 /*	$NetBSD: isa_shark_machdep.c,v 1.1 2002/02/10 01:57:55 thorpej 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