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