167646539SMike Smith /*- 246f3ff79SMike Smith * Copyright (c) 1997, 1998 Nicolas Souchu 367646539SMike Smith * All rights reserved. 467646539SMike Smith * 567646539SMike Smith * Redistribution and use in source and binary forms, with or without 667646539SMike Smith * modification, are permitted provided that the following conditions 767646539SMike Smith * are met: 867646539SMike Smith * 1. Redistributions of source code must retain the above copyright 967646539SMike Smith * notice, this list of conditions and the following disclaimer. 1067646539SMike Smith * 2. Redistributions in binary form must reproduce the above copyright 1167646539SMike Smith * notice, this list of conditions and the following disclaimer in the 1267646539SMike Smith * documentation and/or other materials provided with the distribution. 1367646539SMike Smith * 1467646539SMike Smith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1567646539SMike Smith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1667646539SMike Smith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1767646539SMike Smith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1867646539SMike Smith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1967646539SMike Smith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2067646539SMike Smith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2167646539SMike Smith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2267646539SMike Smith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2367646539SMike Smith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2467646539SMike Smith * SUCH DAMAGE. 2567646539SMike Smith * 26f1d19042SArchie Cobbs * $Id: ppc.c,v 1.11 1998/10/31 11:37:09 nsouch Exp $ 2767646539SMike Smith * 2867646539SMike Smith */ 2967646539SMike Smith #include "ppc.h" 3067646539SMike Smith 3167646539SMike Smith #if NPPC > 0 3267646539SMike Smith 3367646539SMike Smith #include <sys/param.h> 3467646539SMike Smith #include <sys/systm.h> 3567646539SMike Smith #include <sys/conf.h> 3667646539SMike Smith #include <sys/malloc.h> 3754ad6085SNicolas Souchu #include <sys/kernel.h> 3867646539SMike Smith 3967646539SMike Smith #include <machine/clock.h> 4067646539SMike Smith 4167646539SMike Smith #include <vm/vm.h> 4267646539SMike Smith #include <vm/vm_param.h> 4367646539SMike Smith #include <vm/pmap.h> 4467646539SMike Smith 4567646539SMike Smith #include <i386/isa/isa_device.h> 4667646539SMike Smith 4767646539SMike Smith #include <dev/ppbus/ppbconf.h> 4846f3ff79SMike Smith #include <dev/ppbus/ppb_msq.h> 4946f3ff79SMike Smith 5067646539SMike Smith #include <i386/isa/ppcreg.h> 5167646539SMike Smith 5267646539SMike Smith static int ppcprobe(struct isa_device *); 5367646539SMike Smith static int ppcattach(struct isa_device *); 5467646539SMike Smith 5567646539SMike Smith struct isa_driver ppcdriver = { 5667646539SMike Smith ppcprobe, ppcattach, "ppc" 5767646539SMike Smith }; 5867646539SMike Smith 5967646539SMike Smith static struct ppc_data *ppcdata[NPPC]; 6067646539SMike Smith static int nppc = 0; 6167646539SMike Smith 6267646539SMike Smith static char *ppc_types[] = { 6346f3ff79SMike Smith "SMC-like", "SMC FDC37C665GT", "SMC FDC37C666GT", "PC87332", "PC87306", 64af548787SNicolas Souchu "82091AA", "Generic", "W83877F", "W83877AF", "Winbond", "PC87334", 0 6567646539SMike Smith }; 6667646539SMike Smith 6746f3ff79SMike Smith /* list of available modes */ 6846f3ff79SMike Smith static char *ppc_avms[] = { 6946f3ff79SMike Smith "COMPATIBLE", "NIBBLE-only", "PS2-only", "PS2/NIBBLE", "EPP-only", 7046f3ff79SMike Smith "EPP/NIBBLE", "EPP/PS2", "EPP/PS2/NIBBLE", "ECP-only", 7146f3ff79SMike Smith "ECP/NIBBLE", "ECP/PS2", "ECP/PS2/NIBBLE", "ECP/EPP", 7246f3ff79SMike Smith "ECP/EPP/NIBBLE", "ECP/EPP/PS2", "ECP/EPP/PS2/NIBBLE", 0 7346f3ff79SMike Smith }; 7446f3ff79SMike Smith 7546f3ff79SMike Smith /* list of current executing modes 7646f3ff79SMike Smith * Note that few modes do not actually exist. 7746f3ff79SMike Smith */ 7867646539SMike Smith static char *ppc_modes[] = { 7946f3ff79SMike Smith "COMPATIBLE", "NIBBLE", "PS/2", "PS/2", "EPP", 8046f3ff79SMike Smith "EPP", "EPP", "EPP", "ECP", 8146f3ff79SMike Smith "ECP", "ECP+PS2", "ECP+PS2", "ECP+EPP", 8246f3ff79SMike Smith "ECP+EPP", "ECP+EPP", "ECP+EPP", 0 8367646539SMike Smith }; 8467646539SMike Smith 8567646539SMike Smith static char *ppc_epp_protocol[] = { " (EPP 1.9)", " (EPP 1.7)", 0 }; 8667646539SMike Smith 8767646539SMike Smith /* 8867646539SMike Smith * BIOS printer list - used by BIOS probe. 8967646539SMike Smith */ 9067646539SMike Smith #define BIOS_PPC_PORTS 0x408 9167646539SMike Smith #define BIOS_PORTS (short *)(KERNBASE+BIOS_PPC_PORTS) 9267646539SMike Smith #define BIOS_MAX_PPC 4 9367646539SMike Smith 9467646539SMike Smith /* 9567646539SMike Smith * All these functions are default actions for IN/OUT operations. 9667646539SMike Smith * They may be redefined if needed. 9767646539SMike Smith */ 9867646539SMike Smith static void ppc_outsb_epp(int unit, char *addr, int cnt) { 9967646539SMike Smith outsb(ppcdata[unit]->ppc_base + PPC_EPP_DATA, addr, cnt); } 10067646539SMike Smith static void ppc_outsw_epp(int unit, char *addr, int cnt) { 10167646539SMike Smith outsw(ppcdata[unit]->ppc_base + PPC_EPP_DATA, addr, cnt); } 10267646539SMike Smith static void ppc_outsl_epp(int unit, char *addr, int cnt) { 10367646539SMike Smith outsl(ppcdata[unit]->ppc_base + PPC_EPP_DATA, addr, cnt); } 10467646539SMike Smith static void ppc_insb_epp(int unit, char *addr, int cnt) { 10567646539SMike Smith insb(ppcdata[unit]->ppc_base + PPC_EPP_DATA, addr, cnt); } 10667646539SMike Smith static void ppc_insw_epp(int unit, char *addr, int cnt) { 10767646539SMike Smith insw(ppcdata[unit]->ppc_base + PPC_EPP_DATA, addr, cnt); } 10867646539SMike Smith static void ppc_insl_epp(int unit, char *addr, int cnt) { 10967646539SMike Smith insl(ppcdata[unit]->ppc_base + PPC_EPP_DATA, addr, cnt); } 11067646539SMike Smith 11167646539SMike Smith static char ppc_rdtr(int unit) { return r_dtr(ppcdata[unit]); } 11267646539SMike Smith static char ppc_rstr(int unit) { return r_str(ppcdata[unit]); } 11367646539SMike Smith static char ppc_rctr(int unit) { return r_ctr(ppcdata[unit]); } 11467646539SMike Smith static char ppc_repp(int unit) { return r_epp(ppcdata[unit]); } 11567646539SMike Smith static char ppc_recr(int unit) { return r_ecr(ppcdata[unit]); } 11667646539SMike Smith static char ppc_rfifo(int unit) { return r_fifo(ppcdata[unit]); } 11767646539SMike Smith 11867646539SMike Smith static void ppc_wdtr(int unit, char byte) { w_dtr(ppcdata[unit], byte); } 11967646539SMike Smith static void ppc_wstr(int unit, char byte) { w_str(ppcdata[unit], byte); } 12067646539SMike Smith static void ppc_wctr(int unit, char byte) { w_ctr(ppcdata[unit], byte); } 12167646539SMike Smith static void ppc_wepp(int unit, char byte) { w_epp(ppcdata[unit], byte); } 12267646539SMike Smith static void ppc_wecr(int unit, char byte) { w_ecr(ppcdata[unit], byte); } 12367646539SMike Smith static void ppc_wfifo(int unit, char byte) { w_fifo(ppcdata[unit], byte); } 12467646539SMike Smith 12567646539SMike Smith static void ppc_reset_epp_timeout(int); 12667646539SMike Smith static void ppc_ecp_sync(int); 127fe310de8SBruce Evans static ointhand2_t ppcintr; 12867646539SMike Smith 1290a40e22aSNicolas Souchu static int ppc_exec_microseq(int, struct ppb_microseq **); 13046f3ff79SMike Smith static int ppc_generic_setmode(int, int); 131edcfcf27SNicolas Souchu static int ppc_smclike_setmode(int, int); 13246f3ff79SMike Smith 133edcfcf27SNicolas Souchu static struct ppb_adapter ppc_smclike_adapter = { 134edcfcf27SNicolas Souchu 135edcfcf27SNicolas Souchu 0, /* no intr handler, filled by chipset dependent code */ 136edcfcf27SNicolas Souchu 137edcfcf27SNicolas Souchu ppc_reset_epp_timeout, ppc_ecp_sync, 138edcfcf27SNicolas Souchu 139edcfcf27SNicolas Souchu ppc_exec_microseq, 140edcfcf27SNicolas Souchu 141edcfcf27SNicolas Souchu ppc_smclike_setmode, 142edcfcf27SNicolas Souchu 143edcfcf27SNicolas Souchu ppc_outsb_epp, ppc_outsw_epp, ppc_outsl_epp, 144edcfcf27SNicolas Souchu ppc_insb_epp, ppc_insw_epp, ppc_insl_epp, 145edcfcf27SNicolas Souchu 146edcfcf27SNicolas Souchu ppc_rdtr, ppc_rstr, ppc_rctr, ppc_repp, ppc_recr, ppc_rfifo, 147edcfcf27SNicolas Souchu ppc_wdtr, ppc_wstr, ppc_wctr, ppc_wepp, ppc_wecr, ppc_wfifo 148edcfcf27SNicolas Souchu }; 149edcfcf27SNicolas Souchu 150edcfcf27SNicolas Souchu static struct ppb_adapter ppc_generic_adapter = { 15167646539SMike Smith 15267646539SMike Smith 0, /* no intr handler, filled by chipset dependent code */ 15367646539SMike Smith 15467646539SMike Smith ppc_reset_epp_timeout, ppc_ecp_sync, 15567646539SMike Smith 15646f3ff79SMike Smith ppc_exec_microseq, 15746f3ff79SMike Smith 15846f3ff79SMike Smith ppc_generic_setmode, 15946f3ff79SMike Smith 16067646539SMike Smith ppc_outsb_epp, ppc_outsw_epp, ppc_outsl_epp, 16167646539SMike Smith ppc_insb_epp, ppc_insw_epp, ppc_insl_epp, 16267646539SMike Smith 16367646539SMike Smith ppc_rdtr, ppc_rstr, ppc_rctr, ppc_repp, ppc_recr, ppc_rfifo, 16467646539SMike Smith ppc_wdtr, ppc_wstr, ppc_wctr, ppc_wepp, ppc_wecr, ppc_wfifo 16567646539SMike Smith }; 16667646539SMike Smith 16767646539SMike Smith /* 16867646539SMike Smith * ppc_ecp_sync() XXX 16967646539SMike Smith */ 17067646539SMike Smith static void 17167646539SMike Smith ppc_ecp_sync(int unit) { 17267646539SMike Smith 17367646539SMike Smith struct ppc_data *ppc = ppcdata[unit]; 17467646539SMike Smith int i, r; 17567646539SMike Smith 17667646539SMike Smith r = r_ecr(ppc); 17767646539SMike Smith if ((r & 0xe0) != 0x80) 17867646539SMike Smith return; 17967646539SMike Smith 18067646539SMike Smith for (i = 0; i < 100; i++) { 18167646539SMike Smith r = r_ecr(ppc); 18267646539SMike Smith if (r & 0x1) 18367646539SMike Smith return; 18467646539SMike Smith DELAY(100); 18567646539SMike Smith } 18667646539SMike Smith 18746f3ff79SMike Smith printf("ppc%d: ECP sync failed as data still " \ 18846f3ff79SMike Smith "present in FIFO.\n", unit); 18967646539SMike Smith 19067646539SMike Smith return; 19167646539SMike Smith } 19267646539SMike Smith 193fe310de8SBruce Evans static void 19467646539SMike Smith ppcintr(int unit) 19567646539SMike Smith { 19667646539SMike Smith /* call directly upper code */ 19767646539SMike Smith ppb_intr(&ppcdata[unit]->ppc_link); 19867646539SMike Smith 19967646539SMike Smith return; 20067646539SMike Smith } 20167646539SMike Smith 20246f3ff79SMike Smith static int 20346f3ff79SMike Smith ppc_detect_port(struct ppc_data *ppc) 20446f3ff79SMike Smith { 20546f3ff79SMike Smith 20646f3ff79SMike Smith w_ctr(ppc, 0x0c); /* To avoid missing PS2 ports */ 20746f3ff79SMike Smith w_dtr(ppc, 0xaa); 20846f3ff79SMike Smith if (r_dtr(ppc) != (char) 0xaa) 20946f3ff79SMike Smith return (0); 21046f3ff79SMike Smith 21146f3ff79SMike Smith return (1); 21246f3ff79SMike Smith } 21346f3ff79SMike Smith 21467646539SMike Smith /* 21567646539SMike Smith * ppc_pc873xx_detect 21667646539SMike Smith * 21767646539SMike Smith * Probe for a Natsemi PC873xx-family part. 21867646539SMike Smith * 21967646539SMike Smith * References in this function are to the National Semiconductor 22067646539SMike Smith * PC87332 datasheet TL/C/11930, May 1995 revision. 22167646539SMike Smith */ 22267646539SMike Smith static int pc873xx_basetab[] = {0x0398, 0x026e, 0x015c, 0x002e, 0}; 22367646539SMike Smith static int pc873xx_porttab[] = {0x0378, 0x03bc, 0x0278, 0}; 224af548787SNicolas Souchu static int pc873xx_irqtab[] = {5, 7, 5, 0}; 225af548787SNicolas Souchu 226af548787SNicolas Souchu static int pc873xx_regstab[] = { 227af548787SNicolas Souchu PC873_FER, PC873_FAR, PC873_PTR, 228af548787SNicolas Souchu PC873_FCR, PC873_PCR, PC873_PMC, 229af548787SNicolas Souchu PC873_TUP, PC873_SID, PC873_PNP0, 230af548787SNicolas Souchu PC873_PNP1, PC873_LPTBA, -1 231af548787SNicolas Souchu }; 232af548787SNicolas Souchu 233af548787SNicolas Souchu static char *pc873xx_rnametab[] = { 234af548787SNicolas Souchu "FER", "FAR", "PTR", "FCR", "PCR", 235af548787SNicolas Souchu "PMC", "TUP", "SID", "PNP0", "PNP1", 236af548787SNicolas Souchu "LPTBA", NULL 237af548787SNicolas Souchu }; 23867646539SMike Smith 23967646539SMike Smith static int 24046f3ff79SMike Smith ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never forced */ 24167646539SMike Smith { 24267646539SMike Smith static int index = 0; 243f1d19042SArchie Cobbs int idport, irq; 244af548787SNicolas Souchu int ptr, pcr, val, i; 24567646539SMike Smith 24667646539SMike Smith while ((idport = pc873xx_basetab[index++])) { 24767646539SMike Smith 24867646539SMike Smith /* XXX should check first to see if this location is already claimed */ 24967646539SMike Smith 25067646539SMike Smith /* 251af548787SNicolas Souchu * Pull the 873xx through the power-on ID cycle (2.2,1.). 252af548787SNicolas Souchu * We can't use this to locate the chip as it may already have 253af548787SNicolas Souchu * been used by the BIOS. 25467646539SMike Smith */ 255af548787SNicolas Souchu (void)inb(idport); (void)inb(idport); 256af548787SNicolas Souchu (void)inb(idport); (void)inb(idport); 25767646539SMike Smith 25867646539SMike Smith /* 25967646539SMike Smith * Read the SID byte. Possible values are : 26067646539SMike Smith * 261af548787SNicolas Souchu * 01010xxx PC87334 26267646539SMike Smith * 0001xxxx PC87332 26367646539SMike Smith * 01110xxx PC87306 26467646539SMike Smith */ 26567646539SMike Smith outb(idport, PC873_SID); 26667646539SMike Smith val = inb(idport + 1); 26767646539SMike Smith if ((val & 0xf0) == 0x10) { 26867646539SMike Smith ppc->ppc_type = NS_PC87332; 26967646539SMike Smith } else if ((val & 0xf8) == 0x70) { 27067646539SMike Smith ppc->ppc_type = NS_PC87306; 271af548787SNicolas Souchu } else if ((val & 0xf8) == 0x50) { 272af548787SNicolas Souchu ppc->ppc_type = NS_PC87334; 27367646539SMike Smith } else { 27467646539SMike Smith if (bootverbose && (val != 0xff)) 27567646539SMike Smith printf("PC873xx probe at 0x%x got unknown ID 0x%x\n", idport, val); 27667646539SMike Smith continue ; /* not recognised */ 27767646539SMike Smith } 27867646539SMike Smith 279af548787SNicolas Souchu /* print registers */ 280af548787SNicolas Souchu if (bootverbose) { 281af548787SNicolas Souchu printf("PC873xx"); 282af548787SNicolas Souchu for (i=0; pc873xx_regstab[i] != -1; i++) { 283af548787SNicolas Souchu outb(idport, pc873xx_regstab[i]); 284af548787SNicolas Souchu printf(" %s=0x%x", pc873xx_rnametab[i], 285af548787SNicolas Souchu inb(idport + 1) & 0xff); 286af548787SNicolas Souchu } 287af548787SNicolas Souchu printf("\n"); 288af548787SNicolas Souchu } 289af548787SNicolas Souchu 29067646539SMike Smith /* 29167646539SMike Smith * We think we have one. Is it enabled and where we want it to be? 29267646539SMike Smith */ 29367646539SMike Smith outb(idport, PC873_FER); 29467646539SMike Smith val = inb(idport + 1); 29567646539SMike Smith if (!(val & PC873_PPENABLE)) { 29667646539SMike Smith if (bootverbose) 29767646539SMike Smith printf("PC873xx parallel port disabled\n"); 29867646539SMike Smith continue; 29967646539SMike Smith } 30067646539SMike Smith outb(idport, PC873_FAR); 30167646539SMike Smith val = inb(idport + 1) & 0x3; 30267646539SMike Smith /* XXX we should create a driver instance for every port found */ 30367646539SMike Smith if (pc873xx_porttab[val] != ppc->ppc_base) { 30467646539SMike Smith if (bootverbose) 30567646539SMike Smith printf("PC873xx at 0x%x not for driver at port 0x%x\n", 30667646539SMike Smith pc873xx_porttab[val], ppc->ppc_base); 30767646539SMike Smith continue; 30867646539SMike Smith } 30967646539SMike Smith 31067646539SMike Smith outb(idport, PC873_PTR); 311af548787SNicolas Souchu ptr = inb(idport + 1); 312af548787SNicolas Souchu 313af548787SNicolas Souchu /* get irq settings */ 314af548787SNicolas Souchu if (ppc->ppc_base == 0x378) 315af548787SNicolas Souchu irq = (ptr & PC873_LPTBIRQ7) ? 7 : 5; 316af548787SNicolas Souchu else 317af548787SNicolas Souchu irq = pc873xx_irqtab[val]; 318af548787SNicolas Souchu 31967646539SMike Smith if (bootverbose) 320af548787SNicolas Souchu printf("PC873xx irq %d at 0x%x\n", irq, ppc->ppc_base); 32167646539SMike Smith 322af548787SNicolas Souchu /* 323af548787SNicolas Souchu * Check if irq settings are correct 324af548787SNicolas Souchu */ 325af548787SNicolas Souchu if (irq != ppc->ppc_irq) { 326af548787SNicolas Souchu /* 327af548787SNicolas Souchu * If the chipset is not locked and base address is 0x378, 328af548787SNicolas Souchu * we have another chance 329af548787SNicolas Souchu */ 330af548787SNicolas Souchu if (ppc->ppc_base == 0x378 && !(ptr & PC873_CFGLOCK)) { 331af548787SNicolas Souchu if (ppc->ppc_irq == 7) { 332af548787SNicolas Souchu outb(idport + 1, (ptr | PC873_LPTBIRQ7)); 333af548787SNicolas Souchu outb(idport + 1, (ptr | PC873_LPTBIRQ7)); 334af548787SNicolas Souchu } else { 335af548787SNicolas Souchu outb(idport + 1, (ptr & ~PC873_LPTBIRQ7)); 336af548787SNicolas Souchu outb(idport + 1, (ptr & ~PC873_LPTBIRQ7)); 33767646539SMike Smith } 338af548787SNicolas Souchu if (bootverbose) 339af548787SNicolas Souchu printf("PC873xx irq set to %d\n", ppc->ppc_irq); 340af548787SNicolas Souchu } else { 341af548787SNicolas Souchu if (bootverbose) 342af548787SNicolas Souchu printf("PC873xx sorry, can't change irq setting\n"); 34367646539SMike Smith } 34467646539SMike Smith } else { 34567646539SMike Smith if (bootverbose) 346af548787SNicolas Souchu printf("PC873xx irq settings are correct\n"); 34767646539SMike Smith } 34867646539SMike Smith 34967646539SMike Smith outb(idport, PC873_PCR); 350af548787SNicolas Souchu pcr = inb(idport + 1); 351af548787SNicolas Souchu 352af548787SNicolas Souchu if ((ptr & PC873_CFGLOCK) || !chipset_mode) { 353af548787SNicolas Souchu if (bootverbose) 354af548787SNicolas Souchu printf("PC873xx %s", (ptr & PC873_CFGLOCK)?"locked":"unlocked"); 355af548787SNicolas Souchu 356af548787SNicolas Souchu ppc->ppc_avm |= PPB_NIBBLE; 357af548787SNicolas Souchu if (bootverbose) 358af548787SNicolas Souchu printf(", NIBBLE"); 359af548787SNicolas Souchu 360af548787SNicolas Souchu if (pcr & PC873_EPPEN) { 361af548787SNicolas Souchu ppc->ppc_avm |= PPB_EPP; 362af548787SNicolas Souchu 363af548787SNicolas Souchu if (bootverbose) 364af548787SNicolas Souchu printf(", EPP"); 365af548787SNicolas Souchu 366af548787SNicolas Souchu if (pcr & PC873_EPP19) 367af548787SNicolas Souchu ppc->ppc_epp = EPP_1_9; 368af548787SNicolas Souchu else 369af548787SNicolas Souchu ppc->ppc_epp = EPP_1_7; 370af548787SNicolas Souchu 371af548787SNicolas Souchu if ((ppc->ppc_type == NS_PC87332) && bootverbose) { 372af548787SNicolas Souchu outb(idport, PC873_PTR); 373af548787SNicolas Souchu ptr = inb(idport + 1); 374af548787SNicolas Souchu if (ptr & PC873_EPPRDIR) 375af548787SNicolas Souchu printf(", Regular mode"); 376af548787SNicolas Souchu else 377af548787SNicolas Souchu printf(", Automatic mode"); 378af548787SNicolas Souchu } 379af548787SNicolas Souchu } else if (pcr & PC873_ECPEN) { 380af548787SNicolas Souchu ppc->ppc_avm |= PPB_ECP; 381af548787SNicolas Souchu if (bootverbose) 382af548787SNicolas Souchu printf(", ECP"); 383af548787SNicolas Souchu 384af548787SNicolas Souchu if (pcr & PC873_ECPCLK) { /* XXX */ 385af548787SNicolas Souchu ppc->ppc_avm |= PPB_PS2; 386af548787SNicolas Souchu if (bootverbose) 387af548787SNicolas Souchu printf(", PS/2"); 388af548787SNicolas Souchu } 389af548787SNicolas Souchu } else { 390af548787SNicolas Souchu outb(idport, PC873_PTR); 391af548787SNicolas Souchu ptr = inb(idport + 1); 392af548787SNicolas Souchu if (ptr & PC873_EXTENDED) { 393af548787SNicolas Souchu ppc->ppc_avm |= PPB_SPP; 394af548787SNicolas Souchu if (bootverbose) 395af548787SNicolas Souchu printf(", SPP"); 396af548787SNicolas Souchu } 397af548787SNicolas Souchu } 398af548787SNicolas Souchu } else { 399af548787SNicolas Souchu if (bootverbose) 400af548787SNicolas Souchu printf("PC873xx unlocked"); 401af548787SNicolas Souchu 402af548787SNicolas Souchu if (chipset_mode & PPB_ECP) { 403af548787SNicolas Souchu if ((chipset_mode & PPB_EPP) && bootverbose) 404af548787SNicolas Souchu printf(", ECP+EPP not supported"); 405af548787SNicolas Souchu 406af548787SNicolas Souchu pcr &= ~PC873_EPPEN; 407af548787SNicolas Souchu pcr |= (PC873_ECPEN | PC873_ECPCLK); /* XXX */ 408af548787SNicolas Souchu outb(idport + 1, pcr); 409af548787SNicolas Souchu outb(idport + 1, pcr); 410af548787SNicolas Souchu 411af548787SNicolas Souchu if (bootverbose) 412af548787SNicolas Souchu printf(", ECP"); 413af548787SNicolas Souchu 414af548787SNicolas Souchu } else if (chipset_mode & PPB_EPP) { 415af548787SNicolas Souchu pcr &= ~(PC873_ECPEN | PC873_ECPCLK); 416af548787SNicolas Souchu pcr |= (PC873_EPPEN | PC873_EPP19); 417af548787SNicolas Souchu outb(idport + 1, pcr); 418af548787SNicolas Souchu outb(idport + 1, pcr); 419af548787SNicolas Souchu 420af548787SNicolas Souchu ppc->ppc_epp = EPP_1_9; /* XXX */ 421af548787SNicolas Souchu 422af548787SNicolas Souchu if (bootverbose) 423af548787SNicolas Souchu printf(", EPP1.9"); 42467646539SMike Smith 42567646539SMike Smith /* enable automatic direction turnover */ 426af548787SNicolas Souchu if (ppc->ppc_type == NS_PC87332) { 42767646539SMike Smith outb(idport, PC873_PTR); 428af548787SNicolas Souchu ptr = inb(idport + 1); 429af548787SNicolas Souchu ptr &= ~PC873_EPPRDIR; 430af548787SNicolas Souchu outb(idport + 1, ptr); 431af548787SNicolas Souchu outb(idport + 1, ptr); 43267646539SMike Smith 43367646539SMike Smith if (bootverbose) 434af548787SNicolas Souchu printf(", Automatic mode"); 43567646539SMike Smith } 436af548787SNicolas Souchu } else { 437af548787SNicolas Souchu pcr &= ~(PC873_ECPEN | PC873_ECPCLK | PC873_EPPEN); 438af548787SNicolas Souchu outb(idport + 1, pcr); 439af548787SNicolas Souchu outb(idport + 1, pcr); 440af548787SNicolas Souchu 441af548787SNicolas Souchu /* configure extended bit in PTR */ 442af548787SNicolas Souchu outb(idport, PC873_PTR); 443af548787SNicolas Souchu ptr = inb(idport + 1); 444af548787SNicolas Souchu 445af548787SNicolas Souchu if (chipset_mode & PPB_PS2) { 446af548787SNicolas Souchu ptr |= PC873_EXTENDED; 447af548787SNicolas Souchu 448af548787SNicolas Souchu if (bootverbose) 449af548787SNicolas Souchu printf(", PS/2"); 450af548787SNicolas Souchu 451af548787SNicolas Souchu } else { 452af548787SNicolas Souchu /* default to NIBBLE mode */ 453af548787SNicolas Souchu ptr &= ~PC873_EXTENDED; 454af548787SNicolas Souchu 455af548787SNicolas Souchu if (bootverbose) 456af548787SNicolas Souchu printf(", NIBBLE"); 45767646539SMike Smith } 458af548787SNicolas Souchu outb(idport + 1, ptr); 459af548787SNicolas Souchu outb(idport + 1, ptr); 460af548787SNicolas Souchu } 461af548787SNicolas Souchu 462af548787SNicolas Souchu ppc->ppc_avm = chipset_mode; 463af548787SNicolas Souchu } 464af548787SNicolas Souchu 465af548787SNicolas Souchu if (bootverbose) 466af548787SNicolas Souchu printf("\n"); 467af548787SNicolas Souchu 468af548787SNicolas Souchu ppc->ppc_link.adapter = &ppc_generic_adapter; 469af548787SNicolas Souchu ppc_generic_setmode(ppc->ppc_unit, chipset_mode); 47046f3ff79SMike Smith 47146f3ff79SMike Smith return(chipset_mode); 47267646539SMike Smith } 47346f3ff79SMike Smith return(-1); 47467646539SMike Smith } 47567646539SMike Smith 47667646539SMike Smith static int 47746f3ff79SMike Smith ppc_check_epp_timeout(struct ppc_data *ppc) 47867646539SMike Smith { 47946f3ff79SMike Smith ppc_reset_epp_timeout(ppc->ppc_unit); 48067646539SMike Smith 48146f3ff79SMike Smith return (!(r_str(ppc) & TIMEOUT)); 48267646539SMike Smith } 48367646539SMike Smith 48467646539SMike Smith /* 48567646539SMike Smith * ppc_smc37c66xgt_detect 48667646539SMike Smith * 48767646539SMike Smith * SMC FDC37C66xGT configuration. 48867646539SMike Smith */ 48967646539SMike Smith static int 49046f3ff79SMike Smith ppc_smc37c66xgt_detect(struct ppc_data *ppc, int chipset_mode) 49167646539SMike Smith { 49267646539SMike Smith int s, i; 49367646539SMike Smith char r; 49467646539SMike Smith int type = -1; 49567646539SMike Smith int csr = SMC66x_CSR; /* initial value is 0x3F0 */ 49667646539SMike Smith 49767646539SMike Smith int port_address[] = { -1 /* disabled */ , 0x3bc, 0x378, 0x278 }; 49867646539SMike Smith 49967646539SMike Smith 50067646539SMike Smith #define cio csr+1 /* config IO port is either 0x3F1 or 0x371 */ 50167646539SMike Smith 50267646539SMike Smith /* 50367646539SMike Smith * Detection: enter configuration mode and read CRD register. 50467646539SMike Smith */ 50567646539SMike Smith 50667646539SMike Smith s = splhigh(); 50767646539SMike Smith outb(csr, SMC665_iCODE); 50867646539SMike Smith outb(csr, SMC665_iCODE); 50967646539SMike Smith splx(s); 51067646539SMike Smith 51167646539SMike Smith outb(csr, 0xd); 51267646539SMike Smith if (inb(cio) == 0x65) { 51367646539SMike Smith type = SMC_37C665GT; 51467646539SMike Smith goto config; 51567646539SMike Smith } 51667646539SMike Smith 51767646539SMike Smith for (i = 0; i < 2; i++) { 51867646539SMike Smith s = splhigh(); 51967646539SMike Smith outb(csr, SMC666_iCODE); 52067646539SMike Smith outb(csr, SMC666_iCODE); 52167646539SMike Smith splx(s); 52267646539SMike Smith 52367646539SMike Smith outb(csr, 0xd); 52467646539SMike Smith if (inb(cio) == 0x66) { 52567646539SMike Smith type = SMC_37C666GT; 52667646539SMike Smith break; 52767646539SMike Smith } 52867646539SMike Smith 52967646539SMike Smith /* Another chance, CSR may be hard-configured to be at 0x370 */ 53067646539SMike Smith csr = SMC666_CSR; 53167646539SMike Smith } 53267646539SMike Smith 53367646539SMike Smith config: 53467646539SMike Smith /* 53567646539SMike Smith * If chipset not found, do not continue. 53667646539SMike Smith */ 53767646539SMike Smith if (type == -1) 53846f3ff79SMike Smith return (-1); 53967646539SMike Smith 54067646539SMike Smith /* select CR1 */ 54167646539SMike Smith outb(csr, 0x1); 54267646539SMike Smith 54367646539SMike Smith /* read the port's address: bits 0 and 1 of CR1 */ 54467646539SMike Smith r = inb(cio) & SMC_CR1_ADDR; 54567646539SMike Smith if (port_address[r] != ppc->ppc_base) 54646f3ff79SMike Smith return (-1); 54767646539SMike Smith 54867646539SMike Smith ppc->ppc_type = type; 54967646539SMike Smith 55067646539SMike Smith /* 55167646539SMike Smith * CR1 and CR4 registers bits 3 and 0/1 for mode configuration 55246f3ff79SMike Smith * If SPP mode is detected, try to set ECP+EPP mode 55367646539SMike Smith */ 55467646539SMike Smith 55546f3ff79SMike Smith if (bootverbose) { 55646f3ff79SMike Smith outb(csr, 0x1); 55741990851SNicolas Souchu printf("ppc%d: SMC registers CR1=0x%x", ppc->ppc_unit, 55854ad6085SNicolas Souchu inb(cio) & 0xff); 55946f3ff79SMike Smith 56046f3ff79SMike Smith outb(csr, 0x4); 56146f3ff79SMike Smith printf(" CR4=0x%x", inb(cio) & 0xff); 56246f3ff79SMike Smith } 56346f3ff79SMike Smith 56446f3ff79SMike Smith /* select CR1 */ 56567646539SMike Smith outb(csr, 0x1); 56667646539SMike Smith 56746f3ff79SMike Smith if (!chipset_mode) { 56867646539SMike Smith /* autodetect mode */ 56967646539SMike Smith 57046f3ff79SMike Smith /* 666GT is ~certainly~ hardwired to an extended ECP+EPP mode */ 57146f3ff79SMike Smith if (type == SMC_37C666GT) { 57246f3ff79SMike Smith ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP; 573edcfcf27SNicolas Souchu if (bootverbose) 574edcfcf27SNicolas Souchu printf(" configuration hardwired, supposing " \ 575edcfcf27SNicolas Souchu "ECP+EPP SPP"); 57667646539SMike Smith 57746f3ff79SMike Smith } else 57846f3ff79SMike Smith if ((inb(cio) & SMC_CR1_MODE) == 0) { 57967646539SMike Smith /* already in extended parallel port mode, read CR4 */ 58067646539SMike Smith outb(csr, 0x4); 58167646539SMike Smith r = (inb(cio) & SMC_CR4_EMODE); 58267646539SMike Smith 58367646539SMike Smith switch (r) { 58467646539SMike Smith case SMC_SPP: 58546f3ff79SMike Smith ppc->ppc_avm |= PPB_SPP; 586edcfcf27SNicolas Souchu if (bootverbose) 587edcfcf27SNicolas Souchu printf(" SPP"); 58867646539SMike Smith break; 58967646539SMike Smith 59067646539SMike Smith case SMC_EPPSPP: 59146f3ff79SMike Smith ppc->ppc_avm |= PPB_EPP | PPB_SPP; 592edcfcf27SNicolas Souchu if (bootverbose) 593edcfcf27SNicolas Souchu printf(" EPP SPP"); 59467646539SMike Smith break; 59567646539SMike Smith 59667646539SMike Smith case SMC_ECP: 59746f3ff79SMike Smith ppc->ppc_avm |= PPB_ECP | PPB_SPP; 598edcfcf27SNicolas Souchu if (bootverbose) 599edcfcf27SNicolas Souchu printf(" ECP SPP"); 60067646539SMike Smith break; 60167646539SMike Smith 60267646539SMike Smith case SMC_ECPEPP: 60346f3ff79SMike Smith ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP; 604edcfcf27SNicolas Souchu if (bootverbose) 605edcfcf27SNicolas Souchu printf(" ECP+EPP SPP"); 60667646539SMike Smith break; 60767646539SMike Smith } 60846f3ff79SMike Smith } else { 60946f3ff79SMike Smith /* not an extended port mode */ 61046f3ff79SMike Smith ppc->ppc_avm |= PPB_SPP; 611edcfcf27SNicolas Souchu if (bootverbose) 612edcfcf27SNicolas Souchu printf(" SPP"); 61367646539SMike Smith } 61446f3ff79SMike Smith 61567646539SMike Smith } else { 61667646539SMike Smith /* mode forced */ 61754ad6085SNicolas Souchu ppc->ppc_avm = chipset_mode; 61867646539SMike Smith 61946f3ff79SMike Smith /* 666GT is ~certainly~ hardwired to an extended ECP+EPP mode */ 62067646539SMike Smith if (type == SMC_37C666GT) 62167646539SMike Smith goto end_detect; 62267646539SMike Smith 62367646539SMike Smith r = inb(cio); 62446f3ff79SMike Smith if ((chipset_mode & (PPB_ECP | PPB_EPP)) == 0) { 62546f3ff79SMike Smith /* do not use ECP when the mode is not forced to */ 62667646539SMike Smith outb(cio, r | SMC_CR1_MODE); 627edcfcf27SNicolas Souchu if (bootverbose) 628edcfcf27SNicolas Souchu printf(" SPP"); 62967646539SMike Smith } else { 63067646539SMike Smith /* an extended mode is selected */ 63167646539SMike Smith outb(cio, r & ~SMC_CR1_MODE); 63267646539SMike Smith 63367646539SMike Smith /* read CR4 register and reset mode field */ 63467646539SMike Smith outb(csr, 0x4); 63567646539SMike Smith r = inb(cio) & ~SMC_CR4_EMODE; 63667646539SMike Smith 63746f3ff79SMike Smith if (chipset_mode & PPB_ECP) { 63846f3ff79SMike Smith if (chipset_mode & PPB_EPP) { 63967646539SMike Smith outb(cio, r | SMC_ECPEPP); 640edcfcf27SNicolas Souchu if (bootverbose) 641edcfcf27SNicolas Souchu printf(" ECP+EPP"); 64246f3ff79SMike Smith } else { 64346f3ff79SMike Smith outb(cio, r | SMC_ECP); 644edcfcf27SNicolas Souchu if (bootverbose) 645edcfcf27SNicolas Souchu printf(" ECP"); 64646f3ff79SMike Smith } 64746f3ff79SMike Smith } else { 64846f3ff79SMike Smith /* PPB_EPP is set */ 64946f3ff79SMike Smith outb(cio, r | SMC_EPPSPP); 650edcfcf27SNicolas Souchu if (bootverbose) 651edcfcf27SNicolas Souchu printf(" EPP SPP"); 65267646539SMike Smith } 65367646539SMike Smith } 65446f3ff79SMike Smith ppc->ppc_avm = chipset_mode; 65567646539SMike Smith } 65667646539SMike Smith 65767646539SMike Smith end_detect: 65846f3ff79SMike Smith 65946f3ff79SMike Smith if (bootverbose) 66046f3ff79SMike Smith printf ("\n"); 66146f3ff79SMike Smith 66254ad6085SNicolas Souchu if (ppc->ppc_avm & PPB_EPP) { 66367646539SMike Smith /* select CR4 */ 66467646539SMike Smith outb(csr, 0x4); 66567646539SMike Smith r = inb(cio); 66667646539SMike Smith 66767646539SMike Smith /* 66867646539SMike Smith * Set the EPP protocol... 66967646539SMike Smith * Low=EPP 1.9 (1284 standard) and High=EPP 1.7 67067646539SMike Smith */ 67167646539SMike Smith if (ppc->ppc_epp == EPP_1_9) 67267646539SMike Smith outb(cio, (r & ~SMC_CR4_EPPTYPE)); 67367646539SMike Smith else 67467646539SMike Smith outb(cio, (r | SMC_CR4_EPPTYPE)); 67567646539SMike Smith } 67667646539SMike Smith 67767646539SMike Smith /* end config mode */ 67867646539SMike Smith outb(csr, 0xaa); 67967646539SMike Smith 680edcfcf27SNicolas Souchu ppc->ppc_link.adapter = &ppc_smclike_adapter; 681edcfcf27SNicolas Souchu ppc_smclike_setmode(ppc->ppc_unit, chipset_mode); 68267646539SMike Smith 68346f3ff79SMike Smith return (chipset_mode); 68467646539SMike Smith } 68567646539SMike Smith 68646f3ff79SMike Smith /* 68746f3ff79SMike Smith * Winbond W83877F stuff 68846f3ff79SMike Smith * 68946f3ff79SMike Smith * EFER: extended function enable register 69046f3ff79SMike Smith * EFIR: extended function index register 69146f3ff79SMike Smith * EFDR: extended function data register 69246f3ff79SMike Smith */ 69346f3ff79SMike Smith #define efir ((efer == 0x250) ? 0x251 : 0x3f0) 69446f3ff79SMike Smith #define efdr ((efer == 0x250) ? 0x252 : 0x3f1) 69546f3ff79SMike Smith 69646f3ff79SMike Smith static int w83877f_efers[] = { 0x250, 0x3f0, 0x3f0, 0x250 }; 69746f3ff79SMike Smith static int w83877f_keys[] = { 0x89, 0x86, 0x87, 0x88 }; 69846f3ff79SMike Smith static int w83877f_keyiter[] = { 1, 2, 2, 1 }; 69946f3ff79SMike Smith static int w83877f_hefs[] = { WINB_HEFERE, WINB_HEFRAS, WINB_HEFERE | WINB_HEFRAS, 0 }; 70067646539SMike Smith 70167646539SMike Smith static int 70246f3ff79SMike Smith ppc_w83877f_detect(struct ppc_data *ppc, int chipset_mode) 70367646539SMike Smith { 704f1d19042SArchie Cobbs int i, j, efer; 70546f3ff79SMike Smith unsigned char r, hefere, hefras; 70667646539SMike Smith 70746f3ff79SMike Smith for (i = 0; i < 4; i ++) { 70846f3ff79SMike Smith /* first try to enable configuration registers */ 70946f3ff79SMike Smith efer = w83877f_efers[i]; 71067646539SMike Smith 71146f3ff79SMike Smith /* write the key to the EFER */ 71246f3ff79SMike Smith for (j = 0; j < w83877f_keyiter[i]; j ++) 71346f3ff79SMike Smith outb (efer, w83877f_keys[i]); 71446f3ff79SMike Smith 71546f3ff79SMike Smith /* then check HEFERE and HEFRAS bits */ 71646f3ff79SMike Smith outb (efir, 0x0c); 71746f3ff79SMike Smith hefere = inb(efdr) & WINB_HEFERE; 71846f3ff79SMike Smith 71946f3ff79SMike Smith outb (efir, 0x16); 72046f3ff79SMike Smith hefras = inb(efdr) & WINB_HEFRAS; 72146f3ff79SMike Smith 72246f3ff79SMike Smith /* 72346f3ff79SMike Smith * HEFRAS HEFERE 72446f3ff79SMike Smith * 0 1 write 89h to 250h (power-on default) 72546f3ff79SMike Smith * 1 0 write 86h twice to 3f0h 72646f3ff79SMike Smith * 1 1 write 87h twice to 3f0h 72746f3ff79SMike Smith * 0 0 write 88h to 250h 72846f3ff79SMike Smith */ 72946f3ff79SMike Smith if ((hefere | hefras) == w83877f_hefs[i]) 73046f3ff79SMike Smith goto found; 73167646539SMike Smith } 73267646539SMike Smith 73346f3ff79SMike Smith return (-1); /* failed */ 73467646539SMike Smith 73546f3ff79SMike Smith found: 73646f3ff79SMike Smith /* check base port address - read from CR23 */ 73746f3ff79SMike Smith outb(efir, 0x23); 73846f3ff79SMike Smith if (ppc->ppc_base != inb(efdr) * 4) /* 4 bytes boundaries */ 73946f3ff79SMike Smith return (-1); 74046f3ff79SMike Smith 74146f3ff79SMike Smith /* read CHIP ID from CR9/bits0-3 */ 74246f3ff79SMike Smith outb(efir, 0x9); 74346f3ff79SMike Smith 74446f3ff79SMike Smith switch (inb(efdr) & WINB_CHIPID) { 74546f3ff79SMike Smith case WINB_W83877F_ID: 74646f3ff79SMike Smith ppc->ppc_type = WINB_W83877F; 74746f3ff79SMike Smith break; 74846f3ff79SMike Smith 74946f3ff79SMike Smith case WINB_W83877AF_ID: 75046f3ff79SMike Smith ppc->ppc_type = WINB_W83877AF; 75146f3ff79SMike Smith break; 75246f3ff79SMike Smith 75346f3ff79SMike Smith default: 75446f3ff79SMike Smith ppc->ppc_type = WINB_UNKNOWN; 75546f3ff79SMike Smith } 75646f3ff79SMike Smith 75746f3ff79SMike Smith if (bootverbose) { 75846f3ff79SMike Smith /* dump of registers */ 75946f3ff79SMike Smith printf("ppc%d: 0x%x - ", ppc->ppc_unit, w83877f_keys[i]); 76046f3ff79SMike Smith for (i = 0; i <= 0xd; i ++) { 76146f3ff79SMike Smith outb(efir, i); 76246f3ff79SMike Smith printf("0x%x ", inb(efdr)); 76346f3ff79SMike Smith } 76446f3ff79SMike Smith for (i = 0x10; i <= 0x17; i ++) { 76546f3ff79SMike Smith outb(efir, i); 76646f3ff79SMike Smith printf("0x%x ", inb(efdr)); 76746f3ff79SMike Smith } 76846f3ff79SMike Smith outb(efir, 0x1e); 76946f3ff79SMike Smith printf("0x%x ", inb(efdr)); 77046f3ff79SMike Smith for (i = 0x20; i <= 0x29; i ++) { 77146f3ff79SMike Smith outb(efir, i); 77246f3ff79SMike Smith printf("0x%x ", inb(efdr)); 77346f3ff79SMike Smith } 77446f3ff79SMike Smith printf("\n"); 775edcfcf27SNicolas Souchu printf("ppc%d:", ppc->ppc_unit); 77646f3ff79SMike Smith } 77746f3ff79SMike Smith 778edcfcf27SNicolas Souchu ppc->ppc_link.adapter = &ppc_generic_adapter; 779edcfcf27SNicolas Souchu 78046f3ff79SMike Smith if (!chipset_mode) { 78146f3ff79SMike Smith /* autodetect mode */ 78246f3ff79SMike Smith 78346f3ff79SMike Smith /* select CR0 */ 78446f3ff79SMike Smith outb(efir, 0x0); 78546f3ff79SMike Smith r = inb(efdr) & (WINB_PRTMODS0 | WINB_PRTMODS1); 78646f3ff79SMike Smith 78746f3ff79SMike Smith /* select CR9 */ 78846f3ff79SMike Smith outb(efir, 0x9); 78946f3ff79SMike Smith r |= (inb(efdr) & WINB_PRTMODS2); 79046f3ff79SMike Smith 79146f3ff79SMike Smith switch (r) { 79246f3ff79SMike Smith case WINB_W83757: 79346f3ff79SMike Smith if (bootverbose) 79446f3ff79SMike Smith printf("ppc%d: W83757 compatible mode\n", 79546f3ff79SMike Smith ppc->ppc_unit); 79646f3ff79SMike Smith return (-1); /* generic or SMC-like */ 79746f3ff79SMike Smith 79846f3ff79SMike Smith case WINB_EXTFDC: 79946f3ff79SMike Smith case WINB_EXTADP: 80046f3ff79SMike Smith case WINB_EXT2FDD: 80146f3ff79SMike Smith case WINB_JOYSTICK: 80246f3ff79SMike Smith if (bootverbose) 803edcfcf27SNicolas Souchu printf(" not in parallel port mode\n"); 80446f3ff79SMike Smith return (-1); 80546f3ff79SMike Smith 80646f3ff79SMike Smith case (WINB_PARALLEL | WINB_EPP_SPP): 80746f3ff79SMike Smith ppc->ppc_avm |= PPB_EPP | PPB_SPP; 808edcfcf27SNicolas Souchu if (bootverbose) 809edcfcf27SNicolas Souchu printf(" EPP SPP"); 81046f3ff79SMike Smith break; 81146f3ff79SMike Smith 81246f3ff79SMike Smith case (WINB_PARALLEL | WINB_ECP): 81346f3ff79SMike Smith ppc->ppc_avm |= PPB_ECP | PPB_SPP; 814edcfcf27SNicolas Souchu if (bootverbose) 815edcfcf27SNicolas Souchu printf(" ECP SPP"); 81646f3ff79SMike Smith break; 81746f3ff79SMike Smith 81846f3ff79SMike Smith case (WINB_PARALLEL | WINB_ECP_EPP): 81946f3ff79SMike Smith ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP; 820edcfcf27SNicolas Souchu ppc->ppc_link.adapter = &ppc_smclike_adapter; 821edcfcf27SNicolas Souchu 822edcfcf27SNicolas Souchu if (bootverbose) 823edcfcf27SNicolas Souchu printf(" ECP+EPP SPP"); 82446f3ff79SMike Smith break; 82546f3ff79SMike Smith default: 82646f3ff79SMike Smith printf("%s: unknown case (0x%x)!\n", __FUNCTION__, r); 82746f3ff79SMike Smith } 82846f3ff79SMike Smith 82946f3ff79SMike Smith } else { 83046f3ff79SMike Smith /* mode forced */ 83146f3ff79SMike Smith 83246f3ff79SMike Smith /* select CR9 and set PRTMODS2 bit */ 83346f3ff79SMike Smith outb(efir, 0x9); 83446f3ff79SMike Smith outb(efdr, inb(efdr) & ~WINB_PRTMODS2); 83546f3ff79SMike Smith 83646f3ff79SMike Smith /* select CR0 and reset PRTMODSx bits */ 83746f3ff79SMike Smith outb(efir, 0x0); 83846f3ff79SMike Smith outb(efdr, inb(efdr) & ~(WINB_PRTMODS0 | WINB_PRTMODS1)); 83946f3ff79SMike Smith 84046f3ff79SMike Smith if (chipset_mode & PPB_ECP) { 841edcfcf27SNicolas Souchu if (chipset_mode & PPB_EPP) { 84246f3ff79SMike Smith outb(efdr, inb(efdr) | WINB_ECP_EPP); 843edcfcf27SNicolas Souchu if (bootverbose) 844edcfcf27SNicolas Souchu printf(" ECP+EPP"); 845edcfcf27SNicolas Souchu 846edcfcf27SNicolas Souchu ppc->ppc_link.adapter = &ppc_smclike_adapter; 847edcfcf27SNicolas Souchu 848edcfcf27SNicolas Souchu } else { 84946f3ff79SMike Smith outb(efdr, inb(efdr) | WINB_ECP); 850edcfcf27SNicolas Souchu if (bootverbose) 851edcfcf27SNicolas Souchu printf(" ECP"); 852edcfcf27SNicolas Souchu } 85346f3ff79SMike Smith } else { 85446f3ff79SMike Smith /* select EPP_SPP otherwise */ 85546f3ff79SMike Smith outb(efdr, inb(efdr) | WINB_EPP_SPP); 856edcfcf27SNicolas Souchu if (bootverbose) 857edcfcf27SNicolas Souchu printf(" EPP SPP"); 85846f3ff79SMike Smith } 85946f3ff79SMike Smith ppc->ppc_avm = chipset_mode; 86046f3ff79SMike Smith } 86146f3ff79SMike Smith 862edcfcf27SNicolas Souchu if (bootverbose) 863edcfcf27SNicolas Souchu printf("\n"); 864edcfcf27SNicolas Souchu 86546f3ff79SMike Smith /* exit configuration mode */ 86646f3ff79SMike Smith outb(efer, 0xaa); 86746f3ff79SMike Smith 868edcfcf27SNicolas Souchu ppc->ppc_link.adapter->setmode(ppc->ppc_unit, chipset_mode); 86946f3ff79SMike Smith 87046f3ff79SMike Smith return (chipset_mode); 87167646539SMike Smith } 87267646539SMike Smith 87367646539SMike Smith /* 87467646539SMike Smith * ppc_generic_detect 87567646539SMike Smith */ 87667646539SMike Smith static int 87746f3ff79SMike Smith ppc_generic_detect(struct ppc_data *ppc, int chipset_mode) 87867646539SMike Smith { 879edcfcf27SNicolas Souchu /* default to generic */ 880edcfcf27SNicolas Souchu ppc->ppc_link.adapter = &ppc_generic_adapter; 881edcfcf27SNicolas Souchu 882edcfcf27SNicolas Souchu if (bootverbose) 883edcfcf27SNicolas Souchu printf("ppc%d:", ppc->ppc_unit); 884edcfcf27SNicolas Souchu 88546f3ff79SMike Smith if (!chipset_mode) { 88646f3ff79SMike Smith /* first, check for ECP */ 88746f3ff79SMike Smith w_ecr(ppc, 0x20); 88846f3ff79SMike Smith if ((r_ecr(ppc) & 0xe0) == 0x20) { 88946f3ff79SMike Smith ppc->ppc_avm |= PPB_ECP | PPB_SPP; 890edcfcf27SNicolas Souchu if (bootverbose) 891edcfcf27SNicolas Souchu printf(" ECP SPP"); 89246f3ff79SMike Smith 89346f3ff79SMike Smith /* search for SMC style ECP+EPP mode */ 89446f3ff79SMike Smith w_ecr(ppc, 0x80); 89546f3ff79SMike Smith } 89667646539SMike Smith 89767646539SMike Smith /* try to reset EPP timeout bit */ 89846f3ff79SMike Smith if (ppc_check_epp_timeout(ppc)) { 89946f3ff79SMike Smith ppc->ppc_avm |= PPB_EPP; 90067646539SMike Smith 901edcfcf27SNicolas Souchu if (ppc->ppc_avm & PPB_ECP) { 90246f3ff79SMike Smith /* SMC like chipset found */ 90346f3ff79SMike Smith ppc->ppc_type = SMC_LIKE; 904edcfcf27SNicolas Souchu ppc->ppc_link.adapter = &ppc_smclike_adapter; 905edcfcf27SNicolas Souchu 906edcfcf27SNicolas Souchu if (bootverbose) 907edcfcf27SNicolas Souchu printf(" ECP+EPP"); 908edcfcf27SNicolas Souchu } else { 909edcfcf27SNicolas Souchu if (bootverbose) 910edcfcf27SNicolas Souchu printf(" EPP"); 911edcfcf27SNicolas Souchu } 912edcfcf27SNicolas Souchu } else { 913edcfcf27SNicolas Souchu /* restore to standard mode */ 914edcfcf27SNicolas Souchu w_ecr(ppc, 0x0); 91567646539SMike Smith } 91667646539SMike Smith 917edcfcf27SNicolas Souchu /* XXX try to detect NIBBLE and PS2 modes */ 91846f3ff79SMike Smith ppc->ppc_avm |= PPB_NIBBLE; 91967646539SMike Smith 920edcfcf27SNicolas Souchu if (bootverbose) 921edcfcf27SNicolas Souchu printf(" SPP"); 92267646539SMike Smith 923edcfcf27SNicolas Souchu } else { 924edcfcf27SNicolas Souchu ppc->ppc_avm = chipset_mode; 925edcfcf27SNicolas Souchu } 926edcfcf27SNicolas Souchu 927edcfcf27SNicolas Souchu if (bootverbose) 928edcfcf27SNicolas Souchu printf("\n"); 929edcfcf27SNicolas Souchu 930edcfcf27SNicolas Souchu ppc->ppc_link.adapter->setmode(ppc->ppc_unit, chipset_mode); 93146f3ff79SMike Smith 93246f3ff79SMike Smith return (chipset_mode); 93367646539SMike Smith } 93467646539SMike Smith 93567646539SMike Smith /* 93667646539SMike Smith * ppc_detect() 93767646539SMike Smith * 93867646539SMike Smith * mode is the mode suggested at boot 93967646539SMike Smith */ 94067646539SMike Smith static int 94146f3ff79SMike Smith ppc_detect(struct ppc_data *ppc, int chipset_mode) { 94267646539SMike Smith 94346f3ff79SMike Smith int i, mode; 94467646539SMike Smith 94546f3ff79SMike Smith /* list of supported chipsets */ 94646f3ff79SMike Smith int (*chipset_detect[])(struct ppc_data *, int) = { 94746f3ff79SMike Smith ppc_pc873xx_detect, 94846f3ff79SMike Smith ppc_smc37c66xgt_detect, 94946f3ff79SMike Smith ppc_w83877f_detect, 95046f3ff79SMike Smith ppc_generic_detect, 95146f3ff79SMike Smith NULL 95246f3ff79SMike Smith }; 95367646539SMike Smith 95446f3ff79SMike Smith /* if can't find the port and mode not forced return error */ 95546f3ff79SMike Smith if (!ppc_detect_port(ppc) && chipset_mode == 0) 95646f3ff79SMike Smith return (EIO); /* failed, port not present */ 95767646539SMike Smith 95846f3ff79SMike Smith /* assume centronics compatible mode is supported */ 95946f3ff79SMike Smith ppc->ppc_avm = PPB_COMPATIBLE; 96067646539SMike Smith 96146f3ff79SMike Smith /* we have to differenciate available chipset modes, 96246f3ff79SMike Smith * chipset running modes and IEEE-1284 operating modes 96346f3ff79SMike Smith * 96446f3ff79SMike Smith * after detection, the port must support running in compatible mode 96546f3ff79SMike Smith */ 966af548787SNicolas Souchu if (ppc->ppc_flags & 0x40) { 967af548787SNicolas Souchu if (bootverbose) 968af548787SNicolas Souchu printf("ppc: chipset forced to generic\n"); 969af548787SNicolas Souchu 970af548787SNicolas Souchu ppc->ppc_mode = ppc_generic_detect(ppc, chipset_mode); 971af548787SNicolas Souchu 972af548787SNicolas Souchu } else { 97346f3ff79SMike Smith for (i=0; chipset_detect[i] != NULL; i++) { 97446f3ff79SMike Smith if ((mode = chipset_detect[i](ppc, chipset_mode)) != -1) { 97546f3ff79SMike Smith ppc->ppc_mode = mode; 97646f3ff79SMike Smith break; 97746f3ff79SMike Smith } 97846f3ff79SMike Smith } 979af548787SNicolas Souchu } 98046f3ff79SMike Smith 98146f3ff79SMike Smith return (0); 98246f3ff79SMike Smith } 98346f3ff79SMike Smith 98446f3ff79SMike Smith /* 98546f3ff79SMike Smith * ppc_exec_microseq() 98646f3ff79SMike Smith * 98746f3ff79SMike Smith * Execute a microsequence. 98846f3ff79SMike Smith * Microsequence mechanism is supposed to handle fast I/O operations. 98946f3ff79SMike Smith */ 99046f3ff79SMike Smith static int 9910a40e22aSNicolas Souchu ppc_exec_microseq(int unit, struct ppb_microseq **p_msq) 99246f3ff79SMike Smith { 99346f3ff79SMike Smith struct ppc_data *ppc = ppcdata[unit]; 9940a40e22aSNicolas Souchu struct ppb_microseq *mi; 99546f3ff79SMike Smith char cc, *p; 99654ad6085SNicolas Souchu int i, iter, len; 99746f3ff79SMike Smith int error; 99846f3ff79SMike Smith 99954ad6085SNicolas Souchu register int reg; 100054ad6085SNicolas Souchu register char mask; 100154ad6085SNicolas Souchu register int accum = 0; 100254ad6085SNicolas Souchu register char *ptr = 0; 100346f3ff79SMike Smith 10040a40e22aSNicolas Souchu struct ppb_microseq *stack = 0; 100546f3ff79SMike Smith 100646f3ff79SMike Smith /* microsequence registers are equivalent to PC-like port registers */ 100746f3ff79SMike Smith #define r_reg(register,ppc) ((char)inb((ppc)->ppc_base + register)) 100846f3ff79SMike Smith #define w_reg(register,ppc,byte) outb((ppc)->ppc_base + register, byte) 100946f3ff79SMike Smith 10100a40e22aSNicolas Souchu #define INCR_PC (mi ++) /* increment program counter */ 101146f3ff79SMike Smith 10120a40e22aSNicolas Souchu mi = *p_msq; 101346f3ff79SMike Smith for (;;) { 101446f3ff79SMike Smith switch (mi->opcode) { 101546f3ff79SMike Smith case MS_OP_RSET: 101646f3ff79SMike Smith cc = r_reg(mi->arg[0].i, ppc); 101754ad6085SNicolas Souchu cc &= (char)mi->arg[2].i; /* clear mask */ 101854ad6085SNicolas Souchu cc |= (char)mi->arg[1].i; /* assert mask */ 101946f3ff79SMike Smith w_reg(mi->arg[0].i, ppc, cc); 102046f3ff79SMike Smith INCR_PC; 102146f3ff79SMike Smith break; 102246f3ff79SMike Smith 102346f3ff79SMike Smith case MS_OP_RASSERT_P: 102454ad6085SNicolas Souchu reg = mi->arg[1].i; 102554ad6085SNicolas Souchu ptr = ppc->ppc_ptr; 102654ad6085SNicolas Souchu 102754ad6085SNicolas Souchu if ((len = mi->arg[0].i) == MS_ACCUM) { 102854ad6085SNicolas Souchu accum = ppc->ppc_accum; 102954ad6085SNicolas Souchu for (; accum; accum--) 103054ad6085SNicolas Souchu w_reg(reg, ppc, *ptr++); 103154ad6085SNicolas Souchu ppc->ppc_accum = accum; 103254ad6085SNicolas Souchu } else 103354ad6085SNicolas Souchu for (i=0; i<len; i++) 103454ad6085SNicolas Souchu w_reg(reg, ppc, *ptr++); 103554ad6085SNicolas Souchu ppc->ppc_ptr = ptr; 103654ad6085SNicolas Souchu 103746f3ff79SMike Smith INCR_PC; 103846f3ff79SMike Smith break; 103946f3ff79SMike Smith 104046f3ff79SMike Smith case MS_OP_RFETCH_P: 104154ad6085SNicolas Souchu reg = mi->arg[1].i; 104254ad6085SNicolas Souchu mask = (char)mi->arg[2].i; 104354ad6085SNicolas Souchu ptr = ppc->ppc_ptr; 104454ad6085SNicolas Souchu 104554ad6085SNicolas Souchu if ((len = mi->arg[0].i) == MS_ACCUM) { 104654ad6085SNicolas Souchu accum = ppc->ppc_accum; 104754ad6085SNicolas Souchu for (; accum; accum--) 104854ad6085SNicolas Souchu *ptr++ = r_reg(reg, ppc) & mask; 104954ad6085SNicolas Souchu ppc->ppc_accum = accum; 105054ad6085SNicolas Souchu } else 105154ad6085SNicolas Souchu for (i=0; i<len; i++) 105254ad6085SNicolas Souchu *ptr++ = r_reg(reg, ppc) & mask; 105354ad6085SNicolas Souchu ppc->ppc_ptr = ptr; 105454ad6085SNicolas Souchu 105546f3ff79SMike Smith INCR_PC; 105646f3ff79SMike Smith break; 105746f3ff79SMike Smith 105846f3ff79SMike Smith case MS_OP_RFETCH: 105946f3ff79SMike Smith *((char *) mi->arg[2].p) = r_reg(mi->arg[0].i, ppc) & 106054ad6085SNicolas Souchu (char)mi->arg[1].i; 106146f3ff79SMike Smith INCR_PC; 106246f3ff79SMike Smith break; 106346f3ff79SMike Smith 106446f3ff79SMike Smith case MS_OP_RASSERT: 106554ad6085SNicolas Souchu case MS_OP_DELAY: 106646f3ff79SMike Smith 106746f3ff79SMike Smith /* let's suppose the next instr. is the same */ 106846f3ff79SMike Smith prefetch: 106946f3ff79SMike Smith for (;mi->opcode == MS_OP_RASSERT; INCR_PC) 107054ad6085SNicolas Souchu w_reg(mi->arg[0].i, ppc, (char)mi->arg[1].i); 107146f3ff79SMike Smith 107246f3ff79SMike Smith if (mi->opcode == MS_OP_DELAY) { 107346f3ff79SMike Smith DELAY(mi->arg[0].i); 107446f3ff79SMike Smith INCR_PC; 107546f3ff79SMike Smith goto prefetch; 107646f3ff79SMike Smith } 107746f3ff79SMike Smith break; 107846f3ff79SMike Smith 107954ad6085SNicolas Souchu case MS_OP_ADELAY: 108054ad6085SNicolas Souchu if (mi->arg[0].i) 108154ad6085SNicolas Souchu tsleep(NULL, PPBPRI, "ppbdelay", 108254ad6085SNicolas Souchu mi->arg[0].i * (hz/1000)); 108346f3ff79SMike Smith INCR_PC; 108446f3ff79SMike Smith break; 108546f3ff79SMike Smith 108646f3ff79SMike Smith case MS_OP_TRIG: 108746f3ff79SMike Smith reg = mi->arg[0].i; 108846f3ff79SMike Smith iter = mi->arg[1].i; 108946f3ff79SMike Smith p = (char *)mi->arg[2].p; 109046f3ff79SMike Smith 109154ad6085SNicolas Souchu /* XXX delay limited to 255 us */ 109246f3ff79SMike Smith for (i=0; i<iter; i++) { 109346f3ff79SMike Smith w_reg(reg, ppc, *p++); 109446f3ff79SMike Smith DELAY((unsigned char)*p++); 109546f3ff79SMike Smith } 109646f3ff79SMike Smith INCR_PC; 109746f3ff79SMike Smith break; 109846f3ff79SMike Smith 109946f3ff79SMike Smith case MS_OP_SET: 110054ad6085SNicolas Souchu ppc->ppc_accum = mi->arg[0].i; 110146f3ff79SMike Smith INCR_PC; 110246f3ff79SMike Smith break; 110346f3ff79SMike Smith 110446f3ff79SMike Smith case MS_OP_DBRA: 110554ad6085SNicolas Souchu if (--ppc->ppc_accum > 0) 11060a40e22aSNicolas Souchu mi += mi->arg[0].i; 110746f3ff79SMike Smith else 110846f3ff79SMike Smith INCR_PC; 110946f3ff79SMike Smith break; 111046f3ff79SMike Smith 111146f3ff79SMike Smith case MS_OP_BRSET: 111246f3ff79SMike Smith cc = r_str(ppc); 111354ad6085SNicolas Souchu if ((cc & (char)mi->arg[0].i) == (char)mi->arg[0].i) 11140a40e22aSNicolas Souchu mi += mi->arg[1].i; 111546f3ff79SMike Smith else 111646f3ff79SMike Smith INCR_PC; 111746f3ff79SMike Smith break; 111846f3ff79SMike Smith 111946f3ff79SMike Smith case MS_OP_BRCLEAR: 112046f3ff79SMike Smith cc = r_str(ppc); 112154ad6085SNicolas Souchu if ((cc & (char)mi->arg[0].i) == 0) 11220a40e22aSNicolas Souchu mi += mi->arg[1].i; 112346f3ff79SMike Smith else 112446f3ff79SMike Smith INCR_PC; 112546f3ff79SMike Smith break; 112646f3ff79SMike Smith 112754ad6085SNicolas Souchu case MS_OP_BRSTAT: 112854ad6085SNicolas Souchu cc = r_str(ppc); 112954ad6085SNicolas Souchu if ((cc & ((char)mi->arg[0].i | (char)mi->arg[1].i)) == 113054ad6085SNicolas Souchu (char)mi->arg[0].i) 11310a40e22aSNicolas Souchu mi += mi->arg[2].i; 113254ad6085SNicolas Souchu else 113354ad6085SNicolas Souchu INCR_PC; 113454ad6085SNicolas Souchu break; 113554ad6085SNicolas Souchu 113646f3ff79SMike Smith case MS_OP_C_CALL: 113746f3ff79SMike Smith /* 113846f3ff79SMike Smith * If the C call returns !0 then end the microseq. 113946f3ff79SMike Smith * The current state of ptr is passed to the C function 114046f3ff79SMike Smith */ 114154ad6085SNicolas Souchu if ((error = mi->arg[0].f(mi->arg[1].p, ppc->ppc_ptr))) 114246f3ff79SMike Smith return (error); 114346f3ff79SMike Smith 114446f3ff79SMike Smith INCR_PC; 114546f3ff79SMike Smith break; 114646f3ff79SMike Smith 114746f3ff79SMike Smith case MS_OP_PTR: 114854ad6085SNicolas Souchu ppc->ppc_ptr = (char *)mi->arg[0].p; 114946f3ff79SMike Smith INCR_PC; 115046f3ff79SMike Smith break; 115146f3ff79SMike Smith 115246f3ff79SMike Smith case MS_OP_CALL: 11530a40e22aSNicolas Souchu if (stack) 115446f3ff79SMike Smith panic("%s: too much calls", __FUNCTION__); 115546f3ff79SMike Smith 115646f3ff79SMike Smith if (mi->arg[0].p) { 115746f3ff79SMike Smith /* store the state of the actual 115846f3ff79SMike Smith * microsequence 115946f3ff79SMike Smith */ 11600a40e22aSNicolas Souchu stack = mi; 116146f3ff79SMike Smith 116246f3ff79SMike Smith /* jump to the new microsequence */ 11630a40e22aSNicolas Souchu mi = (struct ppb_microseq *)mi->arg[0].p; 116446f3ff79SMike Smith } else 116546f3ff79SMike Smith INCR_PC; 116646f3ff79SMike Smith 116746f3ff79SMike Smith break; 116846f3ff79SMike Smith 116946f3ff79SMike Smith case MS_OP_SUBRET: 117046f3ff79SMike Smith /* retrieve microseq and pc state before the call */ 11710a40e22aSNicolas Souchu mi = stack; 117246f3ff79SMike Smith 117346f3ff79SMike Smith /* reset the stack */ 11740a40e22aSNicolas Souchu stack = 0; 117546f3ff79SMike Smith 117646f3ff79SMike Smith /* XXX return code */ 117746f3ff79SMike Smith 117846f3ff79SMike Smith INCR_PC; 117946f3ff79SMike Smith break; 118046f3ff79SMike Smith 118146f3ff79SMike Smith case MS_OP_PUT: 118246f3ff79SMike Smith case MS_OP_GET: 118346f3ff79SMike Smith case MS_OP_RET: 118446f3ff79SMike Smith /* can't return to ppb level during the execution 118546f3ff79SMike Smith * of a submicrosequence */ 11860a40e22aSNicolas Souchu if (stack) 118746f3ff79SMike Smith panic("%s: can't return to ppb level", 118846f3ff79SMike Smith __FUNCTION__); 118946f3ff79SMike Smith 119046f3ff79SMike Smith /* update pc for ppb level of execution */ 11910a40e22aSNicolas Souchu *p_msq = mi; 119246f3ff79SMike Smith 119346f3ff79SMike Smith /* return to ppb level of execution */ 119446f3ff79SMike Smith return (0); 119546f3ff79SMike Smith 119646f3ff79SMike Smith default: 119746f3ff79SMike Smith panic("%s: unknown microsequence opcode 0x%x", 119846f3ff79SMike Smith __FUNCTION__, mi->opcode); 119946f3ff79SMike Smith } 120046f3ff79SMike Smith } 120146f3ff79SMike Smith 120246f3ff79SMike Smith /* unreached */ 120346f3ff79SMike Smith } 120446f3ff79SMike Smith 120546f3ff79SMike Smith /* 120646f3ff79SMike Smith * Configure current operating mode 120746f3ff79SMike Smith */ 120846f3ff79SMike Smith static int 120946f3ff79SMike Smith ppc_generic_setmode(int unit, int mode) 121046f3ff79SMike Smith { 121146f3ff79SMike Smith struct ppc_data *ppc = ppcdata[unit]; 121246f3ff79SMike Smith 121346f3ff79SMike Smith /* back to compatible mode, XXX don't know yet what to do here */ 121446f3ff79SMike Smith if (mode == 0) { 121546f3ff79SMike Smith ppc->ppc_mode = PPB_COMPATIBLE; 121646f3ff79SMike Smith return (0); 121746f3ff79SMike Smith } 121846f3ff79SMike Smith 121946f3ff79SMike Smith /* check if mode is available */ 122046f3ff79SMike Smith if (!(ppc->ppc_avm & mode)) 122146f3ff79SMike Smith return (EOPNOTSUPP); 122246f3ff79SMike Smith 122346f3ff79SMike Smith /* if ECP mode, configure ecr register */ 1224edcfcf27SNicolas Souchu if (ppc->ppc_avm & PPB_ECP) { 1225edcfcf27SNicolas Souchu 1226edcfcf27SNicolas Souchu /* XXX disable DMA, enable interrupts */ 1227edcfcf27SNicolas Souchu if (mode & PPB_EPP) 1228edcfcf27SNicolas Souchu return (EOPNOTSUPP); 1229edcfcf27SNicolas Souchu else if (mode & PPB_PS2) 1230edcfcf27SNicolas Souchu /* select PS2 mode with ECP */ 1231edcfcf27SNicolas Souchu w_ecr(ppc, 0x20); 1232edcfcf27SNicolas Souchu else if (mode & PPB_ECP) 1233edcfcf27SNicolas Souchu /* select ECP mode */ 1234edcfcf27SNicolas Souchu w_ecr(ppc, 0x60); 1235edcfcf27SNicolas Souchu else 1236edcfcf27SNicolas Souchu /* select standard parallel port mode */ 1237edcfcf27SNicolas Souchu w_ecr(ppc, 0x00); 1238edcfcf27SNicolas Souchu } 123946f3ff79SMike Smith 124046f3ff79SMike Smith ppc->ppc_mode = mode; 124167646539SMike Smith 124267646539SMike Smith return (0); 124367646539SMike Smith } 124467646539SMike Smith 1245edcfcf27SNicolas Souchu int 1246edcfcf27SNicolas Souchu ppc_smclike_setmode(int unit, int mode) 1247edcfcf27SNicolas Souchu { 1248edcfcf27SNicolas Souchu struct ppc_data *ppc = ppcdata[unit]; 1249edcfcf27SNicolas Souchu 1250edcfcf27SNicolas Souchu /* back to compatible mode, XXX don't know yet what to do here */ 1251edcfcf27SNicolas Souchu if (mode == 0) { 1252edcfcf27SNicolas Souchu ppc->ppc_mode = PPB_COMPATIBLE; 1253edcfcf27SNicolas Souchu return (0); 1254edcfcf27SNicolas Souchu } 1255edcfcf27SNicolas Souchu 1256edcfcf27SNicolas Souchu /* check if mode is available */ 1257edcfcf27SNicolas Souchu if (!(ppc->ppc_avm & mode)) 1258edcfcf27SNicolas Souchu return (EOPNOTSUPP); 1259edcfcf27SNicolas Souchu 1260edcfcf27SNicolas Souchu /* if ECP mode, configure ecr register */ 1261edcfcf27SNicolas Souchu if (ppc->ppc_avm & PPB_ECP) { 1262edcfcf27SNicolas Souchu 1263edcfcf27SNicolas Souchu /* XXX disable DMA, enable interrupts */ 1264edcfcf27SNicolas Souchu if (mode & PPB_EPP) 1265edcfcf27SNicolas Souchu /* select EPP mode */ 1266edcfcf27SNicolas Souchu w_ecr(ppc, 0x80); 1267edcfcf27SNicolas Souchu else if (mode & PPB_PS2) 1268edcfcf27SNicolas Souchu /* select PS2 mode with ECP */ 1269edcfcf27SNicolas Souchu w_ecr(ppc, 0x20); 1270edcfcf27SNicolas Souchu else if (mode & PPB_ECP) 1271edcfcf27SNicolas Souchu /* select ECP mode */ 1272edcfcf27SNicolas Souchu w_ecr(ppc, 0x60); 1273edcfcf27SNicolas Souchu else 1274edcfcf27SNicolas Souchu /* select standard parallel port mode */ 1275edcfcf27SNicolas Souchu w_ecr(ppc, 0x00); 1276edcfcf27SNicolas Souchu } 1277edcfcf27SNicolas Souchu 1278edcfcf27SNicolas Souchu ppc->ppc_mode = mode; 1279edcfcf27SNicolas Souchu 1280edcfcf27SNicolas Souchu 1281edcfcf27SNicolas Souchu return (0); 1282edcfcf27SNicolas Souchu } 1283edcfcf27SNicolas Souchu 128467646539SMike Smith /* 128567646539SMike Smith * EPP timeout, according to the PC87332 manual 128667646539SMike Smith * Semantics of clearing EPP timeout bit. 128767646539SMike Smith * PC87332 - reading SPP_STR does it... 128867646539SMike Smith * SMC - write 1 to EPP timeout bit XXX 128967646539SMike Smith * Others - (???) write 0 to EPP timeout bit 129067646539SMike Smith */ 129167646539SMike Smith static void 129267646539SMike Smith ppc_reset_epp_timeout(int unit) 129367646539SMike Smith { 129467646539SMike Smith struct ppc_data *ppc = ppcdata[unit]; 129567646539SMike Smith register char r; 129667646539SMike Smith 129767646539SMike Smith r = r_str(ppc); 129867646539SMike Smith w_str(ppc, r | 0x1); 129967646539SMike Smith w_str(ppc, r & 0xfe); 130067646539SMike Smith 130167646539SMike Smith return; 130267646539SMike Smith } 130367646539SMike Smith 130467646539SMike Smith static int 130567646539SMike Smith ppcprobe(struct isa_device *dvp) 130667646539SMike Smith { 130767646539SMike Smith static short next_bios_ppc = 0; 130867646539SMike Smith struct ppc_data *ppc; 130967646539SMike Smith 131067646539SMike Smith /* 131167646539SMike Smith * If port not specified, use bios list. 131267646539SMike Smith */ 131367646539SMike Smith if(dvp->id_iobase < 0) { 131467646539SMike Smith if((next_bios_ppc < BIOS_MAX_PPC) && 131567646539SMike Smith (*(BIOS_PORTS+next_bios_ppc) != 0) ) { 131667646539SMike Smith dvp->id_iobase = *(BIOS_PORTS+next_bios_ppc++); 131754ad6085SNicolas Souchu printf("ppc: parallel port found at 0x%x\n", 131854ad6085SNicolas Souchu dvp->id_iobase); 131967646539SMike Smith } else 132067646539SMike Smith return (0); 132167646539SMike Smith } 132267646539SMike Smith 132367646539SMike Smith /* 132467646539SMike Smith * Port was explicitly specified. 132567646539SMike Smith * This allows probing of ports unknown to the BIOS. 132667646539SMike Smith */ 132767646539SMike Smith 132867646539SMike Smith /* 132967646539SMike Smith * Allocate the ppc_data structure. 133067646539SMike Smith */ 133167646539SMike Smith ppc = malloc(sizeof(struct ppc_data), M_DEVBUF, M_NOWAIT); 133267646539SMike Smith if (!ppc) { 133367646539SMike Smith printf("ppc: cannot malloc!\n"); 133467646539SMike Smith goto error; 133567646539SMike Smith } 133667646539SMike Smith bzero(ppc, sizeof(struct ppc_data)); 133767646539SMike Smith 133867646539SMike Smith ppc->ppc_base = dvp->id_iobase; 133967646539SMike Smith ppc->ppc_unit = dvp->id_unit; 134067646539SMike Smith ppc->ppc_type = GENERIC; 134167646539SMike Smith 1342af548787SNicolas Souchu /* store boot flags */ 1343af548787SNicolas Souchu ppc->ppc_flags = dvp->id_flags; 1344af548787SNicolas Souchu 134546f3ff79SMike Smith ppc->ppc_mode = PPB_COMPATIBLE; 134646f3ff79SMike Smith ppc->ppc_epp = (dvp->id_flags & 0x10) >> 4; 134767646539SMike Smith 134867646539SMike Smith /* 1349edcfcf27SNicolas Souchu * XXX Try and detect if interrupts are working 135067646539SMike Smith */ 135146f3ff79SMike Smith if (!(dvp->id_flags & 0x20)) 1352af548787SNicolas Souchu ppc->ppc_irq = ffs(dvp->id_irq) - 1; 135367646539SMike Smith 135467646539SMike Smith ppcdata[ppc->ppc_unit] = ppc; 135567646539SMike Smith nppc ++; 135667646539SMike Smith 135767646539SMike Smith /* 1358edcfcf27SNicolas Souchu * Link the Parallel Port Chipset (adapter) to 1359edcfcf27SNicolas Souchu * the future ppbus. Default to a generic chipset 1360edcfcf27SNicolas Souchu */ 1361edcfcf27SNicolas Souchu ppc->ppc_link.adapter_unit = ppc->ppc_unit; 1362edcfcf27SNicolas Souchu ppc->ppc_link.adapter = &ppc_generic_adapter; 1363edcfcf27SNicolas Souchu 1364edcfcf27SNicolas Souchu /* 1365dc733423SDag-Erling Smørgrav * Try to detect the chipset and its mode. 136667646539SMike Smith */ 136746f3ff79SMike Smith if (ppc_detect(ppc, dvp->id_flags & 0xf)) 136867646539SMike Smith goto error; 136967646539SMike Smith 137067646539SMike Smith return (1); 137167646539SMike Smith 137267646539SMike Smith error: 137367646539SMike Smith return (0); 137467646539SMike Smith } 137567646539SMike Smith 137667646539SMike Smith static int 137767646539SMike Smith ppcattach(struct isa_device *isdp) 137867646539SMike Smith { 137967646539SMike Smith struct ppc_data *ppc = ppcdata[isdp->id_unit]; 138067646539SMike Smith struct ppb_data *ppbus; 138167646539SMike Smith 138246f3ff79SMike Smith printf("ppc%d: %s chipset (%s) in %s mode%s\n", ppc->ppc_unit, 138346f3ff79SMike Smith ppc_types[ppc->ppc_type], ppc_avms[ppc->ppc_avm], 138446f3ff79SMike Smith ppc_modes[ppc->ppc_mode], (PPB_IS_EPP(ppc->ppc_mode)) ? 138567646539SMike Smith ppc_epp_protocol[ppc->ppc_epp] : ""); 138667646539SMike Smith 1387fe310de8SBruce Evans isdp->id_ointr = ppcintr; 1388fe310de8SBruce Evans 138967646539SMike Smith /* 139067646539SMike Smith * Prepare ppbus data area for upper level code. 139167646539SMike Smith */ 139267646539SMike Smith ppbus = ppb_alloc_bus(); 139367646539SMike Smith 139467646539SMike Smith if (!ppbus) 139567646539SMike Smith return (0); 139667646539SMike Smith 139767646539SMike Smith ppc->ppc_link.ppbus = ppbus; 139867646539SMike Smith ppbus->ppb_link = &ppc->ppc_link; 139967646539SMike Smith 140067646539SMike Smith /* 140167646539SMike Smith * Probe the ppbus and attach devices found. 140267646539SMike Smith */ 140367646539SMike Smith ppb_attachdevs(ppbus); 140467646539SMike Smith 140567646539SMike Smith return (1); 140667646539SMike Smith } 140767646539SMike Smith #endif 1408