summaryrefslogtreecommitdiffstats
path: root/sys/pccard
diff options
context:
space:
mode:
authorimp <imp@FreeBSD.org>2002-03-20 19:02:08 +0000
committerimp <imp@FreeBSD.org>2002-03-20 19:02:08 +0000
commit7dc99a3ca097b6630ffbe249f00705eecc1322f1 (patch)
tree9e5d1c22261af26c145629115b742aea0c8e40b3 /sys/pccard
parent5cb9993cfd3a3b955f8efc9f4463620b00e3b153 (diff)
downloadFreeBSD-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.c8
-rw-r--r--sys/pccard/pcic.c110
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)
OpenPOWER on IntegriCloud