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