ppc.c revision 144973
168349Sobrien/*- 2133359Sobrien * Copyright (c) 1997-2000 Nicolas Souchu 3133359Sobrien * Copyright (c) 2001 Alcove - Nicolas Souchu 4133359Sobrien * All rights reserved. 5133359Sobrien * 6133359Sobrien * Redistribution and use in source and binary forms, with or without 7133359Sobrien * modification, are permitted provided that the following conditions 8133359Sobrien * are met: 9133359Sobrien * 1. Redistributions of source code must retain the above copyright 10133359Sobrien * notice, this list of conditions and the following disclaimer. 11133359Sobrien * 2. Redistributions in binary form must reproduce the above copyright 12133359Sobrien * notice, this list of conditions and the following disclaimer in the 13133359Sobrien * documentation and/or other materials provided with the distribution. 14133359Sobrien * 15133359Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16133359Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17133359Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18133359Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19133359Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20133359Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21133359Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22133359Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23133359Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24133359Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25133359Sobrien * SUCH DAMAGE. 26133359Sobrien */ 27133359Sobrien 28133359Sobrien#include <sys/cdefs.h> 2968349Sobrien__FBSDID("$FreeBSD: head/sys/dev/ppc/ppc.c 144973 2005-04-12 23:32:26Z imp $"); 3068349Sobrien 3168349Sobrien#include "opt_ppc.h" 3280588Sobrien 33191736Sobrien#include <sys/param.h> 34191736Sobrien#include <sys/systm.h> 35267843Sdelphij#include <sys/kernel.h> 36191736Sobrien#include <sys/module.h> 37191736Sobrien#include <sys/bus.h> 38133359Sobrien#include <sys/malloc.h> 3968349Sobrien 4084685Sobrien#include <vm/vm.h> 4184685Sobrien#include <vm/pmap.h> 4284685Sobrien#include <machine/clock.h> 43267843Sdelphij#include <machine/bus.h> 44267843Sdelphij#include <machine/resource.h> 45267843Sdelphij#include <machine/vmparam.h> 4668349Sobrien#include <sys/rman.h> 47169942Sobrien 4868349Sobrien#include <isa/isareg.h> 49103373Sobrien#include <isa/isavar.h> 5074784Sobrien 5174784Sobrien#include <dev/ppbus/ppbconf.h> 5274784Sobrien#include <dev/ppbus/ppb_msq.h> 53186690Sobrien 54267843Sdelphij#include <dev/ppc/ppcvar.h> 55267843Sdelphij#include <dev/ppc/ppcreg.h> 56267843Sdelphij 5768349Sobrien#include "ppbus_if.h" 58267843Sdelphij 59267843Sdelphijstatic int ppc_isa_probe(device_t dev); 60267843Sdelphij 61267843Sdelphijstatic void ppcintr(void *arg); 62267843Sdelphij 63267843Sdelphij#define LOG_PPC(function, ppc, string) \ 6468349Sobrien if (bootverbose) printf("%s: %s\n", function, string) 6568349Sobrien 6668349Sobrien 6768349Sobrien#define DEVTOSOFTC(dev) ((struct ppc_data *)device_get_softc(dev)) 6875937Sobrien 6975937Sobriendevclass_t ppc_devclass; 7075937Sobrien 7175937Sobrienstatic device_method_t ppc_methods[] = { 7275937Sobrien /* device interface */ 7375937Sobrien DEVMETHOD(device_probe, ppc_isa_probe), 7475937Sobrien DEVMETHOD(device_attach, ppc_attach), 7575937Sobrien 7675937Sobrien /* bus interface */ 7768349Sobrien DEVMETHOD(bus_read_ivar, ppc_read_ivar), 7875937Sobrien DEVMETHOD(bus_setup_intr, ppc_setup_intr), 7975937Sobrien DEVMETHOD(bus_teardown_intr, ppc_teardown_intr), 8075937Sobrien DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 8168349Sobrien 8275937Sobrien /* ppbus interface */ 8375937Sobrien DEVMETHOD(ppbus_io, ppc_io), 8475937Sobrien DEVMETHOD(ppbus_exec_microseq, ppc_exec_microseq), 8575937Sobrien DEVMETHOD(ppbus_reset_epp, ppc_reset_epp), 86267843Sdelphij DEVMETHOD(ppbus_setmode, ppc_setmode), 87267843Sdelphij DEVMETHOD(ppbus_ecp_sync, ppc_ecp_sync), 88267843Sdelphij DEVMETHOD(ppbus_read, ppc_read), 89159764Sobrien DEVMETHOD(ppbus_write, ppc_write), 90159764Sobrien 91159764Sobrien { 0, 0 } 92159764Sobrien }; 93159764Sobrien 94159764Sobrienstatic driver_t ppc_driver = { 95267843Sdelphij "ppc", 96267843Sdelphij ppc_methods, 97267843Sdelphij sizeof(struct ppc_data), 98267843Sdelphij}; 99267843Sdelphij 100267843Sdelphijstatic char *ppc_models[] = { 101267843Sdelphij "SMC-like", "SMC FDC37C665GT", "SMC FDC37C666GT", "PC87332", "PC87306", 102267843Sdelphij "82091AA", "Generic", "W83877F", "W83877AF", "Winbond", "PC87334", 103267843Sdelphij "SMC FDC37C935", "PC87303", 0 104267843Sdelphij}; 105267843Sdelphij 106267843Sdelphij/* list of available modes */ 107267843Sdelphijstatic char *ppc_avms[] = { 108169962Sobrien "COMPATIBLE", "NIBBLE-only", "PS2-only", "PS2/NIBBLE", "EPP-only", 109169962Sobrien "EPP/NIBBLE", "EPP/PS2", "EPP/PS2/NIBBLE", "ECP-only", 110169962Sobrien "ECP/NIBBLE", "ECP/PS2", "ECP/PS2/NIBBLE", "ECP/EPP", 111169962Sobrien "ECP/EPP/NIBBLE", "ECP/EPP/PS2", "ECP/EPP/PS2/NIBBLE", 0 112169942Sobrien}; 113169962Sobrien 114133359Sobrien/* list of current executing modes 115192348Sdelphij * Note that few modes do not actually exist. 116192348Sdelphij */ 117267843Sdelphijstatic char *ppc_modes[] = { 118267843Sdelphij "COMPATIBLE", "NIBBLE", "PS/2", "PS/2", "EPP", 119159764Sobrien "EPP", "EPP", "EPP", "ECP", 120267843Sdelphij "ECP", "ECP+PS2", "ECP+PS2", "ECP+EPP", 121159764Sobrien "ECP+EPP", "ECP+EPP", "ECP+EPP", 0 122159764Sobrien}; 123226048Sobrien 124267843Sdelphijstatic char *ppc_epp_protocol[] = { " (EPP 1.9)", " (EPP 1.7)", 0 }; 125133359Sobrien 126267843Sdelphij#ifdef __i386__ 127267843Sdelphij/* 128133359Sobrien * BIOS printer list - used by BIOS probe. 129133359Sobrien */ 130133359Sobrien#define BIOS_PPC_PORTS 0x408 131133359Sobrien#define BIOS_PORTS (short *)(KERNBASE+BIOS_PPC_PORTS) 132169942Sobrien#define BIOS_MAX_PPC 4 133191736Sobrien#endif 134267843Sdelphij 135267843Sdelphij/* 136267843Sdelphij * ppc_ecp_sync() XXX 137133359Sobrien */ 138169942Sobrienvoid 139139368Sobrienppc_ecp_sync(device_t dev) { 140175296Sobrien 141186690Sobrien int i, r; 142191736Sobrien struct ppc_data *ppc = DEVTOSOFTC(dev); 143191736Sobrien 14468349Sobrien if (!(ppc->ppc_avm & PPB_ECP) && !(ppc->ppc_dtm & PPB_ECP)) 145186690Sobrien return; 146133359Sobrien 14768349Sobrien r = r_ecr(ppc); 148186690Sobrien if ((r & 0xe0) != PPC_ECR_EPP) 149159764Sobrien return; 150186690Sobrien 151186690Sobrien for (i = 0; i < 100; i++) { 152186690Sobrien r = r_ecr(ppc); 153186690Sobrien if (r & 0x1) 154186690Sobrien return; 155186690Sobrien DELAY(100); 156186690Sobrien } 157191736Sobrien 158186690Sobrien printf("ppc%d: ECP sync failed as data still " \ 159186690Sobrien "present in FIFO.\n", ppc->ppc_unit); 160186690Sobrien 161186690Sobrien return; 162186690Sobrien} 16380588Sobrien 16474784Sobrien/* 165103373Sobrien * ppc_detect_fifo() 16680588Sobrien * 16780588Sobrien * Detect parallel port FIFO 168103373Sobrien */ 16980588Sobrienstatic int 17080588Sobrienppc_detect_fifo(struct ppc_data *ppc) 171133359Sobrien{ 172133359Sobrien char ecr_sav; 17380588Sobrien char ctr_sav, ctr, cc; 17480588Sobrien short i; 17580588Sobrien 17680588Sobrien /* save registers */ 17780588Sobrien ecr_sav = r_ecr(ppc); 17880588Sobrien ctr_sav = r_ctr(ppc); 17980588Sobrien 180133359Sobrien /* enter ECP configuration mode, no interrupt, no DMA */ 181133359Sobrien w_ecr(ppc, 0xf4); 18280588Sobrien 18380588Sobrien /* read PWord size - transfers in FIFO mode must be PWord aligned */ 184133359Sobrien ppc->ppc_pword = (r_cnfgA(ppc) & PPC_PWORD_MASK); 185133359Sobrien 186133359Sobrien /* XXX 16 and 32 bits implementations not supported */ 187133359Sobrien if (ppc->ppc_pword != PPC_PWORD_8) { 188133359Sobrien LOG_PPC(__func__, ppc, "PWord not supported"); 189133359Sobrien goto error; 190133359Sobrien } 191133359Sobrien 192133359Sobrien w_ecr(ppc, 0x34); /* byte mode, no interrupt, no DMA */ 19380588Sobrien ctr = r_ctr(ppc); 19480588Sobrien w_ctr(ppc, ctr | PCD); /* set direction to 1 */ 19580588Sobrien 196267843Sdelphij /* enter ECP test mode, no interrupt, no DMA */ 197186690Sobrien w_ecr(ppc, 0xd4); 198169962Sobrien 199169962Sobrien /* flush the FIFO */ 200169962Sobrien for (i=0; i<1024; i++) { 201267843Sdelphij if (r_ecr(ppc) & PPC_FIFO_EMPTY) 202267843Sdelphij break; 203267843Sdelphij cc = r_fifo(ppc); 204267843Sdelphij } 205267843Sdelphij 206267843Sdelphij if (i >= 1024) { 207267843Sdelphij LOG_PPC(__func__, ppc, "can't flush FIFO"); 208267843Sdelphij goto error; 209267843Sdelphij } 210267843Sdelphij 211169962Sobrien /* enable interrupts, no DMA */ 212186690Sobrien w_ecr(ppc, 0xd0); 213267843Sdelphij 214169962Sobrien /* determine readIntrThreshold 215169962Sobrien * fill the FIFO until serviceIntr is set 216267843Sdelphij */ 217169962Sobrien for (i=0; i<1024; i++) { 218169962Sobrien w_fifo(ppc, (char)i); 219169962Sobrien if (!ppc->ppc_rthr && (r_ecr(ppc) & PPC_SERVICE_INTR)) { 220169962Sobrien /* readThreshold reached */ 221169962Sobrien ppc->ppc_rthr = i+1; 222169962Sobrien } 223169962Sobrien if (r_ecr(ppc) & PPC_FIFO_FULL) { 224169962Sobrien ppc->ppc_fifo = i+1; 225169962Sobrien break; 226169962Sobrien } 227169962Sobrien } 228169962Sobrien 229169962Sobrien if (i >= 1024) { 230169962Sobrien LOG_PPC(__func__, ppc, "can't fill FIFO"); 231169962Sobrien goto error; 232169962Sobrien } 233169962Sobrien 234169962Sobrien w_ecr(ppc, 0xd4); /* test mode, no interrupt, no DMA */ 235169962Sobrien w_ctr(ppc, ctr & ~PCD); /* set direction to 0 */ 236169962Sobrien w_ecr(ppc, 0xd0); /* enable interrupts */ 237169962Sobrien 238169962Sobrien /* determine writeIntrThreshold 239169962Sobrien * empty the FIFO until serviceIntr is set 240169962Sobrien */ 241169962Sobrien for (i=ppc->ppc_fifo; i>0; i--) { 242169962Sobrien if (r_fifo(ppc) != (char)(ppc->ppc_fifo-i)) { 243169962Sobrien LOG_PPC(__func__, ppc, "invalid data in FIFO"); 244169962Sobrien goto error; 245169962Sobrien } 246175296Sobrien if (r_ecr(ppc) & PPC_SERVICE_INTR) { 247175296Sobrien /* writeIntrThreshold reached */ 248175296Sobrien ppc->ppc_wthr = ppc->ppc_fifo - i+1; 249175296Sobrien } 250175296Sobrien /* if FIFO empty before the last byte, error */ 251175296Sobrien if (i>1 && (r_ecr(ppc) & PPC_FIFO_EMPTY)) { 252191736Sobrien LOG_PPC(__func__, ppc, "data lost in FIFO"); 253191736Sobrien goto error; 254267843Sdelphij } 255267843Sdelphij } 256267843Sdelphij 257267843Sdelphij /* FIFO must be empty after the last byte */ 258267843Sdelphij if (!(r_ecr(ppc) & PPC_FIFO_EMPTY)) { 259267843Sdelphij LOG_PPC(__func__, ppc, "can't empty the FIFO"); 260267843Sdelphij goto error; 261169962Sobrien } 262267843Sdelphij 263267843Sdelphij w_ctr(ppc, ctr_sav); 264267843Sdelphij w_ecr(ppc, ecr_sav); 265267843Sdelphij 266267843Sdelphij return (0); 267267843Sdelphij 268267843Sdelphijerror: 269267843Sdelphij w_ctr(ppc, ctr_sav); 270267843Sdelphij w_ecr(ppc, ecr_sav); 271267843Sdelphij 272267843Sdelphij return (EINVAL); 273169962Sobrien} 274169962Sobrien 27580588Sobrienstatic int 276169962Sobrienppc_detect_port(struct ppc_data *ppc) 277267843Sdelphij{ 278169962Sobrien 279169962Sobrien w_ctr(ppc, 0x0c); /* To avoid missing PS2 ports */ 280169962Sobrien w_dtr(ppc, 0xaa); 281267843Sdelphij if (r_dtr(ppc) != 0xaa) 282169962Sobrien return (0); 283169962Sobrien 284169962Sobrien return (1); 285169962Sobrien} 286169962Sobrien 287169962Sobrien/* 288169962Sobrien * EPP timeout, according to the PC87332 manual 289169962Sobrien * Semantics of clearing EPP timeout bit. 290169962Sobrien * PC87332 - reading SPP_STR does it... 291267843Sdelphij * SMC - write 1 to EPP timeout bit XXX 292267843Sdelphij * Others - (?) write 0 to EPP timeout bit 293267843Sdelphij */ 294267843Sdelphijstatic void 295267843Sdelphijppc_reset_epp_timeout(struct ppc_data *ppc) 296267843Sdelphij{ 297267843Sdelphij register char r; 298267843Sdelphij 299267843Sdelphij r = r_str(ppc); 300267843Sdelphij w_str(ppc, r | 0x1); 301267843Sdelphij w_str(ppc, r & 0xfe); 302267843Sdelphij 303267843Sdelphij return; 304267843Sdelphij} 305267843Sdelphij 306267843Sdelphijstatic int 307267843Sdelphijppc_check_epp_timeout(struct ppc_data *ppc) 308267843Sdelphij{ 309267843Sdelphij ppc_reset_epp_timeout(ppc); 310267843Sdelphij 311267843Sdelphij return (!(r_str(ppc) & TIMEOUT)); 312267843Sdelphij} 313267843Sdelphij 314267843Sdelphij/* 315267843Sdelphij * Configure current operating mode 316267843Sdelphij */ 317267843Sdelphijstatic int 318267843Sdelphijppc_generic_setmode(struct ppc_data *ppc, int mode) 319267843Sdelphij{ 320267843Sdelphij u_char ecr = 0; 321267843Sdelphij 322267843Sdelphij /* check if mode is available */ 323267843Sdelphij if (mode && !(ppc->ppc_avm & mode)) 324267843Sdelphij return (EINVAL); 325267843Sdelphij 326267843Sdelphij /* if ECP mode, configure ecr register */ 327267843Sdelphij if ((ppc->ppc_avm & PPB_ECP) || (ppc->ppc_dtm & PPB_ECP)) { 328267843Sdelphij /* return to byte mode (keeping direction bit), 329267843Sdelphij * no interrupt, no DMA to be able to change to 330267843Sdelphij * ECP 331267843Sdelphij */ 332267843Sdelphij w_ecr(ppc, PPC_ECR_RESET); 333267843Sdelphij ecr = PPC_DISABLE_INTR; 334267843Sdelphij 335267843Sdelphij if (mode & PPB_EPP) 336267843Sdelphij return (EINVAL); 337267843Sdelphij else if (mode & PPB_ECP) 338267843Sdelphij /* select ECP mode */ 339267843Sdelphij ecr |= PPC_ECR_ECP; 340267843Sdelphij else if (mode & PPB_PS2) 341267843Sdelphij /* select PS2 mode with ECP */ 342267843Sdelphij ecr |= PPC_ECR_PS2; 343267843Sdelphij else 344267843Sdelphij /* select COMPATIBLE/NIBBLE mode */ 345267843Sdelphij ecr |= PPC_ECR_STD; 346267843Sdelphij 347267843Sdelphij w_ecr(ppc, ecr); 348267843Sdelphij } 349267843Sdelphij 350267843Sdelphij ppc->ppc_mode = mode; 351267843Sdelphij 352267843Sdelphij return (0); 353267843Sdelphij} 354267843Sdelphij 355267843Sdelphij/* 356267843Sdelphij * The ppc driver is free to choose options like FIFO or DMA 357267843Sdelphij * if ECP mode is available. 358267843Sdelphij * 359267843Sdelphij * The 'RAW' option allows the upper drivers to force the ppc mode 360267843Sdelphij * even with FIFO, DMA available. 361267843Sdelphij */ 362267843Sdelphijstatic int 363267843Sdelphijppc_smclike_setmode(struct ppc_data *ppc, int mode) 364267843Sdelphij{ 365267843Sdelphij u_char ecr = 0; 366267843Sdelphij 367267843Sdelphij /* check if mode is available */ 368267843Sdelphij if (mode && !(ppc->ppc_avm & mode)) 369267843Sdelphij return (EINVAL); 370267843Sdelphij 371267843Sdelphij /* if ECP mode, configure ecr register */ 372267843Sdelphij if ((ppc->ppc_avm & PPB_ECP) || (ppc->ppc_dtm & PPB_ECP)) { 373267843Sdelphij /* return to byte mode (keeping direction bit), 374267843Sdelphij * no interrupt, no DMA to be able to change to 375267843Sdelphij * ECP or EPP mode 376169962Sobrien */ 377169962Sobrien w_ecr(ppc, PPC_ECR_RESET); 378169962Sobrien ecr = PPC_DISABLE_INTR; 379169962Sobrien 380169962Sobrien if (mode & PPB_EPP) 381169962Sobrien /* select EPP mode */ 382169962Sobrien ecr |= PPC_ECR_EPP; 383169962Sobrien else if (mode & PPB_ECP) 384169962Sobrien /* select ECP mode */ 385169962Sobrien ecr |= PPC_ECR_ECP; 386186690Sobrien else if (mode & PPB_PS2) 387169962Sobrien /* select PS2 mode with ECP */ 388169962Sobrien ecr |= PPC_ECR_PS2; 389169962Sobrien else 390169962Sobrien /* select COMPATIBLE/NIBBLE mode */ 391267843Sdelphij ecr |= PPC_ECR_STD; 392169962Sobrien 393169962Sobrien w_ecr(ppc, ecr); 394267843Sdelphij } 395267843Sdelphij 396267843Sdelphij ppc->ppc_mode = mode; 397267843Sdelphij 398267843Sdelphij return (0); 399267843Sdelphij} 400267843Sdelphij 401267843Sdelphij#ifdef PPC_PROBE_CHIPSET 402267843Sdelphij/* 403267843Sdelphij * ppc_pc873xx_detect 404267843Sdelphij * 405267843Sdelphij * Probe for a Natsemi PC873xx-family part. 406267843Sdelphij * 407267843Sdelphij * References in this function are to the National Semiconductor 408267843Sdelphij * PC87332 datasheet TL/C/11930, May 1995 revision. 409267843Sdelphij */ 410267843Sdelphijstatic int pc873xx_basetab[] = {0x0398, 0x026e, 0x015c, 0x002e, 0}; 411267843Sdelphijstatic int pc873xx_porttab[] = {0x0378, 0x03bc, 0x0278, 0}; 412267843Sdelphijstatic int pc873xx_irqtab[] = {5, 7, 5, 0}; 41374784Sobrien 414186690Sobrienstatic int pc873xx_regstab[] = { 41574784Sobrien PC873_FER, PC873_FAR, PC873_PTR, 416133359Sobrien PC873_FCR, PC873_PCR, PC873_PMC, 417267843Sdelphij PC873_TUP, PC873_SID, PC873_PNP0, 41874784Sobrien PC873_PNP1, PC873_LPTBA, -1 419267897Sdelphij}; 42074784Sobrien 421267897Sdelphijstatic char *pc873xx_rnametab[] = { 422267843Sdelphij "FER", "FAR", "PTR", "FCR", "PCR", 423267897Sdelphij "PMC", "TUP", "SID", "PNP0", "PNP1", 424267843Sdelphij "LPTBA", NULL 425267897Sdelphij}; 42674784Sobrien 427133359Sobrienstatic int 428133359Sobrienppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never forced */ 429267843Sdelphij{ 430133359Sobrien static int index = 0; 431133359Sobrien int idport, irq; 43274784Sobrien int ptr, pcr, val, i; 433133359Sobrien 434133359Sobrien while ((idport = pc873xx_basetab[index++])) { 435267843Sdelphij 436267843Sdelphij /* XXX should check first to see if this location is already claimed */ 437133359Sobrien 438267843Sdelphij /* 439133359Sobrien * Pull the 873xx through the power-on ID cycle (2.2,1.). 440159764Sobrien * We can't use this to locate the chip as it may already have 44180588Sobrien * been used by the BIOS. 442267843Sdelphij */ 443267843Sdelphij (void)inb(idport); (void)inb(idport); 444133359Sobrien (void)inb(idport); (void)inb(idport); 445139368Sobrien 446267843Sdelphij /* 447267843Sdelphij * Read the SID byte. Possible values are : 448133359Sobrien * 449133359Sobrien * 01010xxx PC87334 45074784Sobrien * 0001xxxx PC87332 451267843Sdelphij * 01110xxx PC87306 452267843Sdelphij * 00110xxx PC87303 453267843Sdelphij */ 454267843Sdelphij outb(idport, PC873_SID); 455267843Sdelphij val = inb(idport + 1); 456267843Sdelphij if ((val & 0xf0) == 0x10) { 457133359Sobrien ppc->ppc_model = NS_PC87332; 458133359Sobrien } else if ((val & 0xf8) == 0x70) { 459226048Sobrien ppc->ppc_model = NS_PC87306; 460267843Sdelphij } else if ((val & 0xf8) == 0x50) { 461267843Sdelphij ppc->ppc_model = NS_PC87334; 462267843Sdelphij } else if ((val & 0xf8) == 0x40) { /* Should be 0x30 by the 463267843Sdelphij documentation, but probing 464267843Sdelphij yielded 0x40... */ 465267843Sdelphij ppc->ppc_model = NS_PC87303; 466226048Sobrien } else { 467267897Sdelphij if (bootverbose && (val != 0xff)) 468226048Sobrien printf("PC873xx probe at 0x%x got unknown ID 0x%x\n", idport, val); 469133359Sobrien continue ; /* not recognised */ 47074784Sobrien } 47174784Sobrien 472133359Sobrien /* print registers */ 473267843Sdelphij if (bootverbose) { 474133359Sobrien printf("PC873xx"); 475267843Sdelphij for (i=0; pc873xx_regstab[i] != -1; i++) { 476267843Sdelphij outb(idport, pc873xx_regstab[i]); 477133359Sobrien printf(" %s=0x%x", pc873xx_rnametab[i], 478267843Sdelphij inb(idport + 1) & 0xff); 479267843Sdelphij } 480267843Sdelphij printf("\n"); 481267843Sdelphij } 482267843Sdelphij 483267843Sdelphij /* 484267843Sdelphij * We think we have one. Is it enabled and where we want it to be? 485267843Sdelphij */ 486267843Sdelphij outb(idport, PC873_FER); 487267843Sdelphij val = inb(idport + 1); 488267843Sdelphij if (!(val & PC873_PPENABLE)) { 489267843Sdelphij if (bootverbose) 490267843Sdelphij printf("PC873xx parallel port disabled\n"); 491267843Sdelphij continue; 492267843Sdelphij } 493267843Sdelphij outb(idport, PC873_FAR); 494267843Sdelphij val = inb(idport + 1); 495267843Sdelphij /* XXX we should create a driver instance for every port found */ 496267843Sdelphij if (pc873xx_porttab[val & 0x3] != ppc->ppc_base) { 497267843Sdelphij 498267843Sdelphij /* First try to change the port address to that requested... */ 499267843Sdelphij 500267843Sdelphij switch(ppc->ppc_base) { 501267843Sdelphij case 0x378: 502267843Sdelphij val &= 0xfc; 503267843Sdelphij break; 504267843Sdelphij 505267843Sdelphij case 0x3bc: 506267843Sdelphij val &= 0xfd; 507267843Sdelphij break; 508267843Sdelphij 509267843Sdelphij case 0x278: 510267843Sdelphij val &= 0xfe; 511267843Sdelphij break; 512267843Sdelphij 513267843Sdelphij default: 514267843Sdelphij val &= 0xfd; 515267843Sdelphij break; 516267843Sdelphij } 517267843Sdelphij 518267843Sdelphij outb(idport, PC873_FAR); 519267843Sdelphij outb(idport + 1, val); 520267843Sdelphij outb(idport + 1, val); 521267843Sdelphij 522267843Sdelphij /* Check for success by reading back the value we supposedly 523267843Sdelphij wrote and comparing...*/ 524267843Sdelphij 525175296Sobrien outb(idport, PC873_FAR); 526267843Sdelphij val = inb(idport + 1) & 0x3; 527267843Sdelphij 528267843Sdelphij /* If we fail, report the failure... */ 529175296Sobrien 530267843Sdelphij if (pc873xx_porttab[val] != ppc->ppc_base) { 531267843Sdelphij if (bootverbose) 532267843Sdelphij printf("PC873xx at 0x%x not for driver at port 0x%x\n", 533267843Sdelphij pc873xx_porttab[val], ppc->ppc_base); 534267843Sdelphij } 535133359Sobrien continue; 536267843Sdelphij } 537133359Sobrien 53874784Sobrien outb(idport, PC873_PTR); 539267843Sdelphij ptr = inb(idport + 1); 540267843Sdelphij 541267843Sdelphij /* get irq settings */ 542267843Sdelphij if (ppc->ppc_base == 0x378) 543267843Sdelphij irq = (ptr & PC873_LPTBIRQ7) ? 7 : 5; 544267843Sdelphij else 545267843Sdelphij irq = pc873xx_irqtab[val]; 546267843Sdelphij 547267843Sdelphij if (bootverbose) 548267843Sdelphij printf("PC873xx irq %d at 0x%x\n", irq, ppc->ppc_base); 549267843Sdelphij 550267843Sdelphij /* 551267843Sdelphij * Check if irq settings are correct 552267843Sdelphij */ 553267843Sdelphij if (irq != ppc->ppc_irq) { 554267843Sdelphij /* 555267843Sdelphij * If the chipset is not locked and base address is 0x378, 556267843Sdelphij * we have another chance 557267843Sdelphij */ 558267843Sdelphij if (ppc->ppc_base == 0x378 && !(ptr & PC873_CFGLOCK)) { 559267843Sdelphij if (ppc->ppc_irq == 7) { 560267843Sdelphij outb(idport + 1, (ptr | PC873_LPTBIRQ7)); 561267843Sdelphij outb(idport + 1, (ptr | PC873_LPTBIRQ7)); 562267843Sdelphij } else { 563267843Sdelphij outb(idport + 1, (ptr & ~PC873_LPTBIRQ7)); 564267843Sdelphij outb(idport + 1, (ptr & ~PC873_LPTBIRQ7)); 565267843Sdelphij } 566267843Sdelphij if (bootverbose) 567267843Sdelphij printf("PC873xx irq set to %d\n", ppc->ppc_irq); 568186690Sobrien } else { 569267843Sdelphij if (bootverbose) 570133359Sobrien printf("PC873xx sorry, can't change irq setting\n"); 57168349Sobrien } 572186690Sobrien } else { 57368349Sobrien if (bootverbose) 574267843Sdelphij printf("PC873xx irq settings are correct\n"); 57568349Sobrien } 576267843Sdelphij 577267843Sdelphij outb(idport, PC873_PCR); 578267843Sdelphij pcr = inb(idport + 1); 579226048Sobrien 580267843Sdelphij if ((ptr & PC873_CFGLOCK) || !chipset_mode) { 581226048Sobrien if (bootverbose) 582169962Sobrien printf("PC873xx %s", (ptr & PC873_CFGLOCK)?"locked":"unlocked"); 583169962Sobrien 584169962Sobrien ppc->ppc_avm |= PPB_NIBBLE; 585169942Sobrien if (bootverbose) 586267843Sdelphij printf(", NIBBLE"); 58768349Sobrien 588133359Sobrien if (pcr & PC873_EPPEN) { 589267843Sdelphij ppc->ppc_avm |= PPB_EPP; 590267843Sdelphij 591267843Sdelphij if (bootverbose) 592267843Sdelphij printf(", EPP"); 593267843Sdelphij 594267843Sdelphij if (pcr & PC873_EPP19) 595267843Sdelphij ppc->ppc_epp = EPP_1_9; 596267843Sdelphij else 597267843Sdelphij ppc->ppc_epp = EPP_1_7; 598267843Sdelphij 599267843Sdelphij if ((ppc->ppc_model == NS_PC87332) && bootverbose) { 600267843Sdelphij outb(idport, PC873_PTR); 601267843Sdelphij ptr = inb(idport + 1); 602133359Sobrien if (ptr & PC873_EPPRDIR) 603267843Sdelphij printf(", Regular mode"); 604133359Sobrien else 60568349Sobrien printf(", Automatic mode"); 60668349Sobrien } 60768349Sobrien } else if (pcr & PC873_ECPEN) { 60868349Sobrien ppc->ppc_avm |= PPB_ECP; 609133359Sobrien if (bootverbose) 610133359Sobrien printf(", ECP"); 611267843Sdelphij 612186690Sobrien if (pcr & PC873_ECPCLK) { /* XXX */ 61368349Sobrien ppc->ppc_avm |= PPB_PS2; 61468349Sobrien if (bootverbose) 615267843Sdelphij printf(", PS/2"); 616267843Sdelphij } 617267843Sdelphij } else { 618133359Sobrien outb(idport, PC873_PTR); 619267843Sdelphij ptr = inb(idport + 1); 620267843Sdelphij if (ptr & PC873_EXTENDED) { 621267843Sdelphij ppc->ppc_avm |= PPB_SPP; 622267843Sdelphij if (bootverbose) 623267843Sdelphij printf(", SPP"); 624267843Sdelphij } 625133359Sobrien } 626267843Sdelphij } else { 627267843Sdelphij if (bootverbose) 628267843Sdelphij printf("PC873xx unlocked"); 629267843Sdelphij 630267843Sdelphij if (chipset_mode & PPB_ECP) { 631267843Sdelphij if ((chipset_mode & PPB_EPP) && bootverbose) 632267843Sdelphij printf(", ECP+EPP not supported"); 633267843Sdelphij 634267843Sdelphij pcr &= ~PC873_EPPEN; 635267843Sdelphij pcr |= (PC873_ECPEN | PC873_ECPCLK); /* XXX */ 636267843Sdelphij outb(idport + 1, pcr); 637267843Sdelphij outb(idport + 1, pcr); 638267843Sdelphij 639267843Sdelphij if (bootverbose) 640267843Sdelphij printf(", ECP"); 641267843Sdelphij 642267843Sdelphij } else if (chipset_mode & PPB_EPP) { 643267843Sdelphij pcr &= ~(PC873_ECPEN | PC873_ECPCLK); 644267843Sdelphij pcr |= (PC873_EPPEN | PC873_EPP19); 645267843Sdelphij outb(idport + 1, pcr); 646267843Sdelphij outb(idport + 1, pcr); 647267843Sdelphij 648267843Sdelphij ppc->ppc_epp = EPP_1_9; /* XXX */ 649267843Sdelphij 65068349Sobrien if (bootverbose) 65168349Sobrien printf(", EPP1.9"); 652169942Sobrien 653267843Sdelphij /* enable automatic direction turnover */ 654267843Sdelphij if (ppc->ppc_model == NS_PC87332) { 655267843Sdelphij outb(idport, PC873_PTR); 656267843Sdelphij ptr = inb(idport + 1); 657267843Sdelphij ptr &= ~PC873_EPPRDIR; 658267843Sdelphij outb(idport + 1, ptr); 659267843Sdelphij outb(idport + 1, ptr); 660267843Sdelphij 661267843Sdelphij if (bootverbose) 662267843Sdelphij printf(", Automatic mode"); 663267843Sdelphij } 664267843Sdelphij } else { 665267843Sdelphij pcr &= ~(PC873_ECPEN | PC873_ECPCLK | PC873_EPPEN); 666267843Sdelphij outb(idport + 1, pcr); 667267843Sdelphij outb(idport + 1, pcr); 668267843Sdelphij 669267843Sdelphij /* configure extended bit in PTR */ 670267843Sdelphij outb(idport, PC873_PTR); 671267843Sdelphij ptr = inb(idport + 1); 672267843Sdelphij 673267843Sdelphij if (chipset_mode & PPB_PS2) { 674267843Sdelphij ptr |= PC873_EXTENDED; 675267843Sdelphij 676267843Sdelphij if (bootverbose) 677267843Sdelphij printf(", PS/2"); 678267843Sdelphij 679267843Sdelphij } else { 680267843Sdelphij /* default to NIBBLE mode */ 681267843Sdelphij ptr &= ~PC873_EXTENDED; 682267843Sdelphij 683267843Sdelphij if (bootverbose) 684267843Sdelphij printf(", NIBBLE"); 685267843Sdelphij } 686267843Sdelphij outb(idport + 1, ptr); 687267843Sdelphij outb(idport + 1, ptr); 688267843Sdelphij } 689267843Sdelphij 690267843Sdelphij ppc->ppc_avm = chipset_mode; 691267843Sdelphij } 692267843Sdelphij 693267843Sdelphij if (bootverbose) 694267843Sdelphij printf("\n"); 695267843Sdelphij 696267843Sdelphij ppc->ppc_type = PPC_TYPE_GENERIC; 697267843Sdelphij ppc_generic_setmode(ppc, chipset_mode); 698267843Sdelphij 699267843Sdelphij return(chipset_mode); 700267843Sdelphij } 701267843Sdelphij return(-1); 702169942Sobrien} 703169942Sobrien 704159764Sobrien/* 705159764Sobrien * ppc_smc37c66xgt_detect 706159764Sobrien * 707169942Sobrien * SMC FDC37C66xGT configuration. 708267843Sdelphij */ 709169942Sobrienstatic int 710159764Sobrienppc_smc37c66xgt_detect(struct ppc_data *ppc, int chipset_mode) 711169962Sobrien{ 712186690Sobrien int s, i; 713186690Sobrien u_char r; 714169962Sobrien int type = -1; 715169962Sobrien int csr = SMC66x_CSR; /* initial value is 0x3F0 */ 716159764Sobrien 717169942Sobrien int port_address[] = { -1 /* disabled */ , 0x3bc, 0x378, 0x278 }; 718169942Sobrien 719159764Sobrien 720159764Sobrien#define cio csr+1 /* config IO port is either 0x3F1 or 0x371 */ 721159764Sobrien 722159764Sobrien /* 723169942Sobrien * Detection: enter configuration mode and read CRD register. 724169942Sobrien */ 725159764Sobrien 726159764Sobrien s = splhigh(); 727159764Sobrien outb(csr, SMC665_iCODE); 728159764Sobrien outb(csr, SMC665_iCODE); 729159764Sobrien splx(s); 730169942Sobrien 731169942Sobrien outb(csr, 0xd); 732159764Sobrien if (inb(cio) == 0x65) { 733159764Sobrien type = SMC_37C665GT; 734159764Sobrien goto config; 735169942Sobrien } 736169942Sobrien 737169942Sobrien for (i = 0; i < 2; i++) { 738159764Sobrien s = splhigh(); 739159764Sobrien outb(csr, SMC666_iCODE); 740169942Sobrien outb(csr, SMC666_iCODE); 741169942Sobrien splx(s); 742169942Sobrien 743159764Sobrien outb(csr, 0xd); 744186690Sobrien if (inb(cio) == 0x66) { 745169942Sobrien type = SMC_37C666GT; 746159764Sobrien break; 747267843Sdelphij } 748267843Sdelphij 749267843Sdelphij /* Another chance, CSR may be hard-configured to be at 0x370 */ 750267843Sdelphij csr = SMC666_CSR; 751267843Sdelphij } 752159764Sobrien 753159764Sobrienconfig: 754159764Sobrien /* 755159764Sobrien * If chipset not found, do not continue. 756159764Sobrien */ 757159764Sobrien if (type == -1) 758159764Sobrien return (-1); 759159764Sobrien 760175296Sobrien /* select CR1 */ 761175296Sobrien outb(csr, 0x1); 762175296Sobrien 763169942Sobrien /* read the port's address: bits 0 and 1 of CR1 */ 764169942Sobrien r = inb(cio) & SMC_CR1_ADDR; 765159764Sobrien if (port_address[(int)r] != ppc->ppc_base) 766169942Sobrien return (-1); 767169942Sobrien 768169942Sobrien ppc->ppc_model = type; 769169942Sobrien 770169942Sobrien /* 771169942Sobrien * CR1 and CR4 registers bits 3 and 0/1 for mode configuration 772169942Sobrien * If SPP mode is detected, try to set ECP+EPP mode 773169942Sobrien */ 774169942Sobrien 775267843Sdelphij if (bootverbose) { 776267843Sdelphij outb(csr, 0x1); 777267843Sdelphij printf("ppc%d: SMC registers CR1=0x%x", ppc->ppc_unit, 778175296Sobrien inb(cio) & 0xff); 779175296Sobrien 780175296Sobrien outb(csr, 0x4); 781169942Sobrien printf(" CR4=0x%x", inb(cio) & 0xff); 782169942Sobrien } 783169942Sobrien 784267843Sdelphij /* select CR1 */ 785267843Sdelphij outb(csr, 0x1); 786267843Sdelphij 787267843Sdelphij if (!chipset_mode) { 788267843Sdelphij /* autodetect mode */ 789159764Sobrien 790169942Sobrien /* 666GT is ~certainly~ hardwired to an extended ECP+EPP mode */ 791169942Sobrien if (type == SMC_37C666GT) { 792159764Sobrien ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP; 793169942Sobrien if (bootverbose) 794169942Sobrien printf(" configuration hardwired, supposing " \ 795169942Sobrien "ECP+EPP SPP"); 796186690Sobrien 797169942Sobrien } else 798169942Sobrien if ((inb(cio) & SMC_CR1_MODE) == 0) { 799169942Sobrien /* already in extended parallel port mode, read CR4 */ 800169942Sobrien outb(csr, 0x4); 801169942Sobrien r = (inb(cio) & SMC_CR4_EMODE); 802169942Sobrien 803169942Sobrien switch (r) { 804169942Sobrien case SMC_SPP: 805169942Sobrien ppc->ppc_avm |= PPB_SPP; 806169942Sobrien if (bootverbose) 807169942Sobrien printf(" SPP"); 808169942Sobrien break; 809169942Sobrien 810169942Sobrien case SMC_EPPSPP: 811169942Sobrien ppc->ppc_avm |= PPB_EPP | PPB_SPP; 812169942Sobrien if (bootverbose) 813169942Sobrien printf(" EPP SPP"); 814169942Sobrien break; 815169942Sobrien 816169942Sobrien case SMC_ECP: 817169942Sobrien ppc->ppc_avm |= PPB_ECP | PPB_SPP; 818169962Sobrien if (bootverbose) 819169962Sobrien printf(" ECP SPP"); 820169962Sobrien break; 821169962Sobrien 822186690Sobrien case SMC_ECPEPP: 823186690Sobrien ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP; 824186690Sobrien if (bootverbose) 825186690Sobrien printf(" ECP+EPP SPP"); 826186690Sobrien break; 827186690Sobrien } 828186690Sobrien } else { 829186690Sobrien /* not an extended port mode */ 830186690Sobrien ppc->ppc_avm |= PPB_SPP; 831186690Sobrien if (bootverbose) 832186690Sobrien printf(" SPP"); 833186690Sobrien } 834186690Sobrien 835186690Sobrien } else { 836186690Sobrien /* mode forced */ 837186690Sobrien ppc->ppc_avm = chipset_mode; 838186690Sobrien 839186690Sobrien /* 666GT is ~certainly~ hardwired to an extended ECP+EPP mode */ 840186690Sobrien if (type == SMC_37C666GT) 841186690Sobrien goto end_detect; 842186690Sobrien 843186690Sobrien r = inb(cio); 844186690Sobrien if ((chipset_mode & (PPB_ECP | PPB_EPP)) == 0) { 845186690Sobrien /* do not use ECP when the mode is not forced to */ 846186690Sobrien outb(cio, r | SMC_CR1_MODE); 847169942Sobrien if (bootverbose) 848159764Sobrien printf(" SPP"); 849159764Sobrien } else { 850169942Sobrien /* an extended mode is selected */ 851169942Sobrien outb(cio, r & ~SMC_CR1_MODE); 852169942Sobrien 853159764Sobrien /* read CR4 register and reset mode field */ 854159764Sobrien outb(csr, 0x4); 855159764Sobrien r = inb(cio) & ~SMC_CR4_EMODE; 856186690Sobrien 857186690Sobrien if (chipset_mode & PPB_ECP) { 858159764Sobrien if (chipset_mode & PPB_EPP) { 859159764Sobrien outb(cio, r | SMC_ECPEPP); 860159764Sobrien if (bootverbose) 861159764Sobrien printf(" ECP+EPP"); 862159764Sobrien } else { 863159764Sobrien outb(cio, r | SMC_ECP); 864159764Sobrien if (bootverbose) 865159764Sobrien printf(" ECP"); 866159764Sobrien } 867159764Sobrien } else { 868226048Sobrien /* PPB_EPP is set */ 869226048Sobrien outb(cio, r | SMC_EPPSPP); 870226048Sobrien if (bootverbose) 871186690Sobrien printf(" EPP SPP"); 872226048Sobrien } 873226048Sobrien } 874226048Sobrien ppc->ppc_avm = chipset_mode; 875226048Sobrien } 876226048Sobrien 877226048Sobrien /* set FIFO threshold to 16 */ 878226048Sobrien if (ppc->ppc_avm & PPB_ECP) { 879226048Sobrien /* select CRA */ 880226048Sobrien outb(csr, 0xa); 881226048Sobrien outb(cio, 16); 882226048Sobrien } 883226048Sobrien 884226048Sobrienend_detect: 885226048Sobrien 886226048Sobrien if (bootverbose) 887226048Sobrien printf ("\n"); 888226048Sobrien 889226048Sobrien if (ppc->ppc_avm & PPB_EPP) { 890226048Sobrien /* select CR4 */ 891226048Sobrien outb(csr, 0x4); 892226048Sobrien r = inb(cio); 893226048Sobrien 894226048Sobrien /* 895226048Sobrien * Set the EPP protocol... 896226048Sobrien * Low=EPP 1.9 (1284 standard) and High=EPP 1.7 897226048Sobrien */ 898226048Sobrien if (ppc->ppc_epp == EPP_1_9) 899226048Sobrien outb(cio, (r & ~SMC_CR4_EPPTYPE)); 900226048Sobrien else 901226048Sobrien outb(cio, (r | SMC_CR4_EPPTYPE)); 902226048Sobrien } 903226048Sobrien 904226048Sobrien /* end config mode */ 905226048Sobrien outb(csr, 0xaa); 906186690Sobrien 907186690Sobrien ppc->ppc_type = PPC_TYPE_SMCLIKE; 908186690Sobrien ppc_smclike_setmode(ppc, chipset_mode); 909186690Sobrien 910186690Sobrien return (chipset_mode); 911186690Sobrien} 912186690Sobrien 913186690Sobrien/* 914186690Sobrien * SMC FDC37C935 configuration 915186690Sobrien * Found on many Alpha machines 916186690Sobrien */ 917186690Sobrienstatic int 918186690Sobrienppc_smc37c935_detect(struct ppc_data *ppc, int chipset_mode) 919186690Sobrien{ 920186690Sobrien int s; 921186690Sobrien int type = -1; 922186690Sobrien 923186690Sobrien s = splhigh(); 924186690Sobrien outb(SMC935_CFG, 0x55); /* enter config mode */ 925186690Sobrien outb(SMC935_CFG, 0x55); 926186690Sobrien splx(s); 927186690Sobrien 928186690Sobrien outb(SMC935_IND, SMC935_ID); /* check device id */ 929186690Sobrien if (inb(SMC935_DAT) == 0x2) 930186690Sobrien type = SMC_37C935; 931186690Sobrien 932186690Sobrien if (type == -1) { 933186690Sobrien outb(SMC935_CFG, 0xaa); /* exit config mode */ 934267843Sdelphij return (-1); 935267843Sdelphij } 936267843Sdelphij 937186690Sobrien ppc->ppc_model = type; 938186690Sobrien 939186690Sobrien outb(SMC935_IND, SMC935_LOGDEV); /* select parallel port, */ 940186690Sobrien outb(SMC935_DAT, 3); /* which is logical device 3 */ 941186690Sobrien 942186690Sobrien /* set io port base */ 943226048Sobrien outb(SMC935_IND, SMC935_PORTHI); 944226048Sobrien outb(SMC935_DAT, (u_char)((ppc->ppc_base & 0xff00) >> 8)); 945186690Sobrien outb(SMC935_IND, SMC935_PORTLO); 946186690Sobrien outb(SMC935_DAT, (u_char)(ppc->ppc_base & 0xff)); 947186690Sobrien 948186690Sobrien if (!chipset_mode) 949226048Sobrien ppc->ppc_avm = PPB_COMPATIBLE; /* default mode */ 950226048Sobrien else { 951226048Sobrien ppc->ppc_avm = chipset_mode; 952226048Sobrien outb(SMC935_IND, SMC935_PPMODE); 953226048Sobrien outb(SMC935_DAT, SMC935_CENT); /* start in compatible mode */ 954186690Sobrien 955186690Sobrien /* SPP + EPP or just plain SPP */ 956186690Sobrien if (chipset_mode & (PPB_SPP)) { 957226048Sobrien if (chipset_mode & PPB_EPP) { 958226048Sobrien if (ppc->ppc_epp == EPP_1_9) { 959226048Sobrien outb(SMC935_IND, SMC935_PPMODE); 960226048Sobrien outb(SMC935_DAT, SMC935_EPP19SPP); 961226048Sobrien } 962226048Sobrien if (ppc->ppc_epp == EPP_1_7) { 963226048Sobrien outb(SMC935_IND, SMC935_PPMODE); 964226048Sobrien outb(SMC935_DAT, SMC935_EPP17SPP); 965226048Sobrien } 966186690Sobrien } else { 967191736Sobrien outb(SMC935_IND, SMC935_PPMODE); 968191736Sobrien outb(SMC935_DAT, SMC935_SPP); 969186690Sobrien } 970226048Sobrien } 971226048Sobrien 972186690Sobrien /* ECP + EPP or just plain ECP */ 973186690Sobrien if (chipset_mode & PPB_ECP) { 974186690Sobrien if (chipset_mode & PPB_EPP) { 975186690Sobrien if (ppc->ppc_epp == EPP_1_9) { 976186690Sobrien outb(SMC935_IND, SMC935_PPMODE); 977186690Sobrien outb(SMC935_DAT, SMC935_ECPEPP19); 978186690Sobrien } 979186690Sobrien if (ppc->ppc_epp == EPP_1_7) { 980186690Sobrien outb(SMC935_IND, SMC935_PPMODE); 981186690Sobrien outb(SMC935_DAT, SMC935_ECPEPP17); 982186690Sobrien } 983186690Sobrien } else { 984267843Sdelphij outb(SMC935_IND, SMC935_PPMODE); 985267843Sdelphij outb(SMC935_DAT, SMC935_ECP); 986267843Sdelphij } 987267843Sdelphij } 988267843Sdelphij } 989267843Sdelphij 990267843Sdelphij outb(SMC935_CFG, 0xaa); /* exit config mode */ 991267843Sdelphij 992267843Sdelphij ppc->ppc_type = PPC_TYPE_SMCLIKE; 993267843Sdelphij ppc_smclike_setmode(ppc, chipset_mode); 994267843Sdelphij 995267843Sdelphij return (chipset_mode); 996267843Sdelphij} 997267843Sdelphij 998267843Sdelphij/* 999267843Sdelphij * Winbond W83877F stuff 1000267843Sdelphij * 1001267843Sdelphij * EFER: extended function enable register 1002267843Sdelphij * EFIR: extended function index register 1003267843Sdelphij * EFDR: extended function data register 1004267843Sdelphij */ 1005267843Sdelphij#define efir ((efer == 0x250) ? 0x251 : 0x3f0) 1006267843Sdelphij#define efdr ((efer == 0x250) ? 0x252 : 0x3f1) 1007267843Sdelphij 100874784Sobrienstatic int w83877f_efers[] = { 0x250, 0x3f0, 0x3f0, 0x250 }; 1009186690Sobrienstatic int w83877f_keys[] = { 0x89, 0x86, 0x87, 0x88 }; 101074784Sobrienstatic int w83877f_keyiter[] = { 1, 2, 2, 1 }; 1011186690Sobrienstatic int w83877f_hefs[] = { WINB_HEFERE, WINB_HEFRAS, WINB_HEFERE | WINB_HEFRAS, 0 }; 1012186690Sobrien 1013267843Sdelphijstatic int 1014186690Sobrienppc_w83877f_detect(struct ppc_data *ppc, int chipset_mode) 1015226048Sobrien{ 1016226048Sobrien int i, j, efer; 1017226048Sobrien unsigned char r, hefere, hefras; 1018267843Sdelphij 1019226048Sobrien for (i = 0; i < 4; i ++) { 1020186690Sobrien /* first try to enable configuration registers */ 1021186690Sobrien efer = w83877f_efers[i]; 1022186690Sobrien 1023186690Sobrien /* write the key to the EFER */ 1024186690Sobrien for (j = 0; j < w83877f_keyiter[i]; j ++) 1025186690Sobrien outb (efer, w83877f_keys[i]); 1026226048Sobrien 1027226048Sobrien /* then check HEFERE and HEFRAS bits */ 1028226048Sobrien outb (efir, 0x0c); 1029267843Sdelphij hefere = inb(efdr) & WINB_HEFERE; 1030226048Sobrien 1031226048Sobrien outb (efir, 0x16); 1032226048Sobrien hefras = inb(efdr) & WINB_HEFRAS; 1033226048Sobrien 1034226048Sobrien /* 1035226048Sobrien * HEFRAS HEFERE 1036226048Sobrien * 0 1 write 89h to 250h (power-on default) 1037226048Sobrien * 1 0 write 86h twice to 3f0h 1038226048Sobrien * 1 1 write 87h twice to 3f0h 1039226048Sobrien * 0 0 write 88h to 250h 1040226048Sobrien */ 1041226048Sobrien if ((hefere | hefras) == w83877f_hefs[i]) 1042226048Sobrien goto found; 1043226048Sobrien } 1044226048Sobrien 1045186690Sobrien return (-1); /* failed */ 1046186690Sobrien 1047186690Sobrienfound: 1048226048Sobrien /* check base port address - read from CR23 */ 1049186690Sobrien outb(efir, 0x23); 1050186690Sobrien if (ppc->ppc_base != inb(efdr) * 4) /* 4 bytes boundaries */ 1051186690Sobrien return (-1); 1052186690Sobrien 1053186690Sobrien /* read CHIP ID from CR9/bits0-3 */ 1054186690Sobrien outb(efir, 0x9); 1055186690Sobrien 1056186690Sobrien switch (inb(efdr) & WINB_CHIPID) { 1057186690Sobrien case WINB_W83877F_ID: 1058186690Sobrien ppc->ppc_model = WINB_W83877F; 1059267843Sdelphij break; 1060186690Sobrien 1061186690Sobrien case WINB_W83877AF_ID: 1062186690Sobrien ppc->ppc_model = WINB_W83877AF; 1063186690Sobrien break; 1064186690Sobrien 1065186690Sobrien default: 1066267843Sdelphij ppc->ppc_model = WINB_UNKNOWN; 1067186690Sobrien } 1068186690Sobrien 1069186690Sobrien if (bootverbose) { 1070186690Sobrien /* dump of registers */ 1071186690Sobrien printf("ppc%d: 0x%x - ", ppc->ppc_unit, w83877f_keys[i]); 1072186690Sobrien for (i = 0; i <= 0xd; i ++) { 1073226048Sobrien outb(efir, i); 1074226048Sobrien printf("0x%x ", inb(efdr)); 1075267843Sdelphij } 1076267843Sdelphij for (i = 0x10; i <= 0x17; i ++) { 1077267843Sdelphij outb(efir, i); 1078267843Sdelphij printf("0x%x ", inb(efdr)); 1079267843Sdelphij } 1080267843Sdelphij outb(efir, 0x1e); 1081267843Sdelphij printf("0x%x ", inb(efdr)); 1082267843Sdelphij for (i = 0x20; i <= 0x29; i ++) { 1083186690Sobrien outb(efir, i); 1084267843Sdelphij printf("0x%x ", inb(efdr)); 1085267843Sdelphij } 1086186690Sobrien printf("\n"); 1087186690Sobrien printf("ppc%d:", ppc->ppc_unit); 1088267843Sdelphij } 1089267843Sdelphij 1090234250Sobrien ppc->ppc_type = PPC_TYPE_GENERIC; 1091226048Sobrien 1092186690Sobrien if (!chipset_mode) { 1093186690Sobrien /* autodetect mode */ 1094186690Sobrien 1095186690Sobrien /* select CR0 */ 1096186690Sobrien outb(efir, 0x0); 1097186690Sobrien r = inb(efdr) & (WINB_PRTMODS0 | WINB_PRTMODS1); 1098133359Sobrien 1099226048Sobrien /* select CR9 */ 1100226048Sobrien outb(efir, 0x9); 1101226048Sobrien r |= (inb(efdr) & WINB_PRTMODS2); 1102226048Sobrien 1103226048Sobrien switch (r) { 1104267843Sdelphij case WINB_W83757: 1105267843Sdelphij if (bootverbose) 1106267843Sdelphij printf("ppc%d: W83757 compatible mode\n", 1107267843Sdelphij ppc->ppc_unit); 1108267843Sdelphij return (-1); /* generic or SMC-like */ 1109267843Sdelphij 1110267843Sdelphij case WINB_EXTFDC: 1111267843Sdelphij case WINB_EXTADP: 1112267843Sdelphij case WINB_EXT2FDD: 1113267843Sdelphij case WINB_JOYSTICK: 1114267843Sdelphij if (bootverbose) 1115267843Sdelphij printf(" not in parallel port mode\n"); 1116267843Sdelphij return (-1); 1117267843Sdelphij 1118267843Sdelphij case (WINB_PARALLEL | WINB_EPP_SPP): 1119267843Sdelphij ppc->ppc_avm |= PPB_EPP | PPB_SPP; 1120267843Sdelphij if (bootverbose) 1121267843Sdelphij printf(" EPP SPP"); 1122267843Sdelphij break; 1123267843Sdelphij 1124267843Sdelphij case (WINB_PARALLEL | WINB_ECP): 1125267843Sdelphij ppc->ppc_avm |= PPB_ECP | PPB_SPP; 1126267843Sdelphij if (bootverbose) 1127267843Sdelphij printf(" ECP SPP"); 1128267843Sdelphij break; 1129267843Sdelphij 1130267843Sdelphij case (WINB_PARALLEL | WINB_ECP_EPP): 1131267843Sdelphij ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP; 1132267843Sdelphij ppc->ppc_type = PPC_TYPE_SMCLIKE; 1133267843Sdelphij 1134267843Sdelphij if (bootverbose) 1135267843Sdelphij printf(" ECP+EPP SPP"); 1136267843Sdelphij break; 1137267843Sdelphij default: 1138267843Sdelphij printf("%s: unknown case (0x%x)!\n", __func__, r); 1139267843Sdelphij } 1140267843Sdelphij 1141267843Sdelphij } else { 1142267843Sdelphij /* mode forced */ 1143267843Sdelphij 1144267843Sdelphij /* select CR9 and set PRTMODS2 bit */ 1145267843Sdelphij outb(efir, 0x9); 1146267843Sdelphij outb(efdr, inb(efdr) & ~WINB_PRTMODS2); 1147267843Sdelphij 1148267843Sdelphij /* select CR0 and reset PRTMODSx bits */ 1149267843Sdelphij outb(efir, 0x0); 1150267843Sdelphij outb(efdr, inb(efdr) & ~(WINB_PRTMODS0 | WINB_PRTMODS1)); 1151267843Sdelphij 1152267843Sdelphij if (chipset_mode & PPB_ECP) { 1153267843Sdelphij if (chipset_mode & PPB_EPP) { 1154267843Sdelphij outb(efdr, inb(efdr) | WINB_ECP_EPP); 1155267843Sdelphij if (bootverbose) 1156267843Sdelphij printf(" ECP+EPP"); 1157267843Sdelphij 1158267843Sdelphij ppc->ppc_type = PPC_TYPE_SMCLIKE; 1159226048Sobrien 1160267843Sdelphij } else { 1161267843Sdelphij outb(efdr, inb(efdr) | WINB_ECP); 116268349Sobrien if (bootverbose) 1163267843Sdelphij printf(" ECP"); 1164267843Sdelphij } 1165267843Sdelphij } else { 1166267843Sdelphij /* select EPP_SPP otherwise */ 1167267843Sdelphij outb(efdr, inb(efdr) | WINB_EPP_SPP); 1168267843Sdelphij if (bootverbose) 1169267843Sdelphij printf(" EPP SPP"); 1170267843Sdelphij } 1171267843Sdelphij ppc->ppc_avm = chipset_mode; 1172267843Sdelphij } 1173267843Sdelphij 1174267843Sdelphij if (bootverbose) 1175267843Sdelphij printf("\n"); 1176267843Sdelphij 1177267843Sdelphij /* exit configuration mode */ 1178267843Sdelphij outb(efer, 0xaa); 1179267843Sdelphij 1180267843Sdelphij switch (ppc->ppc_type) { 1181267843Sdelphij case PPC_TYPE_SMCLIKE: 1182267843Sdelphij ppc_smclike_setmode(ppc, chipset_mode); 1183267843Sdelphij break; 1184267843Sdelphij default: 1185267843Sdelphij ppc_generic_setmode(ppc, chipset_mode); 1186267843Sdelphij break; 1187267843Sdelphij } 1188267843Sdelphij 1189267843Sdelphij return (chipset_mode); 1190267843Sdelphij} 1191267843Sdelphij#endif 1192267843Sdelphij 1193267843Sdelphij/* 1194267843Sdelphij * ppc_generic_detect 1195267843Sdelphij */ 1196267843Sdelphijstatic int 1197267843Sdelphijppc_generic_detect(struct ppc_data *ppc, int chipset_mode) 1198267843Sdelphij{ 119968349Sobrien /* default to generic */ 1200267843Sdelphij ppc->ppc_type = PPC_TYPE_GENERIC; 1201267843Sdelphij 1202226048Sobrien if (bootverbose) 1203186690Sobrien printf("ppc%d:", ppc->ppc_unit); 1204267843Sdelphij 1205267843Sdelphij /* first, check for ECP */ 1206186690Sobrien w_ecr(ppc, PPC_ECR_PS2); 1207186690Sobrien if ((r_ecr(ppc) & 0xe0) == PPC_ECR_PS2) { 120868349Sobrien ppc->ppc_dtm |= PPB_ECP | PPB_SPP; 1209267843Sdelphij if (bootverbose) 1210169942Sobrien printf(" ECP SPP"); 1211169942Sobrien 1212267843Sdelphij /* search for SMC style ECP+EPP mode */ 1213267843Sdelphij w_ecr(ppc, PPC_ECR_EPP); 1214267843Sdelphij } 1215267843Sdelphij 1216267843Sdelphij /* try to reset EPP timeout bit */ 121774784Sobrien if (ppc_check_epp_timeout(ppc)) { 121874784Sobrien ppc->ppc_dtm |= PPB_EPP; 1219133359Sobrien 1220133359Sobrien if (ppc->ppc_dtm & PPB_ECP) { 1221186690Sobrien /* SMC like chipset found */ 1222133359Sobrien ppc->ppc_model = SMC_LIKE; 1223186690Sobrien ppc->ppc_type = PPC_TYPE_SMCLIKE; 1224186690Sobrien 1225186690Sobrien if (bootverbose) 1226226048Sobrien printf(" ECP+EPP"); 1227226048Sobrien } else { 1228226048Sobrien if (bootverbose) 1229226048Sobrien printf(" EPP"); 1230226048Sobrien } 1231226048Sobrien } else { 1232226048Sobrien /* restore to standard mode */ 1233226048Sobrien w_ecr(ppc, PPC_ECR_STD); 1234226048Sobrien } 1235234250Sobrien 1236226048Sobrien /* XXX try to detect NIBBLE and PS2 modes */ 1237226048Sobrien ppc->ppc_dtm |= PPB_NIBBLE; 1238226048Sobrien 1239226048Sobrien if (bootverbose) 1240226048Sobrien printf(" SPP"); 1241226048Sobrien 1242226048Sobrien if (chipset_mode) 1243226048Sobrien ppc->ppc_avm = chipset_mode; 1244226048Sobrien else 1245226048Sobrien ppc->ppc_avm = ppc->ppc_dtm; 1246226048Sobrien 1247226048Sobrien if (bootverbose) 1248226048Sobrien printf("\n"); 1249226048Sobrien 1250234250Sobrien switch (ppc->ppc_type) { 1251226048Sobrien case PPC_TYPE_SMCLIKE: 1252226048Sobrien ppc_smclike_setmode(ppc, chipset_mode); 1253186690Sobrien break; 1254186690Sobrien default: 1255226048Sobrien ppc_generic_setmode(ppc, chipset_mode); 1256226048Sobrien break; 1257226048Sobrien } 1258226048Sobrien 1259226048Sobrien return (chipset_mode); 1260267843Sdelphij} 1261226048Sobrien 1262226048Sobrien/* 1263226048Sobrien * ppc_detect() 1264186690Sobrien * 1265267843Sdelphij * mode is the mode suggested at boot 1266186690Sobrien */ 1267186690Sobrienstatic int 1268186690Sobrienppc_detect(struct ppc_data *ppc, int chipset_mode) { 1269267843Sdelphij 1270267843Sdelphij#ifdef PPC_PROBE_CHIPSET 1271267843Sdelphij int i, mode; 1272267843Sdelphij 1273267843Sdelphij /* list of supported chipsets */ 1274186690Sobrien int (*chipset_detect[])(struct ppc_data *, int) = { 1275186690Sobrien ppc_pc873xx_detect, 1276267843Sdelphij ppc_smc37c66xgt_detect, 1277267843Sdelphij ppc_w83877f_detect, 1278267843Sdelphij ppc_smc37c935_detect, 1279267843Sdelphij ppc_generic_detect, 128068349Sobrien NULL 1281267843Sdelphij }; 1282267843Sdelphij#endif 1283267843Sdelphij 1284267843Sdelphij /* if can't find the port and mode not forced return error */ 1285267843Sdelphij if (!ppc_detect_port(ppc) && chipset_mode == 0) 1286159764Sobrien return (EIO); /* failed, port not present */ 1287267843Sdelphij 1288267843Sdelphij /* assume centronics compatible mode is supported */ 1289267843Sdelphij ppc->ppc_avm = PPB_COMPATIBLE; 1290267843Sdelphij 1291267843Sdelphij#ifdef PPC_PROBE_CHIPSET 1292169962Sobrien /* we have to differenciate available chipset modes, 1293169962Sobrien * chipset running modes and IEEE-1284 operating modes 1294159764Sobrien * 1295267843Sdelphij * after detection, the port must support running in compatible mode 1296267843Sdelphij */ 1297267843Sdelphij if (ppc->ppc_flags & 0x40) { 1298159764Sobrien if (bootverbose) 129974784Sobrien printf("ppc: chipset forced to generic\n"); 1300267843Sdelphij#endif 1301267843Sdelphij 130274784Sobrien ppc->ppc_mode = ppc_generic_detect(ppc, chipset_mode); 1303267843Sdelphij 130468349Sobrien#ifdef PPC_PROBE_CHIPSET 130568349Sobrien } else { 130668349Sobrien for (i=0; chipset_detect[i] != NULL; i++) { 130768349Sobrien if ((mode = chipset_detect[i](ppc, chipset_mode)) != -1) { 130868349Sobrien ppc->ppc_mode = mode; 1309169942Sobrien break; 1310169942Sobrien } 131168349Sobrien } 1312169962Sobrien } 131368349Sobrien#endif 131468349Sobrien 131568349Sobrien /* configure/detect ECP FIFO */ 131668349Sobrien if ((ppc->ppc_avm & PPB_ECP) && !(ppc->ppc_flags & 0x80)) 131768349Sobrien ppc_detect_fifo(ppc); 131868349Sobrien 1319133359Sobrien return (0); 132068349Sobrien} 132168349Sobrien 1322133359Sobrien/* 1323133359Sobrien * ppc_exec_microseq() 1324133359Sobrien * 132568349Sobrien * Execute a microsequence. 132668349Sobrien * Microsequence mechanism is supposed to handle fast I/O operations. 1327133359Sobrien */ 1328133359Sobrienint 1329133359Sobrienppc_exec_microseq(device_t dev, struct ppb_microseq **p_msq) 1330159764Sobrien{ 1331133359Sobrien struct ppc_data *ppc = DEVTOSOFTC(dev); 1332133359Sobrien struct ppb_microseq *mi; 1333133359Sobrien char cc, *p; 1334159764Sobrien int i, iter, len; 1335133359Sobrien int error; 1336133359Sobrien 1337133359Sobrien register int reg; 1338159764Sobrien register char mask; 1339175296Sobrien register int accum = 0; 1340175296Sobrien register char *ptr = 0; 1341175296Sobrien 1342103373Sobrien struct ppb_microseq *stack = 0; 134368349Sobrien 1344169942Sobrien/* microsequence registers are equivalent to PC-like port registers */ 1345169942Sobrien 1346169942Sobrien#define r_reg(reg,ppc) (bus_space_read_1((ppc)->bst, (ppc)->bsh, reg)) 1347169942Sobrien#define w_reg(reg, ppc, byte) (bus_space_write_1((ppc)->bst, (ppc)->bsh, reg, byte)) 1348169942Sobrien 1349267843Sdelphij#define INCR_PC (mi ++) /* increment program counter */ 1350169942Sobrien 1351169942Sobrien mi = *p_msq; 1352267843Sdelphij for (;;) { 1353169942Sobrien switch (mi->opcode) { 1354169942Sobrien case MS_OP_RSET: 1355267843Sdelphij cc = r_reg(mi->arg[0].i, ppc); 1356175296Sobrien cc &= (char)mi->arg[2].i; /* clear mask */ 1357175296Sobrien cc |= (char)mi->arg[1].i; /* assert mask */ 1358175296Sobrien w_reg(mi->arg[0].i, ppc, cc); 1359169942Sobrien INCR_PC; 1360169942Sobrien break; 1361133359Sobrien 1362133359Sobrien case MS_OP_RASSERT_P: 1363139368Sobrien reg = mi->arg[1].i; 1364139368Sobrien ptr = ppc->ppc_ptr; 1365133359Sobrien 1366159764Sobrien if ((len = mi->arg[0].i) == MS_ACCUM) { 1367169962Sobrien accum = ppc->ppc_accum; 1368191736Sobrien for (; accum; accum--) 1369267843Sdelphij w_reg(reg, ppc, *ptr++); 1370267843Sdelphij ppc->ppc_accum = accum; 1371267843Sdelphij } else 1372103373Sobrien for (i=0; i<len; i++) 137368349Sobrien w_reg(reg, ppc, *ptr++); 1374133359Sobrien ppc->ppc_ptr = ptr; 1375139368Sobrien 1376133359Sobrien INCR_PC; 1377133359Sobrien break; 137868349Sobrien 1379169962Sobrien case MS_OP_RFETCH_P: 138068349Sobrien reg = mi->arg[1].i; 138168349Sobrien mask = (char)mi->arg[2].i; 138268349Sobrien ptr = ppc->ppc_ptr; 1383169962Sobrien 1384186690Sobrien if ((len = mi->arg[0].i) == MS_ACCUM) { 1385169962Sobrien accum = ppc->ppc_accum; 1386169962Sobrien for (; accum; accum--) 1387169962Sobrien *ptr++ = r_reg(reg, ppc) & mask; 1388169962Sobrien ppc->ppc_accum = accum; 1389267843Sdelphij } else 1390267843Sdelphij for (i=0; i<len; i++) 1391226048Sobrien *ptr++ = r_reg(reg, ppc) & mask; 1392226048Sobrien ppc->ppc_ptr = ptr; 1393226048Sobrien 1394226048Sobrien INCR_PC; 1395169962Sobrien break; 1396169962Sobrien 1397169962Sobrien case MS_OP_RFETCH: 1398169962Sobrien *((char *) mi->arg[2].p) = r_reg(mi->arg[0].i, ppc) & 1399186690Sobrien (char)mi->arg[1].i; 1400186690Sobrien INCR_PC; 1401169962Sobrien break; 1402169962Sobrien 1403169962Sobrien case MS_OP_RASSERT: 1404169962Sobrien case MS_OP_DELAY: 1405169962Sobrien 1406169962Sobrien /* let's suppose the next instr. is the same */ 1407186690Sobrien prefetch: 1408186690Sobrien for (;mi->opcode == MS_OP_RASSERT; INCR_PC) 1409169962Sobrien w_reg(mi->arg[0].i, ppc, (char)mi->arg[1].i); 1410169962Sobrien 1411169962Sobrien if (mi->opcode == MS_OP_DELAY) { 1412169962Sobrien DELAY(mi->arg[0].i); 1413169962Sobrien INCR_PC; 1414186690Sobrien goto prefetch; 1415186690Sobrien } 1416186690Sobrien break; 1417186690Sobrien 1418186690Sobrien case MS_OP_ADELAY: 1419186690Sobrien if (mi->arg[0].i) 1420186690Sobrien tsleep(NULL, PPBPRI, "ppbdelay", 1421169962Sobrien mi->arg[0].i * (hz/1000)); 1422169962Sobrien INCR_PC; 1423226048Sobrien break; 1424169962Sobrien 1425226048Sobrien case MS_OP_TRIG: 1426169962Sobrien reg = mi->arg[0].i; 1427169962Sobrien iter = mi->arg[1].i; 1428226048Sobrien p = (char *)mi->arg[2].p; 1429169962Sobrien 1430226048Sobrien /* XXX delay limited to 255 us */ 1431169962Sobrien for (i=0; i<iter; i++) { 1432169962Sobrien w_reg(reg, ppc, *p++); 1433169962Sobrien DELAY((unsigned char)*p++); 1434169962Sobrien } 1435169962Sobrien INCR_PC; 1436169962Sobrien break; 1437169962Sobrien 1438169962Sobrien case MS_OP_SET: 1439169962Sobrien ppc->ppc_accum = mi->arg[0].i; 1440169962Sobrien INCR_PC; 1441169962Sobrien break; 1442169962Sobrien 1443169962Sobrien case MS_OP_DBRA: 1444169962Sobrien if (--ppc->ppc_accum > 0) 1445169962Sobrien mi += mi->arg[0].i; 1446169962Sobrien INCR_PC; 1447169962Sobrien break; 1448169962Sobrien 1449169962Sobrien case MS_OP_BRSET: 1450169962Sobrien cc = r_str(ppc); 1451169962Sobrien if ((cc & (char)mi->arg[0].i) == (char)mi->arg[0].i) 1452169962Sobrien mi += mi->arg[1].i; 1453169962Sobrien INCR_PC; 1454169962Sobrien break; 1455169962Sobrien 1456169962Sobrien case MS_OP_BRCLEAR: 1457169962Sobrien cc = r_str(ppc); 1458169962Sobrien if ((cc & (char)mi->arg[0].i) == 0) 1459169962Sobrien mi += mi->arg[1].i; 1460169962Sobrien INCR_PC; 1461169962Sobrien break; 1462169962Sobrien 1463169962Sobrien case MS_OP_BRSTAT: 1464169962Sobrien cc = r_str(ppc); 1465169962Sobrien if ((cc & ((char)mi->arg[0].i | (char)mi->arg[1].i)) == 1466169962Sobrien (char)mi->arg[0].i) 1467169962Sobrien mi += mi->arg[2].i; 1468169962Sobrien INCR_PC; 1469169962Sobrien break; 1470169962Sobrien 1471186690Sobrien case MS_OP_C_CALL: 1472186690Sobrien /* 1473186690Sobrien * If the C call returns !0 then end the microseq. 1474186690Sobrien * The current state of ptr is passed to the C function 1475169962Sobrien */ 1476169962Sobrien if ((error = mi->arg[0].f(mi->arg[1].p, ppc->ppc_ptr))) 1477169962Sobrien return (error); 1478169962Sobrien 1479186690Sobrien INCR_PC; 1480169962Sobrien break; 1481186690Sobrien 1482169962Sobrien case MS_OP_PTR: 1483186690Sobrien ppc->ppc_ptr = (char *)mi->arg[0].p; 1484169962Sobrien INCR_PC; 1485169962Sobrien break; 1486169962Sobrien 1487169962Sobrien case MS_OP_CALL: 1488169962Sobrien if (stack) 1489169962Sobrien panic("%s: too much calls", __func__); 1490169962Sobrien 1491169962Sobrien if (mi->arg[0].p) { 1492169962Sobrien /* store the state of the actual 1493169962Sobrien * microsequence 1494169962Sobrien */ 1495169962Sobrien stack = mi; 1496169962Sobrien 1497169962Sobrien /* jump to the new microsequence */ 1498169962Sobrien mi = (struct ppb_microseq *)mi->arg[0].p; 1499169962Sobrien } else 1500169962Sobrien INCR_PC; 1501169962Sobrien 1502169962Sobrien break; 1503169962Sobrien 1504169962Sobrien case MS_OP_SUBRET: 1505169962Sobrien /* retrieve microseq and pc state before the call */ 1506169962Sobrien mi = stack; 1507169962Sobrien 1508169962Sobrien /* reset the stack */ 1509169962Sobrien stack = 0; 1510169962Sobrien 1511169962Sobrien /* XXX return code */ 1512169962Sobrien 1513169962Sobrien INCR_PC; 1514169962Sobrien break; 1515169962Sobrien 1516169962Sobrien case MS_OP_PUT: 1517169962Sobrien case MS_OP_GET: 1518169962Sobrien case MS_OP_RET: 1519169962Sobrien /* can't return to ppb level during the execution 1520169962Sobrien * of a submicrosequence */ 1521169962Sobrien if (stack) 1522169962Sobrien panic("%s: can't return to ppb level", 1523169962Sobrien __func__); 1524169962Sobrien 1525169962Sobrien /* update pc for ppb level of execution */ 1526169962Sobrien *p_msq = mi; 1527169962Sobrien 1528169962Sobrien /* return to ppb level of execution */ 1529169962Sobrien return (0); 1530169962Sobrien 1531169962Sobrien default: 1532169962Sobrien panic("%s: unknown microsequence opcode 0x%x", 1533169962Sobrien __func__, mi->opcode); 1534169962Sobrien } 1535169962Sobrien } 1536169962Sobrien 1537169962Sobrien /* unreached */ 153868349Sobrien} 153968349Sobrien 154068349Sobrienstatic void 1541133359Sobrienppcintr(void *arg) 1542267843Sdelphij{ 1543267843Sdelphij device_t dev = (device_t)arg; 154468349Sobrien struct ppc_data *ppc = (struct ppc_data *)device_get_softc(dev); 1545169962Sobrien u_char ctr, ecr, str; 1546169962Sobrien 1547169962Sobrien str = r_str(ppc); 1548169942Sobrien ctr = r_ctr(ppc); 154968349Sobrien ecr = r_ecr(ppc); 1550159764Sobrien 155184685Sobrien#if PPC_DEBUG > 1 1552169962Sobrien printf("![%x/%x/%x]", ctr, ecr, str); 1553159825Sobrien#endif 1554267843Sdelphij 155568349Sobrien /* don't use ecp mode with IRQENABLE set */ 1556159764Sobrien if (ctr & IRQENABLE) { 155768349Sobrien return; 1558267843Sdelphij } 1559267843Sdelphij 1560267843Sdelphij /* interrupts are generated by nFault signal 156168349Sobrien * only in ECP mode */ 156268349Sobrien if ((str & nFAULT) && (ppc->ppc_mode & PPB_ECP)) { 1563159764Sobrien /* check if ppc driver has programmed the 156468349Sobrien * nFault interrupt */ 1565169962Sobrien if (ppc->ppc_irqstat & PPC_IRQ_nFAULT) { 1566169962Sobrien 1567169962Sobrien w_ecr(ppc, ecr | PPC_nFAULT_INTR); 1568169962Sobrien ppc->ppc_irqstat &= ~PPC_IRQ_nFAULT; 1569169962Sobrien } else { 1570169962Sobrien /* shall be handled by underlying layers XXX */ 1571159764Sobrien return; 1572267843Sdelphij } 1573267843Sdelphij } 1574159764Sobrien 1575159764Sobrien if (ppc->ppc_irqstat & PPC_IRQ_DMA) { 1576267843Sdelphij /* disable interrupts (should be done by hardware though) */ 1577267843Sdelphij w_ecr(ppc, ecr | PPC_SERVICE_INTR); 1578267843Sdelphij ppc->ppc_irqstat &= ~PPC_IRQ_DMA; 1579267843Sdelphij ecr = r_ecr(ppc); 1580267843Sdelphij 1581267843Sdelphij /* check if DMA completed */ 1582267843Sdelphij if ((ppc->ppc_avm & PPB_ECP) && (ecr & PPC_ENABLE_DMA)) { 1583267843Sdelphij#ifdef PPC_DEBUG 1584267843Sdelphij printf("a"); 1585267843Sdelphij#endif 1586159764Sobrien /* stop DMA */ 1587159764Sobrien w_ecr(ppc, ecr & ~PPC_ENABLE_DMA); 1588159764Sobrien ecr = r_ecr(ppc); 1589186690Sobrien 1590186690Sobrien if (ppc->ppc_dmastat == PPC_DMA_STARTED) { 1591169942Sobrien#ifdef PPC_DEBUG 1592159764Sobrien printf("d"); 1593159764Sobrien#endif 1594159764Sobrien isa_dmadone( 1595226048Sobrien ppc->ppc_dmaflags, 1596159764Sobrien ppc->ppc_dmaddr, 1597159764Sobrien ppc->ppc_dmacnt, 1598169962Sobrien ppc->ppc_dmachan); 1599159764Sobrien 1600159764Sobrien ppc->ppc_dmastat = PPC_DMA_COMPLETE; 1601267843Sdelphij 1602267843Sdelphij /* wakeup the waiting process */ 1603267843Sdelphij wakeup(ppc); 1604267843Sdelphij } 1605267843Sdelphij } 1606267843Sdelphij } else if (ppc->ppc_irqstat & PPC_IRQ_FIFO) { 1607159764Sobrien 1608267843Sdelphij /* classic interrupt I/O */ 1609267843Sdelphij ppc->ppc_irqstat &= ~PPC_IRQ_FIFO; 1610169962Sobrien } 1611186690Sobrien 1612159764Sobrien return; 1613159764Sobrien} 1614159764Sobrien 1615226048Sobrienint 1616159764Sobrienppc_read(device_t dev, char *buf, int len, int mode) 1617169962Sobrien{ 1618159764Sobrien return (EINVAL); 1619159764Sobrien} 1620159764Sobrien 1621169962Sobrien/* 162268349Sobrien * Call this function if you want to send data in any advanced mode 162368349Sobrien * of your parallel port: FIFO, DMA 1624159764Sobrien * 1625159764Sobrien * If what you want is not possible (no ECP, no DMA...), 1626169962Sobrien * EINVAL is returned 1627169962Sobrien */ 1628169962Sobrienint 1629169962Sobrienppc_write(device_t dev, char *buf, int len, int how) 1630169962Sobrien{ 163168349Sobrien struct ppc_data *ppc = DEVTOSOFTC(dev); 1632169962Sobrien char ecr, ecr_sav, ctr, ctr_sav; 1633169962Sobrien int s, error = 0; 1634169962Sobrien int spin; 1635169962Sobrien 163668349Sobrien#ifdef PPC_DEBUG 163768349Sobrien printf("w"); 1638133359Sobrien#endif 163968349Sobrien 1640133359Sobrien ecr_sav = r_ecr(ppc); 1641139368Sobrien ctr_sav = r_ctr(ppc); 164268349Sobrien 164368349Sobrien /* 164468349Sobrien * Send buffer with DMA, FIFO and interrupts 1645133359Sobrien */ 164674784Sobrien if ((ppc->ppc_avm & PPB_ECP) && (ppc->ppc_registered)) { 164768349Sobrien 164868349Sobrien if (ppc->ppc_dmachan > 0) { 164968349Sobrien 165068349Sobrien /* byte mode, no intr, no DMA, dir=0, flush fifo 165168349Sobrien */ 165268349Sobrien ecr = PPC_ECR_STD | PPC_DISABLE_INTR; 165368349Sobrien w_ecr(ppc, ecr); 1654133359Sobrien 165568349Sobrien /* disable nAck interrupts */ 165668349Sobrien ctr = r_ctr(ppc); 1657133359Sobrien ctr &= ~IRQENABLE; 165868349Sobrien w_ctr(ppc, ctr); 1659159764Sobrien 1660159764Sobrien ppc->ppc_dmaflags = 0; 1661159764Sobrien ppc->ppc_dmaddr = (caddr_t)buf; 166268349Sobrien ppc->ppc_dmacnt = (u_int)len; 166368349Sobrien 1664133359Sobrien switch (ppc->ppc_mode) { 166568349Sobrien case PPB_COMPATIBLE: 166668349Sobrien /* compatible mode with FIFO, no intr, DMA, dir=0 */ 166768349Sobrien ecr = PPC_ECR_FIFO | PPC_DISABLE_INTR | PPC_ENABLE_DMA; 1668133359Sobrien break; 166968349Sobrien case PPB_ECP: 167068349Sobrien ecr = PPC_ECR_ECP | PPC_DISABLE_INTR | PPC_ENABLE_DMA; 167168349Sobrien break; 167268349Sobrien default: 167368349Sobrien error = EINVAL; 1674133359Sobrien goto error; 167568349Sobrien } 1676175296Sobrien 1677175296Sobrien w_ecr(ppc, ecr); 1678175296Sobrien ecr = r_ecr(ppc); 1679175296Sobrien 1680175296Sobrien /* enter splhigh() not to be preempted 1681175296Sobrien * by the dma interrupt, we may miss 1682175296Sobrien * the wakeup otherwise 1683175296Sobrien */ 1684175296Sobrien s = splhigh(); 1685175296Sobrien 1686191736Sobrien ppc->ppc_dmastat = PPC_DMA_INIT; 1687191736Sobrien 1688191736Sobrien /* enable interrupts */ 1689191736Sobrien ecr &= ~PPC_SERVICE_INTR; 1690191736Sobrien ppc->ppc_irqstat = PPC_IRQ_DMA; 1691191736Sobrien w_ecr(ppc, ecr); 169268349Sobrien 1693133359Sobrien isa_dmastart( 1694139368Sobrien ppc->ppc_dmaflags, 1695139368Sobrien ppc->ppc_dmaddr, 1696133359Sobrien ppc->ppc_dmacnt, 169768349Sobrien ppc->ppc_dmachan); 169868349Sobrien#ifdef PPC_DEBUG 169968349Sobrien printf("s%d", ppc->ppc_dmacnt); 170068349Sobrien#endif 1701169962Sobrien ppc->ppc_dmastat = PPC_DMA_STARTED; 1702169962Sobrien 170380588Sobrien /* Wait for the DMA completed interrupt. We hope we won't 1704159764Sobrien * miss it, otherwise a signal will be necessary to unlock the 170580588Sobrien * process. 170680588Sobrien */ 1707169962Sobrien do { 1708169962Sobrien /* release CPU */ 170980588Sobrien error = tsleep(ppc, 171080588Sobrien PPBPRI | PCATCH, "ppcdma", 0); 1711159764Sobrien 1712159764Sobrien } while (error == EWOULDBLOCK); 1713159764Sobrien 1714159764Sobrien splx(s); 1715159764Sobrien 1716159764Sobrien if (error) { 1717169962Sobrien#ifdef PPC_DEBUG 1718169962Sobrien printf("i"); 1719169962Sobrien#endif 1720169962Sobrien /* stop DMA */ 1721159764Sobrien isa_dmadone( 1722159764Sobrien ppc->ppc_dmaflags, ppc->ppc_dmaddr, 1723159764Sobrien ppc->ppc_dmacnt, ppc->ppc_dmachan); 1724159764Sobrien 1725133359Sobrien /* no dma, no interrupt, flush the fifo */ 1726139368Sobrien w_ecr(ppc, PPC_ECR_RESET); 1727139368Sobrien 172868349Sobrien ppc->ppc_dmastat = PPC_DMA_INTERRUPTED; 1729169962Sobrien goto error; 173068349Sobrien } 1731169962Sobrien 1732169962Sobrien /* wait for an empty fifo */ 1733169962Sobrien while (!(r_ecr(ppc) & PPC_FIFO_EMPTY)) { 1734169962Sobrien 173568349Sobrien for (spin=100; spin; spin--) 173668349Sobrien if (r_ecr(ppc) & PPC_FIFO_EMPTY) 1737169962Sobrien goto fifo_empty; 173868349Sobrien#ifdef PPC_DEBUG 1739267843Sdelphij printf("Z"); 1740267843Sdelphij#endif 1741267843Sdelphij error = tsleep(ppc, PPBPRI | PCATCH, "ppcfifo", hz/100); 174268349Sobrien if (error != EWOULDBLOCK) { 1743267843Sdelphij#ifdef PPC_DEBUG 1744267843Sdelphij printf("I"); 1745267843Sdelphij#endif 1746267843Sdelphij /* no dma, no interrupt, flush the fifo */ 1747267843Sdelphij w_ecr(ppc, PPC_ECR_RESET); 1748267843Sdelphij 1749267843Sdelphij ppc->ppc_dmastat = PPC_DMA_INTERRUPTED; 1750267843Sdelphij error = EINTR; 1751267843Sdelphij goto error; 1752267843Sdelphij } 1753267843Sdelphij } 1754267843Sdelphij 1755267843Sdelphijfifo_empty: 1756267843Sdelphij /* no dma, no interrupt, flush the fifo */ 1757267843Sdelphij w_ecr(ppc, PPC_ECR_RESET); 1758267843Sdelphij 1759267843Sdelphij } else 1760267843Sdelphij error = EINVAL; /* XXX we should FIFO and 1761267843Sdelphij * interrupts */ 1762267843Sdelphij } else 1763267843Sdelphij error = EINVAL; 1764267843Sdelphij 1765267843Sdelphijerror: 1766267843Sdelphij 1767267843Sdelphij /* PDRQ must be kept unasserted until nPDACK is 1768267843Sdelphij * deasserted for a minimum of 350ns (SMC datasheet) 1769267843Sdelphij * 1770267843Sdelphij * Consequence may be a FIFO that never empty 1771267843Sdelphij */ 1772267843Sdelphij DELAY(1); 1773267843Sdelphij 1774267843Sdelphij w_ecr(ppc, ecr_sav); 1775267843Sdelphij w_ctr(ppc, ctr_sav); 1776267843Sdelphij 1777267843Sdelphij return (error); 1778267843Sdelphij} 1779267843Sdelphij 178068349Sobrienvoid 178168349Sobrienppc_reset_epp(device_t dev) 1782169962Sobrien{ 1783267843Sdelphij struct ppc_data *ppc = DEVTOSOFTC(dev); 1784267843Sdelphij 1785267843Sdelphij ppc_reset_epp_timeout(ppc); 1786267843Sdelphij 1787267843Sdelphij return; 1788133359Sobrien} 1789139368Sobrien 179068349Sobrienint 179168349Sobrienppc_setmode(device_t dev, int mode) 1792169962Sobrien{ 179368349Sobrien struct ppc_data *ppc = DEVTOSOFTC(dev); 179480588Sobrien 1795169962Sobrien switch (ppc->ppc_type) { 1796169962Sobrien case PPC_TYPE_SMCLIKE: 179780588Sobrien return (ppc_smclike_setmode(ppc, mode)); 1798139368Sobrien break; 1799159764Sobrien 1800169962Sobrien case PPC_TYPE_GENERIC: 1801169962Sobrien default: 180268349Sobrien return (ppc_generic_setmode(ppc, mode)); 180380588Sobrien break; 1804186690Sobrien } 1805226048Sobrien 1806169962Sobrien /* not reached */ 1807169962Sobrien return (ENXIO); 1808169962Sobrien} 180980588Sobrien 1810133359Sobrienstatic struct isa_pnp_id lpc_ids[] = { 1811169942Sobrien { 0x0004d041, "Standard parallel printer port" }, /* PNP0400 */ 1812159764Sobrien { 0x0104d041, "ECP parallel printer port" }, /* PNP0401 */ 1813169962Sobrien { 0 } 181480588Sobrien}; 1815169962Sobrien 1816169962Sobrienstatic int 1817186690Sobrienppc_isa_probe(device_t dev) 1818133359Sobrien{ 181968349Sobrien device_t parent; 1820169962Sobrien int error; 1821169962Sobrien 1822169962Sobrien parent = device_get_parent(dev); 1823186690Sobrien 1824186690Sobrien error = ISA_PNP_PROBE(parent, dev, lpc_ids); 1825186690Sobrien if (error == ENXIO) 1826169962Sobrien return (ENXIO); 1827186690Sobrien else if (error != 0) /* XXX shall be set after detection */ 1828186690Sobrien device_set_desc(dev, "Parallel port"); 1829226048Sobrien 1830226048Sobrien return(ppc_probe(dev)); 1831186690Sobrien} 1832186690Sobrien 1833186690Sobrienint 1834169962Sobrienppc_probe(device_t dev) 183568349Sobrien{ 1836226048Sobrien#ifdef __i386__ 1837226048Sobrien static short next_bios_ppc = 0; 1838226048Sobrien#endif 183968349Sobrien struct ppc_data *ppc; 1840226048Sobrien int error; 1841169962Sobrien u_long port; 1842226048Sobrien 184368349Sobrien /* 1844169962Sobrien * Allocate the ppc_data structure. 1845169962Sobrien */ 1846169962Sobrien ppc = DEVTOSOFTC(dev); 1847169962Sobrien bzero(ppc, sizeof(struct ppc_data)); 1848169962Sobrien 1849169962Sobrien ppc->rid_irq = ppc->rid_drq = ppc->rid_ioport = 0; 1850169962Sobrien ppc->res_irq = ppc->res_drq = ppc->res_ioport = 0; 1851169962Sobrien 1852169962Sobrien /* retrieve ISA parameters */ 1853226048Sobrien error = bus_get_resource(dev, SYS_RES_IOPORT, 0, &port, NULL); 1854226048Sobrien 1855226048Sobrien#ifdef __i386__ 1856226048Sobrien /* 1857226048Sobrien * If port not specified, use bios list. 1858226048Sobrien */ 1859267843Sdelphij if (error) { 1860267843Sdelphij if((next_bios_ppc < BIOS_MAX_PPC) && 1861267843Sdelphij (*(BIOS_PORTS+next_bios_ppc) != 0) ) { 1862226048Sobrien port = *(BIOS_PORTS+next_bios_ppc++); 1863226048Sobrien if (bootverbose) 1864226048Sobrien device_printf(dev, "parallel port found at 0x%x\n", 1865226048Sobrien (int) port); 1866226048Sobrien } else { 1867226048Sobrien device_printf(dev, "parallel port not found.\n"); 1868226048Sobrien return ENXIO; 1869226048Sobrien } 1870226048Sobrien bus_set_resource(dev, SYS_RES_IOPORT, 0, port, 1871226048Sobrien IO_LPTSIZE_EXTENDED); 1872226048Sobrien } 1873226048Sobrien#endif 1874226048Sobrien#ifdef __alpha__ 1875226048Sobrien /* 1876226048Sobrien * There isn't a bios list on alpha. Put it in the usual place. 1877226048Sobrien */ 1878226048Sobrien if (error) { 1879226048Sobrien bus_set_resource(dev, SYS_RES_IOPORT, 0, 0x3bc, 1880226048Sobrien IO_LPTSIZE_NORMAL); 1881226048Sobrien } 1882226048Sobrien#endif 1883267843Sdelphij 1884267843Sdelphij /* IO port is mandatory */ 1885267843Sdelphij 1886267843Sdelphij /* Try "extended" IO port range...*/ 1887267843Sdelphij ppc->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT, 1888226048Sobrien &ppc->rid_ioport, 0, ~0, 1889267843Sdelphij IO_LPTSIZE_EXTENDED, RF_ACTIVE); 1890226048Sobrien 1891226048Sobrien if (ppc->res_ioport != 0) { 1892226048Sobrien if (bootverbose) 1893226048Sobrien device_printf(dev, "using extended I/O port range\n"); 1894226048Sobrien } else { 1895226048Sobrien /* Failed? If so, then try the "normal" IO port range... */ 1896226048Sobrien ppc->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT, 189768349Sobrien &ppc->rid_ioport, 0, ~0, 1898226048Sobrien IO_LPTSIZE_NORMAL, 1899133359Sobrien RF_ACTIVE); 1900139368Sobrien if (ppc->res_ioport != 0) { 1901226048Sobrien if (bootverbose) 1902226048Sobrien device_printf(dev, "using normal I/O port range\n"); 190368349Sobrien } else { 190468349Sobrien device_printf(dev, "cannot reserve I/O port range\n"); 1905169962Sobrien goto error; 1906186690Sobrien } 1907186690Sobrien } 1908169962Sobrien 190968349Sobrien ppc->ppc_base = rman_get_start(ppc->res_ioport); 1910169962Sobrien 1911169962Sobrien ppc->bsh = rman_get_bushandle(ppc->res_ioport); 191268349Sobrien ppc->bst = rman_get_bustag(ppc->res_ioport); 1913169962Sobrien 1914169962Sobrien ppc->ppc_flags = device_get_flags(dev); 1915169962Sobrien 1916169962Sobrien if (!(ppc->ppc_flags & 0x20)) { 1917169962Sobrien ppc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 191880588Sobrien &ppc->rid_irq, 1919133359Sobrien RF_SHAREABLE); 1920133359Sobrien ppc->res_drq = bus_alloc_resource_any(dev, SYS_RES_DRQ, 1921133359Sobrien &ppc->rid_drq, 1922133359Sobrien RF_ACTIVE); 192368349Sobrien } 192468349Sobrien 192568349Sobrien if (ppc->res_irq) 192668349Sobrien ppc->ppc_irq = rman_get_start(ppc->res_irq); 192768349Sobrien if (ppc->res_drq) 1928186690Sobrien ppc->ppc_dmachan = rman_get_start(ppc->res_drq); 1929186690Sobrien 1930186690Sobrien ppc->ppc_unit = device_get_unit(dev); 1931186690Sobrien ppc->ppc_model = GENERIC; 1932186690Sobrien 1933186690Sobrien ppc->ppc_mode = PPB_COMPATIBLE; 1934186690Sobrien ppc->ppc_epp = (ppc->ppc_flags & 0x10) >> 4; 1935186690Sobrien 1936186690Sobrien ppc->ppc_type = PPC_TYPE_GENERIC; 1937186690Sobrien 1938186690Sobrien /* 193968349Sobrien * Try to detect the chipset and its mode. 194068349Sobrien */ 194168349Sobrien if (ppc_detect(ppc, ppc->ppc_flags & 0xf)) 194268349Sobrien goto error; 194368349Sobrien 194468349Sobrien return (0); 194568349Sobrien 194668349Sobrienerror: 194768349Sobrien if (ppc->res_irq != 0) { 194868349Sobrien bus_release_resource(dev, SYS_RES_IRQ, ppc->rid_irq, 194968349Sobrien ppc->res_irq); 195068349Sobrien } 1951159764Sobrien if (ppc->res_ioport != 0) { 1952159764Sobrien bus_deactivate_resource(dev, SYS_RES_IOPORT, ppc->rid_ioport, 1953159764Sobrien ppc->res_ioport); 195468349Sobrien bus_release_resource(dev, SYS_RES_IOPORT, ppc->rid_ioport, 1955169962Sobrien ppc->res_ioport); 1956159764Sobrien } 1957159764Sobrien if (ppc->res_drq != 0) { 195868349Sobrien bus_deactivate_resource(dev, SYS_RES_DRQ, ppc->rid_drq, 195968349Sobrien ppc->res_drq); 196068349Sobrien bus_release_resource(dev, SYS_RES_DRQ, ppc->rid_drq, 196168349Sobrien ppc->res_drq); 196268349Sobrien } 1963169962Sobrien return (ENXIO); 1964169962Sobrien} 1965169962Sobrien 1966169962Sobrienint 196768349Sobrienppc_attach(device_t dev) 1968169962Sobrien{ 196968349Sobrien struct ppc_data *ppc = DEVTOSOFTC(dev); 197068349Sobrien 197168349Sobrien device_t ppbus; 197268349Sobrien device_t parent = device_get_parent(dev); 197368349Sobrien 197468349Sobrien device_printf(dev, "%s chipset (%s) in %s mode%s\n", 197568349Sobrien ppc_models[ppc->ppc_model], ppc_avms[ppc->ppc_avm], 1976169962Sobrien ppc_modes[ppc->ppc_mode], (PPB_IS_EPP(ppc->ppc_mode)) ? 197768349Sobrien ppc_epp_protocol[ppc->ppc_epp] : ""); 197868349Sobrien 197968349Sobrien if (ppc->ppc_fifo) 198068349Sobrien device_printf(dev, "FIFO with %d/%d/%d bytes threshold\n", 1981186690Sobrien ppc->ppc_fifo, ppc->ppc_wthr, ppc->ppc_rthr); 198268349Sobrien 198368349Sobrien if ((ppc->ppc_avm & PPB_ECP) && (ppc->ppc_dmachan > 0)) { 198468349Sobrien /* acquire the DMA channel forever */ /* XXX */ 1985186690Sobrien isa_dma_acquire(ppc->ppc_dmachan); 1986186690Sobrien isa_dmainit(ppc->ppc_dmachan, 1024); /* nlpt.BUFSIZE */ 1987169942Sobrien } 1988169942Sobrien 1989169942Sobrien /* add ppbus as a child of this isa to parallel bridge */ 1990169942Sobrien ppbus = device_add_child(dev, "ppbus", -1); 1991169942Sobrien 1992169942Sobrien /* 1993169942Sobrien * Probe the ppbus and attach devices found. 199468349Sobrien */ 1995169942Sobrien device_probe_and_attach(ppbus); 1996169942Sobrien 1997169942Sobrien /* register the ppc interrupt handler as default */ 1998169942Sobrien if (ppc->res_irq) { 1999169942Sobrien /* default to the tty mask for registration */ /* XXX */ 2000169942Sobrien if (BUS_SETUP_INTR(parent, dev, ppc->res_irq, INTR_TYPE_TTY, 2001133359Sobrien ppcintr, dev, &ppc->intr_cookie) == 0) { 2002133359Sobrien 2003103373Sobrien /* remember the ppcintr is registered */ 2004133359Sobrien ppc->ppc_registered = 1; 2005133359Sobrien } 200668349Sobrien } 2007103373Sobrien 2008186690Sobrien return (0); 200968349Sobrien} 201068349Sobrien 201168349Sobrienu_char 2012186690Sobrienppc_io(device_t ppcdev, int iop, u_char *addr, int cnt, u_char byte) 2013186690Sobrien{ 2014186690Sobrien struct ppc_data *ppc = DEVTOSOFTC(ppcdev); 2015186690Sobrien switch (iop) { 2016169942Sobrien case PPB_OUTSB_EPP: 2017186690Sobrien bus_space_write_multi_1(ppc->bst, ppc->bsh, PPC_EPP_DATA, addr, cnt); 2018186690Sobrien break; 2019186690Sobrien case PPB_OUTSW_EPP: 2020186690Sobrien bus_space_write_multi_2(ppc->bst, ppc->bsh, PPC_EPP_DATA, (u_int16_t *)addr, cnt); 2021186690Sobrien break; 2022186690Sobrien case PPB_OUTSL_EPP: 2023186690Sobrien bus_space_write_multi_4(ppc->bst, ppc->bsh, PPC_EPP_DATA, (u_int32_t *)addr, cnt); 2024186690Sobrien break; 2025186690Sobrien case PPB_INSB_EPP: 2026186690Sobrien bus_space_read_multi_1(ppc->bst, ppc->bsh, PPC_EPP_DATA, addr, cnt); 2027186690Sobrien break; 2028186690Sobrien case PPB_INSW_EPP: 2029186690Sobrien bus_space_read_multi_2(ppc->bst, ppc->bsh, PPC_EPP_DATA, (u_int16_t *)addr, cnt); 2030267843Sdelphij break; 2031267843Sdelphij case PPB_INSL_EPP: 2032267843Sdelphij bus_space_read_multi_4(ppc->bst, ppc->bsh, PPC_EPP_DATA, (u_int32_t *)addr, cnt); 2033267843Sdelphij break; 2034267843Sdelphij case PPB_RDTR: 2035186690Sobrien return (r_dtr(ppc)); 2036186690Sobrien case PPB_RSTR: 2037186690Sobrien return (r_str(ppc)); 2038186690Sobrien case PPB_RCTR: 2039186690Sobrien return (r_ctr(ppc)); 2040186690Sobrien case PPB_REPP_A: 2041186690Sobrien return (r_epp_A(ppc)); 2042186690Sobrien case PPB_REPP_D: 2043186690Sobrien return (r_epp_D(ppc)); 2044186690Sobrien case PPB_RECR: 2045186690Sobrien return (r_ecr(ppc)); 2046186690Sobrien case PPB_RFIFO: 2047186690Sobrien return (r_fifo(ppc)); 2048186690Sobrien case PPB_WDTR: 2049186690Sobrien w_dtr(ppc, byte); 2050186690Sobrien break; 2051186690Sobrien case PPB_WSTR: 2052186690Sobrien w_str(ppc, byte); 2053186690Sobrien break; 2054186690Sobrien case PPB_WCTR: 2055186690Sobrien w_ctr(ppc, byte); 2056186690Sobrien break; 2057186690Sobrien case PPB_WEPP_A: 2058186690Sobrien w_epp_A(ppc, byte); 2059186690Sobrien break; 2060186690Sobrien case PPB_WEPP_D: 2061186690Sobrien w_epp_D(ppc, byte); 2062186690Sobrien break; 2063186690Sobrien case PPB_WECR: 2064186690Sobrien w_ecr(ppc, byte); 2065186690Sobrien break; 2066186690Sobrien case PPB_WFIFO: 2067186690Sobrien w_fifo(ppc, byte); 2068186690Sobrien break; 2069186690Sobrien default: 2070186690Sobrien panic("%s: unknown I/O operation", __func__); 2071191736Sobrien break; 2072267843Sdelphij } 2073267843Sdelphij 2074191736Sobrien return (0); /* not significative */ 2075191736Sobrien} 2076191736Sobrien 2077191736Sobrienint 2078267843Sdelphijppc_read_ivar(device_t bus, device_t dev, int index, uintptr_t *val) 2079191736Sobrien{ 2080267843Sdelphij struct ppc_data *ppc = (struct ppc_data *)device_get_softc(bus); 2081267843Sdelphij 2082267843Sdelphij switch (index) { 2083267843Sdelphij case PPC_IVAR_EPP_PROTO: 2084191736Sobrien *val = (u_long)ppc->ppc_epp; 2085191736Sobrien break; 2086191736Sobrien case PPC_IVAR_IRQ: 2087267843Sdelphij *val = (u_long)ppc->ppc_irq; 2088267843Sdelphij break; 2089267843Sdelphij default: 2090267843Sdelphij return (ENOENT); 2091267843Sdelphij } 2092267843Sdelphij 2093191736Sobrien return (0); 2094226048Sobrien} 2095226048Sobrien 2096267843Sdelphij/* 2097191736Sobrien * Resource is useless here since ppbus devices' interrupt handlers are 2098267843Sdelphij * multiplexed to the same resource initially allocated by ppc 2099267843Sdelphij */ 2100267843Sdelphijint 2101267843Sdelphijppc_setup_intr(device_t bus, device_t child, struct resource *r, int flags, 2102191736Sobrien void (*ihand)(void *), void *arg, void **cookiep) 2103267843Sdelphij{ 2104267843Sdelphij int error; 2105267843Sdelphij struct ppc_data *ppc = DEVTOSOFTC(bus); 2106267843Sdelphij 2107267843Sdelphij if (ppc->ppc_registered) { 2108191736Sobrien /* XXX refuse registration if DMA is in progress */ 2109191736Sobrien 2110191736Sobrien /* first, unregister the default interrupt handler */ 2111191736Sobrien if ((error = BUS_TEARDOWN_INTR(device_get_parent(bus), 2112191736Sobrien bus, ppc->res_irq, ppc->intr_cookie))) 2113191736Sobrien return (error); 2114191736Sobrien 2115191736Sobrien/* bus_deactivate_resource(bus, SYS_RES_IRQ, ppc->rid_irq, */ 2116191736Sobrien/* ppc->res_irq); */ 2117267843Sdelphij 2118267843Sdelphij /* DMA/FIFO operation won't be possible anymore */ 2119267843Sdelphij ppc->ppc_registered = 0; 2120267843Sdelphij } 2121267843Sdelphij 2122267843Sdelphij /* pass registration to the upper layer, ignore the incoming resource */ 2123267843Sdelphij return (BUS_SETUP_INTR(device_get_parent(bus), child, 2124267843Sdelphij r, flags, ihand, arg, cookiep)); 2125267843Sdelphij} 2126267843Sdelphij 2127267843Sdelphij/* 2128267843Sdelphij * When no underlying device has a registered interrupt, register the ppc 2129267843Sdelphij * layer one 2130186690Sobrien */ 2131186690Sobrienint 2132186690Sobrienppc_teardown_intr(device_t bus, device_t child, struct resource *r, void *ih) 2133186690Sobrien{ 2134186690Sobrien int error; 2135186690Sobrien struct ppc_data *ppc = DEVTOSOFTC(bus); 2136267843Sdelphij device_t parent = device_get_parent(bus); 2137186690Sobrien 2138267843Sdelphij /* pass unregistration to the upper layer */ 2139267843Sdelphij if ((error = BUS_TEARDOWN_INTR(parent, child, r, ih))) 2140186690Sobrien return (error); 2141186690Sobrien 2142186690Sobrien /* default to the tty mask for registration */ /* XXX */ 2143169942Sobrien if (ppc->ppc_irq && 2144169942Sobrien !(error = BUS_SETUP_INTR(parent, bus, ppc->res_irq, 2145267843Sdelphij INTR_TYPE_TTY, ppcintr, bus, &ppc->intr_cookie))) { 2146169942Sobrien 2147169942Sobrien /* remember the ppcintr is registered */ 2148169942Sobrien ppc->ppc_registered = 1; 2149169942Sobrien } 2150169942Sobrien 2151267843Sdelphij return (error); 2152169942Sobrien} 2153169942Sobrien 2154169942SobrienDRIVER_MODULE(ppc, isa, ppc_driver, ppc_devclass, 0, 0); 2155169942SobrienDRIVER_MODULE(ppc, acpi, ppc_driver, ppc_devclass, 0, 0); 2156267843Sdelphij