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