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