1 /* $NetBSD: plumpcmcia.c,v 1.23 2007/12/15 00:39:17 perry Exp $ */
4 * Copyright (c) 1999, 2000 UCHIYAMA Yasushi. All rights reserved.
5 * Copyright (c) 1997 Marc Horowitz. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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.
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: plumpcmcia.c,v 1.23 2007/12/15 00:39:17 perry Exp $");
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/device.h>
39 #include <sys/kthread.h>
41 #include <machine/bus.h>
42 #include <machine/config_hook.h>
43 #include <machine/bus_space_hpcmips.h>
45 #include <dev/pcmcia/pcmciareg.h>
46 #include <dev/pcmcia/pcmciavar.h>
47 #include <dev/pcmcia/pcmciachip.h>
49 #include <hpcmips/tx/tx39var.h>
50 #include <hpcmips/dev/plumvar.h>
51 #include <hpcmips/dev/plumicuvar.h>
52 #include <hpcmips/dev/plumpowervar.h>
53 #include <hpcmips/dev/plumpcmciareg.h>
55 #ifdef PLUMPCMCIA_DEBUG
56 #define DPRINTF_ENABLE
57 #define DPRINTF_DEBUG plumpcmcia_debug
59 #include <machine/debug.h>
61 int plumpcmcia_match(struct device
*, struct cfdata
*, void *);
62 void plumpcmcia_attach(struct device
*, struct device
*, void *);
63 int plumpcmcia_print(void *, const char *);
65 int plumpcmcia_power(void *, int, long, void *);
67 struct plumpcmcia_softc
;
69 struct plumpcmcia_handle
{
71 struct device
*ph_parent
;
73 struct device
*ph_pcmcia
;
75 /* PCMCIA controller register space */
76 bus_space_tag_t ph_regt
;
77 bus_space_handle_t ph_regh
;
80 int ph_ioarea
; /* not PCMCIA window */
85 } ph_io
[PLUM_PCMCIA_IO_WINS
];
87 bus_space_tag_t ph_iot
;
88 bus_space_handle_t ph_ioh
;
92 /* I/O Memory space */
93 int ph_memarea
; /* not PCMCIA window */
99 } ph_mem
[PLUM_PCMCIA_MEM_WINS
];
101 bus_space_tag_t ph_memt
;
102 bus_space_handle_t ph_memh
;
103 bus_addr_t ph_membase
;
104 bus_size_t ph_memsize
;
106 /* Card interrupt handler */
111 enum plumpcmcia_event_type
{
112 PLUM_PCMCIA_EVENT_INSERT
,
113 PLUM_PCMCIA_EVENT_REMOVE
,
116 struct plumpcmcia_event
{
118 enum plumpcmcia_event_type pe_type
;
119 struct plumpcmcia_handle
*pe_ph
;
120 SIMPLEQ_ENTRY(plumpcmcia_event
) pe_link
;
123 struct plumpcmcia_softc
{
124 struct device sc_dev
;
125 plum_chipset_tag_t sc_pc
;
128 bus_space_tag_t sc_regt
;
129 bus_space_handle_t sc_regh
;
131 /* power management hook */
135 lwp_t
*sc_event_thread
;
136 SIMPLEQ_HEAD (, plumpcmcia_event
) sc_event_head
;
139 struct plumpcmcia_handle sc_ph
[PLUMPCMCIA_NSLOTS
];
142 static void plumpcmcia_attach_socket(struct plumpcmcia_handle
*);
143 static int plumpcmcia_chip_mem_alloc(pcmcia_chipset_handle_t
, bus_size_t
,
144 struct pcmcia_mem_handle
*);
145 static void plumpcmcia_chip_mem_free(pcmcia_chipset_handle_t
,
146 struct pcmcia_mem_handle
*);
147 static int plumpcmcia_chip_mem_map(pcmcia_chipset_handle_t
, int, bus_addr_t
,
148 bus_size_t
, struct pcmcia_mem_handle
*, bus_size_t
*, int *);
149 static void plumpcmcia_chip_mem_unmap(pcmcia_chipset_handle_t
, int);
150 static int plumpcmcia_chip_io_alloc(pcmcia_chipset_handle_t
, bus_addr_t
,
151 bus_size_t
, bus_size_t
, struct pcmcia_io_handle
*);
152 static void plumpcmcia_chip_io_free(pcmcia_chipset_handle_t
,
153 struct pcmcia_io_handle
*);
154 static int plumpcmcia_chip_io_map(pcmcia_chipset_handle_t
, int, bus_addr_t
,
155 bus_size_t
, struct pcmcia_io_handle
*, int *);
156 static void plumpcmcia_chip_io_unmap(pcmcia_chipset_handle_t
, int);
157 static void plumpcmcia_chip_socket_enable(pcmcia_chipset_handle_t
);
158 static void plumpcmcia_chip_socket_disable(pcmcia_chipset_handle_t
);
159 static void plumpcmcia_chip_socket_settype(pcmcia_chipset_handle_t
, int);
160 static void *plumpcmcia_chip_intr_establish(pcmcia_chipset_handle_t
,
161 struct pcmcia_function
*, int, int (*)(void *), void *);
162 static void plumpcmcia_chip_intr_disestablish(pcmcia_chipset_handle_t
, void *);
163 static void plumpcmcia_wait_ready( struct plumpcmcia_handle
*);
164 static void plumpcmcia_chip_do_mem_map(struct plumpcmcia_handle
*, int);
165 static void plumpcmcia_chip_do_io_map(struct plumpcmcia_handle
*, int);
167 static struct pcmcia_chip_functions plumpcmcia_functions
= {
168 plumpcmcia_chip_mem_alloc
,
169 plumpcmcia_chip_mem_free
,
170 plumpcmcia_chip_mem_map
,
171 plumpcmcia_chip_mem_unmap
,
172 plumpcmcia_chip_io_alloc
,
173 plumpcmcia_chip_io_free
,
174 plumpcmcia_chip_io_map
,
175 plumpcmcia_chip_io_unmap
,
176 plumpcmcia_chip_intr_establish
,
177 plumpcmcia_chip_intr_disestablish
,
178 plumpcmcia_chip_socket_enable
,
179 plumpcmcia_chip_socket_disable
,
180 plumpcmcia_chip_socket_settype
,
184 #define PLUM_PCMCIA_EVENT_QUEUE_MAX 5
185 static struct plumpcmcia_event __event_queue_pool
[PLUM_PCMCIA_EVENT_QUEUE_MAX
];
186 static struct plumpcmcia_event
*plumpcmcia_event_alloc(void);
187 static void plumpcmcia_event_free(struct plumpcmcia_event
*);
188 static void plum_csc_intr_setup(struct plumpcmcia_softc
*,
189 struct plumpcmcia_handle
*, int);
190 static int plum_csc_intr(void *);
191 static void plumpcmcia_event_thread(void *);
193 #ifdef PLUMPCMCIA_DEBUG
195 #define __DEBUG_FUNC __attribute__((__unused__))
196 static void __ioareadump(plumreg_t
) __DEBUG_FUNC
;
197 static void __memareadump(plumreg_t
) __DEBUG_FUNC
;
198 static void plumpcmcia_dump(struct plumpcmcia_softc
*) __DEBUG_FUNC
;
199 #endif /* PLUMPCMCIA_DEBUG */
201 CFATTACH_DECL(plumpcmcia
, sizeof(struct plumpcmcia_softc
),
202 plumpcmcia_match
, plumpcmcia_attach
, NULL
, NULL
);
205 plumpcmcia_match(struct device
*parent
, struct cfdata
*cf
, void *aux
)
211 plumpcmcia_attach(struct device
*parent
, struct device
*self
, void *aux
)
213 struct plum_attach_args
*pa
= aux
;
214 struct plumpcmcia_softc
*sc
= (void*)self
;
215 struct plumpcmcia_handle
*ph
;
218 sc
->sc_pc
= pa
->pa_pc
;
219 sc
->sc_regt
= pa
->pa_regt
;
221 /* map register area */
222 if (bus_space_map(sc
->sc_regt
, PLUM_PCMCIA_REGBASE
,
223 PLUM_PCMCIA_REGSIZE
, 0, &sc
->sc_regh
)) {
224 printf(": register map failed\n");
228 plumpcmcia_power(sc
, 0, 0, (void *)PWR_RESUME
);
229 /* Add a hard power hook to power saving */
231 sc
->sc_powerhook
= config_hook(CONFIG_HOOK_PMEVENT
,
232 CONFIG_HOOK_PMEVENT_HARDPOWER
,
234 plumpcmcia_power
, sc
);
235 if (sc
->sc_powerhook
== 0)
236 printf(": WARNING unable to establish hard power hook");
240 /* Slot0/1 CSC event queue */
241 SIMPLEQ_INIT (&sc
->sc_event_head
);
242 error
= kthread_create(PRI_NONE
, 0, NULL
, plumpcmcia_event_thread
,
243 sc
, &sc
->sc_event_thread
, "%s", sc
->sc_dev
.dv_xname
);
248 ph
->ph_plum_irq
= PLUM_INT_C1IO
;
249 ph
->ph_memarea
= PLUM_PCMCIA_MEMWINCTRL_MAP_AREA1
;
250 ph
->ph_membase
= PLUM_PCMCIA_MEMBASE1
;
251 ph
->ph_memsize
= PLUM_PCMCIA_MEMSIZE1
;
252 ph
->ph_ioarea
= PLUM_PCMCIA_IOWINADDRCTRL_AREA1
;
253 ph
->ph_iobase
= PLUM_PCMCIA_IOBASE1
;
254 ph
->ph_iosize
= PLUM_PCMCIA_IOSIZE1
;
255 ph
->ph_regt
= sc
->sc_regt
;
256 bus_space_subregion(sc
->sc_regt
, sc
->sc_regh
,
257 PLUM_PCMCIA_REGSPACE_SLOT0
,
258 PLUM_PCMCIA_REGSPACE_SIZE
,
260 ph
->ph_iot
= pa
->pa_iot
;
261 ph
->ph_memt
= pa
->pa_iot
;
262 ph
->ph_parent
= (void*)sc
;
264 plum_csc_intr_setup(sc
, ph
, PLUM_INT_C1SC
);
265 plum_power_establish(sc
->sc_pc
, PLUM_PWR_PCC1
);
266 plumpcmcia_attach_socket(ph
);
270 ph
->ph_plum_irq
= PLUM_INT_C2IO
;
271 ph
->ph_memarea
= PLUM_PCMCIA_MEMWINCTRL_MAP_AREA2
;
272 ph
->ph_membase
= PLUM_PCMCIA_MEMBASE2
;
273 ph
->ph_memsize
= PLUM_PCMCIA_MEMSIZE2
;
274 ph
->ph_ioarea
= PLUM_PCMCIA_IOWINADDRCTRL_AREA2
;
275 ph
->ph_iobase
= PLUM_PCMCIA_IOBASE2
;
276 ph
->ph_iosize
= PLUM_PCMCIA_IOSIZE2
;
277 ph
->ph_regt
= sc
->sc_regt
;
278 bus_space_subregion(sc
->sc_regt
, sc
->sc_regh
,
279 PLUM_PCMCIA_REGSPACE_SLOT1
,
280 PLUM_PCMCIA_REGSPACE_SIZE
,
282 ph
->ph_iot
= pa
->pa_iot
;
283 ph
->ph_memt
= pa
->pa_iot
;
284 ph
->ph_parent
= (void*)sc
;
286 plum_csc_intr_setup(sc
, ph
, PLUM_INT_C2SC
);
287 plum_power_establish(sc
->sc_pc
, PLUM_PWR_PCC2
);
288 plumpcmcia_attach_socket(ph
);
292 plumpcmcia_print(void *arg
, const char *pnp
)
295 aprint_normal("pcmcia at %s", pnp
);
302 plumpcmcia_attach_socket(struct plumpcmcia_handle
*ph
)
304 struct pcmciabus_attach_args paa
;
305 struct plumpcmcia_softc
*sc
= (void*)ph
->ph_parent
;
307 paa
.paa_busname
= "pcmcia";
308 paa
.pct
= (pcmcia_chipset_tag_t
)&plumpcmcia_functions
;
309 paa
.pch
= (pcmcia_chipset_handle_t
)ph
;
311 paa
.iosize
= ph
->ph_iosize
;
313 if ((ph
->ph_pcmcia
= config_found_ia((void*)sc
, "pcmciabus", &paa
,
314 plumpcmcia_print
))) {
316 plum_conf_write(ph
->ph_regt
, ph
->ph_regh
,
317 PLUM_PCMCIA_SLOTCTRL
,
318 PLUM_PCMCIA_SLOTCTRL_ENABLE
);
319 /* Support 3.3V card & enable Voltage Sense Status */
320 plum_conf_write(ph
->ph_regt
, ph
->ph_regh
,
321 PLUM_PCMCIA_FUNCCTRL
,
322 PLUM_PCMCIA_FUNCCTRL_VSSEN
|
323 PLUM_PCMCIA_FUNCCTRL_3VSUPPORT
);
324 pcmcia_card_attach(ph
->ph_pcmcia
);
329 plumpcmcia_chip_intr_establish(pcmcia_chipset_handle_t pch
,
330 struct pcmcia_function
*pf
, int ipl
,
331 int (*ih_fun
)(void *), void *ih_arg
)
333 struct plumpcmcia_handle
*ph
= (void*)pch
;
334 struct plumpcmcia_softc
*sc
= (void*)ph
->ph_parent
;
336 if (!(ph
->ph_card_ih
=
337 plum_intr_establish(sc
->sc_pc
, ph
->ph_plum_irq
,
338 IST_EDGE
, IPL_BIO
, ih_fun
, ih_arg
))) {
339 printf("plumpcmcia_chip_intr_establish: can't establish\n");
343 return (ph
->ph_card_ih
);
347 plumpcmcia_chip_intr_disestablish(pcmcia_chipset_handle_t pch
, void *ih
)
349 struct plumpcmcia_handle
*ph
= (void*)pch
;
350 struct plumpcmcia_softc
*sc
= (void*)ph
->ph_parent
;
352 plum_intr_disestablish(sc
->sc_pc
, ih
);
356 plumpcmcia_chip_mem_alloc(pcmcia_chipset_handle_t pch
, bus_size_t size
,
357 struct pcmcia_mem_handle
*pcmhp
)
359 struct plumpcmcia_handle
*ph
= (void*)pch
;
362 /* convert size to PCIC pages */
363 realsize
= ((size
+ (PLUM_PCMCIA_MEM_PAGESIZE
- 1)) /
364 PLUM_PCMCIA_MEM_PAGESIZE
) * PLUM_PCMCIA_MEM_PAGESIZE
;
366 if (bus_space_alloc(ph
->ph_memt
, ph
->ph_membase
,
367 ph
->ph_membase
+ ph
->ph_memsize
,
368 realsize
, PLUM_PCMCIA_MEM_PAGESIZE
,
369 0, 0, 0, &pcmhp
->memh
)) {
373 pcmhp
->memt
= ph
->ph_memt
;
374 /* Address offset from MEM area base */
375 pcmhp
->addr
= pcmhp
->memh
- ph
->ph_membase
-
376 ((struct bus_space_tag_hpcmips
*)ph
->ph_memt
)->base
;
378 pcmhp
->realsize
= realsize
;
380 DPRINTF(("plumpcmcia_chip_mem_alloc: size %#x->%#x addr %#x->%#x\n",
381 (unsigned)size
, (unsigned)realsize
, (unsigned)pcmhp
->addr
,
382 (unsigned)pcmhp
->memh
));
388 plumpcmcia_chip_mem_free(pcmcia_chipset_handle_t pch
,
389 struct pcmcia_mem_handle
*pcmhp
)
392 bus_space_free(pcmhp
->memt
, pcmhp
->memh
, pcmhp
->size
);
396 plumpcmcia_chip_mem_map(pcmcia_chipset_handle_t pch
, int kind
,
397 bus_addr_t card_addr
, bus_size_t size
,
398 struct pcmcia_mem_handle
*pcmhp
,
399 bus_size_t
*offsetp
, int *windowp
)
401 struct plumpcmcia_handle
*ph
= (void*)pch
;
406 for (win
= -1, i
= 0; i
< PLUM_PCMCIA_MEM_WINS
; i
++) {
407 if ((ph
->ph_memalloc
& (1 << i
)) == 0) {
409 ph
->ph_memalloc
|= (1 << i
);
414 DPRINTF(("plumpcmcia_chip_mem_map: no window\n"));
418 busaddr
= pcmhp
->addr
;
420 *offsetp
= card_addr
% PLUM_PCMCIA_MEM_PAGESIZE
;
421 card_addr
-= *offsetp
;
422 size
+= *offsetp
- 1;
424 card_offset
= (((int32_t)card_addr
) - ((int32_t)busaddr
));
426 DPRINTF(("plumpcmcia_chip_mem_map window %d bus %#x(kv:%#x)+%#x"
427 " size %#x at card addr %#x offset %#x\n", win
,
428 (unsigned)busaddr
, (unsigned)pcmhp
->memh
, (unsigned)*offsetp
,
429 (unsigned)size
, (unsigned)card_addr
, (unsigned)card_offset
));
431 ph
->ph_mem
[win
].pm_addr
= busaddr
;
432 ph
->ph_mem
[win
].pm_size
= size
;
433 ph
->ph_mem
[win
].pm_offset
= card_offset
;
434 ph
->ph_mem
[win
].pm_kind
= kind
;
435 ph
->ph_memalloc
|= (1 << win
);
437 plumpcmcia_chip_do_mem_map(ph
, win
);
443 plumpcmcia_chip_do_mem_map(struct plumpcmcia_handle
*ph
, int win
)
445 bus_space_tag_t regt
= ph
->ph_regt
;
446 bus_space_handle_t regh
= ph
->ph_regh
;
447 plumreg_t reg
, addr
, offset
, size
;
449 if (win
< 0 || win
> 4) {
450 panic("plumpcmcia_chip_do_mem_map: bogus window %d", win
);
453 addr
= (ph
->ph_mem
[win
].pm_addr
) >> PLUM_PCMCIA_MEM_SHIFT
;
454 size
= (ph
->ph_mem
[win
].pm_size
) >> PLUM_PCMCIA_MEM_SHIFT
;
455 offset
= (ph
->ph_mem
[win
].pm_offset
) >> PLUM_PCMCIA_MEM_SHIFT
;
457 /* Attribute memory or not */
458 reg
= ph
->ph_mem
[win
].pm_kind
== PCMCIA_MEM_ATTR
?
459 PLUM_PCMCIA_MEMWINCTRL_REGACTIVE
: 0;
461 /* Notify I/O area to select for PCMCIA controller */
462 reg
= PLUM_PCMCIA_MEMWINCTRL_MAP_SET(reg
, ph
->ph_memarea
);
464 /* Zero wait & 16bit access */
465 reg
|= (PLUM_PCMCIA_MEMWINCTRL_ZERO_WS
|
466 PLUM_PCMCIA_MEMWINCTRL_DATASIZE16
);
467 plum_conf_write(regt
, regh
, PLUM_PCMCIA_MEMWINCTRL(win
), reg
);
469 /* Map Host <-> PC-Card address */
472 plum_conf_write(regt
, regh
, PLUM_PCMCIA_MEMWINSTARTADDR(win
),
474 plum_conf_write(regt
, regh
, PLUM_PCMCIA_MEMWINSTOPADDR(win
),
478 plum_conf_write(regt
, regh
, PLUM_PCMCIA_MEMWINOFSADDR(win
), offset
);
480 /* Enable memory window */
481 reg
= plum_conf_read(regt
, regh
, PLUM_PCMCIA_WINEN
);
482 reg
|= PLUM_PCMCIA_WINEN_MEM(win
);
483 plum_conf_write(regt
, regh
, PLUM_PCMCIA_WINEN
, reg
);
485 DPRINTF(("plumpcmcia_chip_do_mem_map: window:%d %#x(%#x)+%#x\n",
486 win
, offset
, addr
, size
));
492 plumpcmcia_chip_mem_unmap(pcmcia_chipset_handle_t pch
, int window
)
494 struct plumpcmcia_handle
*ph
= (void*)pch
;
495 bus_space_tag_t regt
= ph
->ph_regt
;
496 bus_space_handle_t regh
= ph
->ph_regh
;
499 reg
= plum_conf_read(regt
, regh
, PLUM_PCMCIA_WINEN
);
500 reg
&= ~PLUM_PCMCIA_WINEN_MEM(window
);
501 plum_conf_write(regt
, regh
, PLUM_PCMCIA_WINEN
, reg
);
503 ph
->ph_memalloc
&= ~(1 << window
);
507 plumpcmcia_chip_io_alloc(pcmcia_chipset_handle_t pch
, bus_addr_t start
,
508 bus_size_t size
, bus_size_t align
,
509 struct pcmcia_io_handle
*pcihp
)
511 struct plumpcmcia_handle
*ph
= (void*)pch
;
513 DPRINTF(("plumpcmcia_chip_io_alloc: start=%#x size=%#x ",
514 (unsigned)start
, (unsigned)size
));
516 if (bus_space_map(ph
->ph_iot
, ph
->ph_iobase
+ start
,
517 size
, 0, &pcihp
->ioh
)) {
518 DPRINTF(("bus_space_map failed\n"));
523 DPRINTF(("(mapped) %#x+%#x\n", (unsigned)start
,
526 if (bus_space_alloc(ph
->ph_iot
, ph
->ph_iobase
,
527 ph
->ph_iobase
+ ph
->ph_iosize
, size
,
528 align
, 0, 0, 0, &pcihp
->ioh
)) {
529 DPRINTF(("bus_space_alloc failed\n"));
532 /* Address offset from IO area base */
533 pcihp
->addr
= pcihp
->ioh
- ph
->ph_iobase
-
534 ((struct bus_space_tag_hpcmips
*)ph
->ph_iot
)->base
;
535 pcihp
->flags
= PCMCIA_IO_ALLOCATED
;
536 DPRINTF(("(allocated) %#x+%#x\n", (unsigned)pcihp
->addr
,
540 pcihp
->iot
= ph
->ph_iot
;
547 plumpcmcia_chip_io_map(pcmcia_chipset_handle_t pch
, int width
,
548 bus_addr_t offset
, bus_size_t size
,
549 struct pcmcia_io_handle
*pcihp
, int *windowp
)
551 #ifdef PLUMPCMCIA_DEBUG
552 static char *width_names
[] = { "auto", "io8", "io16" };
553 #endif /* PLUMPCMCIA_DEBUG */
554 struct plumpcmcia_handle
*ph
= (void*)pch
;
558 winofs
= pcihp
->addr
+ offset
;
560 if (winofs
> 0x3ff) {
561 printf("plumpcmcia_chip_io_map: WARNING port %#lx > 0x3ff\n",
565 for (win
= -1, i
= 0; i
< PLUM_PCMCIA_IO_WINS
; i
++) {
566 if ((ph
->ph_ioalloc
& (1 << i
)) == 0) {
568 ph
->ph_ioalloc
|= (1 << i
);
573 DPRINTF(("plumpcmcia_chip_io_map: no window\n"));
578 ph
->ph_io
[win
].pi_addr
= winofs
;
579 ph
->ph_io
[win
].pi_size
= size
;
580 ph
->ph_io
[win
].pi_width
= width
;
582 plumpcmcia_chip_do_io_map(ph
, win
);
584 DPRINTF(("plumpcmcia_chip_io_map: %#x(kv:%#x)+%#x %s\n",
585 (unsigned)offset
, (unsigned)pcihp
->ioh
, (unsigned)size
,
586 width_names
[width
]));
592 plumpcmcia_chip_do_io_map(struct plumpcmcia_handle
*ph
, int win
)
594 bus_space_tag_t regt
= ph
->ph_regt
;
595 bus_space_handle_t regh
= ph
->ph_regh
;
600 plumreg_t ioctlbits
[3] = {
601 PLUM_PCMCIA_IOWINCTRL_IOCS16SRC
,
603 PLUM_PCMCIA_IOWINCTRL_DATASIZE16
606 if (win
< 0 || win
> 1) {
607 panic("plumpcmcia_chip_do_io_map: bogus window %d", win
);
610 addr
= ph
->ph_io
[win
].pi_addr
;
611 size
= ph
->ph_io
[win
].pi_size
;
613 /* Notify I/O area to select for PCMCIA controller */
614 plum_conf_write(regt
, regh
, PLUM_PCMCIA_IOWINADDRCTRL(win
),
617 /* Start/Stop addr */
618 plum_conf_write(regt
, regh
, PLUM_PCMCIA_IOWINSTARTADDR(win
), addr
);
619 plum_conf_write(regt
, regh
, PLUM_PCMCIA_IOWINSTOPADDR(win
),
623 reg
= plum_conf_read(regt
, regh
, PLUM_PCMCIA_IOWINCTRL
);
624 shift
= win
== 0 ? PLUM_PCMCIA_IOWINCTRL_WIN0SHIFT
:
625 PLUM_PCMCIA_IOWINCTRL_WIN1SHIFT
;
627 reg
&= ~(PLUM_PCMCIA_IOWINCTRL_WINMASK
<< shift
);
628 reg
|= ((ioctlbits
[ph
->ph_io
[win
].pi_width
] |
629 PLUM_PCMCIA_IOWINCTRL_ZEROWAIT
) << shift
);
630 plum_conf_write(regt
, regh
, PLUM_PCMCIA_IOWINCTRL
, reg
);
633 reg
= plum_conf_read(regt
, regh
, PLUM_PCMCIA_WINEN
);
634 reg
|= (win
== 0 ? PLUM_PCMCIA_WINEN_IO0
:
635 PLUM_PCMCIA_WINEN_IO1
);
636 plum_conf_write(regt
, regh
, PLUM_PCMCIA_WINEN
, reg
);
642 plumpcmcia_chip_io_free(pcmcia_chipset_handle_t pch
,
643 struct pcmcia_io_handle
*pcihp
)
645 if (pcihp
->flags
& PCMCIA_IO_ALLOCATED
) {
646 bus_space_free(pcihp
->iot
, pcihp
->ioh
, pcihp
->size
);
648 bus_space_unmap(pcihp
->iot
, pcihp
->ioh
, pcihp
->size
);
651 DPRINTF(("plumpcmcia_chip_io_free %#x+%#x\n", pcihp
->ioh
,
652 (unsigned)pcihp
->size
));
656 plumpcmcia_chip_io_unmap(pcmcia_chipset_handle_t pch
, int window
)
658 struct plumpcmcia_handle
*ph
= (void*)pch
;
659 bus_space_tag_t regt
= ph
->ph_regt
;
660 bus_space_handle_t regh
= ph
->ph_regh
;
663 reg
= plum_conf_read(regt
, regh
, PLUM_PCMCIA_WINEN
);
666 panic("plumpcmcia_chip_io_unmap: bogus window");
668 reg
&= ~PLUM_PCMCIA_WINEN_IO0
;
671 reg
&= ~PLUM_PCMCIA_WINEN_IO1
;
674 plum_conf_write(regt
, regh
, PLUM_PCMCIA_WINEN
, reg
);
675 ph
->ph_ioalloc
&= ~(1 << window
);
679 plumpcmcia_wait_ready(struct plumpcmcia_handle
*ph
)
681 bus_space_tag_t regt
= ph
->ph_regt
;
682 bus_space_handle_t regh
= ph
->ph_regh
;
685 for (i
= 0; i
< 10000; i
++) {
686 if ((plum_conf_read(regt
, regh
, PLUM_PCMCIA_STATUS
) &
687 PLUM_PCMCIA_STATUS_READY
) &&
688 (plum_conf_read(regt
, regh
, PLUM_PCMCIA_STATUS
) &
689 PLUM_PCMCIA_STATUS_PWROK
)) {
694 if ((i
> 5000) && (i
% 100 == 99)) {
698 printf("plumpcmcia_wait_ready: failed\n");
702 plumpcmcia_chip_socket_enable(pcmcia_chipset_handle_t pch
)
704 struct plumpcmcia_handle
*ph
= (void *)pch
;
705 bus_space_tag_t regt
= ph
->ph_regt
;
706 bus_space_handle_t regh
= ph
->ph_regh
;
707 plumreg_t reg
, power
;
710 /* this bit is mostly stolen from pcic_attach_card */
712 /* set card type to memory to disable interrupts */
713 reg
= plum_conf_read(regt
, regh
, PLUM_PCMCIA_GENCTRL
);
714 reg
&= ~PLUM_PCMCIA_GENCTRL_CARDTYPE_MASK
;
715 plum_conf_write(regt
, regh
, PLUM_PCMCIA_GENCTRL
, reg
);
717 /* zero out the address windows */
718 plum_conf_write(regt
, regh
, PLUM_PCMCIA_WINEN
, 0);
720 /* power down the socket to reset it, clear the card reset pin */
721 plum_conf_write(regt
, regh
, PLUM_PCMCIA_PWRCTRL
, 0);
724 * wait 300ms until power fails (Tpf). Then, wait 100ms since
725 * we are changing Vcc (Toff).
727 delay((300 + 100) * 1000);
730 * power up the socket
733 reg
= plum_conf_read(regt
, regh
, PLUM_PCMCIA_GENCTRL2
);
734 if ((reg
& PLUM_PCMCIA_GENCTRL2_VCC5V
) ==
735 PLUM_PCMCIA_GENCTRL2_VCC5V
) {
736 power
= PLUM_PCMCIA_PWRCTRL_VCC_CTRLBIT1
; /* 5V */
738 power
= PLUM_PCMCIA_PWRCTRL_VCC_CTRLBIT0
; /* 3.3V */
741 plum_conf_write(regt
, regh
, PLUM_PCMCIA_PWRCTRL
,
742 PLUM_PCMCIA_PWRCTRL_DISABLE_RESETDRV
|
744 PLUM_PCMCIA_PWRCTRL_PWR_ENABLE
);
747 * wait 100ms until power raise (Tpr) and 20ms to become
750 * some machines require some more time to be settled
751 * (300ms is added here).
753 delay((100 + 20 + 300) * 1000);
755 plum_conf_write(regt
, regh
, PLUM_PCMCIA_PWRCTRL
,
756 PLUM_PCMCIA_PWRCTRL_DISABLE_RESETDRV
|
758 PLUM_PCMCIA_PWRCTRL_OE
|
759 PLUM_PCMCIA_PWRCTRL_PWR_ENABLE
);
760 plum_conf_write(regt
, regh
, PLUM_PCMCIA_GENCTRL
, 0);
763 * hold RESET at least 10us.
767 /* clear the reset flag */
768 plum_conf_write(regt
, regh
, PLUM_PCMCIA_GENCTRL
,
769 PLUM_PCMCIA_GENCTRL_RESET
);
771 /* wait 20ms as per pc card standard (r2.01) section 4.3.6 */
775 /* wait for the chip to finish initializing */
776 plumpcmcia_wait_ready(ph
);
778 /* reinstall all the memory and io mappings */
779 for (win
= 0; win
< PLUM_PCMCIA_MEM_WINS
; win
++) {
780 if (ph
->ph_memalloc
& (1 << win
)) {
781 plumpcmcia_chip_do_mem_map(ph
, win
);
785 for (win
= 0; win
< PLUM_PCMCIA_IO_WINS
; win
++) {
786 if (ph
->ph_ioalloc
& (1 << win
)) {
787 plumpcmcia_chip_do_io_map(ph
, win
);
793 plumpcmcia_chip_socket_settype(pcmcia_chipset_handle_t pch
, int type
)
795 struct plumpcmcia_handle
*ph
= (void *)pch
;
796 bus_space_tag_t regt
= ph
->ph_regt
;
797 bus_space_handle_t regh
= ph
->ph_regh
;
800 /* set the card type */
802 reg
= plum_conf_read(regt
, regh
, PLUM_PCMCIA_GENCTRL
);
803 reg
&= ~PLUM_PCMCIA_GENCTRL_CARDTYPE_MASK
;
804 if (type
== PCMCIA_IFTYPE_IO
)
805 reg
|= PLUM_PCMCIA_GENCTRL_CARDTYPE_IO
;
807 reg
|= PLUM_PCMCIA_GENCTRL_CARDTYPE_MEM
;
809 DPRINTF(("%s: plumpcmcia_chip_socket_enable type %s %02x\n",
810 ph
->ph_parent
->dv_xname
,
811 ((cardtype
== PCMCIA_IFTYPE_IO
) ? "io" : "mem"), reg
));
813 plum_conf_write(regt
, regh
, PLUM_PCMCIA_GENCTRL
, reg
);
817 plumpcmcia_chip_socket_disable(pcmcia_chipset_handle_t pch
)
819 struct plumpcmcia_handle
*ph
= (void *)pch
;
820 bus_space_tag_t regt
= ph
->ph_regt
;
821 bus_space_handle_t regh
= ph
->ph_regh
;
824 /* set card type to memory to disable interrupts */
825 reg
= plum_conf_read(regt
, regh
, PLUM_PCMCIA_GENCTRL
);
826 reg
&= ~PLUM_PCMCIA_GENCTRL_CARDTYPE_MASK
;
827 plum_conf_write(regt
, regh
, PLUM_PCMCIA_GENCTRL
, reg
);
829 /* zero out the address windows */
830 plum_conf_write(regt
, regh
, PLUM_PCMCIA_WINEN
, 0);
832 /* power down the socket */
833 plum_conf_write(regt
, regh
, PLUM_PCMCIA_PWRCTRL
, 0);
836 * wait 300ms until power fails (Tpf).
842 plum_csc_intr_setup(struct plumpcmcia_softc
*sc
, struct plumpcmcia_handle
*ph
,
845 bus_space_tag_t regt
= ph
->ph_regt
;
846 bus_space_handle_t regh
= ph
->ph_regh
;
850 /* enable CARD DETECT ENABLE only */
851 plum_conf_write(regt
, regh
, PLUM_PCMCIA_CSCINT
,
852 PLUM_PCMCIA_CSCINT_CARD_DETECT
);
854 /* don't use explicit writeback csc interrupt status */
855 reg
= plum_conf_read(regt
, regh
, PLUM_PCMCIA_GLOBALCTRL
);
856 reg
&= ~PLUM_PCMCIA_GLOBALCTRL_EXPLICIT_WB_CSC_INT
;
857 plum_conf_write(regt
, regh
, PLUM_PCMCIA_GLOBALCTRL
, reg
);
859 /* install interrupt handler (don't fail) */
860 ih
= plum_intr_establish(sc
->sc_pc
, irq
, IST_EDGE
, IPL_TTY
,
866 plum_csc_intr(void *arg
)
868 struct plumpcmcia_handle
*ph
= arg
;
869 struct plumpcmcia_softc
*sc
= (void *)ph
->ph_parent
;
870 struct plumpcmcia_event
*pe
;
871 bus_space_tag_t regt
= ph
->ph_regt
;
872 bus_space_handle_t regh
= ph
->ph_regh
;
876 /* read and clear interrupt status */
877 reg
= plum_conf_read(regt
, regh
, PLUM_PCMCIA_CSCINT_STAT
);
878 if (reg
& PLUM_PCMCIA_CSCINT_CARD_DETECT
) {
879 DPRINTF(("%s: card status change.\n", __func__
));
881 DPRINTF(("%s: unhandled csc event. 0x%02x\n",
886 /* inquire card status (insert or remove) */
887 reg
= plum_conf_read(regt
, regh
, PLUM_PCMCIA_STATUS
);
888 reg
&= (PLUM_PCMCIA_STATUS_CD1
| PLUM_PCMCIA_STATUS_CD2
);
889 if (reg
== (PLUM_PCMCIA_STATUS_CD1
| PLUM_PCMCIA_STATUS_CD2
)) {
891 flag
= PLUM_PCMCIA_EVENT_INSERT
;
894 flag
= PLUM_PCMCIA_EVENT_REMOVE
;
897 /* queue event to event thread and wakeup. */
898 pe
= plumpcmcia_event_alloc();
900 printf("%s: event FIFO overflow (%d).\n", __func__
,
901 PLUM_PCMCIA_EVENT_QUEUE_MAX
);
906 SIMPLEQ_INSERT_TAIL(&sc
->sc_event_head
, pe
, pe_link
);
912 static struct plumpcmcia_event
*
913 plumpcmcia_event_alloc(void)
916 /* I assume called from interrupt context only. so don't lock */
917 for (i
= 0; i
< PLUM_PCMCIA_EVENT_QUEUE_MAX
; i
++) {
918 if (!__event_queue_pool
[i
].__queued
) {
919 __event_queue_pool
[i
].__queued
= 1;
920 return (&__event_queue_pool
[i
]);
927 plumpcmcia_event_free(struct plumpcmcia_event
*pe
)
929 /* I assume context is already locked */
934 plumpcmcia_event_thread(void *arg
)
936 struct plumpcmcia_softc
*sc
= arg
;
937 struct plumpcmcia_event
*pe
;
940 while (/*CONSTCOND*/1) { /* XXX shutdown. -uch */
941 tsleep(sc
, PWAIT
, "CSC wait", 0);
943 while ((pe
= SIMPLEQ_FIRST(&sc
->sc_event_head
))) {
945 switch (pe
->pe_type
) {
947 printf("%s: unknown event.\n", __func__
);
949 case PLUM_PCMCIA_EVENT_INSERT
:
950 DPRINTF(("%s: insert event.\n", __func__
));
951 pcmcia_card_attach(pe
->pe_ph
->ph_pcmcia
);
953 case PLUM_PCMCIA_EVENT_REMOVE
:
954 DPRINTF(("%s: remove event.\n", __func__
));
955 pcmcia_card_detach(pe
->pe_ph
->ph_pcmcia
,
960 SIMPLEQ_REMOVE_HEAD(&sc
->sc_event_head
, pe_link
);
961 plumpcmcia_event_free(pe
);
968 /* power XXX notyet */
970 plumpcmcia_power(void *ctx
, int type
, long id
, void *msg
)
972 struct plumpcmcia_softc
*sc
= ctx
;
973 bus_space_tag_t regt
= sc
->sc_regt
;
974 bus_space_handle_t regh
= sc
->sc_regh
;
979 DPRINTF(("%s: ON\n", sc
->sc_dev
.dv_xname
));
981 plum_conf_write(regt
, regh
, PLUM_PCMCIA_CARDPWRCTRL
,
982 PLUM_PCMCIA_CARDPWRCTRL_ON
);
987 plum_conf_write(regt
, regh
, PLUM_PCMCIA_CARDPWRCTRL
,
988 PLUM_PCMCIA_CARDPWRCTRL_OFF
);
989 DPRINTF(("%s: OFF\n", sc
->sc_dev
.dv_xname
));
996 #ifdef PLUMPCMCIA_DEBUG
998 __ioareadump(plumreg_t reg
)
1001 if (reg
& PLUM_PCMCIA_IOWINADDRCTRL_AREA2
) {
1002 printf("I/O Area 2\n");
1004 printf("I/O Area 1\n");
1009 __memareadump(plumreg_t reg
)
1013 maparea
= PLUM_PCMCIA_MEMWINCTRL_MAP(reg
);
1015 case PLUM_PCMCIA_MEMWINCTRL_MAP_AREA1
:
1016 printf("MEM Area1\n");
1018 case PLUM_PCMCIA_MEMWINCTRL_MAP_AREA2
:
1019 printf("MEM Area2\n");
1021 case PLUM_PCMCIA_MEMWINCTRL_MAP_AREA3
:
1022 printf("MEM Area3\n");
1024 case PLUM_PCMCIA_MEMWINCTRL_MAP_AREA4
:
1025 printf("MEM Area4\n");
1031 plumpcmcia_dump(struct plumpcmcia_softc
*sc
)
1033 bus_space_tag_t regt
= sc
->sc_regt
;
1034 bus_space_handle_t regh
= sc
->sc_regh
;
1039 __memareadump(plum_conf_read(regt
, regh
, PLUM_PCMCIA_MEMWIN0CTRL
));
1040 __memareadump(plum_conf_read(regt
, regh
, PLUM_PCMCIA_MEMWIN1CTRL
));
1041 __memareadump(plum_conf_read(regt
, regh
, PLUM_PCMCIA_MEMWIN2CTRL
));
1042 __memareadump(plum_conf_read(regt
, regh
, PLUM_PCMCIA_MEMWIN3CTRL
));
1043 __memareadump(plum_conf_read(regt
, regh
, PLUM_PCMCIA_MEMWIN4CTRL
));
1045 __ioareadump(plum_conf_read(regt
, regh
, PLUM_PCMCIA_IOWIN0ADDRCTRL
));
1046 __ioareadump(plum_conf_read(regt
, regh
, PLUM_PCMCIA_IOWIN1ADDRCTRL
));
1048 for (j
= 0; j
< 2; j
++) {
1049 printf("[slot %d]\n", j
);
1050 for (i
= 0; i
< 0x120; i
+= 4) {
1051 reg
= plum_conf_read(sc
->sc_regt
, sc
->sc_regh
,
1053 printf("%03x %08x", i
, reg
);
1059 #endif /* PLUMPCMCIA_DEBUG */