1 1.73 andvar /* $NetBSD: stp4020.c,v 1.73 2022/12/24 15:23:02 andvar 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.73 andvar __KERNEL_RCSID(0, "$NetBSD: stp4020.c,v 1.73 2022/12/24 15:23:02 andvar 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.67 chs 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.73 andvar * use the first interrupt and request 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.71 thorpej h->pcmcia = config_found(h->sc->sc_dev, &paa, stp4020print, CFARGS_NONE); 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.69 martin 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.72 andvar DPRINTF(("%s: configuring card for IO usage\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.72 andvar DPRINTF(("%s: configuring card for IO usage\n", device_xname(h->sc->sc_dev))); 992 1.72 andvar DPRINTF(("%s: configuring card for MEM ONLY usage\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