]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/pcic/i82365_isa.c
Use the new ahc_scb_timer_reset API
[FreeBSD/FreeBSD.git] / sys / dev / pcic / i82365_isa.c
1 /*      $NetBSD: i82365_isasubr.c,v 1.3 1999/10/15 06:07:27 haya Exp $  */
2 /*      $NetBSD: i82365_isa.c,v 1.11 1998/06/09 07:25:00 thorpej Exp $  */
3 /* $FreeBSD$ */
4
5 /*
6  * Copyright (c) 1998 Bill Sommerfeld.  All rights reserved.
7  * Copyright (c) 1997 Marc Horowitz.  All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed by Marc Horowitz.
20  * 4. The name of the author may not be used to endorse or promote products
21  *    derived from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/malloc.h>
38 #include <sys/module.h>
39 #include <sys/kernel.h>
40 #include <sys/queue.h>
41 #include <sys/types.h>
42
43 #include <sys/bus.h>
44 #include <machine/bus.h>
45 #include <sys/rman.h>
46 #include <machine/resource.h>
47
48 #include <isa/isavar.h>
49
50 #include <dev/pccard/pccardreg.h>
51 #include <dev/pccard/pccardvar.h>
52
53 #include <dev/pcic/i82365reg.h>
54 #include <dev/pcic/i82365var.h>
55
56 #include "power_if.h"
57 #include "card_if.h"
58
59 /*****************************************************************************
60  * Configurable parameters.
61  *****************************************************************************/
62
63 /*
64  * Default I/O allocation range.  If both are set to non-zero, these
65  * values will be used instead.  Otherwise, the code attempts to probe
66  * the bus width.  Systems with 10 address bits should use 0x300 and 0xff.
67  * Systems with 12 address bits (most) should use 0x400 and 0xbff.
68  */
69
70 #ifndef PCIC_ISA_ALLOC_IOBASE
71 #define PCIC_ISA_ALLOC_IOBASE           0
72 #endif
73
74 #ifndef PCIC_ISA_ALLOC_IOSIZE
75 #define PCIC_ISA_ALLOC_IOSIZE           0
76 #endif
77
78 int     pcic_isa_alloc_iobase = PCIC_ISA_ALLOC_IOBASE;
79 int     pcic_isa_alloc_iosize = PCIC_ISA_ALLOC_IOSIZE;
80
81
82 /*
83  * Default IRQ allocation bitmask.  This defines the range of allowable
84  * IRQs for PCCARD slots.  Useful if order of probing would screw up other
85  * devices, or if PCIC hardware/cards have trouble with certain interrupt
86  * lines.
87  *
88  * We disable IRQ 10 by default, since some common laptops (namely, the
89  * NEC Versa series) reserve IRQ 10 for the docking station SCSI interface.
90  */
91
92 #ifndef PCIC_ISA_INTR_ALLOC_MASK
93 #define PCIC_ISA_INTR_ALLOC_MASK        0xfbff
94 #endif
95
96 int     pcic_isa_intr_alloc_mask = PCIC_ISA_INTR_ALLOC_MASK;
97
98 /*****************************************************************************
99  * End of configurable parameters.
100  *****************************************************************************/
101
102 #define PCICISADEBUG 1
103
104 #ifdef PCICISADEBUG
105 int     pcicisa_debug = PCICISADEBUG;
106 #define DPRINTF(arg) if (pcicisa_debug) printf arg;
107 #define DEVPRINTF(arg) if (pcicisa_debug) device_printf arg;
108 #else
109 #define DPRINTF(arg)
110 #define DEVPRINTF(arg)
111 #endif
112
113 static struct isa_pnp_id pcic_ids[] = {
114         {PCIC_PNP_ACTIONTEC,            NULL},          /* AEI0218 */
115         {PCIC_PNP_IBM3765,              NULL},          /* IBM3765 */
116         {PCIC_PNP_82365,                NULL},          /* PNP0E00 */
117         {PCIC_PNP_CL_PD6720,            NULL},          /* PNP0E01 */
118         {PCIC_PNP_VLSI_82C146,          NULL},          /* PNP0E02 */
119         {PCIC_PNP_82365_CARDBUS,        NULL},          /* PNP0E03 */
120         {PCIC_PNP_SCM_SWAPBOX,          NULL},          /* SCM0469 */
121         {0}
122 };
123
124 static void
125 pcic_isa_bus_width_probe (device_t dev)
126 {
127         struct pcic_softc *sc = PCIC_SOFTC(dev);
128         bus_space_handle_t ioh_high;
129         int i, iobuswidth, tmp1, tmp2;
130         int rid;
131         u_long base;
132         u_int32_t length;
133         bus_space_tag_t iot;
134         bus_space_handle_t ioh;
135         struct resource *r;
136
137         base = rman_get_start(sc->port_res);
138         length = rman_get_size(sc->port_res);
139         iot = sc->iot;
140         ioh = sc->ioh;
141
142         /*
143          * figure out how wide the isa bus is.  Do this by checking if the
144          * pcic controller is mirrored 0x400 above where we expect it to be.
145          */
146
147         iobuswidth = 12;
148         rid = 1;
149         r = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, base + 0x400,
150             base + 0x400 + length, length, RF_ACTIVE);
151         if (!r) {
152                 printf("Can't allocated mirror area for pcic bus width probe\n");
153                 return;
154         }
155         ioh_high = rman_get_bushandle(r);
156         for (i = 0; i < PCIC_NSLOTS; i++) {
157                 if (sc->handle[i].flags & PCIC_FLAG_SOCKETP) {
158                         /*
159                          * read the ident flags from the normal space and
160                          * from the mirror, and compare them
161                          */
162
163                         bus_space_write_1(iot, ioh, PCIC_REG_INDEX,
164                             sc->handle[i].sock + PCIC_IDENT);
165                         tmp1 = bus_space_read_1(iot, ioh, PCIC_REG_DATA);
166
167                         bus_space_write_1(iot, ioh_high, PCIC_REG_INDEX,
168                             sc->handle[i].sock + PCIC_IDENT);
169                         tmp2 = bus_space_read_1(iot, ioh_high, PCIC_REG_DATA);
170
171                         if (tmp1 == tmp2)
172                                 iobuswidth = 10;
173                 }
174         }
175         bus_release_resource(dev, SYS_RES_IOPORT, rid, r);
176
177         /*
178          * XXX mycroft recommends I/O space range 0x400-0xfff .  I should put
179          * this in a header somewhere
180          */
181
182         /*
183          * XXX some hardware doesn't seem to grok addresses in 0x400 range--
184          * apparently missing a bit or more of address lines. (e.g.
185          * CIRRUS_PD672X with Linksys EthernetCard ne2000 clone in TI
186          * TravelMate 5000--not clear which is at fault)
187          * 
188          * Add a kludge to detect 10 bit wide buses and deal with them,
189          * and also a config file option to override the probe.
190          */
191
192         if (iobuswidth == 10) {
193                 sc->iobase = 0x300;
194                 sc->iosize = 0x0ff;
195         } else {
196 #if 0
197                 /*
198                  * This is what we'd like to use, but...
199                  */
200                 sc->iobase = 0x400;
201                 sc->iosize = 0xbff;
202 #else
203                 /*
204                  * ...the above bus width probe doesn't always work.
205                  * So, experimentation has shown the following range
206                  * to not lose on systems that 0x300-0x3ff loses on
207                  * (e.g. the NEC Versa 6030X).
208                  */
209                 sc->iobase = 0x330;
210                 sc->iosize = 0x0cf;
211 #endif
212         }
213
214         DEVPRINTF((dev, "bus_space_alloc range 0x%04lx-0x%04lx (probed)\n",
215             (long) sc->iobase, (long) sc->iobase + sc->iosize));
216
217         if (pcic_isa_alloc_iobase && pcic_isa_alloc_iosize) {
218                 sc->iobase = pcic_isa_alloc_iobase;
219                 sc->iosize = pcic_isa_alloc_iosize;
220
221                 DEVPRINTF((dev, "bus_space_alloc range 0x%04lx-0x%04lx "
222                     "(config override)\n", (long) sc->iobase,
223                     (long) sc->iobase + sc->iosize));
224         }
225 }
226
227 #if 0
228 static int
229 pcic_isa_check(device_t dev, u_int16_t addr)
230 {
231         bus_space_tag_t iot;
232         bus_space_handle_t ioh;
233         int val, found;
234         int rid;
235         struct resource *res;
236
237         rid = 0;
238         res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, addr, addr,
239             PCIC_IOSIZE, RF_ACTIVE);
240         if (!res)
241                 return(ENXIO);
242         iot = rman_get_bustag(res);
243         ioh = rman_get_bushandle(res);
244         found = 0;
245
246         /*
247          * this could be done with a loop, but it would violate the
248          * abstraction
249          */
250         bus_space_write_1(iot, ioh, PCIC_REG_INDEX, C0SA + PCIC_IDENT);
251         val = bus_space_read_1(iot, ioh, PCIC_REG_DATA);
252         if (pcic_ident_ok(val))
253                 found++;
254
255         bus_space_write_1(iot, ioh, PCIC_REG_INDEX, C0SB + PCIC_IDENT);
256         val = bus_space_read_1(iot, ioh, PCIC_REG_DATA);
257         if (pcic_ident_ok(val))
258                 found++;
259
260         bus_space_write_1(iot, ioh, PCIC_REG_INDEX, C1SA + PCIC_IDENT);
261         val = bus_space_read_1(iot, ioh, PCIC_REG_DATA);
262         if (pcic_ident_ok(val))
263                 found++;
264
265         bus_space_write_1(iot, ioh, PCIC_REG_INDEX, C1SB + PCIC_IDENT);
266         val = bus_space_read_1(iot, ioh, PCIC_REG_DATA);
267         if (pcic_ident_ok(val))
268                 found++;
269
270         bus_release_resource(dev, SYS_RES_IOPORT, rid, res);
271
272         return (found);
273 }
274 #endif
275
276 static int
277 pcic_isa_probe(device_t dev)
278 {
279         int error;
280         struct resource *res;
281         int rid;
282         int i;
283         u_long mem;
284
285         /* Check isapnp ids */
286         error = ISA_PNP_PROBE(device_get_parent(dev), dev, pcic_ids);
287         if (error == ENXIO)
288                 return (ENXIO);
289
290         /* If we had some other problem. */
291         if (!(error == 0 || error == ENOENT))
292                 return (error);
293
294         /* If we have the resources we need then we're good to go. */
295         if (bus_get_resource_start(dev, SYS_RES_IOPORT, 0) == 0)
296                 return (ENXIO);
297         rid = 0;
298         res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_ACTIVE);
299         if (res == NULL) {
300                 /*
301                  * No IRQ specified, find one.  This can be due to the PnP
302                  * data not specifying any IRQ
303                  */
304                 for (i = 0; i < 16; i++) {
305                         if (((1 << i) & PCIC_INTR_IRQ_VALIDMASK) == 0)
306                                 continue;
307                         res = bus_alloc_resource(dev, SYS_RES_IRQ,
308                             &rid, i, i, 1, RF_ACTIVE);
309                         if (res != NULL)
310                                 break;
311                 }
312                 if (res == NULL)
313                         return (ENXIO);
314                 mem = rman_get_start(res);
315                 bus_release_resource(dev, SYS_RES_IRQ, rid, res);       
316                 bus_set_resource(dev, SYS_RES_IRQ, 0, i, 1);
317         } else {
318                 bus_release_resource(dev, SYS_RES_IRQ, rid, res);
319         }
320         /* XXX This might not be needed in future, get it directly from
321          * XXX parent */
322         rid = 0;
323         res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, ~0, 
324             1 << 13, RF_ACTIVE);
325         if (res == NULL) {
326                 /*
327                  * We failed to get memory.  Since this XXX comment above
328                  * indicates that this is transient, we try to get a hunk
329                  * of memory in the isa hole.  Sure would be nice if there
330                  * were some MI constants for this.
331                  */
332                 res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 
333                     0xa0000, 0xdffff, 1 << 13, RF_ACTIVE);
334                 if (res != NULL) {
335                         mem = rman_get_start(res);
336                         bus_release_resource(dev, SYS_RES_MEMORY, rid, res);
337                         bus_set_resource(dev, SYS_RES_MEMORY, 0, mem, 1 << 13);
338                 }
339         } else {
340                 bus_release_resource(dev, SYS_RES_MEMORY, rid, res);
341         }
342         if (res == NULL) {
343                 device_printf(dev, "Cannot allocate mem\n");
344                 return ENOMEM;
345         }
346         return (0);
347 }
348
349 static int
350 pcic_isa_attach(device_t dev)
351 {
352         int err = 0;
353
354         if ((err = pcic_attach(dev)) == 0)
355                 pcic_isa_bus_width_probe (dev);
356         return err;
357 }
358
359 static int
360 pcic_isa_detach(device_t dev)
361 {
362         pcic_detach(dev);
363         return 0;
364 }
365
366 static device_method_t pcic_isa_methods[] = {
367         /* Device interface */
368         DEVMETHOD(device_probe,         pcic_isa_probe),
369         DEVMETHOD(device_attach,        pcic_isa_attach),
370         DEVMETHOD(device_detach,        pcic_isa_detach),
371         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
372         DEVMETHOD(device_suspend,       pcic_suspend),
373         DEVMETHOD(device_resume,        pcic_resume),
374
375         /* Bus Interface */
376         DEVMETHOD(bus_driver_added,     bus_generic_driver_added),
377         DEVMETHOD(bus_print_child,      bus_generic_print_child),
378         DEVMETHOD(bus_alloc_resource,   pcic_alloc_resource),
379         DEVMETHOD(bus_release_resource, pcic_release_resource),
380         DEVMETHOD(bus_activate_resource, pcic_activate_resource),
381         DEVMETHOD(bus_deactivate_resource, pcic_deactivate_resource),
382         DEVMETHOD(bus_setup_intr,       pcic_setup_intr),
383         DEVMETHOD(bus_teardown_intr,    pcic_teardown_intr),
384
385         /* pccard/cardbus interface */
386         DEVMETHOD(card_set_res_flags, pcic_set_res_flags),
387         DEVMETHOD(card_set_memory_offset, pcic_set_memory_offset),
388
389         /* Power Interface */
390         DEVMETHOD(power_enable_socket,  pcic_enable_socket),
391         DEVMETHOD(power_disable_socket, pcic_disable_socket),
392         { 0, 0 }
393 };
394
395 static driver_t pcic_driver = {
396         "pcic",
397         pcic_isa_methods,
398         sizeof(struct pcic_softc)
399 };
400
401 static devclass_t pcic_devclass;
402
403 DRIVER_MODULE(pcic, isa, pcic_driver, pcic_devclass, 0, 0);
404 MODULE_DEPEND(pcic, pccard, 1, 1, 1);