diff options
author | imp <imp@FreeBSD.org> | 2002-03-20 19:02:08 +0000 |
---|---|---|
committer | imp <imp@FreeBSD.org> | 2002-03-20 19:02:08 +0000 |
commit | 7dc99a3ca097b6630ffbe249f00705eecc1322f1 (patch) | |
tree | 9e5d1c22261af26c145629115b742aea0c8e40b3 /sys/pccard | |
parent | 5cb9993cfd3a3b955f8efc9f4463620b00e3b153 (diff) | |
download | FreeBSD-src-7dc99a3ca097b6630ffbe249f00705eecc1322f1.zip FreeBSD-src-7dc99a3ca097b6630ffbe249f00705eecc1322f1.tar.gz |
Better power code and better power diagnostics
Diffstat (limited to 'sys/pccard')
-rw-r--r-- | sys/pccard/pccard.c | 8 | ||||
-rw-r--r-- | sys/pccard/pcic.c | 110 |
2 files changed, 82 insertions, 36 deletions
diff --git a/sys/pccard/pccard.c b/sys/pccard/pccard.c index 992f4d1..a65d618 100644 --- a/sys/pccard/pccard.c +++ b/sys/pccard/pccard.c @@ -56,12 +56,6 @@ #define suser_td(a) suser(a) #endif -/* The following might now be obsolete */ -static int pcic_resume_reset = 1; - -SYSCTL_INT(_machdep_pccard, OID_AUTO, pcic_resume_reset, CTLFLAG_RW, - &pcic_resume_reset, 0, ""); - #define MIN(a,b) ((a)<(b)?(a):(b)) static int allocate_driver(struct slot *, struct dev_desc *); @@ -303,7 +297,7 @@ inserted(void *arg) * Enable 5V to the card so that the CIS can be read. */ slt->pwr.vcc = -1; - slt->pwr.vpp = 50; + slt->pwr.vpp = -1; /* * Disable any pending timeouts for this slot, and explicitly diff --git a/sys/pccard/pcic.c b/sys/pccard/pcic.c index 89fe7c3..c4e60d3 100644 --- a/sys/pccard/pcic.c +++ b/sys/pccard/pcic.c @@ -495,10 +495,11 @@ pcic_ioctl(struct slot *slt, int cmd, caddr_t data) * cardbus bridges have minor issues with power via the ExCA registers, * go ahead and do it all via cardbus registers. * - * An expamination of the code will show the relative - * ease that we do Vpp as well. + * An expamination of the code will show the relative ease that we do + * Vpp in comparison to the ExCA case (which may be partially broken). * - * Too bad it appears to not work. + * Too bad it appears to not work. When used we seem to be unable to + * read the card's CIS. */ static int pcic_cardbus_power(struct pcic_slot *sp, struct slot *slt) @@ -514,44 +515,65 @@ pcic_cardbus_power(struct pcic_slot *sp, struct slot *slt) printf("old value 0x%x\n", power); power &= ~CB_SP_CLKSTOP; - switch(slt->pwr.vpp) { + /* + * vcc == -1 means automatically detect the voltage of the card. + * Do so and apply the right amount of power. + */ + if (slt->pwr.vcc == -1) { + if (state & CB_SS_5VCARD) + slt->pwr.vcc = 50; + else if (state & CB_SS_3VCARD) + slt->pwr.vcc = 33; + else if (state & CB_SS_XVCARD) + slt->pwr.vcc = 22; + else if (state & CB_SS_YVCARD) + slt->pwr.vcc = 11; + } + switch(slt->pwr.vcc) { default: return (EINVAL); case 0: - power |= CB_SP_VPP_0V; + power |= CB_SP_VCC_0V; + break; + case 11: + power |= CB_SP_VCC_YV; + break; + case 22: + power |= CB_SP_VCC_XV; break; case 33: - power |= CB_SP_VPP_3V; + power |= CB_SP_VCC_3V; break; case 50: - power |= CB_SP_VPP_5V; - break; - case 120: - power |= CB_SP_VPP_12V; + power |= CB_SP_VCC_5V; break; } - switch(slt->pwr.vcc) { + /* + * vpp == -1 means use vcc voltage. + */ + if (slt->pwr.vpp == -1) + slt->pwr.vpp = slt->pwr.vcc; + switch(slt->pwr.vpp) { default: return (EINVAL); case 0: - power |= CB_SP_VCC_0V; + power |= CB_SP_VPP_0V; + break; + case 11: + power |= CB_SP_VPP_YV; + break; + case 22: + power |= CB_SP_VPP_XV; break; case 33: - power |= CB_SP_VCC_3V; + power |= CB_SP_VPP_3V; break; case 50: - power |= CB_SP_VCC_5V; + power |= CB_SP_VPP_5V; break; - case -1: - if (state & CB_SS_5VCARD) - power |= CB_SP_VCC_5V; - else if (state & CB_SS_3VCARD) - power |= CB_SP_VCC_3V; - else if (state & CB_SS_XVCARD) - power |= CB_SP_VCC_XV; - else if (state & CB_SS_YVCARD) - power |= CB_SP_VCC_YV; + case 120: + power |= CB_SP_VPP_12V; break; } printf("Setting power reg to 0x%x", power); @@ -572,6 +594,7 @@ pcic_power(struct slot *slt) struct pcic_slot *sp = slt->cdata; struct pcic_slot *sp2; struct pcic_softc *sc = sp->sc; + int dodefault = 0; /* * Cardbus power registers are completely different. @@ -579,6 +602,9 @@ pcic_power(struct slot *slt) if (sc->flags & PCIC_CARDBUS_POWER) return (pcic_cardbus_power(sp, slt)); + if (bootverbose) + device_printf(sc->dev, "Power: Vcc=%d Vpp=%d\n", slt->pwr.vcc, + slt->pwr.vpp); /* * If we're automatically detecting what voltage to use, then we need * to ask the bridge what type (voltage-wise) the card is. @@ -647,6 +673,13 @@ pcic_power(struct slot *slt) device_printf(sc->dev, "Autodetected %d.%dV card\n", slt->pwr.vcc / 10, slt->pwr.vcc %10); } + if (slt->pwr.vcc == -1) { + if (bootverbose) + device_printf(sc->dev, + "Couldn't autodetect voltage, assuming 5.0V\n"); + dodefault = 1; + slt->pwr.vcc = 50; + } /* * XXX Note: The Vpp controls varies quit a bit between bridge chips @@ -655,6 +688,8 @@ pcic_power(struct slot *slt) * applications want vpp == vcc and the following code does appear * to do that for all bridge sets. */ + if (slt->pwr.vpp == -1) + slt->pwr.vpp = slt->pwr.vcc; switch(slt->pwr.vpp) { default: return (EINVAL); @@ -707,7 +742,6 @@ pcic_power(struct slot *slt) if (sc->flags & PCIC_DF_POWER) reg |= PCIC_VCC_3V; break; - case -1: /* Treat default like 5.0V */ case 50: if (sc->flags & PCIC_KING_POWER) reg |= PCIC_VCC_5V_KING; @@ -728,25 +762,36 @@ pcic_power(struct slot *slt) break; } sp->putb(sp, PCIC_POWER, reg); + if (bootverbose) + device_printf(sc->dev, "Power applied\n"); DELAY(300*1000); if (slt->pwr.vcc) { reg |= PCIC_OUTENA; sp->putb(sp, PCIC_POWER, reg); + if (bootverbose) + device_printf(sc->dev, "Output enabled\n"); DELAY(100*1000); + if (bootverbose) + device_printf(sc->dev, "Settling complete\n"); } /* * Some chipsets will attempt to preclude us from supplying * 5.0V to cards that only handle 3.3V. We seem to need to * try 3.3V to paper over some power handling issues in other - * parts of the system. I suspect they are in the pccard bus - * driver, but may be in pccardd as well. + * parts of the system. Maybe the proper detection of 3.3V cards + * now obviates the need for this hack, so put a printf in to + * warn the world about it. */ - if (!(sp->getb(sp, PCIC_STATUS) & PCIC_POW) && slt->pwr.vcc == -1) { + if (!(sp->getb(sp, PCIC_STATUS) & PCIC_POW) && dodefault) { slt->pwr.vcc = 33; slt->pwr.vpp = 0; + device_printf(sc->dev, + "Failed at 5.0V. Trying 3.3V. Please report message to mobile@freebsd.org\n"); return (pcic_power(slt)); } + if (bootverbose) + printf("Power complete.\n"); return (0); } @@ -764,7 +809,13 @@ pcic_mapirq(struct slot *slt, int irq) } /* - * pcic_reset - Reset the card and enable initial power. + * pcic_reset - Reset the card and enable initial power. This may + * need to be interrupt driven in the future. We should likely turn + * the reset on, DELAY for a period of time < 250ms, turn it off and + * tsleep for a while and check it when we're woken up. I think that + * we're running afoul of the card status interrupt glitching, causing + * an interrupt storm because the card doesn't seem to be able to + * clear this pin while in reset. */ static void pcic_reset(void *chan) @@ -820,7 +871,8 @@ pcic_reset(void *chan) } /* - * pcic_disable - Disable the slot. + * pcic_disable - Disable the slot. I wonder if these operations can + * cause an interrupt we need to acknowledge? XXX */ static void pcic_disable(struct slot *slt) |