plumpcmcia.c revision 1.13 1 /* $NetBSD: plumpcmcia.c,v 1.13 2002/09/27 20:32:13 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 1999, 2000 UCHIYAMA Yasushi. All rights reserved.
5 * Copyright (c) 1997 Marc Horowitz. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Marc Horowitz.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/device.h>
36 #include <sys/kthread.h>
37
38 #include <machine/bus.h>
39 #include <machine/config_hook.h>
40 #include <machine/bus_space_hpcmips.h>
41
42 #include <dev/pcmcia/pcmciareg.h>
43 #include <dev/pcmcia/pcmciavar.h>
44 #include <dev/pcmcia/pcmciachip.h>
45
46 #include <hpcmips/tx/tx39var.h>
47 #include <hpcmips/dev/plumvar.h>
48 #include <hpcmips/dev/plumicuvar.h>
49 #include <hpcmips/dev/plumpowervar.h>
50 #include <hpcmips/dev/plumpcmciareg.h>
51
52 #ifdef PLUMPCMCIA_DEBUG
53 #define DPRINTF_ENABLE
54 #define DPRINTF_DEBUG plumpcmcia_debug
55 #endif
56 #include <machine/debug.h>
57
58 int plumpcmcia_match(struct device *, struct cfdata *, void *);
59 void plumpcmcia_attach(struct device *, struct device *, void *);
60 int plumpcmcia_print(void *, const char *);
61 int plumpcmcia_submatch(struct device *, struct cfdata *, void *);
62
63 int plumpcmcia_power(void *, int, long, void *);
64
65 struct plumpcmcia_softc;
66
67 struct plumpcmcia_handle {
68 /* parent */
69 struct device *ph_parent;
70 /* child */
71 struct device *ph_pcmcia;
72
73 /* PCMCIA controller register space */
74 bus_space_tag_t ph_regt;
75 bus_space_handle_t ph_regh;
76
77 /* I/O port space */
78 int ph_ioarea; /* not PCMCIA window */
79 struct {
80 bus_addr_t pi_addr;
81 bus_size_t pi_size;
82 int pi_width;
83 } ph_io[PLUM_PCMCIA_IO_WINS];
84 int ph_ioalloc;
85 bus_space_tag_t ph_iot;
86 bus_space_handle_t ph_ioh;
87 bus_addr_t ph_iobase;
88 bus_size_t ph_iosize;
89
90 /* I/O Memory space */
91 int ph_memarea; /* not PCMCIA window */
92 struct {
93 bus_addr_t pm_addr;
94 bus_size_t pm_size;
95 int32_t pm_offset;
96 int pm_kind;
97 } ph_mem[PLUM_PCMCIA_MEM_WINS];
98 int ph_memalloc;
99 bus_space_tag_t ph_memt;
100 bus_space_handle_t ph_memh;
101 bus_addr_t ph_membase;
102 bus_size_t ph_memsize;
103
104 /* Card interrupt handler */
105 int ph_plum_irq;
106 void *ph_card_ih;
107 };
108
109 enum plumpcmcia_event_type {
110 PLUM_PCMCIA_EVENT_INSERT,
111 PLUM_PCMCIA_EVENT_REMOVE,
112 };
113
114 struct plumpcmcia_event {
115 int __queued;
116 enum plumpcmcia_event_type pe_type;
117 struct plumpcmcia_handle *pe_ph;
118 SIMPLEQ_ENTRY(plumpcmcia_event) pe_link;
119 };
120
121 struct plumpcmcia_softc {
122 struct device sc_dev;
123 plum_chipset_tag_t sc_pc;
124
125 /* Register space */
126 bus_space_tag_t sc_regt;
127 bus_space_handle_t sc_regh;
128
129 /* power management hook */
130 void *sc_powerhook;
131
132 /* CSC event */
133 struct proc *sc_event_thread;
134 SIMPLEQ_HEAD (, plumpcmcia_event) sc_event_head;
135
136 /* for each slot */
137 struct plumpcmcia_handle sc_ph[PLUMPCMCIA_NSLOTS];
138 };
139
140 static void plumpcmcia_attach_socket(struct plumpcmcia_handle *);
141 static int plumpcmcia_chip_mem_alloc(pcmcia_chipset_handle_t, bus_size_t,
142 struct pcmcia_mem_handle *);
143 static void plumpcmcia_chip_mem_free(pcmcia_chipset_handle_t,
144 struct pcmcia_mem_handle *);
145 static int plumpcmcia_chip_mem_map(pcmcia_chipset_handle_t, int, bus_addr_t,
146 bus_size_t, struct pcmcia_mem_handle *, bus_size_t *, int *);
147 static void plumpcmcia_chip_mem_unmap(pcmcia_chipset_handle_t, int);
148 static int plumpcmcia_chip_io_alloc(pcmcia_chipset_handle_t, bus_addr_t,
149 bus_size_t, bus_size_t, struct pcmcia_io_handle *);
150 static void plumpcmcia_chip_io_free(pcmcia_chipset_handle_t,
151 struct pcmcia_io_handle *);
152 static int plumpcmcia_chip_io_map(pcmcia_chipset_handle_t, int, bus_addr_t,
153 bus_size_t, struct pcmcia_io_handle *, int *);
154 static void plumpcmcia_chip_io_unmap(pcmcia_chipset_handle_t, int);
155 static void plumpcmcia_chip_socket_enable(pcmcia_chipset_handle_t);
156 static void plumpcmcia_chip_socket_disable(pcmcia_chipset_handle_t);
157 static void *plumpcmcia_chip_intr_establish(pcmcia_chipset_handle_t,
158 struct pcmcia_function *, int, int (*)(void *), void *);
159 static void plumpcmcia_chip_intr_disestablish(pcmcia_chipset_handle_t, void *);
160 static void plumpcmcia_wait_ready( struct plumpcmcia_handle *);
161 static void plumpcmcia_chip_do_mem_map(struct plumpcmcia_handle *, int);
162 static void plumpcmcia_chip_do_io_map(struct plumpcmcia_handle *, int);
163
164 static struct pcmcia_chip_functions plumpcmcia_functions = {
165 plumpcmcia_chip_mem_alloc,
166 plumpcmcia_chip_mem_free,
167 plumpcmcia_chip_mem_map,
168 plumpcmcia_chip_mem_unmap,
169 plumpcmcia_chip_io_alloc,
170 plumpcmcia_chip_io_free,
171 plumpcmcia_chip_io_map,
172 plumpcmcia_chip_io_unmap,
173 plumpcmcia_chip_intr_establish,
174 plumpcmcia_chip_intr_disestablish,
175 plumpcmcia_chip_socket_enable,
176 plumpcmcia_chip_socket_disable
177 };
178
179 /* CSC */
180 #define PLUM_PCMCIA_EVENT_QUEUE_MAX 5
181 static struct plumpcmcia_event __event_queue_pool[PLUM_PCMCIA_EVENT_QUEUE_MAX];
182 static struct plumpcmcia_event *plumpcmcia_event_alloc(void);
183 static void plumpcmcia_event_free(struct plumpcmcia_event *);
184 static void plum_csc_intr_setup(struct plumpcmcia_softc *,
185 struct plumpcmcia_handle *, int);
186 static int plum_csc_intr(void *);
187 static void plumpcmcia_create_event_thread(void *);
188 static void plumpcmcia_event_thread(void *);
189
190 #ifdef PLUMPCMCIA_DEBUG
191 /* debug */
192 #define __DEBUG_FUNC __attribute__((__unused__))
193 static void __ioareadump(plumreg_t) __DEBUG_FUNC;
194 static void __memareadump(plumreg_t) __DEBUG_FUNC;
195 static void plumpcmcia_dump(struct plumpcmcia_softc *) __DEBUG_FUNC;
196 #endif /* PLUMPCMCIA_DEBUG */
197
198 const struct cfattach plumpcmcia_ca = {
199 sizeof(struct plumpcmcia_softc), plumpcmcia_match, plumpcmcia_attach
200 };
201
202 int
203 plumpcmcia_match(struct device *parent, struct cfdata *cf, void *aux)
204 {
205 return (1);
206 }
207
208 void
209 plumpcmcia_attach(struct device *parent, struct device *self, void *aux)
210 {
211 struct plum_attach_args *pa = aux;
212 struct plumpcmcia_softc *sc = (void*)self;
213 struct plumpcmcia_handle *ph;
214
215 sc->sc_pc = pa->pa_pc;
216 sc->sc_regt = pa->pa_regt;
217
218 /* map register area */
219 if (bus_space_map(sc->sc_regt, PLUM_PCMCIA_REGBASE,
220 PLUM_PCMCIA_REGSIZE, 0, &sc->sc_regh)) {
221 printf(": register map failed\n");
222 }
223
224 /* power control */
225 plumpcmcia_power(sc, 0, 0, (void *)PWR_RESUME);
226 /* Add a hard power hook to power saving */
227 #if notyet
228 sc->sc_powerhook = config_hook(CONFIG_HOOK_PMEVENT,
229 CONFIG_HOOK_PMEVENT_HARDPOWER,
230 CONFIG_HOOK_SHARE,
231 plumpcmcia_power, sc);
232 if (sc->sc_powerhook == 0)
233 printf(": WARNING unable to establish hard power hook");
234 #endif
235 printf("\n");
236
237 /* Slot0/1 CSC event queue */
238 SIMPLEQ_INIT (&sc->sc_event_head);
239 kthread_create(plumpcmcia_create_event_thread, sc);
240
241 /* Slot 0 */
242 ph = &sc->sc_ph[0];
243 ph->ph_plum_irq = PLUM_INT_C1IO;
244 ph->ph_memarea = PLUM_PCMCIA_MEMWINCTRL_MAP_AREA1;
245 ph->ph_membase = PLUM_PCMCIA_MEMBASE1;
246 ph->ph_memsize = PLUM_PCMCIA_MEMSIZE1;
247 ph->ph_ioarea = PLUM_PCMCIA_IOWINADDRCTRL_AREA1;
248 ph->ph_iobase = PLUM_PCMCIA_IOBASE1;
249 ph->ph_iosize = PLUM_PCMCIA_IOSIZE1;
250 ph->ph_regt = sc->sc_regt;
251 bus_space_subregion(sc->sc_regt, sc->sc_regh,
252 PLUM_PCMCIA_REGSPACE_SLOT0,
253 PLUM_PCMCIA_REGSPACE_SIZE,
254 &ph->ph_regh);
255 ph->ph_iot = pa->pa_iot;
256 ph->ph_memt = pa->pa_iot;
257 ph->ph_parent = (void*)sc;
258
259 plum_csc_intr_setup(sc, ph, PLUM_INT_C1SC);
260 plum_power_establish(sc->sc_pc, PLUM_PWR_PCC1);
261 plumpcmcia_attach_socket(ph);
262
263 /* Slot 1 */
264 ph = &sc->sc_ph[1];
265 ph->ph_plum_irq = PLUM_INT_C2IO;
266 ph->ph_memarea = PLUM_PCMCIA_MEMWINCTRL_MAP_AREA2;
267 ph->ph_membase = PLUM_PCMCIA_MEMBASE2;
268 ph->ph_memsize = PLUM_PCMCIA_MEMSIZE2;
269 ph->ph_ioarea = PLUM_PCMCIA_IOWINADDRCTRL_AREA2;
270 ph->ph_iobase = PLUM_PCMCIA_IOBASE2;
271 ph->ph_iosize = PLUM_PCMCIA_IOSIZE2;
272 ph->ph_regt = sc->sc_regt;
273 bus_space_subregion(sc->sc_regt, sc->sc_regh,
274 PLUM_PCMCIA_REGSPACE_SLOT1,
275 PLUM_PCMCIA_REGSPACE_SIZE,
276 &ph->ph_regh);
277 ph->ph_iot = pa->pa_iot;
278 ph->ph_memt = pa->pa_iot;
279 ph->ph_parent = (void*)sc;
280
281 plum_csc_intr_setup(sc, ph, PLUM_INT_C2SC);
282 plum_power_establish(sc->sc_pc, PLUM_PWR_PCC2);
283 plumpcmcia_attach_socket(ph);
284 }
285
286 int
287 plumpcmcia_print(void *arg, const char *pnp)
288 {
289 if (pnp) {
290 printf("pcmcia at %s", pnp);
291 }
292
293 return (UNCONF);
294 }
295
296 int
297 plumpcmcia_submatch(struct device *parent, struct cfdata *cf, void *aux)
298 {
299 return (config_match(parent, cf, aux));
300 }
301
302 static void
303 plumpcmcia_attach_socket(struct plumpcmcia_handle *ph)
304 {
305 struct pcmciabus_attach_args paa;
306 struct plumpcmcia_softc *sc = (void*)ph->ph_parent;
307
308 paa.paa_busname = "pcmcia";
309 paa.pct = (pcmcia_chipset_tag_t)&plumpcmcia_functions;
310 paa.pch = (pcmcia_chipset_handle_t)ph;
311 paa.iobase = 0;
312 paa.iosize = ph->ph_iosize;
313
314 if ((ph->ph_pcmcia = config_found_sm((void*)sc, &paa,
315 plumpcmcia_print,
316 plumpcmcia_submatch))) {
317 /* Enable slot */
318 plum_conf_write(ph->ph_regt, ph->ph_regh,
319 PLUM_PCMCIA_SLOTCTRL,
320 PLUM_PCMCIA_SLOTCTRL_ENABLE);
321 /* Support 3.3V card & enable Voltage Sense Status */
322 plum_conf_write(ph->ph_regt, ph->ph_regh,
323 PLUM_PCMCIA_FUNCCTRL,
324 PLUM_PCMCIA_FUNCCTRL_VSSEN |
325 PLUM_PCMCIA_FUNCCTRL_3VSUPPORT);
326 pcmcia_card_attach(ph->ph_pcmcia);
327 }
328 }
329
330 static void *
331 plumpcmcia_chip_intr_establish(pcmcia_chipset_handle_t pch,
332 struct pcmcia_function *pf, int ipl,
333 int (*ih_fun)(void *), void *ih_arg)
334 {
335 struct plumpcmcia_handle *ph = (void*)pch;
336 struct plumpcmcia_softc *sc = (void*)ph->ph_parent;
337
338 if (!(ph->ph_card_ih =
339 plum_intr_establish(sc->sc_pc, ph->ph_plum_irq,
340 IST_EDGE, IPL_BIO, ih_fun, ih_arg))) {
341 printf("plumpcmcia_chip_intr_establish: can't establish\n");
342 return (0);
343 }
344
345 return (ph->ph_card_ih);
346 }
347
348 static void
349 plumpcmcia_chip_intr_disestablish(pcmcia_chipset_handle_t pch, void *ih)
350 {
351 struct plumpcmcia_handle *ph = (void*)pch;
352 struct plumpcmcia_softc *sc = (void*)ph->ph_parent;
353
354 plum_intr_disestablish(sc->sc_pc, ih);
355 }
356
357 static int
358 plumpcmcia_chip_mem_alloc(pcmcia_chipset_handle_t pch, bus_size_t size,
359 struct pcmcia_mem_handle *pcmhp)
360 {
361 struct plumpcmcia_handle *ph = (void*)pch;
362 bus_size_t realsize;
363
364 /* convert size to PCIC pages */
365 realsize = ((size + (PLUM_PCMCIA_MEM_PAGESIZE - 1)) /
366 PLUM_PCMCIA_MEM_PAGESIZE) * PLUM_PCMCIA_MEM_PAGESIZE;
367
368 if (bus_space_alloc(ph->ph_memt, ph->ph_membase,
369 ph->ph_membase + ph->ph_memsize,
370 realsize, PLUM_PCMCIA_MEM_PAGESIZE,
371 0, 0, 0, &pcmhp->memh)) {
372 return (1);
373 }
374
375 pcmhp->memt = ph->ph_memt;
376 /* Address offset from MEM area base */
377 pcmhp->addr = pcmhp->memh - ph->ph_membase -
378 ((struct bus_space_tag_hpcmips*)ph->ph_memt)->base;
379 pcmhp->size = size;
380 pcmhp->realsize = realsize;
381
382 DPRINTF(("plumpcmcia_chip_mem_alloc: size %#x->%#x addr %#x->%#x\n",
383 (unsigned)size, (unsigned)realsize, (unsigned)pcmhp->addr,
384 (unsigned)pcmhp->memh));
385
386 return (0);
387 }
388
389 static void
390 plumpcmcia_chip_mem_free(pcmcia_chipset_handle_t pch,
391 struct pcmcia_mem_handle *pcmhp)
392 {
393
394 bus_space_free(pcmhp->memt, pcmhp->memh, pcmhp->size);
395 }
396
397 static int
398 plumpcmcia_chip_mem_map(pcmcia_chipset_handle_t pch, int kind,
399 bus_addr_t card_addr, bus_size_t size,
400 struct pcmcia_mem_handle *pcmhp,
401 bus_size_t *offsetp, int *windowp)
402 {
403 struct plumpcmcia_handle *ph = (void*)pch;
404 bus_addr_t busaddr;
405 int32_t card_offset;
406 int i, win;
407
408 for (win = -1, i = 0; i < PLUM_PCMCIA_MEM_WINS; i++) {
409 if ((ph->ph_memalloc & (1 << i)) == 0) {
410 win = i;
411 ph->ph_memalloc |= (1 << i);
412 break;
413 }
414 }
415 if (win == -1) {
416 DPRINTF(("plumpcmcia_chip_mem_map: no window\n"));
417 return (1);
418 }
419
420 busaddr = pcmhp->addr;
421
422 *offsetp = card_addr % PLUM_PCMCIA_MEM_PAGESIZE;
423 card_addr -= *offsetp;
424 size += *offsetp - 1;
425 *windowp = win;
426 card_offset = (((int32_t)card_addr) - ((int32_t)busaddr));
427
428 DPRINTF(("plumpcmcia_chip_mem_map window %d bus %#x(kv:%#x)+%#x"
429 " size %#x at card addr %#x offset %#x\n", win,
430 (unsigned)busaddr, (unsigned)pcmhp->memh, (unsigned)*offsetp,
431 (unsigned)size, (unsigned)card_addr, (unsigned)card_offset));
432
433 ph->ph_mem[win].pm_addr = busaddr;
434 ph->ph_mem[win].pm_size = size;
435 ph->ph_mem[win].pm_offset = card_offset;
436 ph->ph_mem[win].pm_kind = kind;
437 ph->ph_memalloc |= (1 << win);
438
439 plumpcmcia_chip_do_mem_map(ph, win);
440
441 return (0);
442 }
443
444 static void
445 plumpcmcia_chip_do_mem_map(struct plumpcmcia_handle *ph, int win)
446 {
447 bus_space_tag_t regt = ph->ph_regt;
448 bus_space_handle_t regh = ph->ph_regh;
449 plumreg_t reg, addr, offset, size;
450
451 if (win < 0 || win > 4) {
452 panic("plumpcmcia_chip_do_mem_map: bogus window %d", win);
453 }
454
455 addr = (ph->ph_mem[win].pm_addr) >> PLUM_PCMCIA_MEM_SHIFT;
456 size = (ph->ph_mem[win].pm_size) >> PLUM_PCMCIA_MEM_SHIFT;
457 offset = (ph->ph_mem[win].pm_offset) >> PLUM_PCMCIA_MEM_SHIFT;
458
459 /* Attribute memory or not */
460 reg = ph->ph_mem[win].pm_kind == PCMCIA_MEM_ATTR ?
461 PLUM_PCMCIA_MEMWINCTRL_REGACTIVE : 0;
462
463 /* Notify I/O area to select for PCMCIA controller */
464 reg = PLUM_PCMCIA_MEMWINCTRL_MAP_SET(reg, ph->ph_memarea);
465
466 /* Zero wait & 16bit access */
467 reg |= (PLUM_PCMCIA_MEMWINCTRL_ZERO_WS |
468 PLUM_PCMCIA_MEMWINCTRL_DATASIZE16);
469 plum_conf_write(regt, regh, PLUM_PCMCIA_MEMWINCTRL(win), reg);
470
471 /* Map Host <-> PC-Card address */
472
473 /* host-side */
474 plum_conf_write(regt, regh, PLUM_PCMCIA_MEMWINSTARTADDR(win),
475 addr);
476 plum_conf_write(regt, regh, PLUM_PCMCIA_MEMWINSTOPADDR(win),
477 addr + size);
478
479 /* card-side */
480 plum_conf_write(regt, regh, PLUM_PCMCIA_MEMWINOFSADDR(win), offset);
481
482 /* Enable memory window */
483 reg = plum_conf_read(regt, regh, PLUM_PCMCIA_WINEN);
484 reg |= PLUM_PCMCIA_WINEN_MEM(win);
485 plum_conf_write(regt, regh, PLUM_PCMCIA_WINEN, reg);
486
487 DPRINTF(("plumpcmcia_chip_do_mem_map: window:%d %#x(%#x)+%#x\n",
488 win, offset, addr, size));
489
490 delay(100);
491 }
492
493 static void
494 plumpcmcia_chip_mem_unmap(pcmcia_chipset_handle_t pch, int window)
495 {
496 struct plumpcmcia_handle *ph = (void*)pch;
497 bus_space_tag_t regt = ph->ph_regt;
498 bus_space_handle_t regh = ph->ph_regh;
499 plumreg_t reg;
500
501 reg = plum_conf_read(regt, regh, PLUM_PCMCIA_WINEN);
502 reg &= ~PLUM_PCMCIA_WINEN_MEM(window);
503 plum_conf_write(regt, regh, PLUM_PCMCIA_WINEN, reg);
504
505 ph->ph_memalloc &= ~(1 << window);
506 }
507
508 static int
509 plumpcmcia_chip_io_alloc(pcmcia_chipset_handle_t pch, bus_addr_t start,
510 bus_size_t size, bus_size_t align,
511 struct pcmcia_io_handle *pcihp)
512 {
513 struct plumpcmcia_handle *ph = (void*)pch;
514
515 DPRINTF(("plumpcmcia_chip_io_alloc: start=%#x size=%#x ",
516 (unsigned)start, (unsigned)size));
517 if (start) {
518 if (bus_space_map(ph->ph_iot, ph->ph_iobase + start,
519 size, 0, &pcihp->ioh)) {
520 DPRINTF(("bus_space_map failed\n"));
521 return (1);
522 }
523 pcihp->flags = 0;
524 pcihp->addr = start;
525 DPRINTF(("(mapped) %#x+%#x\n", (unsigned)start,
526 (unsigned)size));
527 } else {
528 if (bus_space_alloc(ph->ph_iot, ph->ph_iobase,
529 ph->ph_iobase + ph->ph_iosize, size,
530 align, 0, 0, 0, &pcihp->ioh)) {
531 DPRINTF(("bus_space_alloc failed\n"));
532 return 1;
533 }
534 /* Address offset from IO area base */
535 pcihp->addr = pcihp->ioh - ph->ph_iobase -
536 ((struct bus_space_tag_hpcmips*)ph->ph_iot)->base;
537 pcihp->flags = PCMCIA_IO_ALLOCATED;
538 DPRINTF(("(allocated) %#x+%#x\n", (unsigned)pcihp->addr,
539 (unsigned)size));
540 }
541
542 pcihp->iot = ph->ph_iot;
543 pcihp->size = size;
544
545 return (0);
546 }
547
548 static int
549 plumpcmcia_chip_io_map(pcmcia_chipset_handle_t pch, int width,
550 bus_addr_t offset, bus_size_t size,
551 struct pcmcia_io_handle *pcihp, int *windowp)
552 {
553 #ifdef PLUMPCMCIA_DEBUG
554 static char *width_names[] = { "auto", "io8", "io16" };
555 #endif /* PLUMPCMCIA_DEBUG */
556 struct plumpcmcia_handle *ph = (void*)pch;
557 bus_addr_t winofs;
558 int i, win;
559
560 winofs = pcihp->addr + offset;
561
562 if (winofs > 0x3ff) {
563 printf("plumpcmcia_chip_io_map: WARNING port %#lx > 0x3ff\n",
564 winofs);
565 }
566
567 for (win = -1, i = 0; i < PLUM_PCMCIA_IO_WINS; i++) {
568 if ((ph->ph_ioalloc & (1 << i)) == 0) {
569 win = i;
570 ph->ph_ioalloc |= (1 << i);
571 break;
572 }
573 }
574 if (win == -1) {
575 DPRINTF(("plumpcmcia_chip_io_map: no window\n"));
576 return (1);
577 }
578 *windowp = win;
579
580 ph->ph_io[win].pi_addr = winofs;
581 ph->ph_io[win].pi_size = size;
582 ph->ph_io[win].pi_width = width;
583
584 plumpcmcia_chip_do_io_map(ph, win);
585
586 DPRINTF(("plumpcmcia_chip_io_map: %#x(kv:%#x)+%#x %s\n",
587 (unsigned)offset, (unsigned)pcihp->ioh, (unsigned)size,
588 width_names[width]));
589
590 return (0);
591 }
592
593 static void
594 plumpcmcia_chip_do_io_map(struct plumpcmcia_handle *ph, int win)
595 {
596 bus_space_tag_t regt = ph->ph_regt;
597 bus_space_handle_t regh = ph->ph_regh;
598 plumreg_t reg;
599 bus_addr_t addr;
600 bus_size_t size;
601 int shift;
602 plumreg_t ioctlbits[3] = {
603 PLUM_PCMCIA_IOWINCTRL_IOCS16SRC,
604 0,
605 PLUM_PCMCIA_IOWINCTRL_DATASIZE16
606 };
607
608 if (win < 0 || win > 1) {
609 panic("plumpcmcia_chip_do_io_map: bogus window %d", win);
610 }
611
612 addr = ph->ph_io[win].pi_addr;
613 size = ph->ph_io[win].pi_size;
614
615 /* Notify I/O area to select for PCMCIA controller */
616 plum_conf_write(regt, regh, PLUM_PCMCIA_IOWINADDRCTRL(win),
617 ph->ph_ioarea);
618
619 /* Start/Stop addr */
620 plum_conf_write(regt, regh, PLUM_PCMCIA_IOWINSTARTADDR(win), addr);
621 plum_conf_write(regt, regh, PLUM_PCMCIA_IOWINSTOPADDR(win),
622 addr + size - 1);
623
624 /* Set bus width */
625 reg = plum_conf_read(regt, regh, PLUM_PCMCIA_IOWINCTRL);
626 shift = win == 0 ? PLUM_PCMCIA_IOWINCTRL_WIN0SHIFT :
627 PLUM_PCMCIA_IOWINCTRL_WIN1SHIFT;
628
629 reg &= ~(PLUM_PCMCIA_IOWINCTRL_WINMASK << shift);
630 reg |= ((ioctlbits[ph->ph_io[win].pi_width] |
631 PLUM_PCMCIA_IOWINCTRL_ZEROWAIT) << shift);
632 plum_conf_write(regt, regh, PLUM_PCMCIA_IOWINCTRL, reg);
633
634 /* Enable window */
635 reg = plum_conf_read(regt, regh, PLUM_PCMCIA_WINEN);
636 reg |= (win == 0 ? PLUM_PCMCIA_WINEN_IO0 :
637 PLUM_PCMCIA_WINEN_IO1);
638 plum_conf_write(regt, regh, PLUM_PCMCIA_WINEN, reg);
639
640 delay(100);
641 }
642
643 static void
644 plumpcmcia_chip_io_free(pcmcia_chipset_handle_t pch,
645 struct pcmcia_io_handle *pcihp)
646 {
647 if (pcihp->flags & PCMCIA_IO_ALLOCATED) {
648 bus_space_free(pcihp->iot, pcihp->ioh, pcihp->size);
649 } else {
650 bus_space_unmap(pcihp->iot, pcihp->ioh, pcihp->size);
651 }
652
653 DPRINTF(("plumpcmcia_chip_io_free %#x+%#x\n", pcihp->ioh,
654 (unsigned)pcihp->size));
655 }
656
657 static void
658 plumpcmcia_chip_io_unmap(pcmcia_chipset_handle_t pch, int window)
659 {
660 struct plumpcmcia_handle *ph = (void*)pch;
661 bus_space_tag_t regt = ph->ph_regt;
662 bus_space_handle_t regh = ph->ph_regh;
663 plumreg_t reg;
664
665 reg = plum_conf_read(regt, regh, PLUM_PCMCIA_WINEN);
666 switch (window) {
667 default:
668 panic("plumpcmcia_chip_io_unmap: bogus window");
669 case 0:
670 reg &= ~PLUM_PCMCIA_WINEN_IO0;
671 break;
672 case 1:
673 reg &= ~PLUM_PCMCIA_WINEN_IO1;
674 break;
675 }
676 plum_conf_write(regt, regh, PLUM_PCMCIA_WINEN, reg);
677 ph->ph_ioalloc &= ~(1 << window);
678 }
679
680 static void
681 plumpcmcia_wait_ready(struct plumpcmcia_handle *ph)
682 {
683 bus_space_tag_t regt = ph->ph_regt;
684 bus_space_handle_t regh = ph->ph_regh;
685 int i;
686
687 for (i = 0; i < 10000; i++) {
688 if ((plum_conf_read(regt, regh, PLUM_PCMCIA_STATUS) &
689 PLUM_PCMCIA_STATUS_READY) &&
690 (plum_conf_read(regt, regh, PLUM_PCMCIA_STATUS) &
691 PLUM_PCMCIA_STATUS_PWROK)) {
692 return;
693 }
694 delay(500);
695
696 if ((i > 5000) && (i % 100 == 99)) {
697 printf(".");
698 }
699 }
700 printf("plumpcmcia_wait_ready: failed\n");
701 }
702
703 static void
704 plumpcmcia_chip_socket_enable(pcmcia_chipset_handle_t pch)
705 {
706 struct plumpcmcia_handle *ph = (void*)pch;
707 bus_space_tag_t regt = ph->ph_regt;
708 bus_space_handle_t regh = ph->ph_regh;
709 plumreg_t reg, power;
710 int win, cardtype;
711
712 /* this bit is mostly stolen from pcic_attach_card */
713
714 /* power down the socket to reset it, clear the card reset pin */
715
716 plum_conf_write(regt, regh, PLUM_PCMCIA_PWRCTRL, 0);
717
718 /*
719 * wait 300ms until power fails (Tpf). Then, wait 100ms since
720 * we are changing Vcc (Toff).
721 */
722 delay((300 + 100) * 1000);
723
724 /*
725 * power up the socket
726 */
727 /* detect voltage */
728 reg = plum_conf_read(regt, regh, PLUM_PCMCIA_GENCTRL2);
729 if ((reg & PLUM_PCMCIA_GENCTRL2_VCC5V) ==
730 PLUM_PCMCIA_GENCTRL2_VCC5V) {
731 power = PLUM_PCMCIA_PWRCTRL_VCC_CTRLBIT1; /* 5V */
732 } else {
733 power = PLUM_PCMCIA_PWRCTRL_VCC_CTRLBIT0; /* 3.3V */
734 }
735
736 plum_conf_write(regt, regh, PLUM_PCMCIA_PWRCTRL,
737 PLUM_PCMCIA_PWRCTRL_DISABLE_RESETDRV |
738 power |
739 PLUM_PCMCIA_PWRCTRL_PWR_ENABLE);
740
741 /*
742 * wait 100ms until power raise (Tpr) and 20ms to become
743 * stable (Tsu(Vcc)).
744 *
745 * some machines require some more time to be settled
746 * (300ms is added here).
747 */
748 delay((100 + 20 + 300) * 1000);
749
750 plum_conf_write(regt, regh, PLUM_PCMCIA_PWRCTRL,
751 PLUM_PCMCIA_PWRCTRL_DISABLE_RESETDRV |
752 power |
753 PLUM_PCMCIA_PWRCTRL_OE |
754 PLUM_PCMCIA_PWRCTRL_PWR_ENABLE);
755 plum_conf_write(regt, regh, PLUM_PCMCIA_GENCTRL, 0);
756
757 /*
758 * hold RESET at least 10us.
759 */
760 delay(10);
761
762 /* clear the reset flag */
763 plum_conf_write(regt, regh, PLUM_PCMCIA_GENCTRL,
764 PLUM_PCMCIA_GENCTRL_RESET);
765
766 /* wait 20ms as per pc card standard (r2.01) section 4.3.6 */
767
768 delay(20000);
769
770 /* wait for the chip to finish initializing */
771 plumpcmcia_wait_ready(ph);
772
773 /* zero out the address windows */
774
775 plum_conf_write(regt, regh, PLUM_PCMCIA_WINEN, 0);
776
777 /* set the card type */
778
779 cardtype = pcmcia_card_gettype(ph->ph_pcmcia);
780
781 reg = (cardtype == PCMCIA_IFTYPE_IO) ?
782 PLUM_PCMCIA_GENCTRL_CARDTYPE_IO :
783 PLUM_PCMCIA_GENCTRL_CARDTYPE_MEM;
784 reg |= plum_conf_read(regt, regh, PLUM_PCMCIA_GENCTRL);
785 DPRINTF(("%s: plumpcmcia_chip_socket_enable cardtype %s\n",
786 ph->ph_parent->dv_xname,
787 ((cardtype == PCMCIA_IFTYPE_IO) ? "io" : "mem")));
788
789 plum_conf_write(regt, regh, PLUM_PCMCIA_GENCTRL, reg);
790
791 /* reinstall all the memory and io mappings */
792
793 for (win = 0; win < PLUM_PCMCIA_MEM_WINS; win++) {
794 if (ph->ph_memalloc & (1 << win)) {
795 plumpcmcia_chip_do_mem_map(ph, win);
796 }
797 }
798
799 for (win = 0; win < PLUM_PCMCIA_IO_WINS; win++) {
800 if (ph->ph_ioalloc & (1 << win)) {
801 plumpcmcia_chip_do_io_map(ph, win);
802 }
803 }
804
805 }
806
807 static void
808 plumpcmcia_chip_socket_disable(pcmcia_chipset_handle_t pch)
809 {
810 struct plumpcmcia_handle *ph = (void*)pch;
811 bus_space_tag_t regt = ph->ph_regt;
812 bus_space_handle_t regh = ph->ph_regh;
813
814 /* power down the socket */
815 plum_conf_write(regt, regh, PLUM_PCMCIA_PWRCTRL, 0);
816
817 /*
818 * wait 300ms until power fails (Tpf).
819 */
820 delay(300 * 1000);
821 }
822
823 static void
824 plum_csc_intr_setup(struct plumpcmcia_softc *sc, struct plumpcmcia_handle *ph,
825 int irq)
826 {
827 bus_space_tag_t regt = ph->ph_regt;
828 bus_space_handle_t regh = ph->ph_regh;
829 plumreg_t reg;
830 void *ih;
831
832 /* enable CARD DETECT ENABLE only */
833 plum_conf_write(regt, regh, PLUM_PCMCIA_CSCINT,
834 PLUM_PCMCIA_CSCINT_CARD_DETECT);
835
836 /* don't use explicit writeback csc interrupt status */
837 reg = plum_conf_read(regt, regh, PLUM_PCMCIA_GLOBALCTRL);
838 reg &= ~PLUM_PCMCIA_GLOBALCTRL_EXPLICIT_WB_CSC_INT;
839 plum_conf_write(regt, regh, PLUM_PCMCIA_GLOBALCTRL, reg);
840
841 /* install interrupt handler (don't fail) */
842 ih = plum_intr_establish(sc->sc_pc, irq, IST_EDGE, IPL_TTY,
843 plum_csc_intr, ph);
844 KASSERT(ih != 0);
845 }
846
847 static int
848 plum_csc_intr(void *arg)
849 {
850 struct plumpcmcia_handle *ph = arg;
851 struct plumpcmcia_softc *sc = (void *)ph->ph_parent;
852 struct plumpcmcia_event *pe;
853 bus_space_tag_t regt = ph->ph_regt;
854 bus_space_handle_t regh = ph->ph_regh;
855 plumreg_t reg;
856 int flag;
857
858 /* read and clear interrupt status */
859 reg = plum_conf_read(regt, regh, PLUM_PCMCIA_CSCINT_STAT);
860 if (reg & PLUM_PCMCIA_CSCINT_CARD_DETECT) {
861 DPRINTF(("%s: card status change.\n", __FUNCTION__));
862 } else {
863 DPRINTF(("%s: unhandled csc event. 0x%02x\n",
864 __FUNCTION__, reg));
865 return (0);
866 }
867
868 /* inquire card status (insert or remove) */
869 reg = plum_conf_read(regt, regh, PLUM_PCMCIA_STATUS);
870 reg &= (PLUM_PCMCIA_STATUS_CD1 | PLUM_PCMCIA_STATUS_CD2);
871 if (reg == (PLUM_PCMCIA_STATUS_CD1 | PLUM_PCMCIA_STATUS_CD2)) {
872 /* insert */
873 flag = PLUM_PCMCIA_EVENT_INSERT;
874 } else {
875 /* remove */
876 flag = PLUM_PCMCIA_EVENT_REMOVE;
877 }
878
879 /* queue event to event thread and wakeup. */
880 pe = plumpcmcia_event_alloc();
881 if (pe == 0) {
882 printf("%s: event FIFO overflow (%d).\n", __FUNCTION__,
883 PLUM_PCMCIA_EVENT_QUEUE_MAX);
884 return (0);
885 }
886 pe->pe_type = flag;
887 pe->pe_ph = ph;
888 SIMPLEQ_INSERT_TAIL(&sc->sc_event_head, pe, pe_link);
889 wakeup(sc);
890
891 return (0);
892 }
893
894 static struct plumpcmcia_event *
895 plumpcmcia_event_alloc()
896 {
897 int i;
898 /* I assume called from interrupt context only. so don't lock */
899 for (i = 0; i < PLUM_PCMCIA_EVENT_QUEUE_MAX; i++) {
900 if (!__event_queue_pool[i].__queued) {
901 __event_queue_pool[i].__queued = 1;
902 return (&__event_queue_pool[i]);
903 }
904 }
905
906 return (0);
907 }
908
909 static void
910 plumpcmcia_event_free(struct plumpcmcia_event *pe)
911 {
912 /* I assume context is already locked */
913 pe->__queued = 0;
914 }
915
916 static void
917 plumpcmcia_create_event_thread(void *arg)
918 {
919 struct plumpcmcia_softc *sc = arg;
920 int error;
921
922 error = kthread_create1(plumpcmcia_event_thread, sc,
923 &sc->sc_event_thread, "%s",
924 sc->sc_dev.dv_xname);
925 KASSERT(error == 0);
926 }
927
928 static void
929 plumpcmcia_event_thread(void *arg)
930 {
931 struct plumpcmcia_softc *sc = arg;
932 struct plumpcmcia_event *pe;
933 int s;
934
935 while (/*CONSTCOND*/1) { /* XXX shutdown. -uch */
936 tsleep(sc, PWAIT, "CSC wait", 0);
937 s = spltty();
938 while ((pe = SIMPLEQ_FIRST(&sc->sc_event_head))) {
939 splx(s);
940 switch (pe->pe_type) {
941 default:
942 printf("%s: unknown event.\n", __FUNCTION__);
943 break;
944 case PLUM_PCMCIA_EVENT_INSERT:
945 DPRINTF(("%s: insert event.\n", __FUNCTION__));
946 pcmcia_card_attach(pe->pe_ph->ph_pcmcia);
947 break;
948 case PLUM_PCMCIA_EVENT_REMOVE:
949 DPRINTF(("%s: remove event.\n", __FUNCTION__));
950 pcmcia_card_detach(pe->pe_ph->ph_pcmcia,
951 DETACH_FORCE);
952 break;
953 }
954 s = spltty();
955 SIMPLEQ_REMOVE_HEAD(&sc->sc_event_head, pe_link);
956 plumpcmcia_event_free(pe);
957 }
958 splx(s);
959 }
960 /* NOTREACHED */
961 }
962
963 /* power XXX notyet */
964 int
965 plumpcmcia_power(void *ctx, int type, long id, void *msg)
966 {
967 struct plumpcmcia_softc *sc = ctx;
968 bus_space_tag_t regt = sc->sc_regt;
969 bus_space_handle_t regh = sc->sc_regh;
970 int why = (int)msg;
971
972 switch (why) {
973 case PWR_RESUME:
974 DPRINTF(("%s: ON\n", sc->sc_dev.dv_xname));
975 /* power on */
976 plum_conf_write(regt, regh, PLUM_PCMCIA_CARDPWRCTRL,
977 PLUM_PCMCIA_CARDPWRCTRL_ON);
978 break;
979 case PWR_SUSPEND:
980 /* FALLTHROUGH */
981 case PWR_STANDBY:
982 plum_conf_write(regt, regh, PLUM_PCMCIA_CARDPWRCTRL,
983 PLUM_PCMCIA_CARDPWRCTRL_OFF);
984 DPRINTF(("%s: OFF\n", sc->sc_dev.dv_xname));
985 break;
986 }
987
988 return (0);
989 }
990
991 #ifdef PLUMPCMCIA_DEBUG
992 static void
993 __ioareadump(plumreg_t reg)
994 {
995
996 if (reg & PLUM_PCMCIA_IOWINADDRCTRL_AREA2) {
997 printf("I/O Area 2\n");
998 } else {
999 printf("I/O Area 1\n");
1000 }
1001 }
1002
1003 static void
1004 __memareadump(plumreg_t reg)
1005 {
1006 int maparea;
1007
1008 maparea = PLUM_PCMCIA_MEMWINCTRL_MAP(reg);
1009 switch (maparea) {
1010 case PLUM_PCMCIA_MEMWINCTRL_MAP_AREA1:
1011 printf("MEM Area1\n");
1012 break;
1013 case PLUM_PCMCIA_MEMWINCTRL_MAP_AREA2:
1014 printf("MEM Area2\n");
1015 break;
1016 case PLUM_PCMCIA_MEMWINCTRL_MAP_AREA3:
1017 printf("MEM Area3\n");
1018 break;
1019 case PLUM_PCMCIA_MEMWINCTRL_MAP_AREA4:
1020 printf("MEM Area4\n");
1021 break;
1022 }
1023 }
1024
1025 static void
1026 plumpcmcia_dump(struct plumpcmcia_softc *sc)
1027 {
1028 bus_space_tag_t regt = sc->sc_regt;
1029 bus_space_handle_t regh = sc->sc_regh;
1030 plumreg_t reg;
1031
1032 int i, j;
1033
1034 __memareadump(plum_conf_read(regt, regh, PLUM_PCMCIA_MEMWIN0CTRL));
1035 __memareadump(plum_conf_read(regt, regh, PLUM_PCMCIA_MEMWIN1CTRL));
1036 __memareadump(plum_conf_read(regt, regh, PLUM_PCMCIA_MEMWIN2CTRL));
1037 __memareadump(plum_conf_read(regt, regh, PLUM_PCMCIA_MEMWIN3CTRL));
1038 __memareadump(plum_conf_read(regt, regh, PLUM_PCMCIA_MEMWIN4CTRL));
1039
1040 __ioareadump(plum_conf_read(regt, regh, PLUM_PCMCIA_IOWIN0ADDRCTRL));
1041 __ioareadump(plum_conf_read(regt, regh, PLUM_PCMCIA_IOWIN1ADDRCTRL));
1042
1043 for (j = 0; j < 2; j++) {
1044 printf("[slot %d]\n", j);
1045 for (i = 0; i < 0x120; i += 4) {
1046 reg = plum_conf_read(sc->sc_regt, sc->sc_regh,
1047 i + 0x800 * j);
1048 printf("%03x %08x", i, reg);
1049 dbg_bit_print(reg);
1050 }
1051 }
1052 printf("\n");
1053 }
1054 #endif /* PLUMPCMCIA_DEBUG */
1055