1 | /* $NetBSD: if_tlp_cardbus.c,v 1.71 2016/07/14 10:19:06 msaitoh Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, |
9 | * NASA Ames Research Center. |
10 | * |
11 | * Redistribution and use in source and binary forms, with or without |
12 | * modification, are permitted provided that the following conditions |
13 | * are met: |
14 | * 1. Redistributions of source code must retain the above copyright |
15 | * notice, this list of conditions and the following disclaimer. |
16 | * 2. Redistributions in binary form must reproduce the above copyright |
17 | * notice, this list of conditions and the following disclaimer in the |
18 | * documentation and/or other materials provided with the distribution. |
19 | * |
20 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
22 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
23 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
30 | * POSSIBILITY OF SUCH DAMAGE. |
31 | */ |
32 | |
33 | /* |
34 | * CardBus bus front-end for the Digital Semiconductor ``Tulip'' (21x4x) |
35 | * Ethernet controller family driver. |
36 | */ |
37 | |
38 | #include <sys/cdefs.h> |
39 | __KERNEL_RCSID(0, "$NetBSD: if_tlp_cardbus.c,v 1.71 2016/07/14 10:19:06 msaitoh Exp $" ); |
40 | |
41 | #include "opt_inet.h" |
42 | |
43 | #include <sys/param.h> |
44 | #include <sys/systm.h> |
45 | #include <sys/mbuf.h> |
46 | #include <sys/malloc.h> |
47 | #include <sys/kernel.h> |
48 | #include <sys/socket.h> |
49 | #include <sys/ioctl.h> |
50 | #include <sys/errno.h> |
51 | #include <sys/device.h> |
52 | |
53 | #include <machine/endian.h> |
54 | |
55 | #include <net/if.h> |
56 | #include <net/if_dl.h> |
57 | #include <net/if_media.h> |
58 | #include <net/if_ether.h> |
59 | |
60 | #ifdef INET |
61 | #include <netinet/in.h> |
62 | #include <netinet/if_inarp.h> |
63 | #endif |
64 | |
65 | |
66 | #include <sys/bus.h> |
67 | #include <sys/intr.h> |
68 | |
69 | #include <dev/mii/miivar.h> |
70 | #include <dev/mii/mii_bitbang.h> |
71 | |
72 | #include <dev/ic/tulipreg.h> |
73 | #include <dev/ic/tulipvar.h> |
74 | |
75 | #include <dev/pci/pcivar.h> |
76 | #include <dev/pci/pcireg.h> |
77 | #include <dev/pci/pcidevs.h> |
78 | |
79 | #include <dev/cardbus/cardbusvar.h> |
80 | #include <dev/pci/pcidevs.h> |
81 | |
82 | /* |
83 | * PCI configuration space registers used by the Tulip. |
84 | */ |
85 | #define TULIP_PCI_IOBA PCI_BAR(0) /* i/o mapped base */ |
86 | #define TULIP_PCI_MMBA PCI_BAR(1) /* memory mapped base */ |
87 | #define TULIP_PCI_CFDA 0x40 /* configuration driver area */ |
88 | |
89 | #define CFDA_SLEEP 0x80000000 /* sleep mode */ |
90 | #define CFDA_SNOOZE 0x40000000 /* snooze mode */ |
91 | |
92 | struct tulip_cardbus_softc { |
93 | struct tulip_softc sc_tulip; /* real Tulip softc */ |
94 | |
95 | /* CardBus-specific goo. */ |
96 | void *sc_ih; /* interrupt handle */ |
97 | cardbus_devfunc_t sc_ct; /* our CardBus devfuncs */ |
98 | pcitag_t sc_tag; /* our CardBus tag */ |
99 | pcireg_t sc_csr; |
100 | bus_size_t sc_mapsize; /* the size of mapped bus space |
101 | region */ |
102 | |
103 | int sc_bar_reg; /* which BAR to use */ |
104 | pcireg_t sc_bar_val; /* value of the BAR */ |
105 | }; |
106 | |
107 | int tlp_cardbus_match(device_t, cfdata_t, void *); |
108 | void tlp_cardbus_attach(device_t, device_t, void *); |
109 | int tlp_cardbus_detach(device_t, int); |
110 | |
111 | CFATTACH_DECL_NEW(tlp_cardbus, sizeof(struct tulip_cardbus_softc), |
112 | tlp_cardbus_match, tlp_cardbus_attach, tlp_cardbus_detach, tlp_activate); |
113 | |
114 | const struct tulip_cardbus_product { |
115 | u_int32_t tcp_vendor; /* PCI vendor ID */ |
116 | u_int32_t tcp_product; /* PCI product ID */ |
117 | tulip_chip_t tcp_chip; /* base Tulip chip type */ |
118 | } tlp_cardbus_products[] = { |
119 | { PCI_VENDOR_DEC, PCI_PRODUCT_DEC_21142, |
120 | TULIP_CHIP_21142 }, |
121 | |
122 | { PCI_VENDOR_XIRCOM, PCI_PRODUCT_XIRCOM_X3201_3_21143, |
123 | TULIP_CHIP_X3201_3 }, |
124 | |
125 | { PCI_VENDOR_ADMTEK, PCI_PRODUCT_ADMTEK_AN983, |
126 | TULIP_CHIP_AN985 }, |
127 | |
128 | { PCI_VENDOR_ACCTON, PCI_PRODUCT_ACCTON_EN2242, |
129 | TULIP_CHIP_AN985 }, |
130 | |
131 | { PCI_VENDOR_ABOCOM, PCI_PRODUCT_ABOCOM_FE2500, |
132 | TULIP_CHIP_AN985 }, |
133 | |
134 | { PCI_VENDOR_ABOCOM, PCI_PRODUCT_ABOCOM_PCM200, |
135 | TULIP_CHIP_AN985 }, |
136 | |
137 | { PCI_VENDOR_ABOCOM, PCI_PRODUCT_ABOCOM_FE2500MX, |
138 | TULIP_CHIP_AN985 }, |
139 | |
140 | { PCI_VENDOR_HAWKING, PCI_PRODUCT_HAWKING_PN672TX, |
141 | TULIP_CHIP_AN985 }, |
142 | |
143 | { PCI_VENDOR_ADMTEK, PCI_PRODUCT_ADMTEK_AN985, |
144 | TULIP_CHIP_AN985 }, |
145 | |
146 | { PCI_VENDOR_MICROSOFT, PCI_PRODUCT_MICROSOFT_MN120, |
147 | TULIP_CHIP_AN985 }, |
148 | |
149 | { PCI_VENDOR_LINKSYS, PCI_PRODUCT_LINKSYS_PCMPC200, |
150 | TULIP_CHIP_AN985 }, |
151 | |
152 | { 0, 0, |
153 | TULIP_CHIP_INVALID }, |
154 | }; |
155 | |
156 | struct tlp_cardbus_quirks { |
157 | void (*tpq_func)(struct tulip_cardbus_softc *, |
158 | const u_int8_t *); |
159 | u_int8_t tpq_oui[3]; |
160 | }; |
161 | |
162 | void tlp_cardbus_lxt_quirks(struct tulip_cardbus_softc *, |
163 | const u_int8_t *); |
164 | |
165 | const struct tlp_cardbus_quirks tlp_cardbus_21142_quirks[] = { |
166 | { tlp_cardbus_lxt_quirks, { 0x00, 0x40, 0x05 } }, |
167 | { NULL, { 0, 0, 0 } } |
168 | }; |
169 | |
170 | void tlp_cardbus_setup(struct tulip_cardbus_softc *); |
171 | |
172 | int tlp_cardbus_enable(struct tulip_softc *); |
173 | void tlp_cardbus_disable(struct tulip_softc *); |
174 | void tlp_cardbus_power(struct tulip_softc *, int); |
175 | |
176 | void tlp_cardbus_x3201_reset(struct tulip_softc *); |
177 | |
178 | const struct tulip_cardbus_product *tlp_cardbus_lookup |
179 | (const struct cardbus_attach_args *); |
180 | void tlp_cardbus_get_quirks(struct tulip_cardbus_softc *, |
181 | const u_int8_t *, const struct tlp_cardbus_quirks *); |
182 | |
183 | const struct tulip_cardbus_product * |
184 | tlp_cardbus_lookup(const struct cardbus_attach_args *ca) |
185 | { |
186 | const struct tulip_cardbus_product *tcp; |
187 | |
188 | for (tcp = tlp_cardbus_products; tcp->tcp_chip != TULIP_CHIP_INVALID; |
189 | tcp++) { |
190 | if (PCI_VENDOR(ca->ca_id) == tcp->tcp_vendor && |
191 | PCI_PRODUCT(ca->ca_id) == tcp->tcp_product) |
192 | return (tcp); |
193 | } |
194 | return (NULL); |
195 | } |
196 | |
197 | void |
198 | tlp_cardbus_get_quirks(struct tulip_cardbus_softc *csc, const u_int8_t *enaddr, |
199 | const struct tlp_cardbus_quirks *tpq) |
200 | { |
201 | |
202 | for (; tpq->tpq_func != NULL; tpq++) { |
203 | if (tpq->tpq_oui[0] == enaddr[0] && |
204 | tpq->tpq_oui[1] == enaddr[1] && |
205 | tpq->tpq_oui[2] == enaddr[2]) { |
206 | (*tpq->tpq_func)(csc, enaddr); |
207 | return; |
208 | } |
209 | } |
210 | } |
211 | |
212 | int |
213 | tlp_cardbus_match(device_t parent, cfdata_t match, void *aux) |
214 | { |
215 | struct cardbus_attach_args *ca = aux; |
216 | |
217 | if (tlp_cardbus_lookup(ca) != NULL) |
218 | return (1); |
219 | |
220 | return (0); |
221 | } |
222 | |
223 | void |
224 | tlp_cardbus_attach(device_t parent, device_t self, void *aux) |
225 | { |
226 | struct tulip_cardbus_softc *csc = device_private(self); |
227 | struct tulip_softc *sc = &csc->sc_tulip; |
228 | struct cardbus_attach_args *ca = aux; |
229 | cardbus_devfunc_t ct = ca->ca_ct; |
230 | const struct tulip_cardbus_product *tcp; |
231 | u_int8_t enaddr[ETHER_ADDR_LEN]; |
232 | bus_addr_t adr; |
233 | pcireg_t reg; |
234 | |
235 | sc->sc_dev = self; |
236 | sc->sc_devno = 0; |
237 | sc->sc_dmat = ca->ca_dmat; |
238 | csc->sc_ct = ct; |
239 | csc->sc_tag = ca->ca_tag; |
240 | |
241 | tcp = tlp_cardbus_lookup(ca); |
242 | if (tcp == NULL) { |
243 | printf("\n" ); |
244 | panic("tlp_cardbus_attach: impossible" ); |
245 | } |
246 | sc->sc_chip = tcp->tcp_chip; |
247 | |
248 | /* |
249 | * By default, Tulip registers are 8 bytes long (4 bytes |
250 | * followed by a 4 byte pad). |
251 | */ |
252 | sc->sc_regshift = 3; |
253 | |
254 | /* |
255 | * Power management hooks. |
256 | */ |
257 | sc->sc_enable = tlp_cardbus_enable; |
258 | sc->sc_disable = tlp_cardbus_disable; |
259 | sc->sc_power = tlp_cardbus_power; |
260 | |
261 | /* |
262 | * Get revision info, and set some chip-specific variables. |
263 | */ |
264 | sc->sc_rev = PCI_REVISION(ca->ca_class); |
265 | switch (sc->sc_chip) { |
266 | case TULIP_CHIP_21142: |
267 | if (sc->sc_rev >= 0x20) |
268 | sc->sc_chip = TULIP_CHIP_21143; |
269 | break; |
270 | |
271 | case TULIP_CHIP_AN985: |
272 | /* |
273 | * The AN983 and AN985 are very similar, and are |
274 | * differentiated by a "signature" register that |
275 | * is like, but not identical, to a PCI ID register. |
276 | */ |
277 | reg = Cardbus_conf_read(ct, csc->sc_tag, 0x80); |
278 | switch (reg) { |
279 | case 0x09811317: |
280 | sc->sc_chip = TULIP_CHIP_AN985; |
281 | break; |
282 | |
283 | case 0x09851317: |
284 | sc->sc_chip = TULIP_CHIP_AN983; |
285 | break; |
286 | |
287 | } |
288 | break; |
289 | |
290 | default: |
291 | /* Nothing. -- to make gcc happy */ |
292 | break; |
293 | } |
294 | |
295 | aprint_normal(": %s Ethernet, pass %d.%d\n" , |
296 | tlp_chip_name(sc->sc_chip), |
297 | (sc->sc_rev >> 4) & 0xf, sc->sc_rev & 0xf); |
298 | |
299 | /* |
300 | * Map the device. |
301 | */ |
302 | csc->sc_csr = PCI_COMMAND_MASTER_ENABLE; |
303 | if (Cardbus_mapreg_map(ct, TULIP_PCI_MMBA, |
304 | PCI_MAPREG_TYPE_MEM, 0, &sc->sc_st, &sc->sc_sh, &adr, |
305 | &csc->sc_mapsize) == 0) { |
306 | csc->sc_csr |= PCI_COMMAND_MEM_ENABLE; |
307 | csc->sc_bar_reg = TULIP_PCI_MMBA; |
308 | csc->sc_bar_val = adr | PCI_MAPREG_TYPE_MEM; |
309 | } else if (Cardbus_mapreg_map(ct, TULIP_PCI_IOBA, |
310 | PCI_MAPREG_TYPE_IO, 0, &sc->sc_st, &sc->sc_sh, &adr, |
311 | &csc->sc_mapsize) == 0) { |
312 | csc->sc_csr |= PCI_COMMAND_IO_ENABLE; |
313 | csc->sc_bar_reg = TULIP_PCI_IOBA; |
314 | csc->sc_bar_val = adr | PCI_MAPREG_TYPE_IO; |
315 | } else { |
316 | aprint_error_dev(self, "unable to map device registers\n" ); |
317 | return; |
318 | } |
319 | |
320 | /* |
321 | * Bring the chip out of powersave mode and initialize the |
322 | * configuration registers. |
323 | */ |
324 | tlp_cardbus_setup(csc); |
325 | |
326 | /* |
327 | * Read the contents of the Ethernet Address ROM/SROM. |
328 | */ |
329 | switch (sc->sc_chip) { |
330 | case TULIP_CHIP_X3201_3: |
331 | /* |
332 | * No SROM on this chip. |
333 | */ |
334 | break; |
335 | |
336 | default: |
337 | if (tlp_read_srom(sc) == 0) |
338 | goto cant_cope; |
339 | break; |
340 | } |
341 | |
342 | /* |
343 | * Deal with chip/board quirks. This includes setting up |
344 | * the mediasw, and extracting the Ethernet address from |
345 | * the rombuf. |
346 | */ |
347 | switch (sc->sc_chip) { |
348 | case TULIP_CHIP_21142: |
349 | case TULIP_CHIP_21143: |
350 | /* Check for new format SROM. */ |
351 | if (tlp_isv_srom_enaddr(sc, enaddr) != 0) { |
352 | /* |
353 | * We start out with the 2114x ISV media switch. |
354 | * When we search for quirks, we may change to |
355 | * a different switch. |
356 | */ |
357 | sc->sc_mediasw = &tlp_2114x_isv_mediasw; |
358 | } else if (tlp_parse_old_srom(sc, enaddr) == 0) { |
359 | /* |
360 | * Not an ISV SROM, and not in old DEC Address |
361 | * ROM format. Try to snarf it out of the CIS. |
362 | */ |
363 | if (ca->ca_cis.funce.network.netid_present == 0) |
364 | goto cant_cope; |
365 | |
366 | /* Grab the MAC address from the CIS. */ |
367 | memcpy(enaddr, ca->ca_cis.funce.network.netid, |
368 | sizeof(enaddr)); |
369 | } |
370 | |
371 | /* |
372 | * Deal with any quirks this board might have. |
373 | */ |
374 | tlp_cardbus_get_quirks(csc, enaddr, tlp_cardbus_21142_quirks); |
375 | |
376 | /* |
377 | * If we don't already have a media switch, default to |
378 | * MII-over-SIO, with no special reset routine. |
379 | */ |
380 | if (sc->sc_mediasw == NULL) { |
381 | aprint_normal("%s: defaulting to MII-over-SIO; " |
382 | "no bets...\n" , device_xname(self)); |
383 | sc->sc_mediasw = &tlp_sio_mii_mediasw; |
384 | } |
385 | break; |
386 | |
387 | case TULIP_CHIP_AN983: |
388 | case TULIP_CHIP_AN985: |
389 | /* |
390 | * The ADMtek AN985's Ethernet address is located |
391 | * at offset 8 of its EEPROM. |
392 | */ |
393 | memcpy(enaddr, &sc->sc_srom[8], ETHER_ADDR_LEN); |
394 | |
395 | /* |
396 | * The ADMtek AN985 can be configured in Single-Chip |
397 | * mode or MAC-only mode. Single-Chip uses the built-in |
398 | * PHY, MAC-only has an external PHY (usually HomePNA). |
399 | * The selection is based on an EEPROM setting, and both |
400 | * PHYs are access via MII attached to SIO. |
401 | * |
402 | * The AN985 "ghosts" the internal PHY onto all |
403 | * MII addresses, so we have to use a media init |
404 | * routine that limits the search. |
405 | * XXX How does this work with MAC-only mode? |
406 | */ |
407 | sc->sc_mediasw = &tlp_an985_mediasw; |
408 | break; |
409 | |
410 | case TULIP_CHIP_X3201_3: |
411 | /* |
412 | * The X3201 doesn't have an SROM. Lift the MAC address |
413 | * from the CIS. Also, we have a special media switch: |
414 | * MII-on-SIO, plus some special GPIO setup. |
415 | */ |
416 | memcpy(enaddr, ca->ca_cis.funce.network.netid, sizeof(enaddr)); |
417 | sc->sc_reset = tlp_cardbus_x3201_reset; |
418 | sc->sc_mediasw = &tlp_sio_mii_mediasw; |
419 | break; |
420 | |
421 | default: |
422 | cant_cope: |
423 | aprint_error_dev(self, "sorry, unable to handle your board\n" ); |
424 | return; |
425 | } |
426 | |
427 | /* |
428 | * Finish off the attach. |
429 | */ |
430 | tlp_attach(sc, enaddr); |
431 | |
432 | /* |
433 | * Power down the socket. |
434 | */ |
435 | Cardbus_function_disable(csc->sc_ct); |
436 | } |
437 | |
438 | int |
439 | tlp_cardbus_detach(device_t self, int flags) |
440 | { |
441 | struct tulip_cardbus_softc *csc = device_private(self); |
442 | struct tulip_softc *sc = &csc->sc_tulip; |
443 | struct cardbus_devfunc *ct = csc->sc_ct; |
444 | int rv; |
445 | |
446 | #if defined(DIAGNOSTIC) |
447 | if (ct == NULL) |
448 | panic("%s: data structure lacks" , device_xname(self)); |
449 | #endif |
450 | |
451 | rv = tlp_detach(sc); |
452 | if (rv) |
453 | return (rv); |
454 | |
455 | /* |
456 | * Unhook the interrupt handler. |
457 | */ |
458 | if (csc->sc_ih != NULL) |
459 | Cardbus_intr_disestablish(ct, csc->sc_ih); |
460 | |
461 | /* |
462 | * Release bus space and close window. |
463 | */ |
464 | if (csc->sc_bar_reg != 0) |
465 | Cardbus_mapreg_unmap(ct, csc->sc_bar_reg, |
466 | sc->sc_st, sc->sc_sh, csc->sc_mapsize); |
467 | |
468 | return (0); |
469 | } |
470 | |
471 | int |
472 | tlp_cardbus_enable(struct tulip_softc *sc) |
473 | { |
474 | struct tulip_cardbus_softc *csc = (void *) sc; |
475 | cardbus_devfunc_t ct = csc->sc_ct; |
476 | |
477 | /* |
478 | * Power on the socket. |
479 | */ |
480 | Cardbus_function_enable(ct); |
481 | |
482 | /* |
483 | * Set up the PCI configuration registers. |
484 | */ |
485 | tlp_cardbus_setup(csc); |
486 | |
487 | /* |
488 | * Map and establish the interrupt. |
489 | */ |
490 | csc->sc_ih = Cardbus_intr_establish(ct, IPL_NET, tlp_intr, sc); |
491 | if (csc->sc_ih == NULL) { |
492 | aprint_error_dev(sc->sc_dev, |
493 | "unable to establish interrupt\n" ); |
494 | Cardbus_function_disable(csc->sc_ct); |
495 | return (1); |
496 | } |
497 | return (0); |
498 | } |
499 | |
500 | void |
501 | tlp_cardbus_disable(struct tulip_softc *sc) |
502 | { |
503 | struct tulip_cardbus_softc *csc = (void *) sc; |
504 | cardbus_devfunc_t ct = csc->sc_ct; |
505 | |
506 | /* Unhook the interrupt handler. */ |
507 | Cardbus_intr_disestablish(ct, csc->sc_ih); |
508 | csc->sc_ih = NULL; |
509 | |
510 | /* Power down the socket. */ |
511 | Cardbus_function_disable(ct); |
512 | } |
513 | |
514 | void |
515 | tlp_cardbus_power(struct tulip_softc *sc, int why) |
516 | { |
517 | |
518 | switch (why) { |
519 | case PWR_RESUME: |
520 | tlp_cardbus_enable(sc); |
521 | break; |
522 | case PWR_SUSPEND: |
523 | tlp_cardbus_disable(sc); |
524 | break; |
525 | } |
526 | } |
527 | |
528 | void |
529 | tlp_cardbus_setup(struct tulip_cardbus_softc *csc) |
530 | { |
531 | struct tulip_softc *sc = &csc->sc_tulip; |
532 | cardbus_devfunc_t ct = csc->sc_ct; |
533 | pcireg_t reg; |
534 | |
535 | /* |
536 | * Check to see if the device is in power-save mode, and |
537 | * bring it out if necessary. |
538 | */ |
539 | switch (sc->sc_chip) { |
540 | case TULIP_CHIP_21142: |
541 | case TULIP_CHIP_21143: |
542 | case TULIP_CHIP_X3201_3: |
543 | /* |
544 | * Clear the "sleep mode" bit in the CFDA register. |
545 | */ |
546 | reg = Cardbus_conf_read(ct, csc->sc_tag, TULIP_PCI_CFDA); |
547 | if (reg & (CFDA_SLEEP|CFDA_SNOOZE)) |
548 | Cardbus_conf_write(ct, csc->sc_tag, TULIP_PCI_CFDA, |
549 | reg & ~(CFDA_SLEEP|CFDA_SNOOZE)); |
550 | break; |
551 | |
552 | default: |
553 | /* Nothing. -- to make gcc happy */ |
554 | break; |
555 | } |
556 | |
557 | (void)cardbus_set_powerstate(ct, csc->sc_tag, PCI_PWR_D0); |
558 | |
559 | /* Program the BAR. */ |
560 | Cardbus_conf_write(ct, csc->sc_tag, csc->sc_bar_reg, csc->sc_bar_val); |
561 | |
562 | /* Enable the appropriate bits in the PCI CSR. */ |
563 | reg = Cardbus_conf_read(ct, csc->sc_tag, PCI_COMMAND_STATUS_REG); |
564 | reg &= ~(PCI_COMMAND_IO_ENABLE|PCI_COMMAND_MEM_ENABLE); |
565 | reg |= csc->sc_csr; |
566 | Cardbus_conf_write(ct, csc->sc_tag, PCI_COMMAND_STATUS_REG, reg); |
567 | |
568 | /* |
569 | * Make sure the latency timer is set to some reasonable |
570 | * value. |
571 | */ |
572 | reg = Cardbus_conf_read(ct, csc->sc_tag, PCI_BHLC_REG); |
573 | if (PCI_LATTIMER(reg) < 0x20) { |
574 | reg &= ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT); |
575 | reg |= (0x20 << PCI_LATTIMER_SHIFT); |
576 | Cardbus_conf_write(ct, csc->sc_tag, PCI_BHLC_REG, reg); |
577 | } |
578 | } |
579 | |
580 | void |
581 | tlp_cardbus_x3201_reset(struct tulip_softc *sc) |
582 | { |
583 | u_int32_t reg; |
584 | |
585 | reg = TULIP_READ(sc, CSR_SIAGEN); |
586 | |
587 | /* make GP[2,0] outputs */ |
588 | TULIP_WRITE(sc, CSR_SIAGEN, (reg & ~SIAGEN_MD) | SIAGEN_CWE | |
589 | 0x00050000); |
590 | TULIP_WRITE(sc, CSR_SIAGEN, (reg & ~SIAGEN_CWE) | SIAGEN_MD); |
591 | } |
592 | |
593 | void |
594 | tlp_cardbus_lxt_quirks(struct tulip_cardbus_softc *csc, const u_int8_t *enaddr) |
595 | { |
596 | struct tulip_softc *sc = &csc->sc_tulip; |
597 | |
598 | sc->sc_mediasw = &tlp_sio_mii_mediasw; |
599 | } |
600 | |