1 /*-
2 * Copyright (c) 2002-2005 M Warner Losh. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 *
24 * This software may be derived from NetBSD i82365.c and other files with
25 * the following copyright:
26 *
27 * Copyright (c) 1997 Marc Horowitz. All rights reserved.
28 *
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
31 * are met:
32 * 1. Redistributions of source code must retain the above copyright
33 * notice, this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright
35 * notice, this list of conditions and the following disclaimer in the
36 * documentation and/or other materials provided with the distribution.
37 * 3. All advertising materials mentioning features or use of this software
38 * must display the following acknowledgement:
39 * This product includes software developed by Marc Horowitz.
40 * 4. The name of the author may not be used to endorse or promote products
41 * derived from this software without specific prior written permission.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
44 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
45 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
46 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
47 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
48 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
49 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
50 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
51 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
52 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
53 *
54 * $FreeBSD: src/sys/dev/exca/exca.c,v 1.19 2005/01/11 00:32:43 imp Exp $
55 */
56
57 #include <sys/param.h>
58 #include <sys/systm.h>
59 #include <sys/errno.h>
60 #include <sys/kernel.h>
61 #include <sys/malloc.h>
62 #include <sys/queue.h>
63 #include <sys/module.h>
64 #include <sys/lock.h>
65 #include <sys/conf.h>
66
67 #include <sys/bus.h>
68 #include <sys/rman.h>
69
70 #include <bus/pccard/pccardreg.h>
71 #include <bus/pccard/pccardvar.h>
72
73 #include <dev/pccard/exca/excareg.h>
74 #include <dev/pccard/exca/excavar.h>
75
76 #ifdef EXCA_DEBUG
77 #define DEVPRINTF(dev, fmt, args...) device_printf((dev), (fmt), ## args)
78 #define DPRINTF(fmt, args...) kprintf(fmt, ## args)
79 #else
80 #define DEVPRINTF(dev, fmt, args...)
81 #define DPRINTF(fmt, args...)
82 #endif
83
84 #if 0
85 static const char *chip_names[] =
86 {
87 "CardBus socket",
88 "Intel i82365SL-A/B or clone",
89 "Intel i82365sl-DF step",
90 "VLSI chip",
91 "Cirrus Logic PD6710",
92 "Cirrus logic PD6722",
93 "Cirrus Logic PD6729",
94 "Vadem 365",
95 "Vadem 465",
96 "Vadem 468",
97 "Vadem 469",
98 "Ricoh RF5C296",
99 "Ricoh RF5C396",
100 "IBM clone",
101 "IBM KING PCMCIA Controller"
102 };
103 #endif
104
105 static exca_getb_fn exca_mem_getb;
106 static exca_putb_fn exca_mem_putb;
107 static exca_getb_fn exca_io_getb;
108 static exca_putb_fn exca_io_putb;
109
110 /* memory */
111
112 #define EXCA_MEMINFO(NUM) { \
113 EXCA_SYSMEM_ADDR ## NUM ## _START_LSB, \
114 EXCA_SYSMEM_ADDR ## NUM ## _START_MSB, \
115 EXCA_SYSMEM_ADDR ## NUM ## _STOP_LSB, \
116 EXCA_SYSMEM_ADDR ## NUM ## _STOP_MSB, \
117 EXCA_SYSMEM_ADDR ## NUM ## _WIN, \
118 EXCA_CARDMEM_ADDR ## NUM ## _LSB, \
119 EXCA_CARDMEM_ADDR ## NUM ## _MSB, \
120 EXCA_ADDRWIN_ENABLE_MEM ## NUM, \
121 }
122
123 static struct mem_map_index_st {
124 int sysmem_start_lsb;
125 int sysmem_start_msb;
126 int sysmem_stop_lsb;
127 int sysmem_stop_msb;
128 int sysmem_win;
129 int cardmem_lsb;
130 int cardmem_msb;
131 int memenable;
132 } mem_map_index[] = {
133 EXCA_MEMINFO(0),
134 EXCA_MEMINFO(1),
135 EXCA_MEMINFO(2),
136 EXCA_MEMINFO(3),
137 EXCA_MEMINFO(4)
138 };
139 #undef EXCA_MEMINFO
140
141 static uint8_t
exca_mem_getb(struct exca_softc * sc,int reg)142 exca_mem_getb(struct exca_softc *sc, int reg)
143 {
144 return (bus_space_read_1(sc->bst, sc->bsh, sc->offset + reg));
145 }
146
147 static void
exca_mem_putb(struct exca_softc * sc,int reg,uint8_t val)148 exca_mem_putb(struct exca_softc *sc, int reg, uint8_t val)
149 {
150 bus_space_write_1(sc->bst, sc->bsh, sc->offset + reg, val);
151 }
152
153 static uint8_t
exca_io_getb(struct exca_softc * sc,int reg)154 exca_io_getb(struct exca_softc *sc, int reg)
155 {
156 bus_space_write_1(sc->bst, sc->bsh, EXCA_REG_INDEX, reg + sc->offset);
157 return (bus_space_read_1(sc->bst, sc->bsh, EXCA_REG_DATA));
158 }
159
160 static void
exca_io_putb(struct exca_softc * sc,int reg,uint8_t val)161 exca_io_putb(struct exca_softc *sc, int reg, uint8_t val)
162 {
163 bus_space_write_1(sc->bst, sc->bsh, EXCA_REG_INDEX, reg + sc->offset);
164 bus_space_write_1(sc->bst, sc->bsh, EXCA_REG_DATA, val);
165 }
166
167 /*
168 * Helper function. This will map the requested memory slot. We setup the
169 * map before we call this function. This is used to initially force the
170 * mapping, as well as later restore the mapping after it has been destroyed
171 * in some fashion (due to a power event typically).
172 */
173 static void
exca_do_mem_map(struct exca_softc * sc,int win)174 exca_do_mem_map(struct exca_softc *sc, int win)
175 {
176 struct mem_map_index_st *map;
177 struct pccard_mem_handle *mem;
178 uint32_t offset;
179
180 map = &mem_map_index[win];
181 mem = &sc->mem[win];
182 offset = ((mem->cardaddr >> EXCA_CARDMEM_ADDRX_SHIFT) -
183 (mem->addr >> EXCA_SYSMEM_ADDRX_SHIFT)) & 0x3fff;
184 exca_putb(sc, map->sysmem_start_lsb,
185 (mem->addr >> EXCA_SYSMEM_ADDRX_SHIFT) & 0xff);
186 exca_putb(sc, map->sysmem_start_msb,
187 ((mem->addr >> (EXCA_SYSMEM_ADDRX_SHIFT + 8)) &
188 EXCA_SYSMEM_ADDRX_START_MSB_ADDR_MASK));
189
190 exca_putb(sc, map->sysmem_stop_lsb,
191 ((mem->addr + mem->realsize - 1) >>
192 EXCA_SYSMEM_ADDRX_SHIFT) & 0xff);
193 exca_putb(sc, map->sysmem_stop_msb,
194 (((mem->addr + mem->realsize - 1) >>
195 (EXCA_SYSMEM_ADDRX_SHIFT + 8)) &
196 EXCA_SYSMEM_ADDRX_STOP_MSB_ADDR_MASK) |
197 EXCA_SYSMEM_ADDRX_STOP_MSB_WAIT2);
198
199 exca_putb(sc, map->sysmem_win,
200 (mem->addr >> EXCA_MEMREG_WIN_SHIFT) & 0xff);
201
202 exca_putb(sc, map->cardmem_lsb, offset & 0xff);
203 exca_putb(sc, map->cardmem_msb, (((offset >> 8) & 0xff) &
204 EXCA_CARDMEM_ADDRX_MSB_ADDR_MASK) |
205 ((mem->kind == PCCARD_A_MEM_ATTR) ?
206 EXCA_CARDMEM_ADDRX_MSB_REGACTIVE_ATTR : 0));
207
208 #ifdef EXCA_DEBUG
209 if (mem->kind == PCCARD_A_MEM_ATTR)
210 kprintf("attribtue memory\n");
211 else
212 kprintf("common memory\n");
213 #endif
214 exca_setb(sc, EXCA_ADDRWIN_ENABLE, map->memenable |
215 EXCA_ADDRWIN_ENABLE_MEMCS16);
216
217 DELAY(100);
218 #ifdef EXCA_DEBUG
219 {
220 int r1, r2, r3, r4, r5, r6, r7;
221 r1 = exca_getb(sc, map->sysmem_start_msb);
222 r2 = exca_getb(sc, map->sysmem_start_lsb);
223 r3 = exca_getb(sc, map->sysmem_stop_msb);
224 r4 = exca_getb(sc, map->sysmem_stop_lsb);
225 r5 = exca_getb(sc, map->cardmem_msb);
226 r6 = exca_getb(sc, map->cardmem_lsb);
227 r7 = exca_getb(sc, map->sysmem_win);
228 kprintf("exca_do_mem_map win %d: %02x%02x %02x%02x "
229 "%02x%02x %02x (%08x+%06x.%06x*%06x)\n",
230 win, r1, r2, r3, r4, r5, r6, r7,
231 mem->addr, mem->size, mem->realsize,
232 mem->cardaddr);
233 }
234 #endif
235 }
236
237 /*
238 * public interface to map a resource. kind is the type of memory to
239 * map (either common or attribute). Memory created via this interface
240 * starts out at card address 0. Since the only way to set this is
241 * to set it on a struct resource after it has been mapped, we're safe
242 * in maping this assumption. Note that resources can be remapped using
243 * exca_do_mem_map so that's how the card address can be set later.
244 */
245 int
exca_mem_map(struct exca_softc * sc,int kind,struct resource * res)246 exca_mem_map(struct exca_softc *sc, int kind, struct resource *res)
247 {
248 int win;
249
250 for (win = 0; win < EXCA_MEM_WINS; win++) {
251 if ((sc->memalloc & (1 << win)) == 0) {
252 sc->memalloc |= (1 << win);
253 break;
254 }
255 }
256 if (win >= EXCA_MEM_WINS)
257 return (1);
258 if (((rman_get_start(res) >> EXCA_MEMREG_WIN_SHIFT) & 0xff) != 0 &&
259 (sc->flags & EXCA_HAS_MEMREG_WIN) == 0) {
260 device_printf(sc->dev, "Does not support mapping above 24M.");
261 return (1);
262 }
263
264 sc->mem[win].cardaddr = 0;
265 sc->mem[win].memt = rman_get_bustag(res);
266 sc->mem[win].memh = rman_get_bushandle(res);
267 sc->mem[win].addr = rman_get_start(res);
268 sc->mem[win].size = rman_get_end(res) - sc->mem[win].addr + 1;
269 sc->mem[win].realsize = sc->mem[win].size + EXCA_MEM_PAGESIZE - 1;
270 sc->mem[win].realsize = sc->mem[win].realsize -
271 (sc->mem[win].realsize % EXCA_MEM_PAGESIZE);
272 sc->mem[win].kind = kind;
273 DPRINTF("exca_mem_map window %d bus %x+%x card addr %x\n",
274 win, sc->mem[win].addr, sc->mem[win].size, sc->mem[win].cardaddr);
275 exca_do_mem_map(sc, win);
276
277 return (0);
278 }
279
280 /*
281 * Private helper function. This turns off a given memory map that is in
282 * use. We do this by just clearing the enable bit in the pcic. If we needed
283 * to make memory unmapping/mapping pairs faster, we would have to store
284 * more state information about the pcic and then use that to intelligently
285 * to the map/unmap. However, since we don't do that sort of thing often
286 * (generally just at configure time), it isn't a case worth optimizing.
287 */
288 static void
exca_mem_unmap(struct exca_softc * sc,int window)289 exca_mem_unmap(struct exca_softc *sc, int window)
290 {
291 if (window < 0 || window >= EXCA_MEM_WINS)
292 panic("exca_mem_unmap: window out of range");
293
294 exca_clrb(sc, EXCA_ADDRWIN_ENABLE, mem_map_index[window].memenable);
295 sc->memalloc &= ~(1 << window);
296 }
297
298 /*
299 * Find the map that we're using to hold the resoruce. This works well
300 * so long as the client drivers don't do silly things like map the same
301 * area mutliple times, or map both common and attribute memory at the
302 * same time. This latter restriction is a bug. We likely should just
303 * store a pointer to the res in the mem[x] data structure.
304 */
305 static int
exca_mem_findmap(struct exca_softc * sc,struct resource * res)306 exca_mem_findmap(struct exca_softc *sc, struct resource *res)
307 {
308 int win;
309
310 for (win = 0; win < EXCA_MEM_WINS; win++) {
311 if (sc->mem[win].memt == rman_get_bustag(res) &&
312 sc->mem[win].addr == rman_get_start(res) &&
313 sc->mem[win].size == rman_get_size(res))
314 return (win);
315 }
316 return (-1);
317 }
318
319 /*
320 * Set the memory flag. This means that we are setting if the memory
321 * is coming from attribute memory or from common memory on the card.
322 * CIS entries are generally in attribute memory (although they can
323 * reside in common memory). Generally, this is the only use for attribute
324 * memory. However, some cards require their drivers to dance in both
325 * common and/or attribute memory and this interface (and setting the
326 * offset interface) exist for such cards.
327 */
328 int
exca_mem_set_flags(struct exca_softc * sc,struct resource * res,uint32_t flags)329 exca_mem_set_flags(struct exca_softc *sc, struct resource *res, uint32_t flags)
330 {
331 int win;
332
333 win = exca_mem_findmap(sc, res);
334 if (win < 0) {
335 device_printf(sc->dev,
336 "set_res_flags: specified resource not active\n");
337 return (ENOENT);
338 }
339
340 sc->mem[win].kind = flags;
341 exca_do_mem_map(sc, win);
342 return (0);
343 }
344
345 /*
346 * Given a resource, go ahead and unmap it if we can find it in the
347 * resrouce list that's used.
348 */
349 int
exca_mem_unmap_res(struct exca_softc * sc,struct resource * res)350 exca_mem_unmap_res(struct exca_softc *sc, struct resource *res)
351 {
352 int win;
353
354 win = exca_mem_findmap(sc, res);
355 if (win < 0)
356 return (ENOENT);
357 exca_mem_unmap(sc, win);
358 return (0);
359 }
360
361 /*
362 * Set the offset of the memory. We use this for reading the CIS and
363 * frobbing the pccard's pccard registers (POR, etc). Some drivers
364 * need to access this functionality as well, since they have receive
365 * buffers defined in the attribute memory.
366 */
367 int
exca_mem_set_offset(struct exca_softc * sc,struct resource * res,uint32_t cardaddr,uint32_t * deltap)368 exca_mem_set_offset(struct exca_softc *sc, struct resource *res,
369 uint32_t cardaddr, uint32_t *deltap)
370 {
371 int win;
372 uint32_t delta;
373
374 win = exca_mem_findmap(sc, res);
375 if (win < 0) {
376 device_printf(sc->dev,
377 "set_memory_offset: specified resource not active\n");
378 return (ENOENT);
379 }
380 sc->mem[win].cardaddr = rounddown2(cardaddr, EXCA_MEM_PAGESIZE);
381 delta = cardaddr % EXCA_MEM_PAGESIZE;
382 if (deltap)
383 *deltap = delta;
384 sc->mem[win].realsize = sc->mem[win].size + delta +
385 EXCA_MEM_PAGESIZE - 1;
386 sc->mem[win].realsize = sc->mem[win].realsize -
387 (sc->mem[win].realsize % EXCA_MEM_PAGESIZE);
388 exca_do_mem_map(sc, win);
389 return (0);
390 }
391
392
393 /* I/O */
394
395 #define EXCA_IOINFO(NUM) { \
396 EXCA_IOADDR ## NUM ## _START_LSB, \
397 EXCA_IOADDR ## NUM ## _START_MSB, \
398 EXCA_IOADDR ## NUM ## _STOP_LSB, \
399 EXCA_IOADDR ## NUM ## _STOP_MSB, \
400 EXCA_ADDRWIN_ENABLE_IO ## NUM, \
401 EXCA_IOCTL_IO ## NUM ## _WAITSTATE \
402 | EXCA_IOCTL_IO ## NUM ## _ZEROWAIT \
403 | EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_MASK \
404 | EXCA_IOCTL_IO ## NUM ## _DATASIZE_MASK, \
405 { \
406 EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_CARD, \
407 EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_DATASIZE \
408 | EXCA_IOCTL_IO ## NUM ## _DATASIZE_8BIT, \
409 EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_DATASIZE \
410 | EXCA_IOCTL_IO ## NUM ## _DATASIZE_16BIT, \
411 } \
412 }
413
414 static struct io_map_index_st {
415 int start_lsb;
416 int start_msb;
417 int stop_lsb;
418 int stop_msb;
419 int ioenable;
420 int ioctlmask;
421 int ioctlbits[3]; /* indexed by PCCARD_WIDTH_* */
422 } io_map_index[] = {
423 EXCA_IOINFO(0),
424 EXCA_IOINFO(1),
425 };
426 #undef EXCA_IOINFO
427
428 static void
exca_do_io_map(struct exca_softc * sc,int win)429 exca_do_io_map(struct exca_softc *sc, int win)
430 {
431 struct io_map_index_st *map;
432
433 struct pccard_io_handle *io;
434
435 map = &io_map_index[win];
436 io = &sc->io[win];
437 exca_putb(sc, map->start_lsb, io->addr & 0xff);
438 exca_putb(sc, map->start_msb, (io->addr >> 8) & 0xff);
439
440 exca_putb(sc, map->stop_lsb, (io->addr + io->size - 1) & 0xff);
441 exca_putb(sc, map->stop_msb, ((io->addr + io->size - 1) >> 8) & 0xff);
442
443 exca_clrb(sc, EXCA_IOCTL, map->ioctlmask);
444 exca_setb(sc, EXCA_IOCTL, map->ioctlbits[io->width]);
445
446 exca_setb(sc, EXCA_ADDRWIN_ENABLE, map->ioenable);
447 #ifdef EXCA_DEBUG
448 {
449 int r1, r2, r3, r4;
450 r1 = exca_getb(sc, map->start_msb);
451 r2 = exca_getb(sc, map->start_lsb);
452 r3 = exca_getb(sc, map->stop_msb);
453 r4 = exca_getb(sc, map->stop_lsb);
454 DPRINTF("exca_do_io_map window %d: %02x%02x %02x%02x "
455 "(%08x+%08x)\n", win, r1, r2, r3, r4,
456 io->addr, io->size);
457 }
458 #endif
459 }
460
461 int
exca_io_map(struct exca_softc * sc,int width,struct resource * r)462 exca_io_map(struct exca_softc *sc, int width, struct resource *r)
463 {
464 int win;
465 #ifdef EXCA_DEBUG
466 static char *width_names[] = { "auto", "io8", "io16"};
467 #endif
468 for (win=0; win < EXCA_IO_WINS; win++) {
469 if ((sc->ioalloc & (1 << win)) == 0) {
470 sc->ioalloc |= (1 << win);
471 break;
472 }
473 }
474 if (win >= EXCA_IO_WINS)
475 return (1);
476
477 sc->io[win].iot = rman_get_bustag(r);
478 sc->io[win].ioh = rman_get_bushandle(r);
479 sc->io[win].addr = rman_get_start(r);
480 sc->io[win].size = rman_get_end(r) - sc->io[win].addr + 1;
481 sc->io[win].flags = 0;
482 sc->io[win].width = width;
483 DPRINTF("exca_io_map window %d %s port %x+%x\n",
484 win, width_names[width], sc->io[win].addr,
485 sc->io[win].size);
486 exca_do_io_map(sc, win);
487
488 return (0);
489 }
490
491 static void
exca_io_unmap(struct exca_softc * sc,int window)492 exca_io_unmap(struct exca_softc *sc, int window)
493 {
494 if (window >= EXCA_IO_WINS)
495 panic("exca_io_unmap: window out of range");
496
497 exca_clrb(sc, EXCA_ADDRWIN_ENABLE, io_map_index[window].ioenable);
498
499 sc->ioalloc &= ~(1 << window);
500
501 sc->io[window].iot = 0;
502 sc->io[window].ioh = 0;
503 sc->io[window].addr = 0;
504 sc->io[window].size = 0;
505 sc->io[window].flags = 0;
506 sc->io[window].width = 0;
507 }
508
509 static int
exca_io_findmap(struct exca_softc * sc,struct resource * res)510 exca_io_findmap(struct exca_softc *sc, struct resource *res)
511 {
512 int win;
513
514 for (win = 0; win < EXCA_IO_WINS; win++) {
515 if (sc->io[win].iot == rman_get_bustag(res) &&
516 sc->io[win].addr == rman_get_start(res) &&
517 sc->io[win].size == rman_get_size(res))
518 return (win);
519 }
520 return (-1);
521 }
522
523
524 int
exca_io_unmap_res(struct exca_softc * sc,struct resource * res)525 exca_io_unmap_res(struct exca_softc *sc, struct resource *res)
526 {
527 int win;
528
529 win = exca_io_findmap(sc, res);
530 if (win < 0)
531 return (ENOENT);
532 exca_io_unmap(sc, win);
533 return (0);
534 }
535
536 /* Misc */
537
538 /*
539 * If interrupts are enabled, then we should be able to just wait for
540 * an interrupt routine to wake us up. Busy waiting shouldn't be
541 * necessary. Sadly, not all legacy ISA cards support an interrupt
542 * for the busy state transitions, at least according to their datasheets,
543 * so we busy wait a while here..
544 */
545 static void
exca_wait_ready(struct exca_softc * sc)546 exca_wait_ready(struct exca_softc *sc)
547 {
548 int i;
549 DEVPRINTF(sc->dev, "exca_wait_ready: status 0x%02x\n",
550 exca_getb(sc, EXCA_IF_STATUS));
551 for (i = 0; i < 10000; i++) {
552 if (exca_getb(sc, EXCA_IF_STATUS) & EXCA_IF_STATUS_READY)
553 return;
554 DELAY(500);
555 }
556 device_printf(sc->dev, "ready never happened, status = %02x\n",
557 exca_getb(sc, EXCA_IF_STATUS));
558 }
559
560 /*
561 * Reset the card. Ideally, we'd do a lot of this via interrupts.
562 * However, many PC Cards will deassert the ready signal. This means
563 * that they are asserting an interrupt. This makes it hard to
564 * do anything but a busy wait here. One could argue that these
565 * such cards are broken, or that the bridge that allows this sort
566 * of interrupt through isn't quite what you'd want (and may be a standards
567 * violation). However, such arguing would leave a huge class of pc cards
568 * and bridges out of reach for use in the system.
569 *
570 * Maybe I should reevaluate the above based on the power bug I fixed
571 * in OLDCARD.
572 */
573 void
exca_reset(struct exca_softc * sc,device_t child)574 exca_reset(struct exca_softc *sc, device_t child)
575 {
576 int win;
577
578 /* enable socket i/o */
579 exca_setb(sc, EXCA_PWRCTL, EXCA_PWRCTL_OE);
580
581 exca_putb(sc, EXCA_INTR, EXCA_INTR_ENABLE);
582 /* hold reset for 30ms */
583 DELAY(30*1000);
584 /* clear the reset flag */
585 exca_setb(sc, EXCA_INTR, EXCA_INTR_RESET);
586 /* wait 20ms as per pc card standard (r2.01) section 4.3.6 */
587 DELAY(20*1000);
588
589 exca_wait_ready(sc);
590
591 /* disable all address windows */
592 exca_putb(sc, EXCA_ADDRWIN_ENABLE, 0);
593
594 exca_setb(sc, EXCA_INTR, EXCA_INTR_CARDTYPE_IO);
595 DEVPRINTF(sc->dev, "card type is io\n");
596
597 /* reinstall all the memory and io mappings */
598 for (win = 0; win < EXCA_MEM_WINS; ++win)
599 if (sc->memalloc & (1 << win))
600 exca_do_mem_map(sc, win);
601 for (win = 0; win < EXCA_IO_WINS; ++win)
602 if (sc->ioalloc & (1 << win))
603 exca_do_io_map(sc, win);
604 }
605
606 /*
607 * Initialize the exca_softc data structure for the first time.
608 */
609 void
exca_init(struct exca_softc * sc,device_t dev,bus_space_tag_t bst,bus_space_handle_t bsh,uint32_t offset)610 exca_init(struct exca_softc *sc, device_t dev,
611 bus_space_tag_t bst, bus_space_handle_t bsh, uint32_t offset)
612 {
613 sc->dev = dev;
614 sc->memalloc = 0;
615 sc->ioalloc = 0;
616 sc->bst = bst;
617 sc->bsh = bsh;
618 sc->offset = offset;
619 sc->flags = 0;
620 sc->getb = exca_mem_getb;
621 sc->putb = exca_mem_putb;
622 }
623
624 /*
625 * Is this socket valid?
626 */
627 static int
exca_valid_slot(struct exca_softc * exca)628 exca_valid_slot(struct exca_softc *exca)
629 {
630 uint8_t c;
631
632 /* Assume the worst */
633 exca->chipset = EXCA_BOGUS;
634
635 /*
636 * see if there's a PCMCIA controller here
637 * Intel PCMCIA controllers use 0x82 and 0x83
638 * IBM clone chips use 0x88 and 0x89, apparently
639 */
640 c = exca_getb(exca, EXCA_IDENT);
641 if ((c & EXCA_IDENT_IFTYPE_MASK) != EXCA_IDENT_IFTYPE_MEM_AND_IO)
642 return (0);
643 if ((c & EXCA_IDENT_ZERO) != 0)
644 return (0);
645 switch (c & EXCA_IDENT_REV_MASK) {
646 /*
647 * 82365 or clones.
648 */
649 case EXCA_IDENT_REV_I82365SLR0:
650 case EXCA_IDENT_REV_I82365SLR1:
651 exca->chipset = EXCA_I82365;
652 /*
653 * Check for Vadem chips by unlocking their extra
654 * registers and looking for valid ID. Bit 3 in
655 * the ID register is normally 0, except when
656 * EXCA_VADEMREV is set. Other bridges appear
657 * to ignore this frobbing.
658 */
659 bus_space_write_1(exca->bst, exca->bsh, EXCA_REG_INDEX,
660 EXCA_VADEM_COOKIE1);
661 bus_space_write_1(exca->bst, exca->bsh, EXCA_REG_INDEX,
662 EXCA_VADEM_COOKIE2);
663 exca_setb(exca, EXCA_VADEM_VMISC, EXCA_VADEM_REV);
664 c = exca_getb(exca, EXCA_IDENT);
665 if (c & 0x08) {
666 switch (c & 7) {
667 case 1:
668 exca->chipset = EXCA_VG365;
669 break;
670 case 2:
671 exca->chipset = EXCA_VG465;
672 break;
673 case 3:
674 exca->chipset = EXCA_VG468;
675 break;
676 default:
677 exca->chipset = EXCA_VG469;
678 break;
679 }
680 exca_clrb(exca, EXCA_VADEM_VMISC, EXCA_VADEM_REV);
681 break;
682 }
683 /*
684 * Check for RICOH RF5C[23]96 PCMCIA Controller
685 */
686 c = exca_getb(exca, EXCA_RICOH_ID);
687 if (c == EXCA_RID_396) {
688 exca->chipset = EXCA_RF5C396;
689 break;
690 } else if (c == EXCA_RID_296) {
691 exca->chipset = EXCA_RF5C296;
692 break;
693 }
694 /*
695 * Check for Cirrus logic chips.
696 */
697 exca_putb(exca, EXCA_CIRRUS_CHIP_INFO, 0);
698 c = exca_getb(exca, EXCA_CIRRUS_CHIP_INFO);
699 if ((c & EXCA_CIRRUS_CHIP_INFO_CHIP_ID) ==
700 EXCA_CIRRUS_CHIP_INFO_CHIP_ID) {
701 c = exca_getb(exca, EXCA_CIRRUS_CHIP_INFO);
702 if ((c & EXCA_CIRRUS_CHIP_INFO_CHIP_ID) == 0) {
703 if (c & EXCA_CIRRUS_CHIP_INFO_SLOTS)
704 exca->chipset = EXCA_PD6722;
705 else
706 exca->chipset = EXCA_PD6710;
707 break;
708 }
709 }
710 break;
711
712 case EXCA_IDENT_REV_I82365SLDF:
713 /*
714 * Intel i82365sl-DF step or maybe a vlsi 82c146
715 * we detected the vlsi case earlier, so if the controller
716 * isn't set, we know it is a i82365sl step D.
717 */
718 exca->chipset = EXCA_I82365SL_DF;
719 break;
720 case EXCA_IDENT_REV_IBM1:
721 case EXCA_IDENT_REV_IBM2:
722 exca->chipset = EXCA_IBM;
723 break;
724 case EXCA_IDENT_REV_IBM_KING:
725 exca->chipset = EXCA_IBM_KING;
726 break;
727 default:
728 return (0);
729 }
730 return (1);
731 }
732
733 /*
734 * Probe the expected slots. We maybe should set the ID for each of these
735 * slots too while we're at it. But maybe that belongs to a separate
736 * function.
737 *
738 * The caller must guarantee that at least EXCA_NSLOTS are present in exca.
739 */
740 int
exca_probe_slots(device_t dev,struct exca_softc * exca,bus_space_tag_t iot,bus_space_handle_t ioh)741 exca_probe_slots(device_t dev, struct exca_softc *exca, bus_space_tag_t iot,
742 bus_space_handle_t ioh)
743 {
744 int err;
745 int i;
746
747 err = ENXIO;
748 for (i = 0; i < EXCA_NSLOTS; i++) {
749 exca_init(&exca[i], dev, iot, ioh, i * EXCA_SOCKET_SIZE);
750 exca->getb = exca_io_getb;
751 exca->putb = exca_io_putb;
752 if (exca_valid_slot(&exca[i]))
753 err = 0;
754 }
755 return (err);
756 }
757
758 void
exca_insert(struct exca_softc * exca)759 exca_insert(struct exca_softc *exca)
760 {
761 if (exca->pccarddev != NULL) {
762 if (CARD_ATTACH_CARD(exca->pccarddev) != 0)
763 device_printf(exca->dev,
764 "PC Card card activation failed\n");
765 } else {
766 device_printf(exca->dev,
767 "PC Card inserted, but no pccard bus.\n");
768 }
769 }
770
771
772 void
exca_removal(struct exca_softc * exca)773 exca_removal(struct exca_softc *exca)
774 {
775 if (exca->pccarddev != NULL)
776 CARD_DETACH_CARD(exca->pccarddev);
777 }
778
779 int
exca_activate_resource(struct exca_softc * exca,device_t child,int type,int rid,struct resource * res)780 exca_activate_resource(struct exca_softc *exca, device_t child, int type,
781 int rid, struct resource *res)
782 {
783 int err;
784 if (!(rman_get_flags(res) & RF_ACTIVE)) { /* not already activated */
785 switch (type) {
786 case SYS_RES_IOPORT:
787 err = exca_io_map(exca, PCCARD_WIDTH_AUTO, res);
788 break;
789 case SYS_RES_MEMORY:
790 err = exca_mem_map(exca, PCCARD_A_MEM_COM, res);
791 break;
792 default:
793 err = 0;
794 break;
795 }
796 if (err)
797 return (err);
798
799 }
800 return (BUS_ACTIVATE_RESOURCE(device_get_parent(exca->dev), child,
801 type, rid, res));
802 }
803
804 int
exca_deactivate_resource(struct exca_softc * exca,device_t child,int type,int rid,struct resource * res)805 exca_deactivate_resource(struct exca_softc *exca, device_t child, int type,
806 int rid, struct resource *res)
807 {
808 if (rman_get_flags(res) & RF_ACTIVE) { /* if activated */
809 switch (type) {
810 case SYS_RES_IOPORT:
811 if (exca_io_unmap_res(exca, res))
812 return (ENOENT);
813 break;
814 case SYS_RES_MEMORY:
815 if (exca_mem_unmap_res(exca, res))
816 return (ENOENT);
817 break;
818 }
819 }
820 return (BUS_DEACTIVATE_RESOURCE(device_get_parent(exca->dev), child,
821 type, rid, res));
822 }
823
824 #if 0
825 static struct resource *
826 exca_alloc_resource(struct exca_softc *sc, device_t child, int type, int *rid,
827 u_long start, u_long end, u_long count, uint flags)
828 {
829 struct resource *res = NULL;
830 int tmp;
831
832 switch (type) {
833 case SYS_RES_MEMORY:
834 if (start < cbb_start_mem)
835 start = cbb_start_mem;
836 if (end < start)
837 end = start;
838 flags = (flags & ~RF_ALIGNMENT_MASK) |
839 rman_make_alignment_flags(CBB_MEMALIGN);
840 break;
841 case SYS_RES_IOPORT:
842 if (start < cbb_start_16_io)
843 start = cbb_start_16_io;
844 if (end < start)
845 end = start;
846 break;
847 case SYS_RES_IRQ:
848 tmp = rman_get_start(sc->irq_res);
849 if (start > tmp || end < tmp || count != 1) {
850 device_printf(child, "requested interrupt %ld-%ld,"
851 "count = %ld not supported by cbb\n",
852 start, end, count);
853 return (NULL);
854 }
855 flags |= RF_SHAREABLE;
856 start = end = rman_get_start(sc->irq_res);
857 break;
858 }
859 res = BUS_ALLOC_RESOURCE(up, child, type, rid,
860 start, end, count, flags & ~RF_ACTIVE);
861 if (res == NULL)
862 return (NULL);
863 cbb_insert_res(sc, res, type, *rid);
864 if (flags & RF_ACTIVE) {
865 if (bus_activate_resource(child, type, *rid, res) != 0) {
866 bus_release_resource(child, type, *rid, res);
867 return (NULL);
868 }
869 }
870
871 return (res);
872 }
873
874 static int
875 exca_release_resource(struct exca_softc *sc, device_t child, int type,
876 int rid, struct resource *res)
877 {
878 int error;
879
880 if (rman_get_flags(res) & RF_ACTIVE) {
881 error = bus_deactivate_resource(child, type, rid, res);
882 if (error != 0)
883 return (error);
884 }
885 cbb_remove_res(sc, res);
886 return (BUS_RELEASE_RESOURCE(device_get_parent(brdev), child,
887 type, rid, res));
888 }
889 #endif
890
891 static int
exca_modevent(module_t mod,int cmd,void * arg)892 exca_modevent(module_t mod, int cmd, void *arg)
893 {
894 return 0;
895 }
896
897 DEV_MODULE(exca, exca_modevent, NULL);
898 MODULE_VERSION(exca, 1);
899