summaryrefslogtreecommitdiffstats
path: root/sys/dev/ppc
diff options
context:
space:
mode:
authormsmith <msmith@FreeBSD.org>1998-08-03 19:14:33 +0000
committermsmith <msmith@FreeBSD.org>1998-08-03 19:14:33 +0000
commit2fdb23234a18b64b994328bb4be606a420e3b56d (patch)
treef8a4d5d9ba99cb367e9263ec96d08ecb8919f529 /sys/dev/ppc
parentcfef94c8ca2347c78a745676fe6061eb1f172be7 (diff)
downloadFreeBSD-src-2fdb23234a18b64b994328bb4be606a420e3b56d.zip
FreeBSD-src-2fdb23234a18b64b994328bb4be606a420e3b56d.tar.gz
Major ppbus updates from the author.
- ppbus now supports PLIP via the if_plip driver - ieee1284 infrastructure added, including parallel-port PnP - port microsequencer added, for scripting the sort of port I/O that is common with parallel devices without endless calls up and down through the driver structure. - improved bus ownership behaviour among the ppbus-using drivers. - improved I/O chipset feature detection The vpo driver is now implemented using the microsequencer, leading to some performance improvements as well as providing an extensive example of its use. Reviewed by: msmith Submitted by: Nicolas Souchu <Nicolas.Souchu@prism.uvsq.fr>
Diffstat (limited to 'sys/dev/ppc')
-rw-r--r--sys/dev/ppc/ppc.c720
-rw-r--r--sys/dev/ppc/ppcreg.h79
2 files changed, 609 insertions, 190 deletions
diff --git a/sys/dev/ppc/ppc.c b/sys/dev/ppc/ppc.c
index 39d0ece..71daa85 100644
--- a/sys/dev/ppc/ppc.c
+++ b/sys/dev/ppc/ppc.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1997 Nicolas Souchu
+ * Copyright (c) 1997, 1998 Nicolas Souchu
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -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.2 1997/09/01 02:08:41 bde Exp $
+ * $Id: ppc.c,v 1.3 1998/04/17 22:36:37 des Exp $
*
*/
#include "ppc.h"
@@ -44,6 +44,8 @@
#include <i386/isa/isa_device.h>
#include <dev/ppbus/ppbconf.h>
+#include <dev/ppbus/ppb_msq.h>
+
#include <i386/isa/ppcreg.h>
static int ppcprobe(struct isa_device *);
@@ -57,14 +59,26 @@ static struct ppc_data *ppcdata[NPPC];
static int nppc = 0;
static char *ppc_types[] = {
- "SMC", "SMC FDC37C665GT", "SMC FDC37C666GT",
- "NatSemi", "PC87332", "PC87306",
- "Intel 82091AA", "Generic", 0
+ "SMC-like", "SMC FDC37C665GT", "SMC FDC37C666GT", "PC87332", "PC87306",
+ "82091AA", "Generic", "W83877F", "W83877AF", "Winbond", 0
+};
+
+/* list of available modes */
+static char *ppc_avms[] = {
+ "COMPATIBLE", "NIBBLE-only", "PS2-only", "PS2/NIBBLE", "EPP-only",
+ "EPP/NIBBLE", "EPP/PS2", "EPP/PS2/NIBBLE", "ECP-only",
+ "ECP/NIBBLE", "ECP/PS2", "ECP/PS2/NIBBLE", "ECP/EPP",
+ "ECP/EPP/NIBBLE", "ECP/EPP/PS2", "ECP/EPP/PS2/NIBBLE", 0
};
+/* list of current executing modes
+ * Note that few modes do not actually exist.
+ */
static char *ppc_modes[] = {
- "AUTODETECT", "NIBBLE", "PS/2", "EPP", "ECP+EPP", "ECP+PS/2", "ECP",
- "UNKNOWN", 0
+ "COMPATIBLE", "NIBBLE", "PS/2", "PS/2", "EPP",
+ "EPP", "EPP", "EPP", "ECP",
+ "ECP", "ECP+PS2", "ECP+PS2", "ECP+EPP",
+ "ECP+EPP", "ECP+EPP", "ECP+EPP", 0
};
static char *ppc_epp_protocol[] = { " (EPP 1.9)", " (EPP 1.7)", 0 };
@@ -110,12 +124,19 @@ static void ppc_wfifo(int unit, char byte) { w_fifo(ppcdata[unit], byte); }
static void ppc_reset_epp_timeout(int);
static void ppc_ecp_sync(int);
+static int ppc_exec_microseq(int, struct ppb_microseq *, int *);
+static int ppc_generic_setmode(int, int);
+
static struct ppb_adapter ppc_adapter = {
0, /* no intr handler, filled by chipset dependent code */
ppc_reset_epp_timeout, ppc_ecp_sync,
+ ppc_exec_microseq,
+
+ ppc_generic_setmode,
+
ppc_outsb_epp, ppc_outsw_epp, ppc_outsl_epp,
ppc_insb_epp, ppc_insw_epp, ppc_insl_epp,
@@ -143,8 +164,8 @@ ppc_ecp_sync(int unit) {
DELAY(100);
}
- printf("ppc: ECP sync failed as data still " \
- "present in FIFO.\n");
+ printf("ppc%d: ECP sync failed as data still " \
+ "present in FIFO.\n", unit);
return;
}
@@ -158,6 +179,35 @@ ppcintr(int unit)
return;
}
+static void
+ppc_ecp_config(struct ppc_data *ppc, int chipset_mode)
+{
+ /* XXX disable DMA, enable interrupts */
+ if (chipset_mode & PPB_EPP)
+ /* select EPP mode */
+ w_ecr(ppc, 0x80);
+ else if (chipset_mode & PPB_PS2)
+ /* select PS2 mode with ECP */
+ w_ecr(ppc, 0x20);
+ else
+ /* keep ECP mode alone, default for NIBBLE */
+ w_ecr(ppc, 0x70);
+
+ return;
+}
+
+static int
+ppc_detect_port(struct ppc_data *ppc)
+{
+
+ w_ctr(ppc, 0x0c); /* To avoid missing PS2 ports */
+ w_dtr(ppc, 0xaa);
+ if (r_dtr(ppc) != (char) 0xaa)
+ return (0);
+
+ return (1);
+}
+
/*
* ppc_pc873xx_detect
*
@@ -170,11 +220,11 @@ static int pc873xx_basetab[] = {0x0398, 0x026e, 0x015c, 0x002e, 0};
static int pc873xx_porttab[] = {0x0378, 0x03bc, 0x0278, 0};
static int
-ppc_pc873xx_detect(struct ppc_data *ppc)
+ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never forced */
{
static int index = 0;
int base, idport;
- int val, mode;
+ int val;
while ((idport = pc873xx_basetab[index++])) {
@@ -235,7 +285,7 @@ ppc_pc873xx_detect(struct ppc_data *ppc)
printf("PC873xx locked\n");
/* work out what mode we're in */
- mode = PPB_NIBBLE; /* worst case */
+ ppc->ppc_avm |= PPB_NIBBLE; /* worst case */
outb(idport, PC873_PCR);
val = inb(idport + 1);
@@ -243,10 +293,10 @@ ppc_pc873xx_detect(struct ppc_data *ppc)
outb(idport, PC873_PTR);
val = inb(idport + 1);
if (!(val & PC873_EPPRDIR)) {
- mode = PPB_EPP; /* As we would have done it anwyay */
+ ppc->ppc_avm |= PPB_EPP; /* As we would have done it anwyay */
}
} else if ((val & PC873_ECPEN) && (val & PC873_ECPCLK)) {
- mode = PPB_PS2; /* tolerable alternative */
+ ppc->ppc_avm |= PPB_PS2; /* tolerable alternative */
}
} else {
if (bootverbose)
@@ -299,7 +349,7 @@ ppc_pc873xx_detect(struct ppc_data *ppc)
outb(idport + 1, val);
/* we are an EPP-32 port */
- mode = PPB_EPP;
+ ppc->ppc_avm |= PPB_EPP;
} else {
if (bootverbose)
printf("ECP\n");
@@ -309,44 +359,21 @@ ppc_pc873xx_detect(struct ppc_data *ppc)
outb(idport + 1, inb(idport + 1) | PC873_ECPEN | PC873_ECPCLK);
/* we look like a PS/2 port */
- mode = PPB_PS2;
+ ppc->ppc_avm |= PPB_PS2;
}
}
- return(mode);
+
+ return(chipset_mode);
}
- return(0);
+ return(-1);
}
static int
-ppc_detect_ps2(struct ppc_data *ppc)
+ppc_check_epp_timeout(struct ppc_data *ppc)
{
- char save_control, r;
-
- save_control = r_ctr(ppc);
-
- /* Try PS/2 mode */
- w_ctr(ppc, 0xec);
- w_dtr(ppc, 0x55);
-
- /* needed if in ECP mode */
- if (ppc->ppc_mode == PPB_ECP)
- w_ctr(ppc, PCD | 0xec);
- r = r_dtr(ppc);
-
- if (r != (char) 0xff) {
- if (r != (char) 0x55)
- return 0;
-
- w_dtr(ppc, 0xaa);
- r = r_dtr(ppc);
- if (r != (char) 0xaa)
- return 0;
-
- return (PPB_NIBBLE);
- } else
- w_ctr(ppc, save_control);
+ ppc_reset_epp_timeout(ppc->ppc_unit);
- return (PPB_PS2);
+ return (!(r_str(ppc) & TIMEOUT));
}
/*
@@ -355,11 +382,10 @@ ppc_detect_ps2(struct ppc_data *ppc)
* SMC FDC37C66xGT configuration.
*/
static int
-ppc_smc37c66xgt_detect(struct ppc_data *ppc, int mode)
+ppc_smc37c66xgt_detect(struct ppc_data *ppc, int chipset_mode)
{
int s, i;
char r;
- int retry = 0; /* boolean */
int type = -1;
int csr = SMC66x_CSR; /* initial value is 0x3F0 */
@@ -404,7 +430,7 @@ config:
* If chipset not found, do not continue.
*/
if (type == -1)
- return (0);
+ return (-1);
/* select CR1 */
outb(csr, 0x1);
@@ -412,65 +438,72 @@ config:
/* read the port's address: bits 0 and 1 of CR1 */
r = inb(cio) & SMC_CR1_ADDR;
if (port_address[r] != ppc->ppc_base)
- return (0);
+ return (-1);
ppc->ppc_type = type;
/*
* CR1 and CR4 registers bits 3 and 0/1 for mode configuration
- * If SPP mode is detected, try to set ECP+EPP mode end retry
- * detection to verify.
+ * If SPP mode is detected, try to set ECP+EPP mode
*/
-retry:
- /* select CR1 register */
+ if (bootverbose) {
+ outb(csr, 0x1);
+ printf("SMC registers CR1=0x%x", ppc->ppc_unit,
+ inb(cio) & 0xff);
+
+ outb(csr, 0x4);
+ printf(" CR4=0x%x", inb(cio) & 0xff);
+ }
+
+ /* select CR1 */
outb(csr, 0x1);
- if (!mode) {
+ if (!chipset_mode) {
/* autodetect mode */
- /* 666GT chipset is hardwired to an extended mode */
- if (type == SMC_37C666GT)
- mode = PPB_ECP_EPP;
+ /* 666GT is ~certainly~ hardwired to an extended ECP+EPP mode */
+ if (type == SMC_37C666GT) {
+ ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP;
- else if ((inb(cio) & SMC_CR1_MODE) == 0) {
+ } else
+ if ((inb(cio) & SMC_CR1_MODE) == 0) {
/* already in extended parallel port mode, read CR4 */
outb(csr, 0x4);
r = (inb(cio) & SMC_CR4_EMODE);
switch (r) {
case SMC_SPP:
- /* let's detect NIBBLE or PS/2 later */
+ ppc->ppc_avm |= PPB_SPP;
break;
case SMC_EPPSPP:
- mode = PPB_EPP;
+ ppc->ppc_avm |= PPB_EPP | PPB_SPP;
break;
case SMC_ECP:
- /*
- * Yet, don't know what to do with it! XXX
- * So, consider ECP mode as PS/2.
- * (see configuration later).
- */
- mode = PPB_ECP;
+ ppc->ppc_avm |= PPB_ECP | PPB_SPP;
break;
case SMC_ECPEPP:
- mode = PPB_ECP_EPP;
+ ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP;
break;
}
- }
+ } else {
+ /* not an extended port mode */
+ ppc->ppc_avm |= PPB_SPP;
+ }
+
} else {
/* mode forced */
- /* 666GT chipset is hardwired to an extended mode */
+ /* 666GT is ~certainly~ hardwired to an extended ECP+EPP mode */
if (type == SMC_37C666GT)
goto end_detect;
r = inb(cio);
- if (mode == PPB_NIBBLE || mode == PPB_PS2) {
- /* do not use ECP when the mode is forced to SPP */
+ if ((chipset_mode & (PPB_ECP | PPB_EPP)) == 0) {
+ /* do not use ECP when the mode is not forced to */
outb(cio, r | SMC_CR1_MODE);
} else {
/* an extended mode is selected */
@@ -480,30 +513,26 @@ retry:
outb(csr, 0x4);
r = inb(cio) & ~SMC_CR4_EMODE;
- switch (mode) {
- case PPB_EPP:
+ if (chipset_mode & PPB_ECP) {
+ if (chipset_mode & PPB_EPP) {
+ outb(cio, r | SMC_ECPEPP);
+ } else {
+ outb(cio, r | SMC_ECP);
+ }
+ } else {
+ /* PPB_EPP is set */
outb(cio, r | SMC_EPPSPP);
- break;
-
- case PPB_ECP:
- case PPB_ECP_PS2:
- outb(cio, r | SMC_ECP);
- break;
-
- case PPB_ECP_EPP:
- outb(cio, r | SMC_ECPEPP);
- break;
-
- default:
- printf("ppc: unknown mode (%d)\n",
- mode);
- return (0);
}
}
+ ppc->ppc_avm = chipset_mode;
}
end_detect:
- if (PPB_IS_EPP(mode)) {
+
+ if (bootverbose)
+ printf ("\n");
+
+ if (chipset_mode & PPB_EPP) {
/* select CR4 */
outb(csr, 0x4);
r = inb(cio);
@@ -511,11 +540,9 @@ end_detect:
/*
* Set the EPP protocol...
* Low=EPP 1.9 (1284 standard) and High=EPP 1.7
- * ...then check the result.
*/
if (ppc->ppc_epp == EPP_1_9)
outb(cio, (r & ~SMC_CR4_EPPTYPE));
-
else
outb(cio, (r | SMC_CR4_EPPTYPE));
}
@@ -523,86 +550,214 @@ end_detect:
/* end config mode */
outb(csr, 0xaa);
- /*
- * Write 100 to the mode bits and disable DMA, enable intr.
- */
- if (mode == PPB_ECP_EPP)
- w_ecr(ppc, 0x80);
+ if (ppc->ppc_avm & PPB_ECP)
+ ppc_ecp_config(ppc, chipset_mode);
- /*
- * Write 001 to the mode bits and disable DMA, enable intr.
- */
- if (mode == PPB_ECP)
- w_ecr(ppc, 0x20);
+ return (chipset_mode);
+}
+
+/*
+ * Winbond W83877F stuff
+ *
+ * EFER: extended function enable register
+ * EFIR: extended function index register
+ * EFDR: extended function data register
+ */
+#define efir ((efer == 0x250) ? 0x251 : 0x3f0)
+#define efdr ((efer == 0x250) ? 0x252 : 0x3f1)
+
+static int w83877f_efers[] = { 0x250, 0x3f0, 0x3f0, 0x250 };
+static int w83877f_keys[] = { 0x89, 0x86, 0x87, 0x88 };
+static int w83877f_keyiter[] = { 1, 2, 2, 1 };
+static int w83877f_hefs[] = { WINB_HEFERE, WINB_HEFRAS, WINB_HEFERE | WINB_HEFRAS, 0 };
+
+static int
+ppc_w83877f_detect(struct ppc_data *ppc, int chipset_mode)
+{
+ int i, j, efer, base;
+ unsigned char r, hefere, hefras;
+
+ for (i = 0; i < 4; i ++) {
+ /* first try to enable configuration registers */
+ efer = w83877f_efers[i];
+
+ /* write the key to the EFER */
+ for (j = 0; j < w83877f_keyiter[i]; j ++)
+ outb (efer, w83877f_keys[i]);
+
+ /* then check HEFERE and HEFRAS bits */
+ outb (efir, 0x0c);
+ hefere = inb(efdr) & WINB_HEFERE;
+
+ outb (efir, 0x16);
+ hefras = inb(efdr) & WINB_HEFRAS;
- if (PPB_IS_EPP(mode)) {
/*
- * Try to reset EPP timeout bit.
- * If it fails, try PS/2 and NIBBLE modes.
+ * HEFRAS HEFERE
+ * 0 1 write 89h to 250h (power-on default)
+ * 1 0 write 86h twice to 3f0h
+ * 1 1 write 87h twice to 3f0h
+ * 0 0 write 88h to 250h
*/
- ppc_reset_epp_timeout(ppc->ppc_unit);
+ if ((hefere | hefras) == w83877f_hefs[i])
+ goto found;
+ }
- r = r_str(ppc);
- if (!(r & TIMEOUT))
- return (mode);
- } else {
- if (mode)
- return (mode);
+ return (-1); /* failed */
+
+found:
+ /* check base port address - read from CR23 */
+ outb(efir, 0x23);
+ if (ppc->ppc_base != inb(efdr) * 4) /* 4 bytes boundaries */
+ return (-1);
+
+ /* read CHIP ID from CR9/bits0-3 */
+ outb(efir, 0x9);
+
+ switch (inb(efdr) & WINB_CHIPID) {
+ case WINB_W83877F_ID:
+ ppc->ppc_type = WINB_W83877F;
+ break;
+
+ case WINB_W83877AF_ID:
+ ppc->ppc_type = WINB_W83877AF;
+ break;
+
+ default:
+ ppc->ppc_type = WINB_UNKNOWN;
}
- /* detect PS/2 or NIBBLE mode */
- return (ppc_detect_ps2(ppc));
-}
+ if (bootverbose) {
+ /* dump of registers */
+ printf("ppc%d: 0x%x - ", ppc->ppc_unit, w83877f_keys[i]);
+ for (i = 0; i <= 0xd; i ++) {
+ outb(efir, i);
+ printf("0x%x ", inb(efdr));
+ }
+ for (i = 0x10; i <= 0x17; i ++) {
+ outb(efir, i);
+ printf("0x%x ", inb(efdr));
+ }
+ outb(efir, 0x1e);
+ printf("0x%x ", inb(efdr));
+ for (i = 0x20; i <= 0x29; i ++) {
+ outb(efir, i);
+ printf("0x%x ", inb(efdr));
+ }
+ printf("\n");
+ }
-static int
-ppc_check_ecpepp_timeout(struct ppc_data *ppc)
-{
- char r;
+ if (!chipset_mode) {
+ /* autodetect mode */
- ppc_reset_epp_timeout(ppc->ppc_unit);
+ /* select CR0 */
+ outb(efir, 0x0);
+ r = inb(efdr) & (WINB_PRTMODS0 | WINB_PRTMODS1);
+
+ /* select CR9 */
+ outb(efir, 0x9);
+ r |= (inb(efdr) & WINB_PRTMODS2);
+
+ switch (r) {
+ case WINB_W83757:
+ if (bootverbose)
+ printf("ppc%d: W83757 compatible mode\n",
+ ppc->ppc_unit);
+ return (-1); /* generic or SMC-like */
+
+ case WINB_EXTFDC:
+ case WINB_EXTADP:
+ case WINB_EXT2FDD:
+ case WINB_JOYSTICK:
+ if (bootverbose)
+ printf("ppc%d: not in parallel port mode\n",
+ ppc->ppc_unit);
+ return (-1);
+
+ case (WINB_PARALLEL | WINB_EPP_SPP):
+ ppc->ppc_avm |= PPB_EPP | PPB_SPP;
+ break;
- r = r_str(ppc);
- if (!(r & TIMEOUT)) {
- return (PPB_ECP_EPP);
+ case (WINB_PARALLEL | WINB_ECP):
+ ppc->ppc_avm |= PPB_ECP | PPB_SPP;
+ break;
+
+ case (WINB_PARALLEL | WINB_ECP_EPP):
+ ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP;
+ break;
+ default:
+ printf("%s: unknown case (0x%x)!\n", __FUNCTION__, r);
+ }
+
+ } else {
+ /* mode forced */
+
+ /* select CR9 and set PRTMODS2 bit */
+ outb(efir, 0x9);
+ outb(efdr, inb(efdr) & ~WINB_PRTMODS2);
+
+ /* select CR0 and reset PRTMODSx bits */
+ outb(efir, 0x0);
+ outb(efdr, inb(efdr) & ~(WINB_PRTMODS0 | WINB_PRTMODS1));
+
+ if (chipset_mode & PPB_ECP) {
+ if (chipset_mode & PPB_EPP)
+ outb(efdr, inb(efdr) | WINB_ECP_EPP);
+ else
+ outb(efdr, inb(efdr) | WINB_ECP);
+ } else {
+ /* select EPP_SPP otherwise */
+ outb(efdr, inb(efdr) | WINB_EPP_SPP);
+ }
+ ppc->ppc_avm = chipset_mode;
}
+
+ /* exit configuration mode */
+ outb(efer, 0xaa);
- /* If EPP timeout bit is not reset, DON'T use EPP */
- w_ecr(ppc, 0x20);
+ if (ppc->ppc_avm & PPB_ECP)
+ ppc_ecp_config(ppc, chipset_mode);
- return (PPB_ECP_PS2);
+ return (chipset_mode);
}
/*
* ppc_generic_detect
*/
static int
-ppc_generic_detect(struct ppc_data *ppc, int mode)
+ppc_generic_detect(struct ppc_data *ppc, int chipset_mode)
{
- char save_control, r;
+ char save_control;
+
+ if (!chipset_mode) {
+ /* first, check for ECP */
+ w_ecr(ppc, 0x20);
+ if ((r_ecr(ppc) & 0xe0) == 0x20) {
+ ppc->ppc_avm |= PPB_ECP | PPB_SPP;
- /* don't know what to do here */
- if (mode)
- return (mode);
+ /* search for SMC style ECP+EPP mode */
+ w_ecr(ppc, 0x80);
+ }
- /* try to reset EPP timeout bit */
- ppc_reset_epp_timeout(ppc->ppc_unit);
+ /* try to reset EPP timeout bit */
+ if (ppc_check_epp_timeout(ppc)) {
+ ppc->ppc_avm |= PPB_EPP;
- r = r_str(ppc);
- if (!(r & TIMEOUT)) {
- return (PPB_EPP);
- }
+ if (ppc->ppc_avm & PPB_ECP)
+ /* SMC like chipset found */
+ ppc->ppc_type = SMC_LIKE;
+ }
- /* Now check for ECP */
- w_ecr(ppc, 0x20);
- r = r_ecr(ppc);
- if ((r & 0xe0) == 0x20) {
- /* Search for SMC style EPP+ECP mode */
- w_ecr(ppc, 0x80);
+ /* XXX try to detect NIBBLE mode */
+ ppc->ppc_avm |= PPB_NIBBLE;
- return (ppc_check_ecpepp_timeout(ppc));
- }
+ } else
+ ppc->ppc_avm = chipset_mode;
+
+ if (ppc->ppc_avm & PPB_ECP)
+ ppc_ecp_config(ppc, chipset_mode);
- return (ppc_detect_ps2(ppc));
+ return (chipset_mode);
}
/*
@@ -611,22 +766,258 @@ ppc_generic_detect(struct ppc_data *ppc, int mode)
* mode is the mode suggested at boot
*/
static int
-ppc_detect(struct ppc_data *ppc, int mode) {
+ppc_detect(struct ppc_data *ppc, int chipset_mode) {
- if (!ppc->ppc_mode && (ppc->ppc_mode = ppc_pc873xx_detect(ppc)))
- goto end_detect;
+ int i, mode;
- if (!ppc->ppc_mode && (ppc->ppc_mode =
- ppc_smc37c66xgt_detect(ppc, mode)))
- goto end_detect;
+ /* list of supported chipsets */
+ int (*chipset_detect[])(struct ppc_data *, int) = {
+ ppc_pc873xx_detect,
+ ppc_smc37c66xgt_detect,
+ ppc_w83877f_detect,
+ ppc_generic_detect,
+ NULL
+ };
- if (!ppc->ppc_mode && (ppc->ppc_mode = ppc_generic_detect(ppc, mode)))
- goto end_detect;
+ /* if can't find the port and mode not forced return error */
+ if (!ppc_detect_port(ppc) && chipset_mode == 0)
+ return (EIO); /* failed, port not present */
- printf("ppc: port not present at 0x%x.\n", ppc->ppc_base);
- return (PPC_ENOPORT);
+ /* assume centronics compatible mode is supported */
+ ppc->ppc_avm = PPB_COMPATIBLE;
-end_detect:
+ /* we have to differenciate available chipset modes,
+ * chipset running modes and IEEE-1284 operating modes
+ *
+ * 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;
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * ppc_exec_microseq()
+ *
+ * Execute a microsequence.
+ * Microsequence mechanism is supposed to handle fast I/O operations.
+ */
+static int
+ppc_exec_microseq(int unit, struct ppb_microseq *msq, int *ppbpc)
+{
+ struct ppc_data *ppc = ppcdata[unit];
+ struct ppb_microseq *pc;
+ char cc, *p;
+ int i, iter, reg;
+ int error;
+
+ /* static to be reused after few ppc_exec_microseq()/return calls
+ * XXX should be in a context variable shared with ppb level */
+ static int accum;
+ static char *ptr;
+
+ struct ppb_microseq *microseq_stack = 0;
+ struct ppb_microseq *pc_stack = 0;
+
+/* microsequence registers are equivalent to PC-like port registers */
+#define r_reg(register,ppc) ((char)inb((ppc)->ppc_base + register))
+#define w_reg(register,ppc,byte) outb((ppc)->ppc_base + register, byte)
+
+#define INCR_PC (pc ++) /* increment program counter */
+#define mi pc /* microinstruction currently executed */
+
+ /* get the state of pc from ppb level of execution */
+ pc = &msq[*ppbpc];
+
+ for (;;) {
+
+ switch (mi->opcode) {
+ case MS_OP_RSET:
+ cc = r_reg(mi->arg[0].i, ppc);
+ cc &= mi->arg[2].c; /* clear mask */
+ cc |= mi->arg[1].c; /* assert mask */
+ w_reg(mi->arg[0].i, ppc, cc);
+ INCR_PC;
+ break;
+
+ case MS_OP_RASSERT_P:
+ for (i=0; i<mi->arg[0].i; i++)
+ w_reg(mi->arg[1].i, ppc, *ptr++);
+ INCR_PC;
+ break;
+
+ case MS_OP_RFETCH_P:
+ for (i=0; i<mi->arg[0].i; i++)
+ *ptr++ = r_reg(mi->arg[1].i, ppc) &
+ mi->arg[2].c;
+ INCR_PC;
+ break;
+
+ case MS_OP_RFETCH:
+ *((char *) mi->arg[2].p) = r_reg(mi->arg[0].i, ppc) &
+ mi->arg[1].c;
+ INCR_PC;
+ break;
+
+ case MS_OP_RASSERT:
+
+ /* let's suppose the next instr. is the same */
+ prefetch:
+ for (;mi->opcode == MS_OP_RASSERT; INCR_PC)
+ w_reg(mi->arg[0].i, ppc, mi->arg[1].c);
+
+ if (mi->opcode == MS_OP_DELAY) {
+ DELAY(mi->arg[0].i);
+ INCR_PC;
+ goto prefetch;
+ }
+ break;
+
+ case MS_OP_DELAY:
+ DELAY(mi->arg[0].i);
+ INCR_PC;
+ break;
+
+ case MS_OP_TRIG:
+ reg = mi->arg[0].i;
+ iter = mi->arg[1].i;
+ p = (char *)mi->arg[2].p;
+
+ for (i=0; i<iter; i++) {
+ w_reg(reg, ppc, *p++);
+ DELAY((unsigned char)*p++);
+ }
+ INCR_PC;
+ break;
+
+ case MS_OP_SET:
+ accum = mi->arg[0].i;
+ INCR_PC;
+ break;
+
+ case MS_OP_DBRA:
+ if (--accum > 0)
+ pc += mi->arg[0].i;
+ else
+ INCR_PC;
+ break;
+
+ case MS_OP_BRSET:
+ cc = r_str(ppc);
+ if ((cc & mi->arg[0].c) == mi->arg[0].c)
+ pc += mi->arg[1].i;
+ else
+ INCR_PC;
+ break;
+
+ case MS_OP_BRCLEAR:
+ cc = r_str(ppc);
+ if ((cc & mi->arg[0].c) == 0)
+ pc += mi->arg[1].i;
+ else
+ INCR_PC;
+ break;
+
+ case MS_OP_C_CALL:
+ /*
+ * If the C call returns !0 then end the microseq.
+ * The current state of ptr is passed to the C function
+ */
+ if ((error = mi->arg[0].f(mi->arg[1].p, ptr)))
+ return (error);
+
+ INCR_PC;
+ break;
+
+ case MS_OP_PTR:
+ ptr = (char *)mi->arg[0].p;
+ INCR_PC;
+ break;
+
+ case MS_OP_CALL:
+ if (microseq_stack)
+ panic("%s: too much calls", __FUNCTION__);
+
+ if (mi->arg[0].p) {
+ /* store the state of the actual
+ * microsequence
+ */
+ microseq_stack = msq;
+ pc_stack = pc;
+
+ /* jump to the new microsequence */
+ msq = (struct ppb_microseq *)mi->arg[0].p;
+ pc = msq;
+ } else
+ INCR_PC;
+
+ break;
+
+ case MS_OP_SUBRET:
+ /* retrieve microseq and pc state before the call */
+ msq = microseq_stack;
+ pc = pc_stack;
+
+ /* reset the stack */
+ microseq_stack = 0;
+
+ /* XXX return code */
+
+ INCR_PC;
+ break;
+
+ case MS_OP_PUT:
+ case MS_OP_GET:
+ case MS_OP_RET:
+ /* can't return to ppb level during the execution
+ * of a submicrosequence */
+ if (microseq_stack)
+ panic("%s: can't return to ppb level",
+ __FUNCTION__);
+
+ /* update pc for ppb level of execution */
+ *ppbpc = (int)(pc - msq);
+
+ /* return to ppb level of execution */
+ return (0);
+
+ default:
+ panic("%s: unknown microsequence opcode 0x%x",
+ __FUNCTION__, mi->opcode);
+ }
+ }
+
+ /* unreached */
+}
+
+/*
+ * Configure current operating mode
+ */
+static int
+ppc_generic_setmode(int unit, int mode)
+{
+ struct ppc_data *ppc = ppcdata[unit];
+
+ /* back to compatible mode, XXX don't know yet what to do here */
+ if (mode == 0) {
+ ppc->ppc_mode = PPB_COMPATIBLE;
+ return (0);
+ }
+
+ /* check if mode is available */
+ if (!(ppc->ppc_avm & mode))
+ return (EOPNOTSUPP);
+
+ /* if ECP mode, configure ecr register */
+ if (ppc->ppc_avm & PPB_ECP)
+ ppc_ecp_config(ppc, mode);
+
+ ppc->ppc_mode = mode;
return (0);
}
@@ -688,16 +1079,14 @@ ppcprobe(struct isa_device *dvp)
ppc->ppc_unit = dvp->id_unit;
ppc->ppc_type = GENERIC;
- /* PPB_AUTODETECT is default to allow chipset detection even if
- * mode is forced by dvp->id_flags (see later, ppc_detect() call) */
- ppc->ppc_mode = PPB_AUTODETECT;
- ppc->ppc_epp = (dvp->id_flags & 0x8) >> 3;
+ ppc->ppc_mode = PPB_COMPATIBLE;
+ ppc->ppc_epp = (dvp->id_flags & 0x10) >> 4;
/*
* XXX
* Try and detect if interrupts are working.
*/
- if (!(dvp->id_flags & 0x10))
+ if (!(dvp->id_flags & 0x20))
ppc->ppc_irq = (dvp->id_irq);
ppcdata[ppc->ppc_unit] = ppc;
@@ -706,7 +1095,7 @@ ppcprobe(struct isa_device *dvp)
/*
* Try to detect the chipset and its mode.
*/
- if (ppc_detect(ppc, dvp->id_flags & 0x7))
+ if (ppc_detect(ppc, dvp->id_flags & 0xf))
goto error;
end_probe:
@@ -722,6 +1111,7 @@ ppcattach(struct isa_device *isdp)
{
struct ppc_data *ppc = ppcdata[isdp->id_unit];
struct ppb_data *ppbus;
+ char * mode;
/*
* Link the Parallel Port Chipset (adapter) to
@@ -730,9 +1120,9 @@ ppcattach(struct isa_device *isdp)
ppc->ppc_link.adapter_unit = ppc->ppc_unit;
ppc->ppc_link.adapter = &ppc_adapter;
- printf("ppc%d: %s chipset in %s mode%s\n", ppc->ppc_unit,
- ppc_types[ppc->ppc_type], ppc_modes[ppc->ppc_mode],
- (PPB_IS_EPP(ppc->ppc_mode)) ?
+ printf("ppc%d: %s chipset (%s) in %s mode%s\n", ppc->ppc_unit,
+ ppc_types[ppc->ppc_type], ppc_avms[ppc->ppc_avm],
+ ppc_modes[ppc->ppc_mode], (PPB_IS_EPP(ppc->ppc_mode)) ?
ppc_epp_protocol[ppc->ppc_epp] : "");
/*
diff --git a/sys/dev/ppc/ppcreg.h b/sys/dev/ppc/ppcreg.h
index 7ab6189e..27ab1a1 100644
--- a/sys/dev/ppc/ppcreg.h
+++ b/sys/dev/ppc/ppcreg.h
@@ -23,23 +23,25 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: ppcreg.h,v 1.1 1997/08/14 14:01:36 msmith Exp $
+ * $Id: ppcreg.h,v 1.2 1997/08/16 14:07:26 msmith Exp $
*
*/
-#ifndef __PPC_H
-#define __PPC_H
+#ifndef __PPCREG_H
+#define __PPCREG_H
/*
* Parallel Port Chipset type.
*/
-#define SMC_UNKNOWN 0x0
+#define SMC_LIKE 0x0
#define SMC_37C665GT 0x1
#define SMC_37C666GT 0x2
-#define NS_UNKNOWN 0x3
-#define NS_PC87332 0x4
-#define NS_PC87306 0x5
-#define INTEL_820191AA 0x6
-#define GENERIC 0x7
+#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
/*
* Generic structure to hold parallel port chipset info.
@@ -49,10 +51,13 @@ struct ppc_data {
int ppc_unit;
int ppc_type;
+ int ppc_mode; /* chipset current mode */
+ int ppc_avm; /* chipset available modes */
+
#define ppc_base ppc_link.base
-#define ppc_mode ppc_link.mode
#define ppc_epp ppc_link.epp_protocol
#define ppc_irq ppc_link.id_irq
+#define ppc_subm ppc_link.submicroseq
unsigned char ppc_flags;
@@ -60,11 +65,6 @@ struct ppc_data {
};
/*
- * Parallel Port Chipset errors. XXX
- */
-#define PPC_ENOPORT 9
-
-/*
* Parallel Port Chipset registers.
*/
#define PPC_SPP_DTR 0 /* SPP data register */
@@ -74,12 +74,12 @@ struct ppc_data {
#define PPC_ECP_FIFO 0x400 /* ECP fifo register */
#define PPC_ECP_ECR 0x402 /* ECP extended control register */
-#define r_dtr(ppc) inb((ppc)->ppc_base + PPC_SPP_DTR)
-#define r_str(ppc) inb((ppc)->ppc_base + PPC_SPP_STR)
-#define r_ctr(ppc) inb((ppc)->ppc_base + PPC_SPP_CTR)
-#define r_epp(ppc) inb((ppc)->ppc_base + PPC_EPP_DATA)
-#define r_ecr(ppc) inb((ppc)->ppc_base + PPC_ECP_ECR)
-#define r_fifo(ppc) inb((ppc)->ppc_base + PPC_ECP_FIFO)
+#define r_dtr(ppc) ((char)inb((ppc)->ppc_base + PPC_SPP_DTR))
+#define r_str(ppc) ((char)inb((ppc)->ppc_base + PPC_SPP_STR))
+#define r_ctr(ppc) ((char)inb((ppc)->ppc_base + PPC_SPP_CTR))
+#define r_epp(ppc) ((char)inb((ppc)->ppc_base + PPC_EPP_DATA))
+#define r_ecr(ppc) ((char)inb((ppc)->ppc_base + PPC_ECP_ECR))
+#define r_fifo(ppc) ((char)inb((ppc)->ppc_base + PPC_ECP_FIFO))
#define w_dtr(ppc,byte) outb((ppc)->ppc_base + PPC_SPP_DTR, byte)
#define w_str(ppc,byte) outb((ppc)->ppc_base + PPC_SPP_STR, byte)
@@ -111,7 +111,7 @@ struct ppc_data {
#define PC873_SID 0x08
/*
- * Register defines for the SMC FDC37C66xGT parts.
+ * Register defines for the SMC FDC37C66xGT parts
*/
/* Init codes */
@@ -124,9 +124,9 @@ struct ppc_data {
/* Bits */
#define SMC_CR1_ADDR 0x3 /* bit 0 and 1 */
-#define SMC_CR1_MODE 0x8 /* bit 3 */
+#define SMC_CR1_MODE (1<<3) /* bit 3 */
#define SMC_CR4_EMODE 0x3 /* bits 0 and 1 */
-#define SMC_CR4_EPPTYPE 0x40 /* bit 6 */
+#define SMC_CR4_EPPTYPE (1<<6) /* bit 6 */
/* Extended modes */
#define SMC_SPP 0x0 /* SPP */
@@ -134,5 +134,34 @@ struct ppc_data {
#define SMC_ECP 0x2 /* ECP */
#define SMC_ECPEPP 0x3 /* ECP and EPP */
-#endif
+/*
+ * Register defines for the Winbond W83877F parts
+ */
+#define WINB_W83877F_ID 0xa
+#define WINB_W83877AF_ID 0xb
+
+/* Configuration bits */
+#define WINB_HEFERE (1<<5) /* CROC bit 5 */
+#define WINB_HEFRAS (1<<0) /* CR16 bit 0 */
+
+#define WINB_PNPCVS (1<<2) /* CR16 bit 2 */
+#define WINB_CHIPID 0xf /* CR9 bits 0-3 */
+
+#define WINB_PRTMODS0 (1<<2) /* CR0 bit 2 */
+#define WINB_PRTMODS1 (1<<3) /* CR0 bit 3 */
+#define WINB_PRTMODS2 (1<<7) /* CR9 bit 7 */
+
+/* W83877F modes: CR9/bit7 | CR0/bit3 | CR0/bit2 */
+#define WINB_W83757 0x0
+#define WINB_EXTFDC 0x4
+#define WINB_EXTADP 0x8
+#define WINB_EXT2FDD 0xc
+#define WINB_JOYSTICK 0x80
+
+#define WINB_PARALLEL 0x80
+#define WINB_EPP_SPP 0x4
+#define WINB_ECP 0x8
+#define WINB_ECP_EPP 0xc
+
+#endif
OpenPOWER on IntegriCloud