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