diff options
author | nsouch <nsouch@FreeBSD.org> | 1998-10-31 11:37:09 +0000 |
---|---|---|
committer | nsouch <nsouch@FreeBSD.org> | 1998-10-31 11:37:09 +0000 |
commit | 2ae8dc409583e4ed96ca74b7f4817f015685e45f (patch) | |
tree | 6c1dd20e560277a32eb4ff159dc40b87e98b90cc /sys | |
parent | 3b006890f16badfe89b25127eb04b14cfc373659 (diff) | |
download | FreeBSD-src-2ae8dc409583e4ed96ca74b7f4817f015685e45f.zip FreeBSD-src-2ae8dc409583e4ed96ca74b7f4817f015685e45f.tar.gz |
pcf.c: timeout management added
ppc.c: nsc code improved. Actually, a complete rewrite.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/pcf/pcf.c | 137 | ||||
-rw-r--r-- | sys/dev/ppc/ppc.c | 291 | ||||
-rw-r--r-- | sys/dev/ppc/ppcreg.h | 28 | ||||
-rw-r--r-- | sys/i386/isa/pcf.c | 137 | ||||
-rw-r--r-- | sys/i386/isa/ppc.c | 291 | ||||
-rw-r--r-- | sys/i386/isa/ppcreg.h | 28 | ||||
-rw-r--r-- | sys/isa/ppc.c | 291 | ||||
-rw-r--r-- | sys/isa/ppcreg.h | 28 |
8 files changed, 837 insertions, 394 deletions
diff --git a/sys/dev/pcf/pcf.c b/sys/dev/pcf/pcf.c index bee0e15..771dd30 100644 --- a/sys/dev/pcf/pcf.c +++ b/sys/dev/pcf/pcf.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: pcf.c,v 1.1 1998/09/03 21:01:22 nsouch Exp $ + * $Id: pcf.c,v 1.2 1998/10/22 05:58:40 bde Exp $ * */ #include <sys/param.h> @@ -41,7 +41,7 @@ #include <dev/iicbus/iiconf.h> #include "iicbus_if.h" -#define TIMEOUT 99999 /* XXX */ +#define TIMEOUT 9999 /* XXX */ /* Status bits of S1 register (read only) */ #define nBB 0x01 /* busy when low set/reset by STOP/START*/ @@ -67,13 +67,15 @@ #define SLAVE_TRANSMITTER 0x1 #define SLAVE_RECEIVER 0x2 +#define PCF_DEFAULT_ADDR 0xaa + struct pcf_softc { int pcf_base; /* isa port */ + u_char pcf_addr; /* interface I2C address */ - int pcf_count; - int pcf_own_address; /* own address */ int pcf_slave_mode; /* receiver or transmitter */ + int pcf_started; /* 1 if start condition sent */ device_t iicbus; /* the corresponding iicbus */ }; @@ -103,8 +105,8 @@ static int pcf_probe(device_t); static int pcf_attach(device_t); static void pcf_print_child(device_t, device_t); -static int pcf_repeated_start(device_t, u_char); -static int pcf_start(device_t, u_char); +static int pcf_repeated_start(device_t, u_char, int); +static int pcf_start(device_t, u_char, int); static int pcf_stop(device_t); static int pcf_write(device_t, char *, int, int *); static int pcf_read(device_t, char *, int, int *); @@ -120,6 +122,7 @@ static device_method_t pcf_methods[] = { DEVMETHOD(bus_print_child, pcf_print_child), /* iicbus interface */ + DEVMETHOD(iicbus_callback, iicbus_null_callback), DEVMETHOD(iicbus_repeated_start, pcf_repeated_start), DEVMETHOD(iicbus_start, pcf_start), DEVMETHOD(iicbus_stop, pcf_stop), @@ -165,6 +168,7 @@ pcfprobe_isa(struct isa_device *dvp) /* XXX add the pcf device to the root_bus until isa bus exists */ pcfdev = device_add_child(root_bus, "pcf", pcf->pcf_unit, NULL); + device_probe_and_attach(pcfdev); if (!pcfdev) goto error; @@ -188,15 +192,20 @@ static int pcf_probe(device_t pcfdev) { struct pcf_softc *pcf = (struct pcf_softc *)device_get_softc(pcfdev); + int unit = device_get_unit(pcfdev); - /* XXX try do detect chipset */ + /* retrieve base address from isa initialization + * + * XXX should use ivars with isabus + */ + pcf->pcf_base = pcfdata[unit]->pcf_base; - device_set_desc(pcfdev, "PCF8584 I2C bus controller"); + /* reset the chip */ + pcf_rst_card(pcfdev, IIC_FASTEST, PCF_DEFAULT_ADDR, NULL); - pcf->iicbus = iicbus_alloc_bus(pcfdev); + /* XXX try do detect chipset */ - if (!pcf->iicbus) - return (EINVAL); + device_set_desc(pcfdev, "PCF8584 I2C bus controller"); return (0); } @@ -205,13 +214,11 @@ static int pcf_attach(device_t pcfdev) { struct pcf_softc *pcf = (struct pcf_softc *)device_get_softc(pcfdev); - int unit = device_get_unit(pcfdev); - /* retrieve base address from isa initialization - * - * XXX should use ivars with isabus - */ - pcf->pcf_base = pcfdata[unit]->pcf_base; + pcf->iicbus = iicbus_alloc_bus(pcfdev); + + if (!pcf->iicbus) + return (EINVAL); /* probe and attach the iicbus */ device_probe_and_attach(pcf->iicbus); @@ -222,8 +229,10 @@ pcf_attach(device_t pcfdev) static void pcf_print_child(device_t bus, device_t dev) { + struct pcf_softc *pcf = (struct pcf_softc *)device_get_softc(bus); + printf(" on %s%d addr 0x%x", device_get_name(bus), - device_get_unit(bus), iicbus_get_own_address(dev)); + device_get_unit(bus), (int)pcf->pcf_addr); return; } @@ -293,13 +302,39 @@ static int pcf_stop(device_t pcfdev) { struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); - /* set stop condition and enable IT */ - PCF_SET_S1(pcf, PIN|ES0|ENI|STO|ACK); + /* + * Send STOP condition iff the START condition was previously sent. + * STOP is sent only once even if a iicbus_stop() is called after + * an iicbus_read()... see pcf_read(): the pcf needs to send the stop + * before the last char is read. + */ + if (pcf->pcf_started) { + /* set stop condition and enable IT */ + PCF_SET_S1(pcf, PIN|ES0|ENI|STO|ACK); + + pcf->pcf_started = 0; + } return (0); } -static int pcf_repeated_start(device_t pcfdev, u_char slave) + +static int pcf_noack(struct pcf_softc *pcf, int timeout) +{ + int noack; + int k = timeout/10; + + do { + noack = PCF_GET_S1(pcf) & LRB; + if (!noack) + break; + DELAY(10); /* XXX wait 10 us */ + } while (k--); + + return (noack); +} + +static int pcf_repeated_start(device_t pcfdev, u_char slave, int timeout) { struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); int error = 0; @@ -315,8 +350,8 @@ static int pcf_repeated_start(device_t pcfdev, u_char slave) if ((error = pcf_wait_byte(pcf))) goto error; - /* check ACK */ - if (PCF_GET_S1(pcf) & LRB) { + /* check for ack */ + if (pcf_noack(pcf, timeout)) { error = IIC_ENOACK; goto error; } @@ -328,7 +363,7 @@ error: return (error); } -static int pcf_start(device_t pcfdev, u_char slave) +static int pcf_start(device_t pcfdev, u_char slave, int timeout) { struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); int error = 0; @@ -343,12 +378,14 @@ static int pcf_start(device_t pcfdev, u_char slave) /* START only */ PCF_SET_S1(pcf, PIN|ES0|STA|ACK); + pcf->pcf_started = 1; + /* wait for address sent, polling */ if ((error = pcf_wait_byte(pcf))) goto error; - /* check ACK */ - if (PCF_GET_S1(pcf) & LRB) { + /* check for ACK */ + if (pcf_noack(pcf, timeout)) { error = IIC_ENOACK; goto error; } @@ -468,19 +505,23 @@ error: return; } -static int pcf_rst_card(device_t pcfdev, u_char speed) +static int pcf_rst_card(device_t pcfdev, u_char speed, u_char addr, u_char *oldaddr) { struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); - u_char ownaddr; + + if (oldaddr) + *oldaddr = pcf->pcf_addr; /* retrieve own address from bus level */ - if ((ownaddr = iicbus_get_own_address(pcf->iicbus)) == 0) - ownaddr = 0xaa; + if (!addr) + pcf->pcf_addr = PCF_DEFAULT_ADDR; + else + pcf->pcf_addr = addr; PCF_SET_S1(pcf, PIN); /* initialize S1 */ /* own address S'O<>0 */ - PCF_SET_S0(pcf, ownaddr >> 1); + PCF_SET_S0(pcf, pcf->pcf_addr >> 1); /* select clock register */ PCF_SET_S1(pcf, PIN|ES1); @@ -511,7 +552,7 @@ static int pcf_rst_card(device_t pcfdev, u_char speed) } static int -pcf_write(device_t pcfdev, char *buf, int len, int *sent) +pcf_write(device_t pcfdev, char *buf, int len, int *sent, int timeout /* us */) { struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); int bytes, error = 0; @@ -525,10 +566,12 @@ pcf_write(device_t pcfdev, char *buf, int len, int *sent) PCF_SET_S0(pcf, *buf++); + /* wait for the byte to be send */ if ((error = pcf_wait_byte(pcf))) goto error; - if (PCF_GET_S1(pcf) & LRB) { + /* check if ack received */ + if (pcf_noack(pcf, timeout)) { error = IIC_ENOACK; goto error; } @@ -549,7 +592,8 @@ error: } static int -pcf_read(device_t pcfdev, char *buf, int len, int *read) +pcf_read(device_t pcfdev, char *buf, int len, int *read, int last, + int delay /* us */) { struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); int bytes, error = 0; @@ -560,7 +604,7 @@ pcf_read(device_t pcfdev, char *buf, int len, int *read) /* trig the bus to get the first data byte in S0 */ if (len) { - if (len == 1) + if (len == 1 && last) /* just one byte to read */ PCF_SET_S1(pcf, ES0); /* no ack */ @@ -570,26 +614,25 @@ pcf_read(device_t pcfdev, char *buf, int len, int *read) bytes = 0; while (len) { + /* XXX delay needed here */ + + /* wait for trigged byte */ if ((error = pcf_wait_byte(pcf))) { pcf_stop(pcfdev); goto error; } - if (len == 1) { - - /* ok, last data byte already in S0 */ + if (len == 1 && last) + /* ok, last data byte already in S0, no I2C activity + * on next PCF_GET_S0() */ pcf_stop(pcfdev); - *buf = PCF_GET_S0(pcf); + else if (len == 2 && last) + /* next trigged byte with no ack */ + PCF_SET_S1(pcf, ES0); - } else { - if (len == 2) - /* next trigged byte with no ack */ - PCF_SET_S1(pcf, ES0); - - /* read last data byte, trig for next data byte */ - *buf++ = PCF_GET_S0(pcf); - } + /* receive byte, trig next byte */ + *buf++ = PCF_GET_S0(pcf); len --; bytes ++; diff --git a/sys/dev/ppc/ppc.c b/sys/dev/ppc/ppc.c index 39f4b4e..a22dfb0 100644 --- a/sys/dev/ppc/ppc.c +++ b/sys/dev/ppc/ppc.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: ppc.c,v 1.9 1998/09/20 14:47:01 nsouch Exp $ + * $Id: ppc.c,v 1.10 1998/10/22 05:58:40 bde Exp $ * */ #include "ppc.h" @@ -61,7 +61,7 @@ static int nppc = 0; static char *ppc_types[] = { "SMC-like", "SMC FDC37C665GT", "SMC FDC37C666GT", "PC87332", "PC87306", - "82091AA", "Generic", "W83877F", "W83877AF", "Winbond", 0 + "82091AA", "Generic", "W83877F", "W83877AF", "Winbond", "PC87334", 0 }; /* list of available modes */ @@ -221,27 +221,44 @@ ppc_detect_port(struct ppc_data *ppc) */ static int pc873xx_basetab[] = {0x0398, 0x026e, 0x015c, 0x002e, 0}; static int pc873xx_porttab[] = {0x0378, 0x03bc, 0x0278, 0}; +static int pc873xx_irqtab[] = {5, 7, 5, 0}; + +static int pc873xx_regstab[] = { + PC873_FER, PC873_FAR, PC873_PTR, + PC873_FCR, PC873_PCR, PC873_PMC, + PC873_TUP, PC873_SID, PC873_PNP0, + PC873_PNP1, PC873_LPTBA, -1 +}; + +static char *pc873xx_rnametab[] = { + "FER", "FAR", "PTR", "FCR", "PCR", + "PMC", "TUP", "SID", "PNP0", "PNP1", + "LPTBA", NULL +}; static int ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never forced */ { static int index = 0; - int base, idport; - int val; + int base, idport, irq; + int ptr, pcr, val, i; while ((idport = pc873xx_basetab[index++])) { /* XXX should check first to see if this location is already claimed */ /* - * Pull the 873xx through the power-on ID cycle (2.2,1.). We can't use this - * to locate the chip as it may already have been used by the BIOS. + * Pull the 873xx through the power-on ID cycle (2.2,1.). + * We can't use this to locate the chip as it may already have + * been used by the BIOS. */ - (void)inb(idport); (void)inb(idport); (void)inb(idport); (void)inb(idport); + (void)inb(idport); (void)inb(idport); + (void)inb(idport); (void)inb(idport); /* * Read the SID byte. Possible values are : * + * 01010xxx PC87334 * 0001xxxx PC87332 * 01110xxx PC87306 */ @@ -251,14 +268,27 @@ ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never for ppc->ppc_type = NS_PC87332; } else if ((val & 0xf8) == 0x70) { ppc->ppc_type = NS_PC87306; + } else if ((val & 0xf8) == 0x50) { + ppc->ppc_type = NS_PC87334; } else { if (bootverbose && (val != 0xff)) printf("PC873xx probe at 0x%x got unknown ID 0x%x\n", idport, val); continue ; /* not recognised */ } + + /* print registers */ + if (bootverbose) { + printf("PC873xx"); + for (i=0; pc873xx_regstab[i] != -1; i++) { + outb(idport, pc873xx_regstab[i]); + printf(" %s=0x%x", pc873xx_rnametab[i], + inb(idport + 1) & 0xff); + } + printf("\n"); + } /* - * We think we have one. Is it enabled and where we want it to be? + * We think we have one. Is it enabled and where we want it to be? */ outb(idport, PC873_FER); val = inb(idport + 1); @@ -276,96 +306,168 @@ ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never for pc873xx_porttab[val], ppc->ppc_base); continue; } + + outb(idport, PC873_PTR); + ptr = inb(idport + 1); + + /* get irq settings */ + if (ppc->ppc_base == 0x378) + irq = (ptr & PC873_LPTBIRQ7) ? 7 : 5; + else + irq = pc873xx_irqtab[val]; + + if (bootverbose) + printf("PC873xx irq %d at 0x%x\n", irq, ppc->ppc_base); - /* - * This is the port we want. Can we dink with it to improve - * our chances? + /* + * Check if irq settings are correct */ - outb(idport, PC873_PTR); - val = inb(idport + 1); - if (val & PC873_CFGLOCK) { - if (bootverbose) - printf("PC873xx locked\n"); - - /* work out what mode we're in */ - ppc->ppc_avm |= PPB_NIBBLE; /* worst case */ - - outb(idport, PC873_PCR); - val = inb(idport + 1); - if ((val & PC873_EPPEN) && (val & PC873_EPP19)) { - outb(idport, PC873_PTR); - val = inb(idport + 1); - if (!(val & PC873_EPPRDIR)) { - ppc->ppc_avm |= PPB_EPP; /* As we would have done it anwyay */ + if (irq != ppc->ppc_irq) { + /* + * If the chipset is not locked and base address is 0x378, + * we have another chance + */ + if (ppc->ppc_base == 0x378 && !(ptr & PC873_CFGLOCK)) { + if (ppc->ppc_irq == 7) { + outb(idport + 1, (ptr | PC873_LPTBIRQ7)); + outb(idport + 1, (ptr | PC873_LPTBIRQ7)); + } else { + outb(idport + 1, (ptr & ~PC873_LPTBIRQ7)); + outb(idport + 1, (ptr & ~PC873_LPTBIRQ7)); + } + if (bootverbose) + printf("PC873xx irq set to %d\n", ppc->ppc_irq); + } else { + if (bootverbose) + printf("PC873xx sorry, can't change irq setting\n"); } - } else if ((val & PC873_ECPEN) && (val & PC873_ECPCLK)) { - ppc->ppc_avm |= PPB_PS2; /* tolerable alternative */ - } } else { - if (bootverbose) - printf("PC873xx unlocked, "); - -#if 0 /* broken */ - /* - * Frob the zero-wait-state option if possible; it causes - * unreliable operation. - */ - outb(idport, PC873_FCR); - val = inb(idport + 1); - if ((ppc->ppc_type == NS_PC87306) || /* we are a '306 */ - !(val & PC873_ZWSPWDN)) { /* or pin _is_ ZWS */ - val &= ~PC873_ZWS; - outb(idport + 1, val); /* must disable ZWS */ - outb(idport + 1, val); - if (bootverbose) - printf("ZWS %s, ", (val & PC873_ZWS) ? "enabled" : "disabled"); - } + printf("PC873xx irq settings are correct\n"); + } -#endif + outb(idport, PC873_PCR); + pcr = inb(idport + 1); + + if ((ptr & PC873_CFGLOCK) || !chipset_mode) { + if (bootverbose) + printf("PC873xx %s", (ptr & PC873_CFGLOCK)?"locked":"unlocked"); + + ppc->ppc_avm |= PPB_NIBBLE; if (bootverbose) - printf("reconfiguring for "); - - /* - * if the chip is at 0x3bc, we can't use EPP as there's no room - * for the extra registers. - * - * XXX should we use ECP mode always and use the EPP submode? - */ - if (ppc->ppc_base != 0x3bc) { + printf(", NIBBLE"); + + if (pcr & PC873_EPPEN) { + ppc->ppc_avm |= PPB_EPP; + if (bootverbose) - printf("EPP 1.9\n"); - - /* configure for EPP 1.9 operation XXX should be configurable */ - outb(idport, PC873_PCR); - val = inb(idport + 1); - val &= ~(PC873_ECPEN | PC873_ECPCLK); /* disable ECP */ - val |= (PC873_EPPEN | PC873_EPP19); /* enable EPP */ - outb(idport + 1, val); - outb(idport + 1, val); - - /* enable automatic direction turnover */ - outb(idport, PC873_PTR); - val = inb(idport + 1); - val &= ~PC873_EPPRDIR; /* disable "regular" direction change */ - outb(idport + 1, val); - outb(idport + 1, val); + printf(", EPP"); - /* we are an EPP-32 port */ - ppc->ppc_avm |= PPB_EPP; - } else { + if (pcr & PC873_EPP19) + ppc->ppc_epp = EPP_1_9; + else + ppc->ppc_epp = EPP_1_7; + + if ((ppc->ppc_type == NS_PC87332) && bootverbose) { + outb(idport, PC873_PTR); + ptr = inb(idport + 1); + if (ptr & PC873_EPPRDIR) + printf(", Regular mode"); + else + printf(", Automatic mode"); + } + } else if (pcr & PC873_ECPEN) { + ppc->ppc_avm |= PPB_ECP; if (bootverbose) - printf("ECP\n"); - - /* configure as an ECP port to get bidirectional operation for now */ - outb(idport, PC873_PCR); - outb(idport + 1, inb(idport + 1) | PC873_ECPEN | PC873_ECPCLK); + printf(", ECP"); - /* we look like a PS/2 port */ - ppc->ppc_avm |= PPB_PS2; + if (pcr & PC873_ECPCLK) { /* XXX */ + ppc->ppc_avm |= PPB_PS2; + if (bootverbose) + printf(", PS/2"); + } + } else { + outb(idport, PC873_PTR); + ptr = inb(idport + 1); + if (ptr & PC873_EXTENDED) { + ppc->ppc_avm |= PPB_SPP; + if (bootverbose) + printf(", SPP"); + } } + } else { + if (bootverbose) + printf("PC873xx unlocked"); + + if (chipset_mode & PPB_ECP) { + if ((chipset_mode & PPB_EPP) && bootverbose) + printf(", ECP+EPP not supported"); + + pcr &= ~PC873_EPPEN; + pcr |= (PC873_ECPEN | PC873_ECPCLK); /* XXX */ + outb(idport + 1, pcr); + outb(idport + 1, pcr); + + if (bootverbose) + printf(", ECP"); + + } else if (chipset_mode & PPB_EPP) { + pcr &= ~(PC873_ECPEN | PC873_ECPCLK); + pcr |= (PC873_EPPEN | PC873_EPP19); + outb(idport + 1, pcr); + outb(idport + 1, pcr); + + ppc->ppc_epp = EPP_1_9; /* XXX */ + + if (bootverbose) + printf(", EPP1.9"); + + /* enable automatic direction turnover */ + if (ppc->ppc_type == NS_PC87332) { + outb(idport, PC873_PTR); + ptr = inb(idport + 1); + ptr &= ~PC873_EPPRDIR; + outb(idport + 1, ptr); + outb(idport + 1, ptr); + + if (bootverbose) + printf(", Automatic mode"); + } + } else { + pcr &= ~(PC873_ECPEN | PC873_ECPCLK | PC873_EPPEN); + outb(idport + 1, pcr); + outb(idport + 1, pcr); + + /* configure extended bit in PTR */ + outb(idport, PC873_PTR); + ptr = inb(idport + 1); + + if (chipset_mode & PPB_PS2) { + ptr |= PC873_EXTENDED; + + if (bootverbose) + printf(", PS/2"); + + } else { + /* default to NIBBLE mode */ + ptr &= ~PC873_EXTENDED; + + if (bootverbose) + printf(", NIBBLE"); + } + outb(idport + 1, ptr); + outb(idport + 1, ptr); + } + + ppc->ppc_avm = chipset_mode; } + if (bootverbose) + printf("\n"); + + ppc->ppc_link.adapter = &ppc_generic_adapter; + ppc_generic_setmode(ppc->ppc_unit, chipset_mode); + return(chipset_mode); } return(-1); @@ -863,10 +965,18 @@ ppc_detect(struct ppc_data *ppc, int chipset_mode) { * * after detection, the port must support running in compatible mode */ - for (i=0; chipset_detect[i] != NULL; i++) { - if ((mode = chipset_detect[i](ppc, chipset_mode)) != -1) { - ppc->ppc_mode = mode; - break; + if (ppc->ppc_flags & 0x40) { + if (bootverbose) + printf("ppc: chipset forced to generic\n"); + + ppc->ppc_mode = ppc_generic_detect(ppc, chipset_mode); + + } else { + for (i=0; chipset_detect[i] != NULL; i++) { + if ((mode = chipset_detect[i](ppc, chipset_mode)) != -1) { + ppc->ppc_mode = mode; + break; + } } } @@ -1232,6 +1342,9 @@ ppcprobe(struct isa_device *dvp) ppc->ppc_unit = dvp->id_unit; ppc->ppc_type = GENERIC; + /* store boot flags */ + ppc->ppc_flags = dvp->id_flags; + ppc->ppc_mode = PPB_COMPATIBLE; ppc->ppc_epp = (dvp->id_flags & 0x10) >> 4; @@ -1239,7 +1352,7 @@ ppcprobe(struct isa_device *dvp) * XXX Try and detect if interrupts are working */ if (!(dvp->id_flags & 0x20)) - ppc->ppc_irq = (dvp->id_irq); + ppc->ppc_irq = ffs(dvp->id_irq) - 1; ppcdata[ppc->ppc_unit] = ppc; nppc ++; diff --git a/sys/dev/ppc/ppcreg.h b/sys/dev/ppc/ppcreg.h index fe7e724..af8c9db 100644 --- a/sys/dev/ppc/ppcreg.h +++ b/sys/dev/ppc/ppcreg.h @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: ppcreg.h,v 1.3 1998/08/03 19:14:33 msmith Exp $ + * $Id: ppcreg.h,v 1.4 1998/09/13 18:26:44 nsouch Exp $ * */ #ifndef __PPCREG_H @@ -32,16 +32,17 @@ /* * Parallel Port Chipset type. */ -#define SMC_LIKE 0x0 -#define SMC_37C665GT 0x1 -#define SMC_37C666GT 0x2 -#define NS_PC87332 0x3 -#define NS_PC87306 0x4 -#define INTEL_820191AA 0x5 /* XXX not implemented */ -#define GENERIC 0x6 -#define WINB_W83877F 0x7 -#define WINB_W83877AF 0x8 -#define WINB_UNKNOWN 0x9 +#define SMC_LIKE 0 +#define SMC_37C665GT 1 +#define SMC_37C666GT 2 +#define NS_PC87332 3 +#define NS_PC87306 4 +#define INTEL_820191AA 5 /* XXX not implemented */ +#define GENERIC 6 +#define WINB_W83877F 7 +#define WINB_W83877AF 8 +#define WINB_UNKNOWN 9 +#define NS_PC87334 10 /* * Generic structure to hold parallel port chipset info. @@ -100,6 +101,8 @@ struct ppc_data { #define PC873_PTR 0x02 #define PC873_CFGLOCK (1<<6) #define PC873_EPPRDIR (1<<7) +#define PC873_EXTENDED (1<<7) +#define PC873_LPTBIRQ7 (1<<3) #define PC873_FCR 0x03 #define PC873_ZWS (1<<5) #define PC873_ZWSPWDN (1<<6) @@ -111,6 +114,9 @@ struct ppc_data { #define PC873_PMC 0x06 #define PC873_TUP 0x07 #define PC873_SID 0x08 +#define PC873_PNP0 0x1b +#define PC873_PNP1 0x1c +#define PC873_LPTBA 0x19 /* * Register defines for the SMC FDC37C66xGT parts diff --git a/sys/i386/isa/pcf.c b/sys/i386/isa/pcf.c index bee0e15..771dd30 100644 --- a/sys/i386/isa/pcf.c +++ b/sys/i386/isa/pcf.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: pcf.c,v 1.1 1998/09/03 21:01:22 nsouch Exp $ + * $Id: pcf.c,v 1.2 1998/10/22 05:58:40 bde Exp $ * */ #include <sys/param.h> @@ -41,7 +41,7 @@ #include <dev/iicbus/iiconf.h> #include "iicbus_if.h" -#define TIMEOUT 99999 /* XXX */ +#define TIMEOUT 9999 /* XXX */ /* Status bits of S1 register (read only) */ #define nBB 0x01 /* busy when low set/reset by STOP/START*/ @@ -67,13 +67,15 @@ #define SLAVE_TRANSMITTER 0x1 #define SLAVE_RECEIVER 0x2 +#define PCF_DEFAULT_ADDR 0xaa + struct pcf_softc { int pcf_base; /* isa port */ + u_char pcf_addr; /* interface I2C address */ - int pcf_count; - int pcf_own_address; /* own address */ int pcf_slave_mode; /* receiver or transmitter */ + int pcf_started; /* 1 if start condition sent */ device_t iicbus; /* the corresponding iicbus */ }; @@ -103,8 +105,8 @@ static int pcf_probe(device_t); static int pcf_attach(device_t); static void pcf_print_child(device_t, device_t); -static int pcf_repeated_start(device_t, u_char); -static int pcf_start(device_t, u_char); +static int pcf_repeated_start(device_t, u_char, int); +static int pcf_start(device_t, u_char, int); static int pcf_stop(device_t); static int pcf_write(device_t, char *, int, int *); static int pcf_read(device_t, char *, int, int *); @@ -120,6 +122,7 @@ static device_method_t pcf_methods[] = { DEVMETHOD(bus_print_child, pcf_print_child), /* iicbus interface */ + DEVMETHOD(iicbus_callback, iicbus_null_callback), DEVMETHOD(iicbus_repeated_start, pcf_repeated_start), DEVMETHOD(iicbus_start, pcf_start), DEVMETHOD(iicbus_stop, pcf_stop), @@ -165,6 +168,7 @@ pcfprobe_isa(struct isa_device *dvp) /* XXX add the pcf device to the root_bus until isa bus exists */ pcfdev = device_add_child(root_bus, "pcf", pcf->pcf_unit, NULL); + device_probe_and_attach(pcfdev); if (!pcfdev) goto error; @@ -188,15 +192,20 @@ static int pcf_probe(device_t pcfdev) { struct pcf_softc *pcf = (struct pcf_softc *)device_get_softc(pcfdev); + int unit = device_get_unit(pcfdev); - /* XXX try do detect chipset */ + /* retrieve base address from isa initialization + * + * XXX should use ivars with isabus + */ + pcf->pcf_base = pcfdata[unit]->pcf_base; - device_set_desc(pcfdev, "PCF8584 I2C bus controller"); + /* reset the chip */ + pcf_rst_card(pcfdev, IIC_FASTEST, PCF_DEFAULT_ADDR, NULL); - pcf->iicbus = iicbus_alloc_bus(pcfdev); + /* XXX try do detect chipset */ - if (!pcf->iicbus) - return (EINVAL); + device_set_desc(pcfdev, "PCF8584 I2C bus controller"); return (0); } @@ -205,13 +214,11 @@ static int pcf_attach(device_t pcfdev) { struct pcf_softc *pcf = (struct pcf_softc *)device_get_softc(pcfdev); - int unit = device_get_unit(pcfdev); - /* retrieve base address from isa initialization - * - * XXX should use ivars with isabus - */ - pcf->pcf_base = pcfdata[unit]->pcf_base; + pcf->iicbus = iicbus_alloc_bus(pcfdev); + + if (!pcf->iicbus) + return (EINVAL); /* probe and attach the iicbus */ device_probe_and_attach(pcf->iicbus); @@ -222,8 +229,10 @@ pcf_attach(device_t pcfdev) static void pcf_print_child(device_t bus, device_t dev) { + struct pcf_softc *pcf = (struct pcf_softc *)device_get_softc(bus); + printf(" on %s%d addr 0x%x", device_get_name(bus), - device_get_unit(bus), iicbus_get_own_address(dev)); + device_get_unit(bus), (int)pcf->pcf_addr); return; } @@ -293,13 +302,39 @@ static int pcf_stop(device_t pcfdev) { struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); - /* set stop condition and enable IT */ - PCF_SET_S1(pcf, PIN|ES0|ENI|STO|ACK); + /* + * Send STOP condition iff the START condition was previously sent. + * STOP is sent only once even if a iicbus_stop() is called after + * an iicbus_read()... see pcf_read(): the pcf needs to send the stop + * before the last char is read. + */ + if (pcf->pcf_started) { + /* set stop condition and enable IT */ + PCF_SET_S1(pcf, PIN|ES0|ENI|STO|ACK); + + pcf->pcf_started = 0; + } return (0); } -static int pcf_repeated_start(device_t pcfdev, u_char slave) + +static int pcf_noack(struct pcf_softc *pcf, int timeout) +{ + int noack; + int k = timeout/10; + + do { + noack = PCF_GET_S1(pcf) & LRB; + if (!noack) + break; + DELAY(10); /* XXX wait 10 us */ + } while (k--); + + return (noack); +} + +static int pcf_repeated_start(device_t pcfdev, u_char slave, int timeout) { struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); int error = 0; @@ -315,8 +350,8 @@ static int pcf_repeated_start(device_t pcfdev, u_char slave) if ((error = pcf_wait_byte(pcf))) goto error; - /* check ACK */ - if (PCF_GET_S1(pcf) & LRB) { + /* check for ack */ + if (pcf_noack(pcf, timeout)) { error = IIC_ENOACK; goto error; } @@ -328,7 +363,7 @@ error: return (error); } -static int pcf_start(device_t pcfdev, u_char slave) +static int pcf_start(device_t pcfdev, u_char slave, int timeout) { struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); int error = 0; @@ -343,12 +378,14 @@ static int pcf_start(device_t pcfdev, u_char slave) /* START only */ PCF_SET_S1(pcf, PIN|ES0|STA|ACK); + pcf->pcf_started = 1; + /* wait for address sent, polling */ if ((error = pcf_wait_byte(pcf))) goto error; - /* check ACK */ - if (PCF_GET_S1(pcf) & LRB) { + /* check for ACK */ + if (pcf_noack(pcf, timeout)) { error = IIC_ENOACK; goto error; } @@ -468,19 +505,23 @@ error: return; } -static int pcf_rst_card(device_t pcfdev, u_char speed) +static int pcf_rst_card(device_t pcfdev, u_char speed, u_char addr, u_char *oldaddr) { struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); - u_char ownaddr; + + if (oldaddr) + *oldaddr = pcf->pcf_addr; /* retrieve own address from bus level */ - if ((ownaddr = iicbus_get_own_address(pcf->iicbus)) == 0) - ownaddr = 0xaa; + if (!addr) + pcf->pcf_addr = PCF_DEFAULT_ADDR; + else + pcf->pcf_addr = addr; PCF_SET_S1(pcf, PIN); /* initialize S1 */ /* own address S'O<>0 */ - PCF_SET_S0(pcf, ownaddr >> 1); + PCF_SET_S0(pcf, pcf->pcf_addr >> 1); /* select clock register */ PCF_SET_S1(pcf, PIN|ES1); @@ -511,7 +552,7 @@ static int pcf_rst_card(device_t pcfdev, u_char speed) } static int -pcf_write(device_t pcfdev, char *buf, int len, int *sent) +pcf_write(device_t pcfdev, char *buf, int len, int *sent, int timeout /* us */) { struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); int bytes, error = 0; @@ -525,10 +566,12 @@ pcf_write(device_t pcfdev, char *buf, int len, int *sent) PCF_SET_S0(pcf, *buf++); + /* wait for the byte to be send */ if ((error = pcf_wait_byte(pcf))) goto error; - if (PCF_GET_S1(pcf) & LRB) { + /* check if ack received */ + if (pcf_noack(pcf, timeout)) { error = IIC_ENOACK; goto error; } @@ -549,7 +592,8 @@ error: } static int -pcf_read(device_t pcfdev, char *buf, int len, int *read) +pcf_read(device_t pcfdev, char *buf, int len, int *read, int last, + int delay /* us */) { struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); int bytes, error = 0; @@ -560,7 +604,7 @@ pcf_read(device_t pcfdev, char *buf, int len, int *read) /* trig the bus to get the first data byte in S0 */ if (len) { - if (len == 1) + if (len == 1 && last) /* just one byte to read */ PCF_SET_S1(pcf, ES0); /* no ack */ @@ -570,26 +614,25 @@ pcf_read(device_t pcfdev, char *buf, int len, int *read) bytes = 0; while (len) { + /* XXX delay needed here */ + + /* wait for trigged byte */ if ((error = pcf_wait_byte(pcf))) { pcf_stop(pcfdev); goto error; } - if (len == 1) { - - /* ok, last data byte already in S0 */ + if (len == 1 && last) + /* ok, last data byte already in S0, no I2C activity + * on next PCF_GET_S0() */ pcf_stop(pcfdev); - *buf = PCF_GET_S0(pcf); + else if (len == 2 && last) + /* next trigged byte with no ack */ + PCF_SET_S1(pcf, ES0); - } else { - if (len == 2) - /* next trigged byte with no ack */ - PCF_SET_S1(pcf, ES0); - - /* read last data byte, trig for next data byte */ - *buf++ = PCF_GET_S0(pcf); - } + /* receive byte, trig next byte */ + *buf++ = PCF_GET_S0(pcf); len --; bytes ++; diff --git a/sys/i386/isa/ppc.c b/sys/i386/isa/ppc.c index 39f4b4e..a22dfb0 100644 --- a/sys/i386/isa/ppc.c +++ b/sys/i386/isa/ppc.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: ppc.c,v 1.9 1998/09/20 14:47:01 nsouch Exp $ + * $Id: ppc.c,v 1.10 1998/10/22 05:58:40 bde Exp $ * */ #include "ppc.h" @@ -61,7 +61,7 @@ static int nppc = 0; static char *ppc_types[] = { "SMC-like", "SMC FDC37C665GT", "SMC FDC37C666GT", "PC87332", "PC87306", - "82091AA", "Generic", "W83877F", "W83877AF", "Winbond", 0 + "82091AA", "Generic", "W83877F", "W83877AF", "Winbond", "PC87334", 0 }; /* list of available modes */ @@ -221,27 +221,44 @@ ppc_detect_port(struct ppc_data *ppc) */ static int pc873xx_basetab[] = {0x0398, 0x026e, 0x015c, 0x002e, 0}; static int pc873xx_porttab[] = {0x0378, 0x03bc, 0x0278, 0}; +static int pc873xx_irqtab[] = {5, 7, 5, 0}; + +static int pc873xx_regstab[] = { + PC873_FER, PC873_FAR, PC873_PTR, + PC873_FCR, PC873_PCR, PC873_PMC, + PC873_TUP, PC873_SID, PC873_PNP0, + PC873_PNP1, PC873_LPTBA, -1 +}; + +static char *pc873xx_rnametab[] = { + "FER", "FAR", "PTR", "FCR", "PCR", + "PMC", "TUP", "SID", "PNP0", "PNP1", + "LPTBA", NULL +}; static int ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never forced */ { static int index = 0; - int base, idport; - int val; + int base, idport, irq; + int ptr, pcr, val, i; while ((idport = pc873xx_basetab[index++])) { /* XXX should check first to see if this location is already claimed */ /* - * Pull the 873xx through the power-on ID cycle (2.2,1.). We can't use this - * to locate the chip as it may already have been used by the BIOS. + * Pull the 873xx through the power-on ID cycle (2.2,1.). + * We can't use this to locate the chip as it may already have + * been used by the BIOS. */ - (void)inb(idport); (void)inb(idport); (void)inb(idport); (void)inb(idport); + (void)inb(idport); (void)inb(idport); + (void)inb(idport); (void)inb(idport); /* * Read the SID byte. Possible values are : * + * 01010xxx PC87334 * 0001xxxx PC87332 * 01110xxx PC87306 */ @@ -251,14 +268,27 @@ ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never for ppc->ppc_type = NS_PC87332; } else if ((val & 0xf8) == 0x70) { ppc->ppc_type = NS_PC87306; + } else if ((val & 0xf8) == 0x50) { + ppc->ppc_type = NS_PC87334; } else { if (bootverbose && (val != 0xff)) printf("PC873xx probe at 0x%x got unknown ID 0x%x\n", idport, val); continue ; /* not recognised */ } + + /* print registers */ + if (bootverbose) { + printf("PC873xx"); + for (i=0; pc873xx_regstab[i] != -1; i++) { + outb(idport, pc873xx_regstab[i]); + printf(" %s=0x%x", pc873xx_rnametab[i], + inb(idport + 1) & 0xff); + } + printf("\n"); + } /* - * We think we have one. Is it enabled and where we want it to be? + * We think we have one. Is it enabled and where we want it to be? */ outb(idport, PC873_FER); val = inb(idport + 1); @@ -276,96 +306,168 @@ ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never for pc873xx_porttab[val], ppc->ppc_base); continue; } + + outb(idport, PC873_PTR); + ptr = inb(idport + 1); + + /* get irq settings */ + if (ppc->ppc_base == 0x378) + irq = (ptr & PC873_LPTBIRQ7) ? 7 : 5; + else + irq = pc873xx_irqtab[val]; + + if (bootverbose) + printf("PC873xx irq %d at 0x%x\n", irq, ppc->ppc_base); - /* - * This is the port we want. Can we dink with it to improve - * our chances? + /* + * Check if irq settings are correct */ - outb(idport, PC873_PTR); - val = inb(idport + 1); - if (val & PC873_CFGLOCK) { - if (bootverbose) - printf("PC873xx locked\n"); - - /* work out what mode we're in */ - ppc->ppc_avm |= PPB_NIBBLE; /* worst case */ - - outb(idport, PC873_PCR); - val = inb(idport + 1); - if ((val & PC873_EPPEN) && (val & PC873_EPP19)) { - outb(idport, PC873_PTR); - val = inb(idport + 1); - if (!(val & PC873_EPPRDIR)) { - ppc->ppc_avm |= PPB_EPP; /* As we would have done it anwyay */ + if (irq != ppc->ppc_irq) { + /* + * If the chipset is not locked and base address is 0x378, + * we have another chance + */ + if (ppc->ppc_base == 0x378 && !(ptr & PC873_CFGLOCK)) { + if (ppc->ppc_irq == 7) { + outb(idport + 1, (ptr | PC873_LPTBIRQ7)); + outb(idport + 1, (ptr | PC873_LPTBIRQ7)); + } else { + outb(idport + 1, (ptr & ~PC873_LPTBIRQ7)); + outb(idport + 1, (ptr & ~PC873_LPTBIRQ7)); + } + if (bootverbose) + printf("PC873xx irq set to %d\n", ppc->ppc_irq); + } else { + if (bootverbose) + printf("PC873xx sorry, can't change irq setting\n"); } - } else if ((val & PC873_ECPEN) && (val & PC873_ECPCLK)) { - ppc->ppc_avm |= PPB_PS2; /* tolerable alternative */ - } } else { - if (bootverbose) - printf("PC873xx unlocked, "); - -#if 0 /* broken */ - /* - * Frob the zero-wait-state option if possible; it causes - * unreliable operation. - */ - outb(idport, PC873_FCR); - val = inb(idport + 1); - if ((ppc->ppc_type == NS_PC87306) || /* we are a '306 */ - !(val & PC873_ZWSPWDN)) { /* or pin _is_ ZWS */ - val &= ~PC873_ZWS; - outb(idport + 1, val); /* must disable ZWS */ - outb(idport + 1, val); - if (bootverbose) - printf("ZWS %s, ", (val & PC873_ZWS) ? "enabled" : "disabled"); - } + printf("PC873xx irq settings are correct\n"); + } -#endif + outb(idport, PC873_PCR); + pcr = inb(idport + 1); + + if ((ptr & PC873_CFGLOCK) || !chipset_mode) { + if (bootverbose) + printf("PC873xx %s", (ptr & PC873_CFGLOCK)?"locked":"unlocked"); + + ppc->ppc_avm |= PPB_NIBBLE; if (bootverbose) - printf("reconfiguring for "); - - /* - * if the chip is at 0x3bc, we can't use EPP as there's no room - * for the extra registers. - * - * XXX should we use ECP mode always and use the EPP submode? - */ - if (ppc->ppc_base != 0x3bc) { + printf(", NIBBLE"); + + if (pcr & PC873_EPPEN) { + ppc->ppc_avm |= PPB_EPP; + if (bootverbose) - printf("EPP 1.9\n"); - - /* configure for EPP 1.9 operation XXX should be configurable */ - outb(idport, PC873_PCR); - val = inb(idport + 1); - val &= ~(PC873_ECPEN | PC873_ECPCLK); /* disable ECP */ - val |= (PC873_EPPEN | PC873_EPP19); /* enable EPP */ - outb(idport + 1, val); - outb(idport + 1, val); - - /* enable automatic direction turnover */ - outb(idport, PC873_PTR); - val = inb(idport + 1); - val &= ~PC873_EPPRDIR; /* disable "regular" direction change */ - outb(idport + 1, val); - outb(idport + 1, val); + printf(", EPP"); - /* we are an EPP-32 port */ - ppc->ppc_avm |= PPB_EPP; - } else { + if (pcr & PC873_EPP19) + ppc->ppc_epp = EPP_1_9; + else + ppc->ppc_epp = EPP_1_7; + + if ((ppc->ppc_type == NS_PC87332) && bootverbose) { + outb(idport, PC873_PTR); + ptr = inb(idport + 1); + if (ptr & PC873_EPPRDIR) + printf(", Regular mode"); + else + printf(", Automatic mode"); + } + } else if (pcr & PC873_ECPEN) { + ppc->ppc_avm |= PPB_ECP; if (bootverbose) - printf("ECP\n"); - - /* configure as an ECP port to get bidirectional operation for now */ - outb(idport, PC873_PCR); - outb(idport + 1, inb(idport + 1) | PC873_ECPEN | PC873_ECPCLK); + printf(", ECP"); - /* we look like a PS/2 port */ - ppc->ppc_avm |= PPB_PS2; + if (pcr & PC873_ECPCLK) { /* XXX */ + ppc->ppc_avm |= PPB_PS2; + if (bootverbose) + printf(", PS/2"); + } + } else { + outb(idport, PC873_PTR); + ptr = inb(idport + 1); + if (ptr & PC873_EXTENDED) { + ppc->ppc_avm |= PPB_SPP; + if (bootverbose) + printf(", SPP"); + } } + } else { + if (bootverbose) + printf("PC873xx unlocked"); + + if (chipset_mode & PPB_ECP) { + if ((chipset_mode & PPB_EPP) && bootverbose) + printf(", ECP+EPP not supported"); + + pcr &= ~PC873_EPPEN; + pcr |= (PC873_ECPEN | PC873_ECPCLK); /* XXX */ + outb(idport + 1, pcr); + outb(idport + 1, pcr); + + if (bootverbose) + printf(", ECP"); + + } else if (chipset_mode & PPB_EPP) { + pcr &= ~(PC873_ECPEN | PC873_ECPCLK); + pcr |= (PC873_EPPEN | PC873_EPP19); + outb(idport + 1, pcr); + outb(idport + 1, pcr); + + ppc->ppc_epp = EPP_1_9; /* XXX */ + + if (bootverbose) + printf(", EPP1.9"); + + /* enable automatic direction turnover */ + if (ppc->ppc_type == NS_PC87332) { + outb(idport, PC873_PTR); + ptr = inb(idport + 1); + ptr &= ~PC873_EPPRDIR; + outb(idport + 1, ptr); + outb(idport + 1, ptr); + + if (bootverbose) + printf(", Automatic mode"); + } + } else { + pcr &= ~(PC873_ECPEN | PC873_ECPCLK | PC873_EPPEN); + outb(idport + 1, pcr); + outb(idport + 1, pcr); + + /* configure extended bit in PTR */ + outb(idport, PC873_PTR); + ptr = inb(idport + 1); + + if (chipset_mode & PPB_PS2) { + ptr |= PC873_EXTENDED; + + if (bootverbose) + printf(", PS/2"); + + } else { + /* default to NIBBLE mode */ + ptr &= ~PC873_EXTENDED; + + if (bootverbose) + printf(", NIBBLE"); + } + outb(idport + 1, ptr); + outb(idport + 1, ptr); + } + + ppc->ppc_avm = chipset_mode; } + if (bootverbose) + printf("\n"); + + ppc->ppc_link.adapter = &ppc_generic_adapter; + ppc_generic_setmode(ppc->ppc_unit, chipset_mode); + return(chipset_mode); } return(-1); @@ -863,10 +965,18 @@ ppc_detect(struct ppc_data *ppc, int chipset_mode) { * * after detection, the port must support running in compatible mode */ - for (i=0; chipset_detect[i] != NULL; i++) { - if ((mode = chipset_detect[i](ppc, chipset_mode)) != -1) { - ppc->ppc_mode = mode; - break; + if (ppc->ppc_flags & 0x40) { + if (bootverbose) + printf("ppc: chipset forced to generic\n"); + + ppc->ppc_mode = ppc_generic_detect(ppc, chipset_mode); + + } else { + for (i=0; chipset_detect[i] != NULL; i++) { + if ((mode = chipset_detect[i](ppc, chipset_mode)) != -1) { + ppc->ppc_mode = mode; + break; + } } } @@ -1232,6 +1342,9 @@ ppcprobe(struct isa_device *dvp) ppc->ppc_unit = dvp->id_unit; ppc->ppc_type = GENERIC; + /* store boot flags */ + ppc->ppc_flags = dvp->id_flags; + ppc->ppc_mode = PPB_COMPATIBLE; ppc->ppc_epp = (dvp->id_flags & 0x10) >> 4; @@ -1239,7 +1352,7 @@ ppcprobe(struct isa_device *dvp) * XXX Try and detect if interrupts are working */ if (!(dvp->id_flags & 0x20)) - ppc->ppc_irq = (dvp->id_irq); + ppc->ppc_irq = ffs(dvp->id_irq) - 1; ppcdata[ppc->ppc_unit] = ppc; nppc ++; diff --git a/sys/i386/isa/ppcreg.h b/sys/i386/isa/ppcreg.h index fe7e724..af8c9db 100644 --- a/sys/i386/isa/ppcreg.h +++ b/sys/i386/isa/ppcreg.h @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: ppcreg.h,v 1.3 1998/08/03 19:14:33 msmith Exp $ + * $Id: ppcreg.h,v 1.4 1998/09/13 18:26:44 nsouch Exp $ * */ #ifndef __PPCREG_H @@ -32,16 +32,17 @@ /* * Parallel Port Chipset type. */ -#define SMC_LIKE 0x0 -#define SMC_37C665GT 0x1 -#define SMC_37C666GT 0x2 -#define NS_PC87332 0x3 -#define NS_PC87306 0x4 -#define INTEL_820191AA 0x5 /* XXX not implemented */ -#define GENERIC 0x6 -#define WINB_W83877F 0x7 -#define WINB_W83877AF 0x8 -#define WINB_UNKNOWN 0x9 +#define SMC_LIKE 0 +#define SMC_37C665GT 1 +#define SMC_37C666GT 2 +#define NS_PC87332 3 +#define NS_PC87306 4 +#define INTEL_820191AA 5 /* XXX not implemented */ +#define GENERIC 6 +#define WINB_W83877F 7 +#define WINB_W83877AF 8 +#define WINB_UNKNOWN 9 +#define NS_PC87334 10 /* * Generic structure to hold parallel port chipset info. @@ -100,6 +101,8 @@ struct ppc_data { #define PC873_PTR 0x02 #define PC873_CFGLOCK (1<<6) #define PC873_EPPRDIR (1<<7) +#define PC873_EXTENDED (1<<7) +#define PC873_LPTBIRQ7 (1<<3) #define PC873_FCR 0x03 #define PC873_ZWS (1<<5) #define PC873_ZWSPWDN (1<<6) @@ -111,6 +114,9 @@ struct ppc_data { #define PC873_PMC 0x06 #define PC873_TUP 0x07 #define PC873_SID 0x08 +#define PC873_PNP0 0x1b +#define PC873_PNP1 0x1c +#define PC873_LPTBA 0x19 /* * Register defines for the SMC FDC37C66xGT parts diff --git a/sys/isa/ppc.c b/sys/isa/ppc.c index 39f4b4e..a22dfb0 100644 --- a/sys/isa/ppc.c +++ b/sys/isa/ppc.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: ppc.c,v 1.9 1998/09/20 14:47:01 nsouch Exp $ + * $Id: ppc.c,v 1.10 1998/10/22 05:58:40 bde Exp $ * */ #include "ppc.h" @@ -61,7 +61,7 @@ static int nppc = 0; static char *ppc_types[] = { "SMC-like", "SMC FDC37C665GT", "SMC FDC37C666GT", "PC87332", "PC87306", - "82091AA", "Generic", "W83877F", "W83877AF", "Winbond", 0 + "82091AA", "Generic", "W83877F", "W83877AF", "Winbond", "PC87334", 0 }; /* list of available modes */ @@ -221,27 +221,44 @@ ppc_detect_port(struct ppc_data *ppc) */ static int pc873xx_basetab[] = {0x0398, 0x026e, 0x015c, 0x002e, 0}; static int pc873xx_porttab[] = {0x0378, 0x03bc, 0x0278, 0}; +static int pc873xx_irqtab[] = {5, 7, 5, 0}; + +static int pc873xx_regstab[] = { + PC873_FER, PC873_FAR, PC873_PTR, + PC873_FCR, PC873_PCR, PC873_PMC, + PC873_TUP, PC873_SID, PC873_PNP0, + PC873_PNP1, PC873_LPTBA, -1 +}; + +static char *pc873xx_rnametab[] = { + "FER", "FAR", "PTR", "FCR", "PCR", + "PMC", "TUP", "SID", "PNP0", "PNP1", + "LPTBA", NULL +}; static int ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never forced */ { static int index = 0; - int base, idport; - int val; + int base, idport, irq; + int ptr, pcr, val, i; while ((idport = pc873xx_basetab[index++])) { /* XXX should check first to see if this location is already claimed */ /* - * Pull the 873xx through the power-on ID cycle (2.2,1.). We can't use this - * to locate the chip as it may already have been used by the BIOS. + * Pull the 873xx through the power-on ID cycle (2.2,1.). + * We can't use this to locate the chip as it may already have + * been used by the BIOS. */ - (void)inb(idport); (void)inb(idport); (void)inb(idport); (void)inb(idport); + (void)inb(idport); (void)inb(idport); + (void)inb(idport); (void)inb(idport); /* * Read the SID byte. Possible values are : * + * 01010xxx PC87334 * 0001xxxx PC87332 * 01110xxx PC87306 */ @@ -251,14 +268,27 @@ ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never for ppc->ppc_type = NS_PC87332; } else if ((val & 0xf8) == 0x70) { ppc->ppc_type = NS_PC87306; + } else if ((val & 0xf8) == 0x50) { + ppc->ppc_type = NS_PC87334; } else { if (bootverbose && (val != 0xff)) printf("PC873xx probe at 0x%x got unknown ID 0x%x\n", idport, val); continue ; /* not recognised */ } + + /* print registers */ + if (bootverbose) { + printf("PC873xx"); + for (i=0; pc873xx_regstab[i] != -1; i++) { + outb(idport, pc873xx_regstab[i]); + printf(" %s=0x%x", pc873xx_rnametab[i], + inb(idport + 1) & 0xff); + } + printf("\n"); + } /* - * We think we have one. Is it enabled and where we want it to be? + * We think we have one. Is it enabled and where we want it to be? */ outb(idport, PC873_FER); val = inb(idport + 1); @@ -276,96 +306,168 @@ ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never for pc873xx_porttab[val], ppc->ppc_base); continue; } + + outb(idport, PC873_PTR); + ptr = inb(idport + 1); + + /* get irq settings */ + if (ppc->ppc_base == 0x378) + irq = (ptr & PC873_LPTBIRQ7) ? 7 : 5; + else + irq = pc873xx_irqtab[val]; + + if (bootverbose) + printf("PC873xx irq %d at 0x%x\n", irq, ppc->ppc_base); - /* - * This is the port we want. Can we dink with it to improve - * our chances? + /* + * Check if irq settings are correct */ - outb(idport, PC873_PTR); - val = inb(idport + 1); - if (val & PC873_CFGLOCK) { - if (bootverbose) - printf("PC873xx locked\n"); - - /* work out what mode we're in */ - ppc->ppc_avm |= PPB_NIBBLE; /* worst case */ - - outb(idport, PC873_PCR); - val = inb(idport + 1); - if ((val & PC873_EPPEN) && (val & PC873_EPP19)) { - outb(idport, PC873_PTR); - val = inb(idport + 1); - if (!(val & PC873_EPPRDIR)) { - ppc->ppc_avm |= PPB_EPP; /* As we would have done it anwyay */ + if (irq != ppc->ppc_irq) { + /* + * If the chipset is not locked and base address is 0x378, + * we have another chance + */ + if (ppc->ppc_base == 0x378 && !(ptr & PC873_CFGLOCK)) { + if (ppc->ppc_irq == 7) { + outb(idport + 1, (ptr | PC873_LPTBIRQ7)); + outb(idport + 1, (ptr | PC873_LPTBIRQ7)); + } else { + outb(idport + 1, (ptr & ~PC873_LPTBIRQ7)); + outb(idport + 1, (ptr & ~PC873_LPTBIRQ7)); + } + if (bootverbose) + printf("PC873xx irq set to %d\n", ppc->ppc_irq); + } else { + if (bootverbose) + printf("PC873xx sorry, can't change irq setting\n"); } - } else if ((val & PC873_ECPEN) && (val & PC873_ECPCLK)) { - ppc->ppc_avm |= PPB_PS2; /* tolerable alternative */ - } } else { - if (bootverbose) - printf("PC873xx unlocked, "); - -#if 0 /* broken */ - /* - * Frob the zero-wait-state option if possible; it causes - * unreliable operation. - */ - outb(idport, PC873_FCR); - val = inb(idport + 1); - if ((ppc->ppc_type == NS_PC87306) || /* we are a '306 */ - !(val & PC873_ZWSPWDN)) { /* or pin _is_ ZWS */ - val &= ~PC873_ZWS; - outb(idport + 1, val); /* must disable ZWS */ - outb(idport + 1, val); - if (bootverbose) - printf("ZWS %s, ", (val & PC873_ZWS) ? "enabled" : "disabled"); - } + printf("PC873xx irq settings are correct\n"); + } -#endif + outb(idport, PC873_PCR); + pcr = inb(idport + 1); + + if ((ptr & PC873_CFGLOCK) || !chipset_mode) { + if (bootverbose) + printf("PC873xx %s", (ptr & PC873_CFGLOCK)?"locked":"unlocked"); + + ppc->ppc_avm |= PPB_NIBBLE; if (bootverbose) - printf("reconfiguring for "); - - /* - * if the chip is at 0x3bc, we can't use EPP as there's no room - * for the extra registers. - * - * XXX should we use ECP mode always and use the EPP submode? - */ - if (ppc->ppc_base != 0x3bc) { + printf(", NIBBLE"); + + if (pcr & PC873_EPPEN) { + ppc->ppc_avm |= PPB_EPP; + if (bootverbose) - printf("EPP 1.9\n"); - - /* configure for EPP 1.9 operation XXX should be configurable */ - outb(idport, PC873_PCR); - val = inb(idport + 1); - val &= ~(PC873_ECPEN | PC873_ECPCLK); /* disable ECP */ - val |= (PC873_EPPEN | PC873_EPP19); /* enable EPP */ - outb(idport + 1, val); - outb(idport + 1, val); - - /* enable automatic direction turnover */ - outb(idport, PC873_PTR); - val = inb(idport + 1); - val &= ~PC873_EPPRDIR; /* disable "regular" direction change */ - outb(idport + 1, val); - outb(idport + 1, val); + printf(", EPP"); - /* we are an EPP-32 port */ - ppc->ppc_avm |= PPB_EPP; - } else { + if (pcr & PC873_EPP19) + ppc->ppc_epp = EPP_1_9; + else + ppc->ppc_epp = EPP_1_7; + + if ((ppc->ppc_type == NS_PC87332) && bootverbose) { + outb(idport, PC873_PTR); + ptr = inb(idport + 1); + if (ptr & PC873_EPPRDIR) + printf(", Regular mode"); + else + printf(", Automatic mode"); + } + } else if (pcr & PC873_ECPEN) { + ppc->ppc_avm |= PPB_ECP; if (bootverbose) - printf("ECP\n"); - - /* configure as an ECP port to get bidirectional operation for now */ - outb(idport, PC873_PCR); - outb(idport + 1, inb(idport + 1) | PC873_ECPEN | PC873_ECPCLK); + printf(", ECP"); - /* we look like a PS/2 port */ - ppc->ppc_avm |= PPB_PS2; + if (pcr & PC873_ECPCLK) { /* XXX */ + ppc->ppc_avm |= PPB_PS2; + if (bootverbose) + printf(", PS/2"); + } + } else { + outb(idport, PC873_PTR); + ptr = inb(idport + 1); + if (ptr & PC873_EXTENDED) { + ppc->ppc_avm |= PPB_SPP; + if (bootverbose) + printf(", SPP"); + } } + } else { + if (bootverbose) + printf("PC873xx unlocked"); + + if (chipset_mode & PPB_ECP) { + if ((chipset_mode & PPB_EPP) && bootverbose) + printf(", ECP+EPP not supported"); + + pcr &= ~PC873_EPPEN; + pcr |= (PC873_ECPEN | PC873_ECPCLK); /* XXX */ + outb(idport + 1, pcr); + outb(idport + 1, pcr); + + if (bootverbose) + printf(", ECP"); + + } else if (chipset_mode & PPB_EPP) { + pcr &= ~(PC873_ECPEN | PC873_ECPCLK); + pcr |= (PC873_EPPEN | PC873_EPP19); + outb(idport + 1, pcr); + outb(idport + 1, pcr); + + ppc->ppc_epp = EPP_1_9; /* XXX */ + + if (bootverbose) + printf(", EPP1.9"); + + /* enable automatic direction turnover */ + if (ppc->ppc_type == NS_PC87332) { + outb(idport, PC873_PTR); + ptr = inb(idport + 1); + ptr &= ~PC873_EPPRDIR; + outb(idport + 1, ptr); + outb(idport + 1, ptr); + + if (bootverbose) + printf(", Automatic mode"); + } + } else { + pcr &= ~(PC873_ECPEN | PC873_ECPCLK | PC873_EPPEN); + outb(idport + 1, pcr); + outb(idport + 1, pcr); + + /* configure extended bit in PTR */ + outb(idport, PC873_PTR); + ptr = inb(idport + 1); + + if (chipset_mode & PPB_PS2) { + ptr |= PC873_EXTENDED; + + if (bootverbose) + printf(", PS/2"); + + } else { + /* default to NIBBLE mode */ + ptr &= ~PC873_EXTENDED; + + if (bootverbose) + printf(", NIBBLE"); + } + outb(idport + 1, ptr); + outb(idport + 1, ptr); + } + + ppc->ppc_avm = chipset_mode; } + if (bootverbose) + printf("\n"); + + ppc->ppc_link.adapter = &ppc_generic_adapter; + ppc_generic_setmode(ppc->ppc_unit, chipset_mode); + return(chipset_mode); } return(-1); @@ -863,10 +965,18 @@ ppc_detect(struct ppc_data *ppc, int chipset_mode) { * * after detection, the port must support running in compatible mode */ - for (i=0; chipset_detect[i] != NULL; i++) { - if ((mode = chipset_detect[i](ppc, chipset_mode)) != -1) { - ppc->ppc_mode = mode; - break; + if (ppc->ppc_flags & 0x40) { + if (bootverbose) + printf("ppc: chipset forced to generic\n"); + + ppc->ppc_mode = ppc_generic_detect(ppc, chipset_mode); + + } else { + for (i=0; chipset_detect[i] != NULL; i++) { + if ((mode = chipset_detect[i](ppc, chipset_mode)) != -1) { + ppc->ppc_mode = mode; + break; + } } } @@ -1232,6 +1342,9 @@ ppcprobe(struct isa_device *dvp) ppc->ppc_unit = dvp->id_unit; ppc->ppc_type = GENERIC; + /* store boot flags */ + ppc->ppc_flags = dvp->id_flags; + ppc->ppc_mode = PPB_COMPATIBLE; ppc->ppc_epp = (dvp->id_flags & 0x10) >> 4; @@ -1239,7 +1352,7 @@ ppcprobe(struct isa_device *dvp) * XXX Try and detect if interrupts are working */ if (!(dvp->id_flags & 0x20)) - ppc->ppc_irq = (dvp->id_irq); + ppc->ppc_irq = ffs(dvp->id_irq) - 1; ppcdata[ppc->ppc_unit] = ppc; nppc ++; diff --git a/sys/isa/ppcreg.h b/sys/isa/ppcreg.h index fe7e724..af8c9db 100644 --- a/sys/isa/ppcreg.h +++ b/sys/isa/ppcreg.h @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: ppcreg.h,v 1.3 1998/08/03 19:14:33 msmith Exp $ + * $Id: ppcreg.h,v 1.4 1998/09/13 18:26:44 nsouch Exp $ * */ #ifndef __PPCREG_H @@ -32,16 +32,17 @@ /* * Parallel Port Chipset type. */ -#define SMC_LIKE 0x0 -#define SMC_37C665GT 0x1 -#define SMC_37C666GT 0x2 -#define NS_PC87332 0x3 -#define NS_PC87306 0x4 -#define INTEL_820191AA 0x5 /* XXX not implemented */ -#define GENERIC 0x6 -#define WINB_W83877F 0x7 -#define WINB_W83877AF 0x8 -#define WINB_UNKNOWN 0x9 +#define SMC_LIKE 0 +#define SMC_37C665GT 1 +#define SMC_37C666GT 2 +#define NS_PC87332 3 +#define NS_PC87306 4 +#define INTEL_820191AA 5 /* XXX not implemented */ +#define GENERIC 6 +#define WINB_W83877F 7 +#define WINB_W83877AF 8 +#define WINB_UNKNOWN 9 +#define NS_PC87334 10 /* * Generic structure to hold parallel port chipset info. @@ -100,6 +101,8 @@ struct ppc_data { #define PC873_PTR 0x02 #define PC873_CFGLOCK (1<<6) #define PC873_EPPRDIR (1<<7) +#define PC873_EXTENDED (1<<7) +#define PC873_LPTBIRQ7 (1<<3) #define PC873_FCR 0x03 #define PC873_ZWS (1<<5) #define PC873_ZWSPWDN (1<<6) @@ -111,6 +114,9 @@ struct ppc_data { #define PC873_PMC 0x06 #define PC873_TUP 0x07 #define PC873_SID 0x08 +#define PC873_PNP0 0x1b +#define PC873_PNP1 0x1c +#define PC873_LPTBA 0x19 /* * Register defines for the SMC FDC37C66xGT parts |