ts102.c revision 1.8 1 /* $OpenBSD: ts102.c,v 1.14 2005/01/27 17:03:23 millert Exp $ */
2 /* $NetBSD: ts102.c,v 1.8 2007/07/09 20:52:30 ad Exp $ */
3 /*
4 * Copyright (c) 2003, 2004, Miodrag Vallat.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
19 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
23 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 /*
29 * Driver for the PCMCIA controller found in Tadpole SPARCbook 3 series
30 * notebooks.
31 *
32 * Based on the information provided in the SPARCbook 3 Technical Reference
33 * Manual (s3gxtrmb.pdf), chapter 7. A few ramblings against this document
34 * and/or the chip itself are scattered across this file.
35 *
36 * Implementation notes:
37 *
38 * - The TS102 exports its PCMCIA windows as SBus memory ranges: 64MB for
39 * the common memory window, and 16MB for the attribute and I/O windows.
40 *
41 * Mapping the whole windows would consume 192MB of address space, which
42 * is much more that what the iospace can offer.
43 *
44 * A best-effort solution would be to map the windows on demand. However,
45 * due to the wap mapdev() works, the va used for the mappings would be
46 * lost after unmapping (although using an extent to register iospace memory
47 * usage would fix this). So, instead, we will do a fixed mapping of a subset
48 * of each window upon attach - this is similar to what the stp4020 driver
49 * does.
50 *
51 * - IPL for the cards interrupt handles are not respected. See the stp4020
52 * driver source for comments about this.
53 *
54 * Endianness farce:
55 *
56 * - The documentation pretends that the endianness settings only affect the
57 * common memory window. Gee, thanks a lot. What about other windows, then?
58 * As a result, this driver runs with endianness conversions turned off.
59 *
60 * - One of the little-endian SBus and big-endian PCMCIA flags has the reverse
61 * meaning, actually. To achieve a ``no endianness conversion'' status,
62 * one has to be set and the other unset. It does not matter which one,
63 * though.
64 */
65
66 #include <sys/cdefs.h>
67
68 #include <sys/param.h>
69 #include <sys/systm.h>
70 #include <sys/errno.h>
71 #include <sys/malloc.h>
72 #include <sys/extent.h>
73 #include <sys/proc.h>
74 #include <sys/kernel.h>
75 #include <sys/kthread.h>
76 #include <sys/device.h>
77
78 #include <dev/pcmcia/pcmciareg.h>
79 #include <dev/pcmcia/pcmciavar.h>
80 #include <dev/pcmcia/pcmciachip.h>
81
82 #include <machine/bus.h>
83 #include <machine/intr.h>
84 #include <machine/autoconf.h>
85
86 #include <dev/sbus/sbusvar.h>
87 #include <sparc/dev/ts102reg.h>
88
89 #include "tctrl.h"
90
91 #if NTCTRL > 0
92 #include <machine/tctrl.h>
93 #include <sparc/dev/tctrlvar.h>
94 #endif
95
96 #define TS102_NUM_SLOTS 2
97
98 /*
99 * Memory ranges
100 */
101 #define TS102_RANGE_COMMON 0
102 #define TS102_RANGE_ATTR 1
103 #define TS102_RANGE_IO 2
104
105 #define TS102_RANGE_CNT 3
106 #define TS102_NUM_RANGES (TS102_RANGE_CNT * TS102_NUM_SLOTS)
107
108 #define TS102_ARBITRARY_MAP_SIZE (1 * 1024 * 1024)
109
110 struct tslot_softc;
111
112 #ifdef TSLOT_DEBUG
113 #define TSPRINTF printf
114 #else
115 #define TSPRINTF while (0) printf
116 #endif
117
118 /*
119 * Per-slot data
120 */
121 struct tslot_data {
122 struct tslot_softc *td_parent;
123 struct device *td_pcmcia;
124
125 volatile uint8_t *td_regs;
126 bus_addr_t td_space[TS102_RANGE_CNT];
127 bus_space_tag_t td_pcmciat; /* for accessing cards */
128
129 /* Interrupt handler */
130 int (*td_intr)(void *);
131 void *td_intrarg;
132 void *td_softint;
133
134 /* Socket status */
135 int td_slot;
136 int td_status;
137 #define TS_CARD 0x0001
138 };
139
140 struct tslot_softc {
141 struct device sc_dev;
142 struct sbusdev sc_sd;
143
144 bus_space_tag_t sc_bustag; /* socket control io */
145 bus_space_handle_t sc_regh; /* space */
146
147 pcmcia_chipset_tag_t sc_pct;
148
149 lwp_t *sc_thread; /* event thread */
150 uint32_t sc_events; /* sockets with pending events */
151
152 /* bits 0 and 1 are set according to card presence in slot 0 and 1 */
153 uint32_t sc_active;
154
155 struct tslot_data sc_slot[TS102_NUM_SLOTS];
156 };
157
158 static void tslot_attach(struct device *, struct device *, void *);
159 static void tslot_event_thread(void *);
160 static int tslot_intr(void *);
161 static void tslot_intr_disestablish(pcmcia_chipset_handle_t, void *);
162 static void *tslot_intr_establish(pcmcia_chipset_handle_t,
163 struct pcmcia_function *, int, int (*)(void *), void *);
164
165 const char *tslot_intr_string(pcmcia_chipset_handle_t, void *);
166 static int tslot_io_alloc(pcmcia_chipset_handle_t, bus_addr_t, bus_size_t,
167 bus_size_t, struct pcmcia_io_handle *);
168 static void tslot_io_free(pcmcia_chipset_handle_t, struct pcmcia_io_handle *);
169 static int tslot_io_map(pcmcia_chipset_handle_t, int, bus_addr_t, bus_size_t,
170 struct pcmcia_io_handle *, int *);
171 static void tslot_io_unmap(pcmcia_chipset_handle_t, int);
172 static int tslot_match(struct device *, struct cfdata *, void *);
173 static int tslot_mem_alloc(pcmcia_chipset_handle_t, bus_size_t,
174 struct pcmcia_mem_handle *);
175 static void tslot_mem_free(pcmcia_chipset_handle_t, struct pcmcia_mem_handle *);
176 static int tslot_mem_map(pcmcia_chipset_handle_t, int, bus_addr_t, bus_size_t,
177 struct pcmcia_mem_handle *, bus_size_t *, int *);
178 static void tslot_mem_unmap(pcmcia_chipset_handle_t, int);
179 static int tslot_print(void *, const char *);
180 static void tslot_queue_event(struct tslot_softc *, int);
181 static void tslot_reset(struct tslot_data *, uint32_t);
182 static void tslot_slot_disable(pcmcia_chipset_handle_t);
183 static void tslot_slot_enable(pcmcia_chipset_handle_t);
184 static void tslot_slot_intr(struct tslot_data *, int);
185 static void tslot_slot_settype(pcmcia_chipset_handle_t, int);
186 static void tslot_update_lcd(struct tslot_softc *, int, int);
187 static void tslot_intr_dispatch(void *arg);
188
189 CFATTACH_DECL(tslot, sizeof(struct tslot_softc),
190 tslot_match, tslot_attach, NULL, NULL);
191
192 extern struct cfdriver tslot_cd;
193
194 /*
195 * PCMCIA chipset methods
196 */
197 struct pcmcia_chip_functions tslot_functions = {
198 tslot_mem_alloc,
199 tslot_mem_free,
200 tslot_mem_map,
201 tslot_mem_unmap,
202
203 tslot_io_alloc,
204 tslot_io_free,
205 tslot_io_map,
206 tslot_io_unmap,
207
208 tslot_intr_establish,
209 tslot_intr_disestablish,
210
211 tslot_slot_enable,
212 tslot_slot_disable,
213 tslot_slot_settype
214 };
215
216 static uint16_t ts102_read_2(bus_space_tag_t,
217 bus_space_handle_t,
218 bus_size_t);
219 static uint32_t ts102_read_4(bus_space_tag_t,
220 bus_space_handle_t,
221 bus_size_t);
222 static uint64_t ts102_read_8(bus_space_tag_t,
223 bus_space_handle_t,
224 bus_size_t);
225 static void ts102_write_2(bus_space_tag_t,
226 bus_space_handle_t,
227 bus_size_t,
228 uint16_t);
229 static void ts102_write_4(bus_space_tag_t,
230 bus_space_handle_t,
231 bus_size_t,
232 uint32_t);
233 static void ts102_write_8(bus_space_tag_t,
234 bus_space_handle_t,
235 bus_size_t,
236 uint64_t);
237
238 static uint16_t
239 ts102_read_2(bus_space_tag_t space, bus_space_handle_t handle,
240 bus_size_t offset)
241 {
242 return (le16toh(*(volatile uint16_t *)(handle +
243 offset)));
244 }
245
246 static uint32_t
247 ts102_read_4(bus_space_tag_t space, bus_space_handle_t handle,
248 bus_size_t offset)
249 {
250 return (le32toh(*(volatile uint32_t *)(handle +
251 offset)));
252 }
253
254 static uint64_t
255 ts102_read_8(bus_space_tag_t space, bus_space_handle_t handle,
256 bus_size_t offset)
257 {
258 return (le64toh(*(volatile uint64_t *)(handle +
259 offset)));
260 }
261
262 static void
263 ts102_write_2(bus_space_tag_t space, bus_space_handle_t handle,
264 bus_size_t offset, uint16_t value)
265 {
266 (*(volatile uint16_t *)(handle + offset)) =
267 htole16(value);
268 }
269
270 static void
271 ts102_write_4(bus_space_tag_t space, bus_space_handle_t handle,
272 bus_size_t offset, uint32_t value)
273 {
274 (*(volatile uint32_t *)(handle + offset)) =
275 htole32(value);
276 }
277
278 static void
279 ts102_write_8(bus_space_tag_t space, bus_space_handle_t handle,
280 bus_size_t offset, uint64_t value)
281 {
282 (*(volatile uint64_t *)(handle + offset)) =
283 htole64(value);
284 }
285
286
287 #define TSLOT_READ(slot, offset) \
288 *(volatile uint16_t *)((slot)->td_regs + (offset))
289 #define TSLOT_WRITE(slot, offset, value) \
290 *(volatile uint16_t *)((slot)->td_regs + (offset)) = (value)
291
292 /*
293 * Attachment and initialization
294 */
295
296 static int
297 tslot_match(struct device *parent, struct cfdata *vcf, void *aux)
298 {
299 struct sbus_attach_args *sa = aux;
300
301 return (strcmp("ts102", sa->sa_name) == 0);
302 }
303
304 static void
305 tslot_attach(struct device *parent, struct device *self, void *args)
306 {
307 struct sbus_attach_args *sa = args;
308 struct tslot_softc *sc = (struct tslot_softc *)self;
309 struct tslot_data *td;
310 volatile uint8_t *regs;
311 int node, slot, rnum, base, size;
312 uint32_t ranges[30];
313 void *rptr = ranges;
314 bus_space_handle_t hrang = 0;
315 bus_space_tag_t tag;
316
317 node = sa->sa_node;
318 sc->sc_bustag=sa->sa_bustag;
319 if (sbus_bus_map(sa->sa_bustag,
320 sa->sa_slot,
321 sa->sa_offset,
322 sa->sa_size,
323 0, &sc->sc_regh) != 0) {
324 printf("%s: cannot map registers\n", self->dv_xname);
325 return;
326 }
327 regs = (uint8_t *)bus_space_vaddr(sa->sa_bustag, sc->sc_regh);
328
329 tag = bus_space_tag_alloc(sa->sa_bustag, sc);
330 if (tag == NULL) {
331 printf("%s: attach: out of memory\n", self->dv_xname);
332 return;
333 }
334 tag->sparc_read_2 = ts102_read_2;
335 tag->sparc_read_4 = ts102_read_4;
336 tag->sparc_read_8 = ts102_read_8;
337 tag->sparc_write_2 = ts102_write_2;
338 tag->sparc_write_4 = ts102_write_4;
339 tag->sparc_write_8 = ts102_write_8;
340
341 sbus_establish(&sc->sc_sd, self);
342
343 bus_intr_establish(sa->sa_bustag, sa->sa_intr[0].oi_pri,
344 IPL_NONE, tslot_intr, sc);
345
346 printf(": %d slots\n", TS102_NUM_SLOTS);
347
348 size = sizeof(ranges);
349 if (prom_getprop(node, "ranges", 4, &size, &rptr) != 0) {
350 printf("couldn't read ranges\n");
351 return;
352 }
353
354 /*
355 * Setup asynchronous event handler
356 */
357 sc->sc_events = 0;
358
359 TSPRINTF("starting event thread...\n");
360 if (kthread_create(PRI_NONE, 0, NULL, tslot_event_thread, sc,
361 &sc->sc_thread, "%s", self->dv_xname) != 0) {
362 panic("%s: unable to create event kthread",
363 self->dv_xname);
364 }
365
366 sc->sc_pct = (pcmcia_chipset_tag_t)&tslot_functions;
367 sc->sc_active = 0;
368
369 /*
370 * Setup slots
371 */
372 TSPRINTF("mapping resources...\n");
373 for (slot = 0; slot < TS102_NUM_SLOTS; slot++) {
374 td = &sc->sc_slot[slot];
375 TSPRINTF("slot %d, ",slot);
376 for (rnum = 0; rnum < TS102_RANGE_CNT; rnum++) {
377 base = (slot * TS102_RANGE_CNT + rnum) * 5;
378 TSPRINTF("%d: %08x %08x ",rnum,ranges[base + 3],
379 ranges[base + 4]);
380 if(sbus_bus_map(sc->sc_bustag,
381 sa->sa_slot,
382 ranges[base+3],
383 TS102_ARBITRARY_MAP_SIZE,
384 0, &hrang) != 0) {
385 printf("%s: cannot map registers\n",
386 self->dv_xname);
387 return;
388 }
389 TSPRINTF("%08x: %08x ",(uint32_t)ranges[base + 3],
390 (uint32_t)hrang);
391 td->td_space[rnum] = hrang;
392 }
393 td->td_parent = sc;
394 td->td_pcmciat = tag;
395 td->td_softint = NULL;
396 td->td_regs = regs + slot * (TS102_REG_CARD_B_INT -
397 TS102_REG_CARD_A_INT);
398 td->td_slot = slot;
399
400 TSPRINTF("resetting slot %d %d\n", slot, (int)td->td_regs);
401 tslot_reset(td, TS102_ARBITRARY_MAP_SIZE);
402 }
403 }
404
405 static void
406 tslot_reset(struct tslot_data *td, uint32_t iosize)
407 {
408 struct pcmciabus_attach_args paa;
409 int ctl, status;
410
411 paa.paa_busname = "pcmcia";
412 paa.pct = (pcmcia_chipset_tag_t)td->td_parent->sc_pct;
413 paa.pch = (pcmcia_chipset_handle_t)td;
414 paa.iobase = 0;
415 paa.iosize = iosize;
416
417 td->td_pcmcia = config_found(&td->td_parent->sc_dev, &paa, tslot_print);
418
419 if (td->td_pcmcia == NULL) {
420 /*
421 * If no pcmcia attachment, power down the slot.
422 */
423 tslot_slot_disable((pcmcia_chipset_handle_t)td);
424 return;
425 }
426
427 /*
428 * Initialize the slot
429 */
430
431 ctl = TSLOT_READ(td, TS102_REG_CARD_A_CTL);
432
433 /* force low addresses */
434 ctl &= ~(TS102_CARD_CTL_AA_MASK | TS102_CARD_CTL_IA_MASK);
435
436 /* Put SBus and PCMCIA in their respective endian mode */
437 ctl |= TS102_CARD_CTL_SBLE; /* this is not what it looks like! */
438 ctl &= ~TS102_CARD_CTL_PCMBE; /* default */
439
440 /* disable read ahead and address increment */
441 ctl &= ~TS102_CARD_CTL_RAHD;
442 ctl |= TS102_CARD_CTL_INCDIS;
443
444 /* power on */
445 ctl &= ~TS102_CARD_CTL_PWRD;
446 TSLOT_WRITE(td, TS102_REG_CARD_A_CTL, ctl);
447 TSPRINTF("ctl: %x\n", ctl);
448
449 /*
450 * Enable interrupt upon insertion/removal
451 */
452
453 TSLOT_WRITE(td, TS102_REG_CARD_A_INT,
454 TS102_CARD_INT_MASK_CARDDETECT_STATUS);
455
456 status = TSLOT_READ(td, TS102_REG_CARD_A_STS);
457 if (status & TS102_CARD_STS_PRES) {
458 td->td_status = TS_CARD;
459 pcmcia_card_attach(td->td_pcmcia);
460 } else
461 td->td_status = 0;
462 }
463
464 /* XXX there ought to be a common function for this... */
465 static int
466 tslot_print(void *aux, const char *description)
467 {
468 struct pcmciabus_attach_args *paa = aux;
469 struct tslot_data *td = (struct tslot_data *)paa->pch;
470
471 printf(" socket %d", td->td_slot);
472 return (UNCONF);
473 }
474
475 /*
476 * PCMCIA Helpers
477 */
478
479 static int
480 tslot_io_alloc(pcmcia_chipset_handle_t pch, bus_addr_t start, bus_size_t size,
481 bus_size_t align, struct pcmcia_io_handle *pih)
482 {
483 struct tslot_data *td = (struct tslot_data *)pch;
484
485 #ifdef TSLOT_DEBUG
486 printf("[io alloc %x]", (uint32_t)size);
487 #endif
488
489 pih->iot = td->td_pcmciat;
490 pih->ioh = td->td_space[TS102_RANGE_IO];
491 pih->addr = start;
492 pih->size = size;
493 pih->flags = 0;
494
495 return (0);
496 }
497
498 static void
499 tslot_io_free(pcmcia_chipset_handle_t pch, struct pcmcia_io_handle *pih)
500 {
501 #ifdef TSLOT_DEBUG
502 printf("[io free]");
503 #endif
504 }
505
506 static int
507 tslot_io_map(pcmcia_chipset_handle_t pch, int width, bus_addr_t offset,
508 bus_size_t size, struct pcmcia_io_handle *pih, int *windowp)
509 {
510 struct tslot_data *td = (struct tslot_data *)pch;
511
512 #ifdef TSLOT_DEBUG
513 printf("[io map %x/%x", (uint32_t)offset, (uint32_t)size);
514 #endif
515
516 pih->iot = td->td_pcmciat;
517 if (bus_space_subregion(pih->iot, td->td_space[TS102_RANGE_IO],
518 offset, size, &pih->ioh) != 0)
519 printf("io_map failed, offset %x\n", (uint32_t)offset);
520 *windowp = 0; /* TS102_RANGE_IO */
521
522 #ifdef TSLOT_DEBUG
523 printf("->%x/%x]", (uint32_t)pih->ioh, (uint32_t)size);
524 {
525 int addr, line;
526 for( addr = offset; addr < (offset + size); addr += 16) {
527 printf("%04x:", addr);
528 for(line = addr; line < (addr + 16); line += 2) {
529 printf(" %04x", bus_space_read_2(pih->iot,
530 pih->ioh, line));
531 }
532 printf("\n");
533 }
534 }
535 #endif
536
537 return (0);
538 }
539
540 static void
541 tslot_io_unmap(pcmcia_chipset_handle_t pch, int win)
542 {
543 #ifdef TSLOT_DEBUG
544 struct tslot_data *td = (struct tslot_data *)pch;
545
546 printf("[io unmap]");
547 {
548 int addr, line, offset = 0, size = 0x80;
549 for (addr = offset; addr < (offset + size); addr += 16) {
550 printf("%04x:", addr);
551 for (line = addr; line < (addr + 16); line += 2){
552 printf(" %04x", bus_space_read_2(td->td_pcmciat,
553 td->td_space[2], line));
554 }
555 printf("\n");
556 }
557 }
558 #endif
559 }
560
561 static int
562 tslot_mem_alloc(pcmcia_chipset_handle_t pch, bus_size_t size,
563 struct pcmcia_mem_handle *pmh)
564 {
565 struct tslot_data *td = (struct tslot_data *)pch;
566
567 #ifdef TSLOT_DEBUG
568 printf("[mem alloc %x]", (uint32_t)size);
569 #endif
570 pmh->memt = td->td_pcmciat;
571 pmh->size = size;
572 pmh->addr = 0;
573 pmh->mhandle = 0;
574 pmh->realsize = size; /* nothing so far! */
575
576 return (0);
577 }
578
579 static void
580 tslot_mem_free(pcmcia_chipset_handle_t pch, struct pcmcia_mem_handle *pmh)
581 {
582 #ifdef TSLOT_DEBUG
583 printf("[mem free]");
584 #endif
585 }
586
587 static int
588 tslot_mem_map(pcmcia_chipset_handle_t pch, int kind, bus_addr_t addr,
589 bus_size_t size, struct pcmcia_mem_handle *pmh, bus_size_t *offsetp,
590 int *windowp)
591 {
592 struct tslot_data *td = (struct tslot_data *)pch;
593 int slot;
594
595 slot = kind & PCMCIA_MEM_ATTR ? TS102_RANGE_ATTR : TS102_RANGE_COMMON;
596 #ifdef TSLOT_DEBUG
597 printf("[mem map %d %x/%x", slot, (uint32_t)addr, (uint32_t)size);
598 #endif
599
600 pmh->memt = td->td_parent->sc_bustag;
601 if (bus_space_subregion(pmh->memt, td->td_space[slot],
602 addr, size, &pmh->memh) != 0)
603 printf("mem_map failed, offset %x\n", (uint32_t)addr);
604 pmh->realsize = TS102_ARBITRARY_MAP_SIZE - addr;
605 pmh->size = size;
606 *offsetp = 0;
607 *windowp = 0;
608
609 #ifdef TSLOT_DEBUG
610 printf("->%x/%x]", (uint32_t)pmh->memh, (uint32_t)size);
611 #endif
612
613 return (0);
614 }
615
616 static void
617 tslot_mem_unmap(pcmcia_chipset_handle_t pch, int win)
618 {
619 #ifdef TSLOT_DEBUG
620 printf("[mem unmap %d]", win);
621 #endif
622 }
623
624 static void
625 tslot_slot_disable(pcmcia_chipset_handle_t pch)
626 {
627 struct tslot_data *td = (struct tslot_data *)pch;
628 #ifdef TSLOT_DEBUG
629 printf("%s: disable slot %d\n",
630 td->td_parent->sc_dev.dv_xname, td->td_slot);
631 #endif
632
633 /*
634 * Disable card access.
635 */
636 TSLOT_WRITE(td, TS102_REG_CARD_A_STS,
637 TSLOT_READ(td, TS102_REG_CARD_A_STS) & ~TS102_CARD_STS_ACEN);
638
639 /*
640 * Disable interrupts, except for insertion.
641 */
642 TSLOT_WRITE(td, TS102_REG_CARD_A_INT,
643 TS102_CARD_INT_MASK_CARDDETECT_STATUS);
644 }
645
646 static void
647 tslot_slot_enable(pcmcia_chipset_handle_t pch)
648 {
649 struct tslot_data *td = (struct tslot_data *)pch;
650 int status, intr, i;
651
652 #ifdef TSLOT_DEBUG
653 printf("%s: enable slot %d\n",
654 td->td_parent->sc_dev.dv_xname, td->td_slot);
655 #endif
656
657 /* Power down the socket to reset it */
658 status = TSLOT_READ(td, TS102_REG_CARD_A_STS);
659 TSPRINTF("status: %x\n", status);
660 TSLOT_WRITE(td, TS102_REG_CARD_A_STS, status | TS102_CARD_STS_VCCEN);
661
662 /*
663 * wait 300ms until power fails (Tpf). Then, wait 100ms since we
664 * are changing Vcc (Toff).
665 */
666 DELAY((300 + 100) * 1000);
667
668 /*
669 * Power on the card if not already done, and enable card access
670 */
671 status |= TS102_CARD_STS_ACEN;
672 status &= ~TS102_CARD_STS_VCCEN;
673 TSLOT_WRITE(td, TS102_REG_CARD_A_STS, status);
674
675 /*
676 * wait 100ms until power raise (Tpr) and 20ms to become
677 * stable (Tsu(Vcc)).
678 */
679 DELAY((100 + 20) * 1000);
680
681 status &= ~TS102_CARD_STS_VPP1_MASK;
682 status |= TS102_CARD_STS_VPP1_VCC;
683 TSLOT_WRITE(td, TS102_REG_CARD_A_STS, status);
684
685 /*
686 * hold RESET at least 20us.
687 */
688 intr = TSLOT_READ(td, TS102_REG_CARD_A_INT);
689 TSLOT_WRITE(td, TS102_REG_CARD_A_INT, TS102_CARD_INT_SOFT_RESET);
690 DELAY(20);
691 TSLOT_WRITE(td, TS102_REG_CARD_A_INT, intr);
692
693 /* wait 20ms as per pc card standard (r2.01) section 4.3.6 */
694 DELAY(20 * 1000);
695
696 /* We need level-triggered interrupts for PC Card hardware */
697 TSLOT_WRITE(td, TS102_REG_CARD_A_STS,
698 TSLOT_READ(td, TS102_REG_CARD_A_STS) | TS102_CARD_STS_LVL);
699
700 /*
701 * Wait until the card is unbusy. If it is still busy after 3 seconds,
702 * give up. We could enable card interrupts and wait for the interrupt
703 * to happen when BUSY is released, but the interrupt could also be
704 * triggered by the card itself if it's an I/O card, so better poll
705 * here.
706 */
707 for (i = 30000; i != 0; i--) {
708 status = TSLOT_READ(td, TS102_REG_CARD_A_STS);
709 /* If the card has been removed, abort */
710 if ((status & TS102_CARD_STS_PRES) == 0) {
711 tslot_slot_disable(pch);
712 return;
713 }
714 if (status & TS102_CARD_STS_RDY)
715 break;
716 else
717 DELAY(100);
718 }
719
720 if (i == 0) {
721 printf("%s: slot %d still busy after 3 seconds, status 0x%x\n",
722 td->td_parent->sc_dev.dv_xname, td->td_slot,
723 TSLOT_READ(td, TS102_REG_CARD_A_STS));
724 return;
725 }
726 }
727 static void
728 tslot_event_thread(void *v)
729 {
730 struct tslot_softc *sc = v;
731 struct tslot_data *td;
732 int s, status;
733 unsigned int socket;
734
735 #if NTCTRL > 0
736 int i;
737
738 /*
739 * First-time setup of our LCD symbol. When a card is present at boot
740 * time we won't detect a change here and therefore the LCD symbol won't
741 * light up.
742 */
743 for (i = 0; i < TS102_NUM_SLOTS; i++) {
744 td = &sc->sc_slot[i];
745 status = TSLOT_READ(td, TS102_REG_CARD_A_STS);
746 tslot_update_lcd(sc, i, status & TS102_CARD_STS_PRES);
747 }
748 #endif
749
750 for (;;) {
751 s = splhigh();
752
753 if ((socket = ffs(sc->sc_events)) == 0) {
754 splx(s);
755 tsleep(&sc->sc_events, PWAIT, "tslot_event", hz * 30);
756 continue;
757 }
758 socket--;
759 sc->sc_events &= ~(1 << socket);
760 splx(s);
761
762 if (socket >= TS102_NUM_SLOTS) {
763 #ifdef DEBUG
764 printf("%s: invalid slot number %d\n",
765 sc->sc_dev.dv_xname, socket);
766 #endif
767 continue;
768 }
769
770 td = &sc->sc_slot[socket];
771 status = TSLOT_READ(td, TS102_REG_CARD_A_STS);
772
773 if (status & TS102_CARD_STS_PRES) {
774 /* Card insertion */
775 if ((td->td_status & TS_CARD) == 0) {
776 td->td_status |= TS_CARD;
777 tslot_update_lcd(sc, socket, 1);
778 pcmcia_card_attach(td->td_pcmcia);
779 }
780 } else {
781 /* Card removal */
782 if ((td->td_status & TS_CARD) != 0) {
783 tslot_update_lcd(sc, socket, 0);
784 td->td_status &= ~TS_CARD;
785 pcmcia_card_detach(td->td_pcmcia,
786 DETACH_FORCE);
787 }
788 }
789 }
790 }
791
792 /*
793 * Interrupt handling
794 */
795
796 static int
797 tslot_intr(void *v)
798 {
799 struct tslot_softc *sc = v;
800 struct tslot_data *td;
801 int intregs[TS102_NUM_SLOTS], *intreg;
802 int i, s, rc = 0;
803
804 s = splhigh();
805
806 /*
807 * Scan slots, and acknowledge the interrupt if necessary first
808 */
809 for (i = 0; i < TS102_NUM_SLOTS; i++) {
810 td = &sc->sc_slot[i];
811 intreg = &intregs[i];
812 *intreg = TSLOT_READ(td, TS102_REG_CARD_A_INT);
813
814 /*
815 * Acknowledge all interrupt situations at once, even if they
816 * did not occur.
817 */
818 if ((*intreg & (TS102_CARD_INT_STATUS_IRQ |
819 TS102_CARD_INT_STATUS_WP_STATUS_CHANGED |
820 TS102_CARD_INT_STATUS_BATTERY_STATUS_CHANGED |
821 TS102_CARD_INT_STATUS_CARDDETECT_STATUS_CHANGED)) != 0) {
822 rc = 1;
823 TSLOT_WRITE(td, TS102_REG_CARD_A_INT, *intreg |
824 TS102_CARD_INT_RQST_IRQ |
825 TS102_CARD_INT_RQST_WP_STATUS_CHANGED |
826 TS102_CARD_INT_RQST_BATTERY_STATUS_CHANGED |
827 TS102_CARD_INT_RQST_CARDDETECT_STATUS_CHANGED);
828 }
829 }
830
831 #ifdef TSLOT_DEBUG
832 printf("tslot_intr: %x %x\n", intregs[0], intregs[1]);
833 #endif
834
835 /*
836 * Invoke the interrupt handler for each slot
837 */
838 for (i = 0; i < TS102_NUM_SLOTS; i++) {
839 td = &sc->sc_slot[i];
840 intreg = &intregs[i];
841
842 if ((*intreg & (TS102_CARD_INT_STATUS_IRQ |
843 TS102_CARD_INT_STATUS_WP_STATUS_CHANGED |
844 TS102_CARD_INT_STATUS_BATTERY_STATUS_CHANGED |
845 TS102_CARD_INT_STATUS_CARDDETECT_STATUS_CHANGED)) != 0)
846 tslot_slot_intr(td, *intreg);
847 }
848 splx(s);
849
850 return (rc);
851 }
852
853 static void
854 tslot_queue_event(struct tslot_softc *sc, int slot)
855 {
856 int s;
857
858 s = splhigh();
859 sc->sc_events |= (1 << slot);
860 splx(s);
861 wakeup(&sc->sc_events);
862 }
863
864 static void
865 tslot_slot_intr(struct tslot_data *td, int intreg)
866 {
867 struct tslot_softc *sc = td->td_parent;
868 int status, sockstat;
869 uint32_t ireg;
870
871 status = TSLOT_READ(td, TS102_REG_CARD_A_STS);
872 #ifdef TSLOT_DEBUG
873 printf("%s: interrupt on socket %d ir %x sts %x\n",
874 sc->sc_dev.dv_xname, td->td_slot, intreg, status);
875 #endif
876
877 sockstat = td->td_status;
878
879 /*
880 * The TS102 queues interrupt request, and may trigger an interrupt
881 * for a condition the driver does not want to receive anymore (for
882 * example, after a card gets removed).
883 * Thus, only proceed if the driver is currently allowing a particular
884 * condition.
885 */
886
887 if ((intreg & TS102_CARD_INT_STATUS_CARDDETECT_STATUS_CHANGED) != 0 &&
888 (intreg & TS102_CARD_INT_MASK_CARDDETECT_STATUS) != 0) {
889 tslot_queue_event(sc, td->td_slot);
890 #ifdef TSLOT_DEBUG
891 printf("%s: slot %d status changed from %d to %d\n",
892 sc->sc_dev.dv_xname, td->td_slot, sockstat, td->td_status);
893 #endif
894 /*
895 * Ignore extra interrupt bits, they are part of the change.
896 */
897 return;
898 }
899
900 if ((intreg & TS102_CARD_INT_STATUS_IRQ) != 0 &&
901 (intreg & TS102_CARD_INT_MASK_IRQ) != 0) {
902 /* ignore interrupts if we have a pending state change */
903 if (sc->sc_events & (1 << td->td_slot))
904 {
905 TSPRINTF("ev: %d\n", sc->sc_events);
906 return;
907 }
908 if ((sockstat & TS_CARD) == 0) {
909 printf("%s: spurious interrupt on slot %d isr %x\n",
910 sc->sc_dev.dv_xname, td->td_slot, intreg);
911 return;
912 }
913
914 if (td->td_intr != NULL) {
915
916 if (td->td_softint != NULL)
917 softintr_schedule(td->td_softint);
918 /*
919 * Disable this sbus interrupt, until the soft-int
920 * handler had a chance to run
921 */
922 ireg = TSLOT_READ(td, TS102_REG_CARD_A_INT);
923 TSLOT_WRITE(td, TS102_REG_CARD_A_INT, ireg &
924 ~TS102_CARD_INT_MASK_IRQ);
925 }
926 }
927 }
928
929 static void
930 tslot_intr_disestablish(pcmcia_chipset_handle_t pch, void *ih)
931 {
932 struct tslot_data *td = (struct tslot_data *)pch;
933
934 td->td_intr = NULL;
935 td->td_intrarg = NULL;
936 if (td->td_softint) {
937 softintr_disestablish(td->td_softint);
938 td->td_softint = NULL;
939 }
940 }
941
942 const char *
943 tslot_intr_string(pcmcia_chipset_handle_t pch, void *ih)
944 {
945 if (ih == NULL)
946 return ("couldn't establish interrupt");
947 else
948 return (""); /* nothing for now */
949 }
950
951 static void *
952 tslot_intr_establish(pcmcia_chipset_handle_t pch, struct pcmcia_function *pf,
953 int ipl, int (*handler)(void *), void *arg)
954 {
955 struct tslot_data *td = (struct tslot_data *)pch;
956
957 td->td_intr = handler;
958 td->td_intrarg = arg;
959 td->td_softint = softintr_establish(ipl, tslot_intr_dispatch, td);
960
961 return (td);
962 }
963
964 /*
965 * Softinterrupt called to invoke the real driver interrupt handler.
966 */
967 static void
968 tslot_intr_dispatch(void *arg)
969 {
970 struct tslot_data *td = arg;
971 int s;
972 uint32_t ireg;
973
974 /* invoke driver handler */
975 td->td_intr(td->td_intrarg);
976
977 /* enable SBUS interrupts for pcmcia interrupts again */
978 s = splhigh();
979 ireg = TSLOT_READ(td, TS102_REG_CARD_A_INT);
980 TSLOT_WRITE(td, TS102_REG_CARD_A_INT, ireg | TS102_CARD_INT_MASK_IRQ);
981 splx(s);
982 }
983
984 static void
985 tslot_slot_settype(pcmcia_chipset_handle_t pch, int type)
986 {
987 struct tslot_data *td = (struct tslot_data *)pch;
988 uint32_t reg;
989
990 /*
991 * Enable the card interrupts if this is an I/O card.
992 * Note that the TS102_CARD_STS_IO bit in the status register will
993 * never get set, despite what the documentation says!
994 */
995 TSPRINTF("tslot_slot_settype(%d)\n",type);
996 if (type == PCMCIA_IFTYPE_IO) {
997 TSLOT_WRITE(td, TS102_REG_CARD_A_STS,
998 TSLOT_READ(td, TS102_REG_CARD_A_STS) | TS102_CARD_STS_IO);
999 TSLOT_WRITE(td, TS102_REG_CARD_A_INT,
1000 TS102_CARD_INT_MASK_CARDDETECT_STATUS |
1001 TS102_CARD_INT_MASK_IRQ);
1002 reg=TSLOT_READ(td, TS102_REG_CARD_A_STS);
1003 TSPRINTF("status: %x\n", reg);
1004 }
1005 }
1006
1007 static void
1008 tslot_update_lcd(struct tslot_softc *sc, int socket, int status)
1009 {
1010 #if NTCTRL > 0
1011 int was = (sc->sc_active != 0), is;
1012 int mask = 1 << socket;
1013
1014 if (status > 0) {
1015 sc->sc_active |= mask;
1016 } else {
1017 sc->sc_active &= (mask ^ 3);
1018 }
1019 is = (sc->sc_active != 0);
1020 if (was != is) {
1021 tadpole_set_lcd(is, 0x40);
1022 }
1023 #endif
1024 }
1025