Home | History | Annotate | Line # | Download | only in sbus
stp4020.c revision 1.66.12.2
      1  1.66.12.2  jdolecek /*	$NetBSD: stp4020.c,v 1.66.12.2 2017/12/03 11:37:32 jdolecek Exp $ */
      2        1.1        pk 
      3        1.1        pk /*-
      4        1.1        pk  * Copyright (c) 1998 The NetBSD Foundation, Inc.
      5        1.1        pk  * All rights reserved.
      6        1.1        pk  *
      7        1.1        pk  * This code is derived from software contributed to The NetBSD Foundation
      8        1.1        pk  * by Paul Kranenburg.
      9        1.1        pk  *
     10        1.1        pk  * Redistribution and use in source and binary forms, with or without
     11        1.1        pk  * modification, are permitted provided that the following conditions
     12        1.1        pk  * are met:
     13        1.1        pk  * 1. Redistributions of source code must retain the above copyright
     14        1.1        pk  *    notice, this list of conditions and the following disclaimer.
     15        1.1        pk  * 2. Redistributions in binary form must reproduce the above copyright
     16        1.1        pk  *    notice, this list of conditions and the following disclaimer in the
     17        1.1        pk  *    documentation and/or other materials provided with the distribution.
     18        1.1        pk  *
     19        1.1        pk  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20        1.1        pk  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21        1.1        pk  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22        1.1        pk  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23        1.1        pk  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24        1.1        pk  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25        1.1        pk  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26        1.1        pk  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27        1.1        pk  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28        1.1        pk  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29        1.1        pk  * POSSIBILITY OF SUCH DAMAGE.
     30        1.1        pk  */
     31        1.1        pk 
     32        1.1        pk /*
     33        1.1        pk  * STP4020: SBus/PCMCIA bridge supporting two Type-3 PCMCIA cards.
     34        1.1        pk  */
     35       1.12     lukem 
     36       1.12     lukem #include <sys/cdefs.h>
     37  1.66.12.2  jdolecek __KERNEL_RCSID(0, "$NetBSD: stp4020.c,v 1.66.12.2 2017/12/03 11:37:32 jdolecek Exp $");
     38        1.1        pk 
     39        1.1        pk #include <sys/param.h>
     40        1.1        pk #include <sys/systm.h>
     41        1.1        pk #include <sys/errno.h>
     42        1.1        pk #include <sys/malloc.h>
     43       1.15    martin #include <sys/extent.h>
     44        1.1        pk #include <sys/proc.h>
     45        1.1        pk #include <sys/kernel.h>
     46        1.1        pk #include <sys/kthread.h>
     47        1.1        pk #include <sys/device.h>
     48       1.51        ad #include <sys/intr.h>
     49        1.1        pk 
     50        1.1        pk #include <dev/pcmcia/pcmciareg.h>
     51        1.1        pk #include <dev/pcmcia/pcmciavar.h>
     52        1.1        pk #include <dev/pcmcia/pcmciachip.h>
     53        1.1        pk 
     54       1.52        ad #include <sys/bus.h>
     55        1.1        pk 
     56        1.1        pk #include <dev/sbus/sbusvar.h>
     57        1.1        pk #include <dev/sbus/stp4020reg.h>
     58        1.1        pk 
     59        1.1        pk #define STP4020_DEBUG 1	/* XXX-temp */
     60        1.1        pk 
     61       1.15    martin /*
     62       1.15    martin  * We use the three available windows per socket in a simple, fixed
     63       1.15    martin  * arrangement. Each window maps (at full 1 MB size) one of the pcmcia
     64       1.15    martin  * spaces into sbus space.
     65       1.15    martin  */
     66       1.15    martin #define STP_WIN_ATTR	0	/* index of the attribute memory space window */
     67       1.15    martin #define	STP_WIN_MEM	1	/* index of the common memory space window */
     68       1.15    martin #define	STP_WIN_IO	2	/* index of the io space window */
     69       1.15    martin 
     70       1.15    martin 
     71        1.1        pk #if defined(STP4020_DEBUG)
     72        1.1        pk int stp4020_debug = 0;
     73        1.1        pk #define DPRINTF(x)	do { if (stp4020_debug) printf x; } while(0)
     74        1.1        pk #else
     75        1.1        pk #define DPRINTF(x)
     76        1.1        pk #endif
     77        1.1        pk 
     78        1.1        pk /*
     79        1.1        pk  * Event queue; events detected in an interrupt context go here
     80        1.1        pk  * awaiting attention from our event handling thread.
     81        1.1        pk  */
     82        1.1        pk struct stp4020_event {
     83        1.1        pk 	SIMPLEQ_ENTRY(stp4020_event) se_q;
     84        1.1        pk 	int	se_type;
     85        1.1        pk 	int	se_sock;
     86        1.1        pk };
     87        1.1        pk /* Defined event types */
     88        1.1        pk #define STP4020_EVENT_INSERTION	0
     89        1.1        pk #define STP4020_EVENT_REMOVAL	1
     90        1.1        pk 
     91        1.1        pk /*
     92        1.1        pk  * Per socket data.
     93        1.1        pk  */
     94        1.1        pk struct stp4020_socket {
     95        1.1        pk 	struct stp4020_softc	*sc;	/* Back link */
     96        1.1        pk 	int		flags;
     97        1.1        pk #define STP4020_SOCKET_BUSY	0x0001
     98        1.1        pk 	int		sock;		/* Socket number (0 or 1) */
     99       1.28    martin 	int		sbus_intno;	/* Do we use first (0) or second (1)
    100       1.28    martin 					   interrupt? */
    101       1.53    martin #ifndef SUN4U
    102       1.31    martin 	int		int_enable;	/* ICR0 value for interrupt enabled */
    103       1.31    martin 	int		int_disable;	/* ICR0 value for interrupt disabled */
    104       1.53    martin #endif
    105       1.33    martin 	bus_space_tag_t	tag;		/* socket control io	*/
    106       1.33    martin 	bus_space_handle_t	regs;	/*  space		*/
    107       1.33    martin 	bus_space_tag_t	pcmciat;	/* io space for pcmcia  */
    108  1.66.12.1       tls 	device_t	pcmcia;		/* Associated PCMCIA device */
    109        1.1        pk 	int		(*intrhandler)	/* Card driver interrupt handler */
    110       1.42     perry 			   (void *);
    111        1.1        pk 	void		*intrarg;	/* Card interrupt handler argument */
    112       1.53    martin #ifndef SUN4U
    113       1.31    martin 	void		*softint;	/* cookie for the softintr */
    114       1.53    martin #endif
    115       1.31    martin 
    116        1.1        pk 	struct {
    117        1.1        pk 		bus_space_handle_t	winaddr;/* this window's address */
    118        1.1        pk 	} windows[STP4020_NWIN];
    119        1.1        pk 
    120        1.1        pk };
    121        1.1        pk 
    122        1.1        pk struct stp4020_softc {
    123       1.65       mrg 	device_t		sc_dev;
    124        1.1        pk 	pcmcia_chipset_tag_t	sc_pct;	/* Chipset methods */
    125        1.1        pk 
    126       1.50        ad 	struct lwp	*event_thread;		/* event handling thread */
    127        1.1        pk 	SIMPLEQ_HEAD(, stp4020_event)	events;	/* Pending events for thread */
    128        1.1        pk 
    129        1.1        pk 	struct stp4020_socket sc_socks[STP4020_NSOCK];
    130       1.53    martin #ifndef SUN4U
    131       1.53    martin 	bool		sc_use_softint;
    132       1.53    martin #endif
    133        1.1        pk };
    134        1.1        pk 
    135        1.1        pk 
    136       1.42     perry static int	stp4020print(void *, const char *);
    137       1.61    cegger static int	stp4020match(device_t, cfdata_t, void *);
    138       1.61    cegger static void	stp4020attach(device_t, device_t, void *);
    139       1.42     perry static int	stp4020_intr(void *);
    140       1.16    martin static void	stp4020_map_window(struct stp4020_socket *h, int win, int speed);
    141       1.44       jdc static void	stp4020_calc_speed(int bus_speed, int ns, int *length, int *cmd_delay);
    142       1.53    martin #ifndef SUN4U
    143       1.31    martin static void	stp4020_intr_dispatch(void *arg);
    144       1.53    martin #endif
    145        1.1        pk 
    146       1.65       mrg CFATTACH_DECL_NEW(nell, sizeof(struct stp4020_softc),
    147       1.27   thorpej     stp4020match, stp4020attach, NULL, NULL);
    148        1.1        pk 
    149        1.6        pk #ifdef STP4020_DEBUG
    150       1.42     perry static void	stp4020_dump_regs(struct stp4020_socket *);
    151        1.6        pk #endif
    152        1.1        pk 
    153       1.42     perry static int	stp4020_rd_sockctl(struct stp4020_socket *, int);
    154       1.42     perry static void	stp4020_wr_sockctl(struct stp4020_socket *, int, int);
    155       1.42     perry static void	stp4020_wr_winctl(struct stp4020_socket *, int, int, int);
    156       1.42     perry 
    157       1.46    martin void	stp4020_delay(struct stp4020_softc *sc, unsigned int);
    158       1.42     perry void	stp4020_attach_socket(struct stp4020_socket *, int);
    159       1.42     perry void	stp4020_event_thread(void *);
    160       1.42     perry void	stp4020_queue_event(struct stp4020_softc *, int, int);
    161       1.42     perry 
    162       1.42     perry int	stp4020_chip_mem_alloc(pcmcia_chipset_handle_t, bus_size_t,
    163       1.42     perry 				    struct pcmcia_mem_handle *);
    164       1.42     perry void	stp4020_chip_mem_free(pcmcia_chipset_handle_t,
    165       1.42     perry 				   struct pcmcia_mem_handle *);
    166       1.42     perry int	stp4020_chip_mem_map(pcmcia_chipset_handle_t, int, bus_addr_t,
    167        1.1        pk 				  bus_size_t, struct pcmcia_mem_handle *,
    168       1.42     perry 				  bus_size_t *, int *);
    169       1.42     perry void	stp4020_chip_mem_unmap(pcmcia_chipset_handle_t, int);
    170        1.1        pk 
    171       1.42     perry int	stp4020_chip_io_alloc(pcmcia_chipset_handle_t,
    172        1.1        pk 				   bus_addr_t, bus_size_t, bus_size_t,
    173       1.42     perry 				   struct pcmcia_io_handle *);
    174       1.42     perry void	stp4020_chip_io_free(pcmcia_chipset_handle_t,
    175       1.42     perry 				  struct pcmcia_io_handle *);
    176       1.42     perry int	stp4020_chip_io_map(pcmcia_chipset_handle_t, int, bus_addr_t,
    177       1.42     perry 				 bus_size_t, struct pcmcia_io_handle *, int *);
    178       1.42     perry void	stp4020_chip_io_unmap(pcmcia_chipset_handle_t, int);
    179       1.42     perry 
    180       1.42     perry void	stp4020_chip_socket_enable(pcmcia_chipset_handle_t);
    181       1.42     perry void	stp4020_chip_socket_disable(pcmcia_chipset_handle_t);
    182       1.42     perry void	stp4020_chip_socket_settype(pcmcia_chipset_handle_t, int);
    183       1.42     perry void	*stp4020_chip_intr_establish(pcmcia_chipset_handle_t,
    184        1.1        pk 					  struct pcmcia_function *, int,
    185       1.42     perry 					  int (*)(void *), void *);
    186       1.42     perry void	stp4020_chip_intr_disestablish(pcmcia_chipset_handle_t, void *);
    187        1.1        pk 
    188        1.1        pk /* Our PCMCIA chipset methods */
    189        1.1        pk static struct pcmcia_chip_functions stp4020_functions = {
    190        1.1        pk 	stp4020_chip_mem_alloc,
    191        1.1        pk 	stp4020_chip_mem_free,
    192        1.1        pk 	stp4020_chip_mem_map,
    193        1.1        pk 	stp4020_chip_mem_unmap,
    194        1.1        pk 
    195        1.1        pk 	stp4020_chip_io_alloc,
    196        1.1        pk 	stp4020_chip_io_free,
    197        1.1        pk 	stp4020_chip_io_map,
    198        1.1        pk 	stp4020_chip_io_unmap,
    199        1.1        pk 
    200        1.1        pk 	stp4020_chip_intr_establish,
    201        1.1        pk 	stp4020_chip_intr_disestablish,
    202        1.1        pk 
    203        1.1        pk 	stp4020_chip_socket_enable,
    204       1.39   mycroft 	stp4020_chip_socket_disable,
    205       1.39   mycroft 	stp4020_chip_socket_settype,
    206       1.49       jdc 	NULL
    207        1.1        pk };
    208        1.1        pk 
    209        1.1        pk 
    210       1.47     perry static inline int
    211       1.57       dsl stp4020_rd_sockctl(struct stp4020_socket *h, int idx)
    212        1.1        pk {
    213        1.1        pk 	int o = ((STP4020_SOCKREGS_SIZE * (h->sock)) + idx);
    214        1.1        pk 	return (bus_space_read_2(h->tag, h->regs, o));
    215        1.1        pk }
    216        1.1        pk 
    217       1.47     perry static inline void
    218       1.57       dsl stp4020_wr_sockctl(struct stp4020_socket *h, int idx, int v)
    219        1.1        pk {
    220        1.1        pk 	int o = (STP4020_SOCKREGS_SIZE * (h->sock)) + idx;
    221        1.1        pk 	bus_space_write_2(h->tag, h->regs, o, v);
    222        1.1        pk }
    223        1.1        pk 
    224       1.47     perry static inline void
    225       1.57       dsl stp4020_wr_winctl(struct stp4020_socket *h, int win, int idx, int v)
    226        1.1        pk {
    227        1.1        pk 	int o = (STP4020_SOCKREGS_SIZE * (h->sock)) +
    228        1.1        pk 		(STP4020_WINREGS_SIZE * win) + idx;
    229        1.1        pk 
    230        1.1        pk 	bus_space_write_2(h->tag, h->regs, o, v);
    231        1.1        pk }
    232        1.1        pk 
    233       1.33    martin #ifndef SUN4U	/* XXX - move to SBUS machdep function? */
    234       1.33    martin 
    235       1.64   tsutsui static	uint16_t stp4020_read_2(bus_space_tag_t,
    236       1.64   tsutsui 				bus_space_handle_t,
    237       1.64   tsutsui 				bus_size_t);
    238       1.64   tsutsui static	uint32_t stp4020_read_4(bus_space_tag_t,
    239       1.64   tsutsui 				bus_space_handle_t,
    240       1.64   tsutsui 				bus_size_t);
    241       1.64   tsutsui static	uint64_t stp4020_read_8(bus_space_tag_t,
    242       1.64   tsutsui 				bus_space_handle_t,
    243       1.64   tsutsui 				bus_size_t);
    244       1.32       mrg static	void	stp4020_write_2(bus_space_tag_t,
    245       1.32       mrg 				bus_space_handle_t,
    246       1.32       mrg 				bus_size_t,
    247       1.64   tsutsui 				uint16_t);
    248       1.32       mrg static	void	stp4020_write_4(bus_space_tag_t,
    249       1.32       mrg 				bus_space_handle_t,
    250       1.32       mrg 				bus_size_t,
    251       1.64   tsutsui 				uint32_t);
    252       1.32       mrg static	void	stp4020_write_8(bus_space_tag_t,
    253       1.32       mrg 				bus_space_handle_t,
    254       1.32       mrg 				bus_size_t,
    255       1.64   tsutsui 				uint64_t);
    256       1.32       mrg 
    257       1.64   tsutsui static uint16_t
    258       1.57       dsl stp4020_read_2(bus_space_tag_t space, bus_space_handle_t handle, bus_size_t offset)
    259       1.32       mrg {
    260       1.64   tsutsui 	return (le16toh(*(volatile uint16_t *)(handle + offset)));
    261       1.32       mrg }
    262       1.32       mrg 
    263       1.64   tsutsui static uint32_t
    264       1.57       dsl stp4020_read_4(bus_space_tag_t space, bus_space_handle_t handle, bus_size_t offset)
    265       1.32       mrg {
    266       1.64   tsutsui 	return (le32toh(*(volatile uint32_t *)(handle + offset)));
    267       1.32       mrg }
    268       1.32       mrg 
    269       1.64   tsutsui static uint64_t
    270       1.57       dsl stp4020_read_8(bus_space_tag_t space, bus_space_handle_t handle, bus_size_t offset)
    271       1.32       mrg {
    272       1.64   tsutsui 	return (le64toh(*(volatile uint64_t *)(handle + offset)));
    273       1.32       mrg }
    274       1.32       mrg 
    275       1.32       mrg static void
    276       1.64   tsutsui stp4020_write_2(bus_space_tag_t space, bus_space_handle_t handle, bus_size_t offset, uint16_t value)
    277       1.32       mrg {
    278       1.64   tsutsui 	(*(volatile uint16_t *)(handle + offset)) = htole16(value);
    279       1.32       mrg }
    280       1.32       mrg 
    281       1.32       mrg static void
    282       1.64   tsutsui stp4020_write_4(bus_space_tag_t space, bus_space_handle_t handle, bus_size_t offset, uint32_t value)
    283       1.32       mrg {
    284       1.64   tsutsui 	(*(volatile uint32_t *)(handle + offset)) = htole32(value);
    285       1.32       mrg }
    286       1.32       mrg 
    287       1.32       mrg static void
    288       1.64   tsutsui stp4020_write_8(bus_space_tag_t space, bus_space_handle_t handle, bus_size_t offset, uint64_t value)
    289       1.32       mrg {
    290       1.64   tsutsui 	(*(volatile uint64_t *)(handle + offset)) = htole64(value);
    291       1.32       mrg }
    292       1.33    martin #endif	/* SUN4U */
    293        1.1        pk 
    294        1.1        pk int
    295       1.57       dsl stp4020print(void *aux, const char *busname)
    296        1.1        pk {
    297        1.4        pk 	struct pcmciabus_attach_args *paa = aux;
    298        1.3        pk 	struct stp4020_socket *h = paa->pch;
    299        1.3        pk 
    300       1.30   thorpej 	aprint_normal(" socket %d", h->sock);
    301        1.1        pk 	return (UNCONF);
    302        1.1        pk }
    303        1.1        pk 
    304        1.1        pk int
    305       1.61    cegger stp4020match(device_t parent, cfdata_t cf, void *aux)
    306        1.1        pk {
    307        1.1        pk 	struct sbus_attach_args *sa = aux;
    308        1.1        pk 
    309        1.2        pk 	return (strcmp("SUNW,pcmcia", sa->sa_name) == 0);
    310        1.1        pk }
    311        1.1        pk 
    312        1.1        pk /*
    313        1.1        pk  * Attach all the sub-devices we can find
    314        1.1        pk  */
    315        1.1        pk void
    316       1.61    cegger stp4020attach(device_t parent, device_t self, void *aux)
    317        1.1        pk {
    318        1.1        pk 	struct sbus_attach_args *sa = aux;
    319       1.63   tsutsui 	struct stp4020_softc *sc = device_private(self);
    320       1.32       mrg 	bus_space_tag_t tag;
    321       1.53    martin 	int rev, i, sbus_intno, hw_ipl;
    322        1.1        pk 	bus_space_handle_t bh;
    323        1.1        pk 
    324       1.65       mrg 	sc->sc_dev = self;
    325       1.65       mrg 
    326        1.1        pk 	/* Transfer bus tags */
    327       1.37    martin #ifdef SUN4U
    328       1.37    martin 	tag = sa->sa_bustag;
    329       1.37    martin #else
    330       1.38        pk 	tag = bus_space_tag_alloc(sa->sa_bustag, sc);
    331       1.38        pk 	if (tag == NULL) {
    332       1.54    cegger 		aprint_error_dev(self, "attach: out of memory\n");
    333       1.38        pk 		return;
    334       1.38        pk 	}
    335       1.32       mrg 	tag->sparc_read_2 = stp4020_read_2;
    336       1.32       mrg 	tag->sparc_read_4 = stp4020_read_4;
    337       1.32       mrg 	tag->sparc_read_8 = stp4020_read_8;
    338       1.32       mrg 	tag->sparc_write_2 = stp4020_write_2;
    339       1.32       mrg 	tag->sparc_write_4 = stp4020_write_4;
    340       1.32       mrg 	tag->sparc_write_8 = stp4020_write_8;
    341       1.38        pk #endif	/* SUN4U */
    342        1.1        pk 
    343       1.53    martin 	/* check interrupt options, decide if we need a softint */
    344       1.53    martin #ifdef SUN4U
    345       1.53    martin 	/*
    346       1.53    martin 	 * On sparc64 the hardware interrupt priority does not restrict
    347       1.53    martin 	 * the IPL we run our interrupt handler on, so we can always just
    348       1.53    martin 	 * use the first interrupt and reqest the handler to run at
    349       1.53    martin 	 * IPL_VM.
    350       1.53    martin 	 */
    351       1.53    martin 	sbus_intno = 0;
    352       1.53    martin 	hw_ipl = IPL_VM;
    353       1.53    martin #else
    354       1.53    martin 	/*
    355       1.53    martin 	 * We need to check if one of the available interrupts has
    356       1.53    martin 	 * a priority that allows us to establish a handler at IPL_VM.
    357       1.53    martin 	 * If not (hard to imagine), use a soft interrupt.
    358       1.53    martin 	 */
    359       1.53    martin 	sbus_intno = -1;
    360       1.53    martin 	for (i = 0; i < sa->sa_nintr; i++) {
    361       1.53    martin 		struct sbus_softc *bus =
    362       1.53    martin 			(struct sbus_softc *) sa->sa_bustag->cookie;
    363       1.53    martin 		int ipl = bus->sc_intr2ipl[sa->sa_intr[i].oi_pri];
    364       1.53    martin 		if (ipl <= IPL_VM) {
    365       1.53    martin 			sbus_intno = i;
    366       1.53    martin 			sc->sc_use_softint = false;
    367       1.53    martin 			hw_ipl = IPL_VM;
    368       1.53    martin 			break;
    369       1.53    martin 		}
    370       1.53    martin 	}
    371       1.53    martin 	if (sbus_intno == -1) {
    372       1.53    martin 		/*
    373       1.53    martin 		 * We have not found a usable hardware interrupt - so
    374       1.53    martin 		 * use a softint to bounce to the proper IPL.
    375       1.53    martin 		 */
    376       1.53    martin 		printf("no usable HW interrupt found, using softint\n");
    377       1.53    martin 		sbus_intno = 0;
    378       1.53    martin 		sc->sc_use_softint = true;
    379       1.53    martin 		hw_ipl = IPL_NONE;
    380       1.53    martin 	}
    381       1.53    martin #endif
    382       1.53    martin 
    383        1.1        pk 	/* Set up per-socket static initialization */
    384        1.1        pk 	sc->sc_socks[0].sc = sc->sc_socks[1].sc = sc;
    385       1.33    martin 	sc->sc_socks[0].tag = sc->sc_socks[1].tag = sa->sa_bustag;
    386       1.33    martin 	/*
    387       1.33    martin 	 * XXX we rely on "tag" accepting the same handle-domain
    388       1.33    martin 	 * as sa->sa_bustag.
    389       1.33    martin 	 */
    390       1.33    martin 	sc->sc_socks[0].pcmciat = sc->sc_socks[1].pcmciat = tag;
    391       1.28    martin 	sc->sc_socks[0].sbus_intno =
    392       1.28    martin 		sc->sc_socks[1].sbus_intno = sbus_intno;
    393        1.1        pk 
    394        1.9        pk 	if (sa->sa_nreg < 8) {
    395        1.1        pk 		printf("%s: only %d register sets\n",
    396       1.54    cegger 			device_xname(self), sa->sa_nreg);
    397        1.1        pk 		return;
    398        1.1        pk 	}
    399        1.1        pk 
    400        1.1        pk 	if (sa->sa_nintr != 2) {
    401        1.1        pk 		printf("%s: expect 2 interrupt Sbus levels; got %d\n",
    402       1.54    cegger 			device_xname(self), sa->sa_nintr);
    403        1.1        pk 		return;
    404        1.1        pk 	}
    405        1.1        pk 
    406        1.9        pk #define STP4020_BANK_PROM	0
    407        1.1        pk #define STP4020_BANK_CTRL	4
    408        1.1        pk 	for (i = 0; i < 8; i++) {
    409       1.10        pk 
    410        1.1        pk 		/*
    411        1.1        pk 		 * STP4020 Register address map:
    412        1.1        pk 		 *	bank  0:   Forth PROM
    413        1.1        pk 		 *	banks 1-3: socket 0, windows 0-2
    414        1.1        pk 		 *	bank  4:   control registers
    415        1.1        pk 		 *	banks 5-7: socket 1, windows 0-2
    416        1.1        pk 		 */
    417       1.10        pk 
    418        1.9        pk 		if (i == STP4020_BANK_PROM)
    419        1.9        pk 			/* Skip the PROM */
    420        1.9        pk 			continue;
    421        1.9        pk 
    422        1.1        pk 		if (sbus_bus_map(sa->sa_bustag,
    423       1.24    martin 				 sa->sa_reg[i].oa_space,
    424       1.24    martin 				 sa->sa_reg[i].oa_base,
    425       1.24    martin 				 sa->sa_reg[i].oa_size,
    426       1.21       eeh 				 0, &bh) != 0) {
    427       1.54    cegger 			aprint_error_dev(self, "attach: cannot map registers\n");
    428        1.1        pk 			return;
    429       1.43     perry 		}
    430       1.10        pk 
    431       1.10        pk 		if (i == STP4020_BANK_CTRL) {
    432       1.10        pk 			/*
    433       1.10        pk 			 * Copy tag and handle to both socket structures
    434       1.10        pk 			 * for easy access in control/status IO functions.
    435       1.10        pk 			 */
    436       1.10        pk 			sc->sc_socks[0].regs = sc->sc_socks[1].regs = bh;
    437       1.10        pk 		} else if (i < STP4020_BANK_CTRL) {
    438       1.10        pk 			/* banks 1-3 */
    439       1.10        pk 			sc->sc_socks[0].windows[i-1].winaddr = bh;
    440       1.10        pk 		} else {
    441       1.10        pk 			/* banks 5-7 */
    442       1.10        pk 			sc->sc_socks[1].windows[i-5].winaddr = bh;
    443       1.10        pk 		}
    444        1.1        pk 	}
    445        1.1        pk 
    446       1.28    martin 	/* We only use one interrupt level. */
    447       1.28    martin 	if (sa->sa_nintr > sbus_intno) {
    448       1.28    martin 		bus_intr_establish(sa->sa_bustag,
    449       1.28    martin 		    sa->sa_intr[sbus_intno].oi_pri,
    450       1.53    martin 		    hw_ipl, stp4020_intr, sc);
    451        1.7        pk 	}
    452        1.1        pk 
    453        1.1        pk 	rev = stp4020_rd_sockctl(&sc->sc_socks[0], STP4020_ISR1_IDX) &
    454        1.1        pk 		STP4020_ISR1_REV_M;
    455        1.1        pk 	printf(": rev %x\n", rev);
    456        1.1        pk 
    457        1.1        pk 	sc->sc_pct = (pcmcia_chipset_tag_t)&stp4020_functions;
    458        1.1        pk 
    459        1.1        pk 	SIMPLEQ_INIT(&sc->events);
    460        1.1        pk 
    461        1.1        pk 	for (i = 0; i < STP4020_NSOCK; i++) {
    462        1.1        pk 		struct stp4020_socket *h = &sc->sc_socks[i];
    463        1.1        pk 		h->sock = i;
    464        1.1        pk 		h->sc = sc;
    465        1.6        pk #ifdef STP4020_DEBUG
    466       1.18    martin 		if (stp4020_debug)
    467       1.18    martin 			stp4020_dump_regs(h);
    468        1.6        pk #endif
    469       1.16    martin 		stp4020_attach_socket(h, sa->sa_frequency);
    470        1.1        pk 	}
    471       1.50        ad 
    472       1.50        ad 	/*
    473       1.50        ad 	 * Arrange that a kernel thread be created to handle
    474       1.50        ad 	 * insert/removal events.
    475       1.50        ad 	 */
    476       1.50        ad 	if (kthread_create(PRI_NONE, 0, NULL, stp4020_event_thread, sc,
    477       1.54    cegger 	    &sc->event_thread, "%s", device_xname(self))) {
    478       1.54    cegger 		panic("%s: unable to create event thread", device_xname(self));
    479       1.50        ad 	}
    480        1.1        pk }
    481        1.1        pk 
    482        1.1        pk void
    483       1.57       dsl stp4020_attach_socket(struct stp4020_socket *h, int speed)
    484        1.1        pk {
    485        1.1        pk 	struct pcmciabus_attach_args paa;
    486        1.1        pk 	int v;
    487        1.1        pk 
    488       1.31    martin 	/* no interrupt handlers yet */
    489       1.31    martin 	h->intrhandler = NULL;
    490       1.31    martin 	h->intrarg = NULL;
    491       1.53    martin #ifndef SUN4U
    492       1.31    martin 	h->softint = NULL;
    493       1.31    martin 	h->int_enable = 0;
    494       1.31    martin 	h->int_disable = 0;
    495       1.53    martin #endif
    496       1.31    martin 
    497       1.15    martin 	/* Map all three windows */
    498       1.16    martin 	stp4020_map_window(h, STP_WIN_ATTR, speed);
    499       1.16    martin 	stp4020_map_window(h, STP_WIN_MEM, speed);
    500       1.16    martin 	stp4020_map_window(h, STP_WIN_IO, speed);
    501        1.1        pk 
    502        1.1        pk 	/* Configure one pcmcia device per socket */
    503        1.9        pk 	paa.paa_busname = "pcmcia";
    504        1.1        pk 	paa.pct = (pcmcia_chipset_tag_t)h->sc->sc_pct;
    505        1.1        pk 	paa.pch = (pcmcia_chipset_handle_t)h;
    506        1.1        pk 
    507       1.65       mrg 	h->pcmcia = config_found(h->sc->sc_dev, &paa, stp4020print);
    508        1.1        pk 
    509        1.1        pk 	if (h->pcmcia == NULL)
    510        1.1        pk 		return;
    511        1.1        pk 
    512        1.1        pk 	/*
    513        1.1        pk 	 * There's actually a pcmcia bus attached; initialize the slot.
    514        1.1        pk 	 */
    515        1.1        pk 
    516        1.1        pk 	/*
    517       1.16    martin 	 * Clear things up before we enable status change interrupts.
    518       1.16    martin 	 * This seems to not be fully initialized by the PROM.
    519       1.16    martin 	 */
    520       1.16    martin 	stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0);
    521       1.16    martin 	stp4020_wr_sockctl(h, STP4020_ICR0_IDX, 0);
    522       1.16    martin 	stp4020_wr_sockctl(h, STP4020_ISR1_IDX, 0x3fff);
    523       1.16    martin 	stp4020_wr_sockctl(h, STP4020_ISR0_IDX, 0x3fff);
    524       1.16    martin 
    525       1.16    martin 	/*
    526        1.1        pk 	 * Enable socket status change interrupts.
    527       1.28    martin 	 * We only use one common interrupt for status change
    528       1.28    martin 	 * and IO, to avoid locking issues.
    529        1.1        pk 	 */
    530       1.28    martin 	v = STP4020_ICR0_ALL_STATUS_IE
    531       1.28    martin 	    | (h->sbus_intno ? STP4020_ICR0_SCILVL_SB1
    532       1.28    martin 			     : STP4020_ICR0_SCILVL_SB0);
    533        1.1        pk 	stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
    534        1.1        pk 
    535       1.35    martin 	/* Get live status bits from ISR0 and clear pending interrupts */
    536        1.1        pk 	v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
    537       1.35    martin 	stp4020_wr_sockctl(h, STP4020_ISR0_IDX, v);
    538       1.35    martin 
    539        1.1        pk 	if ((v & (STP4020_ISR0_CD1ST|STP4020_ISR0_CD2ST)) == 0)
    540        1.1        pk 		return;
    541        1.1        pk 
    542        1.1        pk 	pcmcia_card_attach(h->pcmcia);
    543        1.1        pk 	h->flags |= STP4020_SOCKET_BUSY;
    544        1.1        pk }
    545        1.1        pk 
    546        1.1        pk /*
    547        1.1        pk  * The actual event handling thread.
    548        1.1        pk  */
    549        1.1        pk void
    550       1.57       dsl stp4020_event_thread(void *arg)
    551        1.1        pk {
    552        1.1        pk 	struct stp4020_softc *sc = arg;
    553        1.1        pk 	struct stp4020_event *e;
    554        1.1        pk 	int s;
    555        1.1        pk 
    556        1.1        pk 	while (1) {
    557        1.1        pk 		struct stp4020_socket *h;
    558        1.1        pk 		int n;
    559        1.1        pk 
    560        1.1        pk 		s = splhigh();
    561        1.1        pk 		if ((e = SIMPLEQ_FIRST(&sc->events)) == NULL) {
    562        1.1        pk 			splx(s);
    563       1.45    martin 			(void)tsleep(&sc->events, PWAIT, "nellevt", 0);
    564        1.1        pk 			continue;
    565        1.1        pk 		}
    566       1.23     lukem 		SIMPLEQ_REMOVE_HEAD(&sc->events, se_q);
    567        1.1        pk 		splx(s);
    568        1.1        pk 
    569        1.1        pk 		n = e->se_sock;
    570        1.1        pk 		if (n < 0 || n >= STP4020_NSOCK)
    571        1.1        pk 			panic("stp4020_event_thread: wayward socket number %d",
    572        1.1        pk 			      n);
    573        1.1        pk 
    574        1.1        pk 		h = &sc->sc_socks[n];
    575        1.1        pk 		switch (e->se_type) {
    576        1.1        pk 		case STP4020_EVENT_INSERTION:
    577        1.1        pk 			pcmcia_card_attach(h->pcmcia);
    578        1.1        pk 			break;
    579        1.1        pk 		case STP4020_EVENT_REMOVAL:
    580        1.1        pk 			pcmcia_card_detach(h->pcmcia, DETACH_FORCE);
    581        1.1        pk 			break;
    582        1.1        pk 		default:
    583        1.1        pk 			panic("stp4020_event_thread: unknown event type %d",
    584        1.1        pk 			      e->se_type);
    585        1.1        pk 		}
    586        1.1        pk 		free(e, M_TEMP);
    587        1.1        pk 	}
    588        1.1        pk }
    589        1.1        pk 
    590        1.1        pk void
    591       1.58       dsl stp4020_queue_event(struct stp4020_softc *sc, int sock, int event)
    592        1.1        pk {
    593        1.1        pk 	struct stp4020_event *e;
    594        1.1        pk 	int s;
    595        1.1        pk 
    596        1.1        pk 	e = malloc(sizeof(*e), M_TEMP, M_NOWAIT);
    597        1.1        pk 	if (e == NULL)
    598        1.1        pk 		panic("stp4020_queue_event: can't allocate event");
    599        1.1        pk 
    600        1.1        pk 	e->se_type = event;
    601        1.1        pk 	e->se_sock = sock;
    602        1.1        pk 	s = splhigh();
    603        1.1        pk 	SIMPLEQ_INSERT_TAIL(&sc->events, e, se_q);
    604        1.1        pk 	splx(s);
    605        1.1        pk 	wakeup(&sc->events);
    606        1.1        pk }
    607        1.1        pk 
    608       1.53    martin #ifndef SUN4U
    609       1.31    martin /*
    610       1.31    martin  * Softinterrupt called to invoke the real driver interrupt handler.
    611       1.31    martin  */
    612       1.31    martin static void
    613       1.57       dsl stp4020_intr_dispatch(void *arg)
    614       1.31    martin {
    615       1.31    martin 	struct stp4020_socket *h = arg;
    616       1.31    martin 	int s;
    617       1.31    martin 
    618       1.31    martin 	/* invoke driver handler */
    619       1.31    martin 	h->intrhandler(h->intrarg);
    620       1.31    martin 
    621       1.31    martin 	/* enable SBUS interrupts for pcmcia interrupts again */
    622       1.31    martin 	s = splhigh();
    623       1.31    martin 	stp4020_wr_sockctl(h, STP4020_ICR0_IDX, h->int_enable);
    624       1.31    martin 	splx(s);
    625       1.31    martin }
    626       1.53    martin #endif
    627       1.31    martin 
    628        1.1        pk int
    629       1.57       dsl stp4020_intr(void *arg)
    630        1.1        pk {
    631        1.1        pk 	struct stp4020_softc *sc = arg;
    632       1.53    martin #ifndef SUN4U
    633       1.53    martin 	int s;
    634       1.53    martin #endif
    635  1.66.12.2  jdolecek 	int i, r = 0;
    636       1.31    martin 
    637       1.31    martin 
    638       1.53    martin #ifndef SUN4U
    639       1.31    martin 	/* protect hardware access by splhigh against softint */
    640       1.31    martin 	s = splhigh();
    641       1.53    martin #endif
    642        1.1        pk 
    643        1.1        pk 	/*
    644        1.1        pk 	 * Check each socket for pending requests.
    645        1.1        pk 	 */
    646        1.1        pk 	for (i = 0 ; i < STP4020_NSOCK; i++) {
    647        1.1        pk 		struct stp4020_socket *h;
    648       1.28    martin 		int v;
    649        1.1        pk 
    650        1.1        pk 		h = &sc->sc_socks[i];
    651       1.31    martin 
    652       1.28    martin 		v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
    653        1.1        pk 
    654       1.31    martin 		/* Ack all interrupts at once. */
    655       1.35    martin 		stp4020_wr_sockctl(h, STP4020_ISR0_IDX, v);
    656        1.1        pk 
    657        1.1        pk #ifdef STP4020_DEBUG
    658        1.1        pk 		if (stp4020_debug != 0) {
    659        1.1        pk 			char bits[64];
    660       1.56  christos 			snprintb(bits, sizeof(bits), STP4020_ISR0_IOBITS, v);
    661        1.1        pk 			printf("stp4020_statintr: ISR0=%s\n", bits);
    662        1.1        pk 		}
    663        1.1        pk #endif
    664        1.1        pk 
    665        1.1        pk 		if ((v & STP4020_ISR0_CDCHG) != 0) {
    666        1.1        pk 			/*
    667        1.1        pk 			 * Card status change detect
    668        1.1        pk 			 */
    669       1.18    martin 			r = 1;
    670       1.18    martin 			if ((v & (STP4020_ISR0_CD1ST|STP4020_ISR0_CD2ST)) == (STP4020_ISR0_CD1ST|STP4020_ISR0_CD2ST)){
    671        1.1        pk 				if ((h->flags & STP4020_SOCKET_BUSY) == 0) {
    672        1.1        pk 					stp4020_queue_event(sc, i,
    673        1.1        pk 						STP4020_EVENT_INSERTION);
    674        1.1        pk 					h->flags |= STP4020_SOCKET_BUSY;
    675        1.1        pk 				}
    676        1.1        pk 			}
    677        1.1        pk 			if ((v & (STP4020_ISR0_CD1ST|STP4020_ISR0_CD2ST)) == 0){
    678        1.1        pk 				if ((h->flags & STP4020_SOCKET_BUSY) != 0) {
    679        1.1        pk 					stp4020_queue_event(sc, i,
    680        1.1        pk 						STP4020_EVENT_REMOVAL);
    681        1.1        pk 					h->flags &= ~STP4020_SOCKET_BUSY;
    682        1.1        pk 				}
    683        1.1        pk 			}
    684        1.1        pk 		}
    685       1.43     perry 
    686       1.28    martin 		if ((v & STP4020_ISR0_IOINT) != 0) {
    687       1.28    martin 			/* we can not deny this is ours, no matter what the
    688       1.28    martin 			   card driver says. */
    689       1.28    martin 			r = 1;
    690       1.28    martin 
    691       1.28    martin 			/* It's a card interrupt */
    692       1.28    martin 			if ((h->flags & STP4020_SOCKET_BUSY) == 0) {
    693       1.28    martin 				printf("stp4020[%d]: spurious interrupt?\n",
    694       1.28    martin 					h->sock);
    695       1.28    martin 				continue;
    696       1.28    martin 			}
    697       1.31    martin 
    698       1.53    martin #ifndef SUN4U
    699       1.31    martin 			/*
    700       1.43     perry 			 * Schedule softint to invoke driver interrupt
    701       1.31    martin 			 * handler
    702       1.31    martin 			 */
    703       1.31    martin 			if (h->softint != NULL)
    704       1.53    martin 				sparc_softintr_schedule(h->softint);
    705       1.31    martin 			/*
    706       1.31    martin 			 * Disable this sbus interrupt, until the soft-int
    707       1.31    martin 			 * handler had a chance to run
    708       1.31    martin 			 */
    709       1.31    martin 			stp4020_wr_sockctl(h, STP4020_ICR0_IDX, h->int_disable);
    710       1.53    martin #else
    711       1.53    martin 			(*h->intrhandler)(h->intrarg);
    712       1.53    martin #endif
    713       1.28    martin 		}
    714        1.1        pk 
    715       1.18    martin 		/* informational messages */
    716        1.1        pk 		if ((v & STP4020_ISR0_BVD1CHG) != 0) {
    717       1.18    martin 			/* ignore if this is caused by insert or removal */
    718       1.15    martin 			r = 1;
    719        1.1        pk 		}
    720        1.1        pk 
    721        1.1        pk 		if ((v & STP4020_ISR0_BVD2CHG) != 0) {
    722       1.18    martin 			/* ignore if this is caused by insert or removal */
    723       1.15    martin 			r = 1;
    724        1.1        pk 		}
    725        1.1        pk 
    726       1.36    martin 		if ((v & STP4020_ISR0_SCINT) != 0) {
    727       1.36    martin 			DPRINTF(("stp4020[%d]: status change\n", h->sock));
    728       1.36    martin 			r = 1;
    729       1.36    martin 		}
    730       1.36    martin 
    731        1.1        pk 		if ((v & STP4020_ISR0_RDYCHG) != 0) {
    732       1.18    martin 			DPRINTF(("stp4020[%d]: Ready/Busy change\n", h->sock));
    733       1.15    martin 			r = 1;
    734        1.1        pk 		}
    735        1.1        pk 
    736        1.1        pk 		if ((v & STP4020_ISR0_WPCHG) != 0) {
    737       1.18    martin 			DPRINTF(("stp4020[%d]: Write protect change\n", h->sock));
    738       1.15    martin 			r = 1;
    739        1.1        pk 		}
    740        1.1        pk 
    741        1.1        pk 		if ((v & STP4020_ISR0_PCTO) != 0) {
    742       1.18    martin 			DPRINTF(("stp4020[%d]: Card access timeout\n", h->sock));
    743       1.15    martin 			r = 1;
    744        1.1        pk 		}
    745       1.18    martin 
    746       1.35    martin 		if ((v & ~STP4020_ISR0_LIVE) && r == 0)
    747       1.35    martin 			printf("stp4020[%d]: unhandled interrupt: 0x%x\n", h->sock, v);
    748       1.35    martin 
    749        1.1        pk 	}
    750       1.53    martin #ifndef SUN4U
    751       1.31    martin 	splx(s);
    752       1.53    martin #endif
    753        1.1        pk 
    754        1.1        pk 	return (r);
    755        1.1        pk }
    756        1.1        pk 
    757       1.16    martin /*
    758       1.16    martin  * The function gets the sbus speed and a access time and calculates
    759       1.16    martin  * values for the CMDLNG and CMDDLAY registers.
    760       1.16    martin  */
    761       1.15    martin static void
    762       1.44       jdc stp4020_calc_speed(int bus_speed, int ns, int *length, int *cmd_delay)
    763        1.1        pk {
    764       1.16    martin 	int result;
    765       1.16    martin 
    766       1.16    martin 	if (ns < STP4020_MEM_SPEED_MIN)
    767       1.16    martin 		ns = STP4020_MEM_SPEED_MIN;
    768       1.16    martin 	else if (ns > STP4020_MEM_SPEED_MAX)
    769       1.16    martin 		ns = STP4020_MEM_SPEED_MAX;
    770       1.16    martin 	result = ns*(bus_speed/1000);
    771       1.16    martin 	if (result % 1000000)
    772       1.16    martin 		result = result/1000000 + 1;
    773       1.16    martin 	else
    774       1.16    martin 		result /= 1000000;
    775       1.16    martin 	*length = result;
    776       1.16    martin 
    777       1.16    martin 	/* the sbus frequency range is limited, so we can keep this simple */
    778       1.44       jdc 	*cmd_delay = ns <= STP4020_MEM_SPEED_MIN? 1 : 2;
    779       1.16    martin }
    780       1.15    martin 
    781       1.16    martin static void
    782       1.16    martin stp4020_map_window(struct stp4020_socket *h, int win, int speed)
    783       1.16    martin {
    784       1.44       jdc 	int v, length, cmd_delay;
    785       1.15    martin 
    786       1.15    martin 	/*
    787       1.16    martin 	 * According to the PC Card standard 300ns access timing should be
    788       1.16    martin 	 * used for attribute memory access. Our pcmcia framework does not
    789       1.16    martin 	 * seem to propagate timing information, so we use that
    790       1.16    martin 	 * everywhere.
    791       1.15    martin 	 */
    792       1.44       jdc 	stp4020_calc_speed(speed, (win==STP_WIN_ATTR)? 300 : 100, &length, &cmd_delay);
    793        1.1        pk 
    794        1.1        pk 	/*
    795       1.15    martin 	 * Fill in the Address Space Select and Base Address
    796       1.15    martin 	 * fields of this windows control register 0.
    797        1.1        pk 	 */
    798       1.44       jdc 	v = ((cmd_delay << STP4020_WCR0_CMDDLY_S)&STP4020_WCR0_CMDDLY_M)
    799       1.16    martin 	    | ((length << STP4020_WCR0_CMDLNG_S)&STP4020_WCR0_CMDLNG_M);
    800       1.15    martin 	switch (win) {
    801       1.15    martin 	case STP_WIN_ATTR:
    802       1.15    martin 		v |= STP4020_WCR0_ASPSEL_AM;
    803       1.15    martin 		break;
    804       1.15    martin 	case STP_WIN_MEM:
    805       1.15    martin 		v |= STP4020_WCR0_ASPSEL_CM;
    806       1.15    martin 		break;
    807       1.15    martin 	case STP_WIN_IO:
    808       1.15    martin 		v |= STP4020_WCR0_ASPSEL_IO;
    809       1.15    martin 		break;
    810       1.15    martin 	}
    811       1.15    martin 	v |= (STP4020_ADDR2PAGE(0) & STP4020_WCR0_BASE_M);
    812       1.15    martin 	stp4020_wr_winctl(h, win, STP4020_WCR0_IDX, v);
    813       1.16    martin 	stp4020_wr_winctl(h, win, STP4020_WCR1_IDX, 1<<STP4020_WCR1_WAITREQ_S);
    814       1.15    martin }
    815        1.1        pk 
    816       1.15    martin int
    817       1.57       dsl stp4020_chip_mem_alloc(pcmcia_chipset_handle_t pch, bus_size_t size, struct pcmcia_mem_handle *pcmhp)
    818       1.15    martin {
    819       1.15    martin 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
    820        1.1        pk 
    821       1.15    martin 	/* we can not do much here, defere work to _mem_map */
    822       1.33    martin 	pcmhp->memt = h->pcmciat;
    823        1.1        pk 	pcmhp->size = size;
    824       1.19    martin 	pcmhp->addr = 0;
    825       1.19    martin 	pcmhp->mhandle = 0;
    826       1.19    martin 	pcmhp->realsize = size;
    827        1.1        pk 
    828        1.1        pk 	return (0);
    829        1.1        pk }
    830        1.1        pk 
    831        1.1        pk void
    832       1.57       dsl stp4020_chip_mem_free(pcmcia_chipset_handle_t pch, struct pcmcia_mem_handle *pcmhp)
    833        1.1        pk {
    834        1.1        pk }
    835        1.1        pk 
    836        1.1        pk int
    837       1.57       dsl stp4020_chip_mem_map(pcmcia_chipset_handle_t pch, int kind, bus_addr_t card_addr, bus_size_t size, struct pcmcia_mem_handle *pcmhp, bus_size_t *offsetp, int *windowp)
    838        1.1        pk {
    839        1.1        pk 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
    840       1.15    martin 	int win = (kind&PCMCIA_MEM_ATTR)? STP_WIN_ATTR : STP_WIN_MEM;
    841        1.8      joda 
    842       1.33    martin 	pcmhp->memt = h->pcmciat;
    843       1.33    martin 	bus_space_subregion(h->pcmciat, h->windows[win].winaddr, card_addr, size, &pcmhp->memh);
    844       1.34    martin #ifdef SUN4U
    845       1.64   tsutsui 	if ((uint8_t)pcmhp->memh._asi == ASI_PHYS_NON_CACHED)
    846       1.34    martin 		pcmhp->memh._asi = ASI_PHYS_NON_CACHED_LITTLE;
    847       1.64   tsutsui 	else if ((uint8_t)pcmhp->memh._asi == ASI_PRIMARY)
    848       1.34    martin 		pcmhp->memh._asi = ASI_PRIMARY_LITTLE;
    849       1.34    martin #endif
    850       1.19    martin 	pcmhp->size = size;
    851       1.19    martin 	pcmhp->realsize = STP4020_WINDOW_SIZE - card_addr;
    852       1.15    martin 	*offsetp = 0;
    853       1.15    martin 	*windowp = 0;
    854        1.1        pk 
    855        1.1        pk 	return (0);
    856        1.1        pk }
    857        1.1        pk 
    858        1.1        pk void
    859       1.57       dsl stp4020_chip_mem_unmap(pcmcia_chipset_handle_t pch, int win)
    860        1.1        pk {
    861        1.1        pk }
    862        1.1        pk 
    863        1.1        pk int
    864       1.57       dsl stp4020_chip_io_alloc(pcmcia_chipset_handle_t pch, bus_addr_t start, bus_size_t size, bus_size_t align, struct pcmcia_io_handle *pcihp)
    865        1.1        pk {
    866        1.1        pk 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
    867        1.1        pk 
    868       1.33    martin 	pcihp->iot = h->pcmciat;
    869       1.15    martin 	pcihp->ioh = h->windows[STP_WIN_IO].winaddr;
    870       1.15    martin 	return 0;
    871        1.1        pk }
    872        1.1        pk 
    873        1.1        pk void
    874       1.57       dsl stp4020_chip_io_free(pcmcia_chipset_handle_t pch, struct pcmcia_io_handle *pcihp)
    875        1.1        pk {
    876        1.1        pk }
    877        1.1        pk 
    878        1.1        pk int
    879       1.57       dsl stp4020_chip_io_map(pcmcia_chipset_handle_t pch, int width, bus_addr_t offset, bus_size_t size, struct pcmcia_io_handle *pcihp, int *windowp)
    880        1.1        pk {
    881        1.1        pk 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
    882        1.1        pk 
    883       1.33    martin 	pcihp->iot = h->pcmciat;
    884       1.33    martin 	bus_space_subregion(h->pcmciat, h->windows[STP_WIN_IO].winaddr, offset, size, &pcihp->ioh);
    885       1.34    martin #ifdef SUN4U
    886       1.64   tsutsui 	if ((uint8_t)pcihp->ioh._asi == ASI_PHYS_NON_CACHED)
    887       1.34    martin 		pcihp->ioh._asi = ASI_PHYS_NON_CACHED_LITTLE;
    888       1.64   tsutsui 	else if ((uint8_t)pcihp->ioh._asi == ASI_PRIMARY)
    889       1.34    martin 		pcihp->ioh._asi = ASI_PRIMARY_LITTLE;
    890       1.34    martin #endif
    891       1.15    martin 	*windowp = 0;
    892       1.15    martin 	return 0;
    893        1.1        pk }
    894        1.1        pk 
    895        1.1        pk void
    896       1.57       dsl stp4020_chip_io_unmap(pcmcia_chipset_handle_t pch, int win)
    897        1.1        pk {
    898        1.1        pk }
    899        1.1        pk 
    900        1.1        pk void
    901       1.57       dsl stp4020_chip_socket_enable(pcmcia_chipset_handle_t pch)
    902        1.1        pk {
    903        1.1        pk 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
    904       1.18    martin 	int i, v;
    905        1.1        pk 
    906        1.1        pk 	/* this bit is mostly stolen from pcic_attach_card */
    907        1.1        pk 
    908        1.1        pk 	/* Power down the socket to reset it, clear the card reset pin */
    909       1.18    martin 	stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0);
    910        1.1        pk 
    911        1.1        pk 	/*
    912        1.1        pk 	 * wait 300ms until power fails (Tpf).  Then, wait 100ms since
    913        1.1        pk 	 * we are changing Vcc (Toff).
    914        1.1        pk 	 */
    915       1.46    martin 	stp4020_delay(h->sc, 300 + 100);
    916        1.1        pk 
    917        1.1        pk 	/* Power up the socket */
    918       1.18    martin 	v = STP4020_ICR1_MSTPWR;
    919        1.1        pk 	stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v);
    920        1.1        pk 
    921        1.1        pk 	/*
    922        1.1        pk 	 * wait 100ms until power raise (Tpr) and 20ms to become
    923        1.1        pk 	 * stable (Tsu(Vcc)).
    924        1.1        pk 	 */
    925       1.46    martin 	stp4020_delay(h->sc, 100 + 20);
    926        1.1        pk 
    927       1.18    martin 	v |= STP4020_ICR1_PCIFOE|STP4020_ICR1_VPP1_VCC;
    928        1.1        pk 	stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v);
    929        1.1        pk 
    930        1.1        pk 	/*
    931        1.1        pk 	 * hold RESET at least 10us.
    932        1.1        pk 	 */
    933        1.1        pk 	delay(10);
    934        1.1        pk 
    935       1.40   mycroft 	/* Clear reset flag, set to memory mode */
    936        1.1        pk 	v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
    937       1.40   mycroft 	v &= ~(STP4020_ICR0_IOIE | STP4020_ICR0_IOILVL | STP4020_ICR0_IFTYPE |
    938       1.40   mycroft 	    STP4020_ICR0_SPKREN);
    939        1.1        pk 	v &= ~STP4020_ICR0_RESET;
    940        1.1        pk 	stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
    941        1.1        pk 
    942        1.1        pk 	/* wait 20ms as per pc card standard (r2.01) section 4.3.6 */
    943       1.46    martin 	stp4020_delay(h->sc, 20);
    944        1.1        pk 
    945        1.1        pk 	/* Wait for the chip to finish initializing (5 seconds max) */
    946        1.1        pk 	for (i = 10000; i > 0; i--) {
    947        1.1        pk 		v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
    948        1.1        pk 		if ((v & STP4020_ISR0_RDYST) != 0)
    949        1.1        pk 			break;
    950        1.1        pk 		delay(500);
    951        1.1        pk 	}
    952        1.1        pk 	if (i <= 0) {
    953        1.1        pk 		char bits[64];
    954       1.56  christos 		snprintb(bits, sizeof(bits),
    955       1.56  christos 		    STP4020_ISR0_IOBITS,
    956       1.56  christos 		    stp4020_rd_sockctl(h, STP4020_ISR0_IDX));
    957        1.1        pk 		printf("stp4020_chip_socket_enable: not ready: status %s\n",
    958        1.1        pk 			bits);
    959        1.1        pk 		return;
    960        1.1        pk 	}
    961       1.39   mycroft }
    962        1.1        pk 
    963       1.39   mycroft void
    964       1.57       dsl stp4020_chip_socket_settype(pcmcia_chipset_handle_t pch, int type)
    965       1.39   mycroft {
    966       1.39   mycroft 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
    967       1.39   mycroft 	int v;
    968        1.1        pk 
    969        1.1        pk 	/*
    970       1.18    martin 	 * Check the card type.
    971       1.18    martin 	 * Enable socket I/O interrupts for IO cards.
    972        1.1        pk 	 */
    973       1.39   mycroft 	v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
    974       1.41   mycroft 	v &= ~(STP4020_ICR0_IOIE | STP4020_ICR0_IOILVL | STP4020_ICR0_IFTYPE |
    975       1.41   mycroft 	    STP4020_ICR0_SPKREN);
    976       1.39   mycroft 	if (type == PCMCIA_IFTYPE_IO) {
    977       1.18    martin 		v |= STP4020_ICR0_IFTYPE_IO|STP4020_ICR0_IOIE
    978       1.28    martin 		    |STP4020_ICR0_SPKREN;
    979       1.28    martin 		v |= h->sbus_intno ? STP4020_ICR0_IOILVL_SB1
    980       1.28    martin 				   : STP4020_ICR0_IOILVL_SB0;
    981       1.53    martin #ifndef SUN4U
    982       1.31    martin 		h->int_enable = v;
    983       1.31    martin 		h->int_disable = v & ~STP4020_ICR0_IOIE;
    984       1.53    martin #endif
    985       1.65       mrg 		DPRINTF(("%s: configuring card for IO useage\n", device_xname(h->sc->sc_dev)));
    986       1.18    martin 	} else {
    987       1.18    martin 		v |= STP4020_ICR0_IFTYPE_MEM;
    988       1.53    martin #ifndef SUN4U
    989       1.35    martin 		h->int_enable = h->int_disable = v;
    990       1.53    martin #endif
    991       1.65       mrg 		DPRINTF(("%s: configuring card for IO useage\n", device_xname(h->sc->sc_dev)));
    992       1.65       mrg 		DPRINTF(("%s: configuring card for MEM ONLY useage\n", device_xname(h->sc->sc_dev)));
    993       1.18    martin 	}
    994        1.1        pk 	stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
    995        1.1        pk }
    996        1.1        pk 
    997        1.1        pk void
    998       1.57       dsl stp4020_chip_socket_disable(pcmcia_chipset_handle_t pch)
    999        1.1        pk {
   1000        1.1        pk 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
   1001        1.1        pk 	int v;
   1002        1.1        pk 
   1003        1.1        pk 	/*
   1004        1.1        pk 	 * Disable socket I/O interrupts.
   1005        1.1        pk 	 */
   1006        1.1        pk 	v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
   1007       1.40   mycroft 	v &= ~(STP4020_ICR0_IOIE | STP4020_ICR0_IOILVL | STP4020_ICR0_IFTYPE |
   1008       1.40   mycroft 	    STP4020_ICR0_SPKREN);
   1009        1.1        pk 	stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
   1010        1.1        pk 
   1011        1.1        pk 	/* Power down the socket */
   1012       1.18    martin 	stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0);
   1013        1.1        pk 
   1014        1.1        pk 	/*
   1015        1.1        pk 	 * wait 300ms until power fails (Tpf).
   1016        1.1        pk 	 */
   1017       1.46    martin 	stp4020_delay(h->sc, 300);
   1018        1.1        pk }
   1019        1.1        pk 
   1020        1.1        pk void *
   1021       1.59       dsl stp4020_chip_intr_establish(pcmcia_chipset_handle_t pch, struct pcmcia_function *pf, int ipl, int (*handler)(void *), void *arg)
   1022        1.1        pk {
   1023        1.1        pk 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
   1024        1.1        pk 
   1025       1.31    martin 	/* only one interrupt handler per slot */
   1026       1.31    martin 	if (h->intrhandler != NULL) return NULL;
   1027       1.31    martin 
   1028        1.1        pk 	h->intrhandler = handler;
   1029        1.1        pk 	h->intrarg = arg;
   1030       1.53    martin #ifndef SUN4U
   1031       1.53    martin 	if (h->sc->sc_use_softint) {
   1032       1.53    martin 		h->softint = sparc_softintr_establish(ipl, stp4020_intr_dispatch, h);
   1033       1.53    martin 		return h->softint;
   1034       1.53    martin 	}
   1035       1.53    martin #endif
   1036       1.53    martin 	return h;
   1037        1.1        pk }
   1038        1.1        pk 
   1039        1.1        pk void
   1040       1.57       dsl stp4020_chip_intr_disestablish(pcmcia_chipset_handle_t pch, void *ih)
   1041        1.1        pk {
   1042        1.1        pk 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
   1043        1.1        pk 
   1044        1.1        pk 	h->intrhandler = NULL;
   1045        1.1        pk 	h->intrarg = NULL;
   1046       1.53    martin #ifndef SUN4U
   1047       1.31    martin 	if (h->softint) {
   1048       1.53    martin 		sparc_softintr_disestablish(h->softint);
   1049       1.31    martin 		h->softint = NULL;
   1050       1.31    martin 	}
   1051       1.53    martin #endif
   1052        1.1        pk }
   1053        1.1        pk 
   1054        1.1        pk /*
   1055        1.1        pk  * Delay and possibly yield CPU.
   1056        1.1        pk  * XXX - assumes a context
   1057        1.1        pk  */
   1058        1.1        pk void
   1059       1.57       dsl stp4020_delay(struct stp4020_softc *sc, unsigned int ms)
   1060        1.1        pk {
   1061       1.46    martin 	unsigned int ticks = mstohz(ms);
   1062        1.1        pk 
   1063        1.1        pk 	if (cold || ticks == 0) {
   1064        1.1        pk 		delay(ms);
   1065        1.1        pk 		return;
   1066        1.1        pk 	}
   1067        1.1        pk 
   1068        1.1        pk #ifdef DIAGNOSTIC
   1069        1.1        pk 	if (ticks > 60*hz)
   1070        1.1        pk 		panic("stp4020: preposterous delay: %u", ticks);
   1071        1.1        pk #endif
   1072       1.46    martin 	tsleep(sc, 0, "nelldel", ticks);
   1073        1.1        pk }
   1074        1.6        pk 
   1075        1.6        pk #ifdef STP4020_DEBUG
   1076        1.6        pk void
   1077       1.57       dsl stp4020_dump_regs(struct stp4020_socket *h)
   1078        1.6        pk {
   1079        1.6        pk 	char bits[64];
   1080        1.6        pk 	/*
   1081        1.6        pk 	 * Dump control and status registers.
   1082        1.6        pk 	 */
   1083        1.6        pk 	printf("socket[%d] registers:\n", h->sock);
   1084       1.56  christos 	snprintb(bits, sizeof(bits), STP4020_ICR0_BITS,
   1085       1.56  christos 	    stp4020_rd_sockctl(h, STP4020_ICR0_IDX));
   1086        1.6        pk 	printf("\tICR0=%s\n", bits);
   1087        1.6        pk 
   1088       1.56  christos 	snprintb(bits, sizeof(bits), STP4020_ICR1_BITS,
   1089       1.56  christos 	    stp4020_rd_sockctl(h, STP4020_ICR1_IDX));
   1090        1.6        pk 	printf("\tICR1=%s\n", bits);
   1091        1.6        pk 
   1092       1.56  christos 	snprintb(bits, sizeof(bits), STP4020_ISR0_IOBITS,
   1093       1.56  christos 	    stp4020_rd_sockctl(h, STP4020_ISR0_IDX));
   1094        1.6        pk 	printf("\tISR0=%s\n", bits);
   1095        1.6        pk 
   1096       1.56  christos 	snprintb(bits, sizeof(bits), STP4020_ISR1_BITS,
   1097       1.56  christos 	    stp4020_rd_sockctl(h, STP4020_ISR1_IDX));
   1098        1.6        pk 	printf("\tISR1=%s\n", bits);
   1099        1.6        pk }
   1100        1.6        pk #endif /* STP4020_DEBUG */
   1101