167646539SMike Smith /*- 20f210c92SNicolas Souchu * Copyright (c) 1997-2000 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 * 26c3aac50fSPeter Wemm * $FreeBSD$ 2767646539SMike Smith * 2867646539SMike Smith */ 2967646539SMike Smith #include "ppc.h" 3067646539SMike Smith 3167646539SMike Smith #if NPPC > 0 3267646539SMike Smith 330f210c92SNicolas Souchu #include "opt_ppc.h" 340f210c92SNicolas Souchu 3567646539SMike Smith #include <sys/param.h> 3667646539SMike Smith #include <sys/systm.h> 3754ad6085SNicolas Souchu #include <sys/kernel.h> 380f210c92SNicolas Souchu #include <sys/bus.h> 390f210c92SNicolas Souchu #include <sys/malloc.h> 4067646539SMike Smith 4167646539SMike Smith #include <vm/vm.h> 4267646539SMike Smith #include <vm/pmap.h> 430f210c92SNicolas Souchu #include <machine/clock.h> 440f210c92SNicolas Souchu #include <machine/bus.h> 450f210c92SNicolas Souchu #include <machine/resource.h> 460f210c92SNicolas Souchu #include <machine/vmparam.h> 470f210c92SNicolas Souchu #include <sys/rman.h> 4867646539SMike Smith 490f210c92SNicolas Souchu #include <isa/isareg.h> 500f210c92SNicolas Souchu #include <isa/isavar.h> 5167646539SMike Smith 5267646539SMike Smith #include <dev/ppbus/ppbconf.h> 5346f3ff79SMike Smith #include <dev/ppbus/ppb_msq.h> 5446f3ff79SMike Smith 55d64d73c9SDoug Rabson #include <isa/ppcreg.h> 5667646539SMike Smith 570f210c92SNicolas Souchu #include "ppbus_if.h" 58bc35c174SNicolas Souchu 59bc35c174SNicolas Souchu #define LOG_PPC(function, ppc, string) \ 60bc35c174SNicolas Souchu if (bootverbose) printf("%s: %s\n", function, string) 61bc35c174SNicolas Souchu 6267646539SMike Smith 630f210c92SNicolas Souchu #define DEVTOSOFTC(dev) ((struct ppc_data *)device_get_softc(dev)) 640f210c92SNicolas Souchu 650f210c92SNicolas Souchu devclass_t ppc_devclass; 660f210c92SNicolas Souchu 670f210c92SNicolas Souchu static int ppc_probe(device_t dev); 680f210c92SNicolas Souchu static int ppc_attach(device_t dev); 690f210c92SNicolas Souchu static int ppc_read_ivar(device_t bus, device_t dev, int index, uintptr_t *val); 700f210c92SNicolas Souchu 710f210c92SNicolas Souchu static void ppc_reset_epp(device_t); 720f210c92SNicolas Souchu static void ppc_ecp_sync(device_t); 730f210c92SNicolas Souchu static void ppcintr(void *arg); 740f210c92SNicolas Souchu 750f210c92SNicolas Souchu static int ppc_exec_microseq(device_t, struct ppb_microseq **); 760f210c92SNicolas Souchu static int ppc_setmode(device_t, int); 770f210c92SNicolas Souchu 780f210c92SNicolas Souchu static int ppc_read(device_t, char *, int, int); 790f210c92SNicolas Souchu static int ppc_write(device_t, char *, int, int); 800f210c92SNicolas Souchu 810f210c92SNicolas Souchu static u_char ppc_io(device_t, int, u_char *, int, u_char); 820f210c92SNicolas Souchu 830f210c92SNicolas Souchu static int ppc_setup_intr(device_t, device_t, struct resource *, int, 840f210c92SNicolas Souchu void (*)(void *), void *, void **); 850f210c92SNicolas Souchu static int ppc_teardown_intr(device_t, device_t, struct resource *, void *); 860f210c92SNicolas Souchu 870f210c92SNicolas Souchu static device_method_t ppc_methods[] = { 880f210c92SNicolas Souchu /* device interface */ 890f210c92SNicolas Souchu DEVMETHOD(device_probe, ppc_probe), 900f210c92SNicolas Souchu DEVMETHOD(device_attach, ppc_attach), 910f210c92SNicolas Souchu 920f210c92SNicolas Souchu /* bus interface */ 930f210c92SNicolas Souchu DEVMETHOD(bus_read_ivar, ppc_read_ivar), 940f210c92SNicolas Souchu DEVMETHOD(bus_setup_intr, ppc_setup_intr), 950f210c92SNicolas Souchu DEVMETHOD(bus_teardown_intr, ppc_teardown_intr), 960f210c92SNicolas Souchu DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 970f210c92SNicolas Souchu 980f210c92SNicolas Souchu /* ppbus interface */ 990f210c92SNicolas Souchu DEVMETHOD(ppbus_io, ppc_io), 1000f210c92SNicolas Souchu DEVMETHOD(ppbus_exec_microseq, ppc_exec_microseq), 1010f210c92SNicolas Souchu DEVMETHOD(ppbus_reset_epp, ppc_reset_epp), 1020f210c92SNicolas Souchu DEVMETHOD(ppbus_setmode, ppc_setmode), 1030f210c92SNicolas Souchu DEVMETHOD(ppbus_ecp_sync, ppc_ecp_sync), 1040f210c92SNicolas Souchu DEVMETHOD(ppbus_read, ppc_read), 1050f210c92SNicolas Souchu DEVMETHOD(ppbus_write, ppc_write), 1060f210c92SNicolas Souchu 1070f210c92SNicolas Souchu { 0, 0 } 10867646539SMike Smith }; 10967646539SMike Smith 1100f210c92SNicolas Souchu static driver_t ppc_driver = { 1110f210c92SNicolas Souchu "ppc", 1120f210c92SNicolas Souchu ppc_methods, 1130f210c92SNicolas Souchu sizeof(struct ppc_data), 1140f210c92SNicolas Souchu }; 11567646539SMike Smith 1160f210c92SNicolas Souchu static char *ppc_models[] = { 11746f3ff79SMike Smith "SMC-like", "SMC FDC37C665GT", "SMC FDC37C666GT", "PC87332", "PC87306", 118af548787SNicolas Souchu "82091AA", "Generic", "W83877F", "W83877AF", "Winbond", "PC87334", 0 11967646539SMike Smith }; 12067646539SMike Smith 12146f3ff79SMike Smith /* list of available modes */ 12246f3ff79SMike Smith static char *ppc_avms[] = { 12346f3ff79SMike Smith "COMPATIBLE", "NIBBLE-only", "PS2-only", "PS2/NIBBLE", "EPP-only", 12446f3ff79SMike Smith "EPP/NIBBLE", "EPP/PS2", "EPP/PS2/NIBBLE", "ECP-only", 12546f3ff79SMike Smith "ECP/NIBBLE", "ECP/PS2", "ECP/PS2/NIBBLE", "ECP/EPP", 12646f3ff79SMike Smith "ECP/EPP/NIBBLE", "ECP/EPP/PS2", "ECP/EPP/PS2/NIBBLE", 0 12746f3ff79SMike Smith }; 12846f3ff79SMike Smith 12946f3ff79SMike Smith /* list of current executing modes 13046f3ff79SMike Smith * Note that few modes do not actually exist. 13146f3ff79SMike Smith */ 13267646539SMike Smith static char *ppc_modes[] = { 13346f3ff79SMike Smith "COMPATIBLE", "NIBBLE", "PS/2", "PS/2", "EPP", 13446f3ff79SMike Smith "EPP", "EPP", "EPP", "ECP", 13546f3ff79SMike Smith "ECP", "ECP+PS2", "ECP+PS2", "ECP+EPP", 13646f3ff79SMike Smith "ECP+EPP", "ECP+EPP", "ECP+EPP", 0 13767646539SMike Smith }; 13867646539SMike Smith 13967646539SMike Smith static char *ppc_epp_protocol[] = { " (EPP 1.9)", " (EPP 1.7)", 0 }; 14067646539SMike Smith 141d64d73c9SDoug Rabson #ifdef __i386__ 14267646539SMike Smith /* 14367646539SMike Smith * BIOS printer list - used by BIOS probe. 14467646539SMike Smith */ 14567646539SMike Smith #define BIOS_PPC_PORTS 0x408 14667646539SMike Smith #define BIOS_PORTS (short *)(KERNBASE+BIOS_PPC_PORTS) 14767646539SMike Smith #define BIOS_MAX_PPC 4 148d64d73c9SDoug Rabson #endif 14967646539SMike Smith 15067646539SMike Smith /* 15167646539SMike Smith * ppc_ecp_sync() XXX 15267646539SMike Smith */ 15367646539SMike Smith static void 1540f210c92SNicolas Souchu ppc_ecp_sync(device_t dev) { 15567646539SMike Smith 15667646539SMike Smith int i, r; 1570f210c92SNicolas Souchu struct ppc_data *ppc = DEVTOSOFTC(dev); 15867646539SMike Smith 159bc35c174SNicolas Souchu if (!(ppc->ppc_avm & PPB_ECP)) 160bc35c174SNicolas Souchu return; 161bc35c174SNicolas Souchu 16267646539SMike Smith r = r_ecr(ppc); 163bc35c174SNicolas Souchu if ((r & 0xe0) != PPC_ECR_EPP) 16467646539SMike Smith return; 16567646539SMike Smith 16667646539SMike Smith for (i = 0; i < 100; i++) { 16767646539SMike Smith r = r_ecr(ppc); 16867646539SMike Smith if (r & 0x1) 16967646539SMike Smith return; 17067646539SMike Smith DELAY(100); 17167646539SMike Smith } 17267646539SMike Smith 17346f3ff79SMike Smith printf("ppc%d: ECP sync failed as data still " \ 1740f210c92SNicolas Souchu "present in FIFO.\n", ppc->ppc_unit); 17567646539SMike Smith 17667646539SMike Smith return; 17767646539SMike Smith } 17867646539SMike Smith 179bc35c174SNicolas Souchu /* 180bc35c174SNicolas Souchu * ppc_detect_fifo() 181bc35c174SNicolas Souchu * 182bc35c174SNicolas Souchu * Detect parallel port FIFO 183bc35c174SNicolas Souchu */ 184bc35c174SNicolas Souchu static int 185bc35c174SNicolas Souchu ppc_detect_fifo(struct ppc_data *ppc) 18667646539SMike Smith { 187bc35c174SNicolas Souchu char ecr_sav; 188bc35c174SNicolas Souchu char ctr_sav, ctr, cc; 189bc35c174SNicolas Souchu short i; 19067646539SMike Smith 191bc35c174SNicolas Souchu /* save registers */ 192bc35c174SNicolas Souchu ecr_sav = r_ecr(ppc); 193bc35c174SNicolas Souchu ctr_sav = r_ctr(ppc); 194bc35c174SNicolas Souchu 195bc35c174SNicolas Souchu /* enter ECP configuration mode, no interrupt, no DMA */ 196bc35c174SNicolas Souchu w_ecr(ppc, 0xf4); 197bc35c174SNicolas Souchu 198bc35c174SNicolas Souchu /* read PWord size - transfers in FIFO mode must be PWord aligned */ 199bc35c174SNicolas Souchu ppc->ppc_pword = (r_cnfgA(ppc) & PPC_PWORD_MASK); 200bc35c174SNicolas Souchu 201bc35c174SNicolas Souchu /* XXX 16 and 32 bits implementations not supported */ 202bc35c174SNicolas Souchu if (ppc->ppc_pword != PPC_PWORD_8) { 203bc35c174SNicolas Souchu LOG_PPC(__FUNCTION__, ppc, "PWord not supported"); 204bc35c174SNicolas Souchu goto error; 205bc35c174SNicolas Souchu } 206bc35c174SNicolas Souchu 207bc35c174SNicolas Souchu w_ecr(ppc, 0x34); /* byte mode, no interrupt, no DMA */ 208bc35c174SNicolas Souchu ctr = r_ctr(ppc); 209bc35c174SNicolas Souchu w_ctr(ppc, ctr | PCD); /* set direction to 1 */ 210bc35c174SNicolas Souchu 211bc35c174SNicolas Souchu /* enter ECP test mode, no interrupt, no DMA */ 212bc35c174SNicolas Souchu w_ecr(ppc, 0xd4); 213bc35c174SNicolas Souchu 214bc35c174SNicolas Souchu /* flush the FIFO */ 215bc35c174SNicolas Souchu for (i=0; i<1024; i++) { 216bc35c174SNicolas Souchu if (r_ecr(ppc) & PPC_FIFO_EMPTY) 217bc35c174SNicolas Souchu break; 218bc35c174SNicolas Souchu cc = r_fifo(ppc); 219bc35c174SNicolas Souchu } 220bc35c174SNicolas Souchu 221bc35c174SNicolas Souchu if (i >= 1024) { 222bc35c174SNicolas Souchu LOG_PPC(__FUNCTION__, ppc, "can't flush FIFO"); 223bc35c174SNicolas Souchu goto error; 224bc35c174SNicolas Souchu } 225bc35c174SNicolas Souchu 226bc35c174SNicolas Souchu /* enable interrupts, no DMA */ 227bc35c174SNicolas Souchu w_ecr(ppc, 0xd0); 228bc35c174SNicolas Souchu 229bc35c174SNicolas Souchu /* determine readIntrThreshold 230bc35c174SNicolas Souchu * fill the FIFO until serviceIntr is set 231bc35c174SNicolas Souchu */ 232bc35c174SNicolas Souchu for (i=0; i<1024; i++) { 233bc35c174SNicolas Souchu w_fifo(ppc, (char)i); 234bc35c174SNicolas Souchu if (!ppc->ppc_rthr && (r_ecr(ppc) & PPC_SERVICE_INTR)) { 235bc35c174SNicolas Souchu /* readThreshold reached */ 236bc35c174SNicolas Souchu ppc->ppc_rthr = i+1; 237bc35c174SNicolas Souchu } 238bc35c174SNicolas Souchu if (r_ecr(ppc) & PPC_FIFO_FULL) { 239bc35c174SNicolas Souchu ppc->ppc_fifo = i+1; 240bc35c174SNicolas Souchu break; 241bc35c174SNicolas Souchu } 242bc35c174SNicolas Souchu } 243bc35c174SNicolas Souchu 244bc35c174SNicolas Souchu if (i >= 1024) { 245bc35c174SNicolas Souchu LOG_PPC(__FUNCTION__, ppc, "can't fill FIFO"); 246bc35c174SNicolas Souchu goto error; 247bc35c174SNicolas Souchu } 248bc35c174SNicolas Souchu 249bc35c174SNicolas Souchu w_ecr(ppc, 0xd4); /* test mode, no interrupt, no DMA */ 250bc35c174SNicolas Souchu w_ctr(ppc, ctr & ~PCD); /* set direction to 0 */ 251bc35c174SNicolas Souchu w_ecr(ppc, 0xd0); /* enable interrupts */ 252bc35c174SNicolas Souchu 253bc35c174SNicolas Souchu /* determine writeIntrThreshold 254bc35c174SNicolas Souchu * empty the FIFO until serviceIntr is set 255bc35c174SNicolas Souchu */ 256bc35c174SNicolas Souchu for (i=ppc->ppc_fifo; i>0; i--) { 257bc35c174SNicolas Souchu if (r_fifo(ppc) != (char)(ppc->ppc_fifo-i)) { 258bc35c174SNicolas Souchu LOG_PPC(__FUNCTION__, ppc, "invalid data in FIFO"); 259bc35c174SNicolas Souchu goto error; 260bc35c174SNicolas Souchu } 261bc35c174SNicolas Souchu if (r_ecr(ppc) & PPC_SERVICE_INTR) { 262bc35c174SNicolas Souchu /* writeIntrThreshold reached */ 263bc35c174SNicolas Souchu ppc->ppc_wthr = ppc->ppc_fifo - i+1; 264bc35c174SNicolas Souchu } 265bc35c174SNicolas Souchu /* if FIFO empty before the last byte, error */ 266bc35c174SNicolas Souchu if (i>1 && (r_ecr(ppc) & PPC_FIFO_EMPTY)) { 267bc35c174SNicolas Souchu LOG_PPC(__FUNCTION__, ppc, "data lost in FIFO"); 268bc35c174SNicolas Souchu goto error; 269bc35c174SNicolas Souchu } 270bc35c174SNicolas Souchu } 271bc35c174SNicolas Souchu 272bc35c174SNicolas Souchu /* FIFO must be empty after the last byte */ 273bc35c174SNicolas Souchu if (!(r_ecr(ppc) & PPC_FIFO_EMPTY)) { 274bc35c174SNicolas Souchu LOG_PPC(__FUNCTION__, ppc, "can't empty the FIFO"); 275bc35c174SNicolas Souchu goto error; 276bc35c174SNicolas Souchu } 277bc35c174SNicolas Souchu 278bc35c174SNicolas Souchu w_ctr(ppc, ctr_sav); 279bc35c174SNicolas Souchu w_ecr(ppc, ecr_sav); 280bc35c174SNicolas Souchu 281bc35c174SNicolas Souchu return (0); 282bc35c174SNicolas Souchu 283bc35c174SNicolas Souchu error: 284bc35c174SNicolas Souchu w_ctr(ppc, ctr_sav); 285bc35c174SNicolas Souchu w_ecr(ppc, ecr_sav); 286bc35c174SNicolas Souchu 287bc35c174SNicolas Souchu return (EINVAL); 28867646539SMike Smith } 28967646539SMike Smith 29046f3ff79SMike Smith static int 29146f3ff79SMike Smith ppc_detect_port(struct ppc_data *ppc) 29246f3ff79SMike Smith { 29346f3ff79SMike Smith 29446f3ff79SMike Smith w_ctr(ppc, 0x0c); /* To avoid missing PS2 ports */ 29546f3ff79SMike Smith w_dtr(ppc, 0xaa); 296a7006f89SNicolas Souchu if (r_dtr(ppc) != 0xaa) 29746f3ff79SMike Smith return (0); 29846f3ff79SMike Smith 29946f3ff79SMike Smith return (1); 30046f3ff79SMike Smith } 30146f3ff79SMike Smith 30267646539SMike Smith /* 3030f210c92SNicolas Souchu * EPP timeout, according to the PC87332 manual 3040f210c92SNicolas Souchu * Semantics of clearing EPP timeout bit. 3050f210c92SNicolas Souchu * PC87332 - reading SPP_STR does it... 3060f210c92SNicolas Souchu * SMC - write 1 to EPP timeout bit XXX 3070f210c92SNicolas Souchu * Others - (?) write 0 to EPP timeout bit 3080f210c92SNicolas Souchu */ 3090f210c92SNicolas Souchu static void 3100f210c92SNicolas Souchu ppc_reset_epp_timeout(struct ppc_data *ppc) 3110f210c92SNicolas Souchu { 3120f210c92SNicolas Souchu register char r; 3130f210c92SNicolas Souchu 3140f210c92SNicolas Souchu r = r_str(ppc); 3150f210c92SNicolas Souchu w_str(ppc, r | 0x1); 3160f210c92SNicolas Souchu w_str(ppc, r & 0xfe); 3170f210c92SNicolas Souchu 3180f210c92SNicolas Souchu return; 3190f210c92SNicolas Souchu } 3200f210c92SNicolas Souchu 3210f210c92SNicolas Souchu static int 3220f210c92SNicolas Souchu ppc_check_epp_timeout(struct ppc_data *ppc) 3230f210c92SNicolas Souchu { 3240f210c92SNicolas Souchu ppc_reset_epp_timeout(ppc); 3250f210c92SNicolas Souchu 3260f210c92SNicolas Souchu return (!(r_str(ppc) & TIMEOUT)); 3270f210c92SNicolas Souchu } 3280f210c92SNicolas Souchu 3290f210c92SNicolas Souchu /* 3300f210c92SNicolas Souchu * Configure current operating mode 3310f210c92SNicolas Souchu */ 3320f210c92SNicolas Souchu static int 3330f210c92SNicolas Souchu ppc_generic_setmode(struct ppc_data *ppc, int mode) 3340f210c92SNicolas Souchu { 3350f210c92SNicolas Souchu u_char ecr = 0; 3360f210c92SNicolas Souchu 3370f210c92SNicolas Souchu /* check if mode is available */ 3380f210c92SNicolas Souchu if (mode && !(ppc->ppc_avm & mode)) 3390f210c92SNicolas Souchu return (EINVAL); 3400f210c92SNicolas Souchu 3410f210c92SNicolas Souchu /* if ECP mode, configure ecr register */ 3420f210c92SNicolas Souchu if (ppc->ppc_avm & PPB_ECP) { 3430f210c92SNicolas Souchu /* return to byte mode (keeping direction bit), 3440f210c92SNicolas Souchu * no interrupt, no DMA to be able to change to 3450f210c92SNicolas Souchu * ECP 3460f210c92SNicolas Souchu */ 3470f210c92SNicolas Souchu w_ecr(ppc, PPC_ECR_RESET); 3480f210c92SNicolas Souchu ecr = PPC_DISABLE_INTR; 3490f210c92SNicolas Souchu 3500f210c92SNicolas Souchu if (mode & PPB_EPP) 3510f210c92SNicolas Souchu return (EINVAL); 3520f210c92SNicolas Souchu else if (mode & PPB_ECP) 3530f210c92SNicolas Souchu /* select ECP mode */ 3540f210c92SNicolas Souchu ecr |= PPC_ECR_ECP; 3550f210c92SNicolas Souchu else if (mode & PPB_PS2) 3560f210c92SNicolas Souchu /* select PS2 mode with ECP */ 3570f210c92SNicolas Souchu ecr |= PPC_ECR_PS2; 3580f210c92SNicolas Souchu else 3590f210c92SNicolas Souchu /* select COMPATIBLE/NIBBLE mode */ 3600f210c92SNicolas Souchu ecr |= PPC_ECR_STD; 3610f210c92SNicolas Souchu 3620f210c92SNicolas Souchu w_ecr(ppc, ecr); 3630f210c92SNicolas Souchu } 3640f210c92SNicolas Souchu 3650f210c92SNicolas Souchu ppc->ppc_mode = mode; 3660f210c92SNicolas Souchu 3670f210c92SNicolas Souchu return (0); 3680f210c92SNicolas Souchu } 3690f210c92SNicolas Souchu 3700f210c92SNicolas Souchu /* 3710f210c92SNicolas Souchu * The ppc driver is free to choose options like FIFO or DMA 3720f210c92SNicolas Souchu * if ECP mode is available. 3730f210c92SNicolas Souchu * 3740f210c92SNicolas Souchu * The 'RAW' option allows the upper drivers to force the ppc mode 3750f210c92SNicolas Souchu * even with FIFO, DMA available. 3760f210c92SNicolas Souchu */ 3770f210c92SNicolas Souchu static int 3780f210c92SNicolas Souchu ppc_smclike_setmode(struct ppc_data *ppc, int mode) 3790f210c92SNicolas Souchu { 3800f210c92SNicolas Souchu u_char ecr = 0; 3810f210c92SNicolas Souchu 3820f210c92SNicolas Souchu /* check if mode is available */ 3830f210c92SNicolas Souchu if (mode && !(ppc->ppc_avm & mode)) 3840f210c92SNicolas Souchu return (EINVAL); 3850f210c92SNicolas Souchu 3860f210c92SNicolas Souchu /* if ECP mode, configure ecr register */ 3870f210c92SNicolas Souchu if (ppc->ppc_avm & PPB_ECP) { 3880f210c92SNicolas Souchu /* return to byte mode (keeping direction bit), 3890f210c92SNicolas Souchu * no interrupt, no DMA to be able to change to 3900f210c92SNicolas Souchu * ECP or EPP mode 3910f210c92SNicolas Souchu */ 3920f210c92SNicolas Souchu w_ecr(ppc, PPC_ECR_RESET); 3930f210c92SNicolas Souchu ecr = PPC_DISABLE_INTR; 3940f210c92SNicolas Souchu 3950f210c92SNicolas Souchu if (mode & PPB_EPP) 3960f210c92SNicolas Souchu /* select EPP mode */ 3970f210c92SNicolas Souchu ecr |= PPC_ECR_EPP; 3980f210c92SNicolas Souchu else if (mode & PPB_ECP) 3990f210c92SNicolas Souchu /* select ECP mode */ 4000f210c92SNicolas Souchu ecr |= PPC_ECR_ECP; 4010f210c92SNicolas Souchu else if (mode & PPB_PS2) 4020f210c92SNicolas Souchu /* select PS2 mode with ECP */ 4030f210c92SNicolas Souchu ecr |= PPC_ECR_PS2; 4040f210c92SNicolas Souchu else 4050f210c92SNicolas Souchu /* select COMPATIBLE/NIBBLE mode */ 4060f210c92SNicolas Souchu ecr |= PPC_ECR_STD; 4070f210c92SNicolas Souchu 4080f210c92SNicolas Souchu w_ecr(ppc, ecr); 4090f210c92SNicolas Souchu } 4100f210c92SNicolas Souchu 4110f210c92SNicolas Souchu ppc->ppc_mode = mode; 4120f210c92SNicolas Souchu 4130f210c92SNicolas Souchu return (0); 4140f210c92SNicolas Souchu } 4150f210c92SNicolas Souchu 4160f210c92SNicolas Souchu #ifdef PPC_PROBE_CHIPSET 4170f210c92SNicolas Souchu /* 41867646539SMike Smith * ppc_pc873xx_detect 41967646539SMike Smith * 42067646539SMike Smith * Probe for a Natsemi PC873xx-family part. 42167646539SMike Smith * 42267646539SMike Smith * References in this function are to the National Semiconductor 42367646539SMike Smith * PC87332 datasheet TL/C/11930, May 1995 revision. 42467646539SMike Smith */ 42567646539SMike Smith static int pc873xx_basetab[] = {0x0398, 0x026e, 0x015c, 0x002e, 0}; 42667646539SMike Smith static int pc873xx_porttab[] = {0x0378, 0x03bc, 0x0278, 0}; 427af548787SNicolas Souchu static int pc873xx_irqtab[] = {5, 7, 5, 0}; 428af548787SNicolas Souchu 429af548787SNicolas Souchu static int pc873xx_regstab[] = { 430af548787SNicolas Souchu PC873_FER, PC873_FAR, PC873_PTR, 431af548787SNicolas Souchu PC873_FCR, PC873_PCR, PC873_PMC, 432af548787SNicolas Souchu PC873_TUP, PC873_SID, PC873_PNP0, 433af548787SNicolas Souchu PC873_PNP1, PC873_LPTBA, -1 434af548787SNicolas Souchu }; 435af548787SNicolas Souchu 436af548787SNicolas Souchu static char *pc873xx_rnametab[] = { 437af548787SNicolas Souchu "FER", "FAR", "PTR", "FCR", "PCR", 438af548787SNicolas Souchu "PMC", "TUP", "SID", "PNP0", "PNP1", 439af548787SNicolas Souchu "LPTBA", NULL 440af548787SNicolas Souchu }; 44167646539SMike Smith 44267646539SMike Smith static int 44346f3ff79SMike Smith ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never forced */ 44467646539SMike Smith { 44567646539SMike Smith static int index = 0; 446f1d19042SArchie Cobbs int idport, irq; 447af548787SNicolas Souchu int ptr, pcr, val, i; 44867646539SMike Smith 44967646539SMike Smith while ((idport = pc873xx_basetab[index++])) { 45067646539SMike Smith 45167646539SMike Smith /* XXX should check first to see if this location is already claimed */ 45267646539SMike Smith 45367646539SMike Smith /* 454af548787SNicolas Souchu * Pull the 873xx through the power-on ID cycle (2.2,1.). 455af548787SNicolas Souchu * We can't use this to locate the chip as it may already have 456af548787SNicolas Souchu * been used by the BIOS. 45767646539SMike Smith */ 458af548787SNicolas Souchu (void)inb(idport); (void)inb(idport); 459af548787SNicolas Souchu (void)inb(idport); (void)inb(idport); 46067646539SMike Smith 46167646539SMike Smith /* 46267646539SMike Smith * Read the SID byte. Possible values are : 46367646539SMike Smith * 464af548787SNicolas Souchu * 01010xxx PC87334 46567646539SMike Smith * 0001xxxx PC87332 46667646539SMike Smith * 01110xxx PC87306 46767646539SMike Smith */ 46867646539SMike Smith outb(idport, PC873_SID); 46967646539SMike Smith val = inb(idport + 1); 47067646539SMike Smith if ((val & 0xf0) == 0x10) { 4710f210c92SNicolas Souchu ppc->ppc_model = NS_PC87332; 47267646539SMike Smith } else if ((val & 0xf8) == 0x70) { 4730f210c92SNicolas Souchu ppc->ppc_model = NS_PC87306; 474af548787SNicolas Souchu } else if ((val & 0xf8) == 0x50) { 4750f210c92SNicolas Souchu ppc->ppc_model = NS_PC87334; 47667646539SMike Smith } else { 47767646539SMike Smith if (bootverbose && (val != 0xff)) 47867646539SMike Smith printf("PC873xx probe at 0x%x got unknown ID 0x%x\n", idport, val); 47967646539SMike Smith continue ; /* not recognised */ 48067646539SMike Smith } 48167646539SMike Smith 482af548787SNicolas Souchu /* print registers */ 483af548787SNicolas Souchu if (bootverbose) { 484af548787SNicolas Souchu printf("PC873xx"); 485af548787SNicolas Souchu for (i=0; pc873xx_regstab[i] != -1; i++) { 486af548787SNicolas Souchu outb(idport, pc873xx_regstab[i]); 487af548787SNicolas Souchu printf(" %s=0x%x", pc873xx_rnametab[i], 488af548787SNicolas Souchu inb(idport + 1) & 0xff); 489af548787SNicolas Souchu } 490af548787SNicolas Souchu printf("\n"); 491af548787SNicolas Souchu } 492af548787SNicolas Souchu 49367646539SMike Smith /* 49467646539SMike Smith * We think we have one. Is it enabled and where we want it to be? 49567646539SMike Smith */ 49667646539SMike Smith outb(idport, PC873_FER); 49767646539SMike Smith val = inb(idport + 1); 49867646539SMike Smith if (!(val & PC873_PPENABLE)) { 49967646539SMike Smith if (bootverbose) 50067646539SMike Smith printf("PC873xx parallel port disabled\n"); 50167646539SMike Smith continue; 50267646539SMike Smith } 50367646539SMike Smith outb(idport, PC873_FAR); 50467646539SMike Smith val = inb(idport + 1) & 0x3; 50567646539SMike Smith /* XXX we should create a driver instance for every port found */ 50667646539SMike Smith if (pc873xx_porttab[val] != ppc->ppc_base) { 50767646539SMike Smith if (bootverbose) 50867646539SMike Smith printf("PC873xx at 0x%x not for driver at port 0x%x\n", 50967646539SMike Smith pc873xx_porttab[val], ppc->ppc_base); 51067646539SMike Smith continue; 51167646539SMike Smith } 51267646539SMike Smith 51367646539SMike Smith outb(idport, PC873_PTR); 514af548787SNicolas Souchu ptr = inb(idport + 1); 515af548787SNicolas Souchu 516af548787SNicolas Souchu /* get irq settings */ 517af548787SNicolas Souchu if (ppc->ppc_base == 0x378) 518af548787SNicolas Souchu irq = (ptr & PC873_LPTBIRQ7) ? 7 : 5; 519af548787SNicolas Souchu else 520af548787SNicolas Souchu irq = pc873xx_irqtab[val]; 521af548787SNicolas Souchu 52267646539SMike Smith if (bootverbose) 523af548787SNicolas Souchu printf("PC873xx irq %d at 0x%x\n", irq, ppc->ppc_base); 52467646539SMike Smith 525af548787SNicolas Souchu /* 526af548787SNicolas Souchu * Check if irq settings are correct 527af548787SNicolas Souchu */ 528af548787SNicolas Souchu if (irq != ppc->ppc_irq) { 529af548787SNicolas Souchu /* 530af548787SNicolas Souchu * If the chipset is not locked and base address is 0x378, 531af548787SNicolas Souchu * we have another chance 532af548787SNicolas Souchu */ 533af548787SNicolas Souchu if (ppc->ppc_base == 0x378 && !(ptr & PC873_CFGLOCK)) { 534af548787SNicolas Souchu if (ppc->ppc_irq == 7) { 535af548787SNicolas Souchu outb(idport + 1, (ptr | PC873_LPTBIRQ7)); 536af548787SNicolas Souchu outb(idport + 1, (ptr | PC873_LPTBIRQ7)); 537af548787SNicolas Souchu } else { 538af548787SNicolas Souchu outb(idport + 1, (ptr & ~PC873_LPTBIRQ7)); 539af548787SNicolas Souchu outb(idport + 1, (ptr & ~PC873_LPTBIRQ7)); 54067646539SMike Smith } 541af548787SNicolas Souchu if (bootverbose) 542af548787SNicolas Souchu printf("PC873xx irq set to %d\n", ppc->ppc_irq); 543af548787SNicolas Souchu } else { 544af548787SNicolas Souchu if (bootverbose) 545af548787SNicolas Souchu printf("PC873xx sorry, can't change irq setting\n"); 54667646539SMike Smith } 54767646539SMike Smith } else { 54867646539SMike Smith if (bootverbose) 549af548787SNicolas Souchu printf("PC873xx irq settings are correct\n"); 55067646539SMike Smith } 55167646539SMike Smith 55267646539SMike Smith outb(idport, PC873_PCR); 553af548787SNicolas Souchu pcr = inb(idport + 1); 554af548787SNicolas Souchu 555af548787SNicolas Souchu if ((ptr & PC873_CFGLOCK) || !chipset_mode) { 556af548787SNicolas Souchu if (bootverbose) 557af548787SNicolas Souchu printf("PC873xx %s", (ptr & PC873_CFGLOCK)?"locked":"unlocked"); 558af548787SNicolas Souchu 559af548787SNicolas Souchu ppc->ppc_avm |= PPB_NIBBLE; 560af548787SNicolas Souchu if (bootverbose) 561af548787SNicolas Souchu printf(", NIBBLE"); 562af548787SNicolas Souchu 563af548787SNicolas Souchu if (pcr & PC873_EPPEN) { 564af548787SNicolas Souchu ppc->ppc_avm |= PPB_EPP; 565af548787SNicolas Souchu 566af548787SNicolas Souchu if (bootverbose) 567af548787SNicolas Souchu printf(", EPP"); 568af548787SNicolas Souchu 569af548787SNicolas Souchu if (pcr & PC873_EPP19) 570af548787SNicolas Souchu ppc->ppc_epp = EPP_1_9; 571af548787SNicolas Souchu else 572af548787SNicolas Souchu ppc->ppc_epp = EPP_1_7; 573af548787SNicolas Souchu 5740f210c92SNicolas Souchu if ((ppc->ppc_model == NS_PC87332) && bootverbose) { 575af548787SNicolas Souchu outb(idport, PC873_PTR); 576af548787SNicolas Souchu ptr = inb(idport + 1); 577af548787SNicolas Souchu if (ptr & PC873_EPPRDIR) 578af548787SNicolas Souchu printf(", Regular mode"); 579af548787SNicolas Souchu else 580af548787SNicolas Souchu printf(", Automatic mode"); 581af548787SNicolas Souchu } 582af548787SNicolas Souchu } else if (pcr & PC873_ECPEN) { 583af548787SNicolas Souchu ppc->ppc_avm |= PPB_ECP; 584af548787SNicolas Souchu if (bootverbose) 585af548787SNicolas Souchu printf(", ECP"); 586af548787SNicolas Souchu 587af548787SNicolas Souchu if (pcr & PC873_ECPCLK) { /* XXX */ 588af548787SNicolas Souchu ppc->ppc_avm |= PPB_PS2; 589af548787SNicolas Souchu if (bootverbose) 590af548787SNicolas Souchu printf(", PS/2"); 591af548787SNicolas Souchu } 592af548787SNicolas Souchu } else { 593af548787SNicolas Souchu outb(idport, PC873_PTR); 594af548787SNicolas Souchu ptr = inb(idport + 1); 595af548787SNicolas Souchu if (ptr & PC873_EXTENDED) { 596af548787SNicolas Souchu ppc->ppc_avm |= PPB_SPP; 597af548787SNicolas Souchu if (bootverbose) 598af548787SNicolas Souchu printf(", SPP"); 599af548787SNicolas Souchu } 600af548787SNicolas Souchu } 601af548787SNicolas Souchu } else { 602af548787SNicolas Souchu if (bootverbose) 603af548787SNicolas Souchu printf("PC873xx unlocked"); 604af548787SNicolas Souchu 605af548787SNicolas Souchu if (chipset_mode & PPB_ECP) { 606af548787SNicolas Souchu if ((chipset_mode & PPB_EPP) && bootverbose) 607af548787SNicolas Souchu printf(", ECP+EPP not supported"); 608af548787SNicolas Souchu 609af548787SNicolas Souchu pcr &= ~PC873_EPPEN; 610af548787SNicolas Souchu pcr |= (PC873_ECPEN | PC873_ECPCLK); /* XXX */ 611af548787SNicolas Souchu outb(idport + 1, pcr); 612af548787SNicolas Souchu outb(idport + 1, pcr); 613af548787SNicolas Souchu 614af548787SNicolas Souchu if (bootverbose) 615af548787SNicolas Souchu printf(", ECP"); 616af548787SNicolas Souchu 617af548787SNicolas Souchu } else if (chipset_mode & PPB_EPP) { 618af548787SNicolas Souchu pcr &= ~(PC873_ECPEN | PC873_ECPCLK); 619af548787SNicolas Souchu pcr |= (PC873_EPPEN | PC873_EPP19); 620af548787SNicolas Souchu outb(idport + 1, pcr); 621af548787SNicolas Souchu outb(idport + 1, pcr); 622af548787SNicolas Souchu 623af548787SNicolas Souchu ppc->ppc_epp = EPP_1_9; /* XXX */ 624af548787SNicolas Souchu 625af548787SNicolas Souchu if (bootverbose) 626af548787SNicolas Souchu printf(", EPP1.9"); 62767646539SMike Smith 62867646539SMike Smith /* enable automatic direction turnover */ 6290f210c92SNicolas Souchu if (ppc->ppc_model == NS_PC87332) { 63067646539SMike Smith outb(idport, PC873_PTR); 631af548787SNicolas Souchu ptr = inb(idport + 1); 632af548787SNicolas Souchu ptr &= ~PC873_EPPRDIR; 633af548787SNicolas Souchu outb(idport + 1, ptr); 634af548787SNicolas Souchu outb(idport + 1, ptr); 63567646539SMike Smith 63667646539SMike Smith if (bootverbose) 637af548787SNicolas Souchu printf(", Automatic mode"); 63867646539SMike Smith } 639af548787SNicolas Souchu } else { 640af548787SNicolas Souchu pcr &= ~(PC873_ECPEN | PC873_ECPCLK | PC873_EPPEN); 641af548787SNicolas Souchu outb(idport + 1, pcr); 642af548787SNicolas Souchu outb(idport + 1, pcr); 643af548787SNicolas Souchu 644af548787SNicolas Souchu /* configure extended bit in PTR */ 645af548787SNicolas Souchu outb(idport, PC873_PTR); 646af548787SNicolas Souchu ptr = inb(idport + 1); 647af548787SNicolas Souchu 648af548787SNicolas Souchu if (chipset_mode & PPB_PS2) { 649af548787SNicolas Souchu ptr |= PC873_EXTENDED; 650af548787SNicolas Souchu 651af548787SNicolas Souchu if (bootverbose) 652af548787SNicolas Souchu printf(", PS/2"); 653af548787SNicolas Souchu 654af548787SNicolas Souchu } else { 655af548787SNicolas Souchu /* default to NIBBLE mode */ 656af548787SNicolas Souchu ptr &= ~PC873_EXTENDED; 657af548787SNicolas Souchu 658af548787SNicolas Souchu if (bootverbose) 659af548787SNicolas Souchu printf(", NIBBLE"); 66067646539SMike Smith } 661af548787SNicolas Souchu outb(idport + 1, ptr); 662af548787SNicolas Souchu outb(idport + 1, ptr); 663af548787SNicolas Souchu } 664af548787SNicolas Souchu 665af548787SNicolas Souchu ppc->ppc_avm = chipset_mode; 666af548787SNicolas Souchu } 667af548787SNicolas Souchu 668af548787SNicolas Souchu if (bootverbose) 669af548787SNicolas Souchu printf("\n"); 670af548787SNicolas Souchu 6710f210c92SNicolas Souchu ppc->ppc_type = PPC_TYPE_GENERIC; 6720f210c92SNicolas Souchu ppc_generic_setmode(ppc, chipset_mode); 67346f3ff79SMike Smith 67446f3ff79SMike Smith return(chipset_mode); 67567646539SMike Smith } 67646f3ff79SMike Smith return(-1); 67767646539SMike Smith } 67867646539SMike Smith 67967646539SMike Smith /* 68067646539SMike Smith * ppc_smc37c66xgt_detect 68167646539SMike Smith * 68267646539SMike Smith * SMC FDC37C66xGT configuration. 68367646539SMike Smith */ 68467646539SMike Smith static int 68546f3ff79SMike Smith ppc_smc37c66xgt_detect(struct ppc_data *ppc, int chipset_mode) 68667646539SMike Smith { 68767646539SMike Smith int s, i; 688c9ab0738SNicolas Souchu u_char r; 68967646539SMike Smith int type = -1; 69067646539SMike Smith int csr = SMC66x_CSR; /* initial value is 0x3F0 */ 69167646539SMike Smith 69267646539SMike Smith int port_address[] = { -1 /* disabled */ , 0x3bc, 0x378, 0x278 }; 69367646539SMike Smith 69467646539SMike Smith 69567646539SMike Smith #define cio csr+1 /* config IO port is either 0x3F1 or 0x371 */ 69667646539SMike Smith 69767646539SMike Smith /* 69867646539SMike Smith * Detection: enter configuration mode and read CRD register. 69967646539SMike Smith */ 70067646539SMike Smith 70167646539SMike Smith s = splhigh(); 70267646539SMike Smith outb(csr, SMC665_iCODE); 70367646539SMike Smith outb(csr, SMC665_iCODE); 70467646539SMike Smith splx(s); 70567646539SMike Smith 70667646539SMike Smith outb(csr, 0xd); 70767646539SMike Smith if (inb(cio) == 0x65) { 70867646539SMike Smith type = SMC_37C665GT; 70967646539SMike Smith goto config; 71067646539SMike Smith } 71167646539SMike Smith 71267646539SMike Smith for (i = 0; i < 2; i++) { 71367646539SMike Smith s = splhigh(); 71467646539SMike Smith outb(csr, SMC666_iCODE); 71567646539SMike Smith outb(csr, SMC666_iCODE); 71667646539SMike Smith splx(s); 71767646539SMike Smith 71867646539SMike Smith outb(csr, 0xd); 71967646539SMike Smith if (inb(cio) == 0x66) { 72067646539SMike Smith type = SMC_37C666GT; 72167646539SMike Smith break; 72267646539SMike Smith } 72367646539SMike Smith 72467646539SMike Smith /* Another chance, CSR may be hard-configured to be at 0x370 */ 72567646539SMike Smith csr = SMC666_CSR; 72667646539SMike Smith } 72767646539SMike Smith 72867646539SMike Smith config: 72967646539SMike Smith /* 73067646539SMike Smith * If chipset not found, do not continue. 73167646539SMike Smith */ 73267646539SMike Smith if (type == -1) 73346f3ff79SMike Smith return (-1); 73467646539SMike Smith 73567646539SMike Smith /* select CR1 */ 73667646539SMike Smith outb(csr, 0x1); 73767646539SMike Smith 73867646539SMike Smith /* read the port's address: bits 0 and 1 of CR1 */ 73967646539SMike Smith r = inb(cio) & SMC_CR1_ADDR; 740c9ab0738SNicolas Souchu if (port_address[(int)r] != ppc->ppc_base) 74146f3ff79SMike Smith return (-1); 74267646539SMike Smith 7430f210c92SNicolas Souchu ppc->ppc_model = type; 74467646539SMike Smith 74567646539SMike Smith /* 74667646539SMike Smith * CR1 and CR4 registers bits 3 and 0/1 for mode configuration 74746f3ff79SMike Smith * If SPP mode is detected, try to set ECP+EPP mode 74867646539SMike Smith */ 74967646539SMike Smith 75046f3ff79SMike Smith if (bootverbose) { 75146f3ff79SMike Smith outb(csr, 0x1); 75241990851SNicolas Souchu printf("ppc%d: SMC registers CR1=0x%x", ppc->ppc_unit, 75354ad6085SNicolas Souchu inb(cio) & 0xff); 75446f3ff79SMike Smith 75546f3ff79SMike Smith outb(csr, 0x4); 75646f3ff79SMike Smith printf(" CR4=0x%x", inb(cio) & 0xff); 75746f3ff79SMike Smith } 75846f3ff79SMike Smith 75946f3ff79SMike Smith /* select CR1 */ 76067646539SMike Smith outb(csr, 0x1); 76167646539SMike Smith 76246f3ff79SMike Smith if (!chipset_mode) { 76367646539SMike Smith /* autodetect mode */ 76467646539SMike Smith 76546f3ff79SMike Smith /* 666GT is ~certainly~ hardwired to an extended ECP+EPP mode */ 76646f3ff79SMike Smith if (type == SMC_37C666GT) { 76746f3ff79SMike Smith ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP; 768edcfcf27SNicolas Souchu if (bootverbose) 769edcfcf27SNicolas Souchu printf(" configuration hardwired, supposing " \ 770edcfcf27SNicolas Souchu "ECP+EPP SPP"); 77167646539SMike Smith 77246f3ff79SMike Smith } else 77346f3ff79SMike Smith if ((inb(cio) & SMC_CR1_MODE) == 0) { 77467646539SMike Smith /* already in extended parallel port mode, read CR4 */ 77567646539SMike Smith outb(csr, 0x4); 77667646539SMike Smith r = (inb(cio) & SMC_CR4_EMODE); 77767646539SMike Smith 77867646539SMike Smith switch (r) { 77967646539SMike Smith case SMC_SPP: 78046f3ff79SMike Smith ppc->ppc_avm |= PPB_SPP; 781edcfcf27SNicolas Souchu if (bootverbose) 782edcfcf27SNicolas Souchu printf(" SPP"); 78367646539SMike Smith break; 78467646539SMike Smith 78567646539SMike Smith case SMC_EPPSPP: 78646f3ff79SMike Smith ppc->ppc_avm |= PPB_EPP | PPB_SPP; 787edcfcf27SNicolas Souchu if (bootverbose) 788edcfcf27SNicolas Souchu printf(" EPP SPP"); 78967646539SMike Smith break; 79067646539SMike Smith 79167646539SMike Smith case SMC_ECP: 79246f3ff79SMike Smith ppc->ppc_avm |= PPB_ECP | PPB_SPP; 793edcfcf27SNicolas Souchu if (bootverbose) 794edcfcf27SNicolas Souchu printf(" ECP SPP"); 79567646539SMike Smith break; 79667646539SMike Smith 79767646539SMike Smith case SMC_ECPEPP: 79846f3ff79SMike Smith ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP; 799edcfcf27SNicolas Souchu if (bootverbose) 800edcfcf27SNicolas Souchu printf(" ECP+EPP SPP"); 80167646539SMike Smith break; 80267646539SMike Smith } 80346f3ff79SMike Smith } else { 80446f3ff79SMike Smith /* not an extended port mode */ 80546f3ff79SMike Smith ppc->ppc_avm |= PPB_SPP; 806edcfcf27SNicolas Souchu if (bootverbose) 807edcfcf27SNicolas Souchu printf(" SPP"); 80867646539SMike Smith } 80946f3ff79SMike Smith 81067646539SMike Smith } else { 81167646539SMike Smith /* mode forced */ 81254ad6085SNicolas Souchu ppc->ppc_avm = chipset_mode; 81367646539SMike Smith 81446f3ff79SMike Smith /* 666GT is ~certainly~ hardwired to an extended ECP+EPP mode */ 81567646539SMike Smith if (type == SMC_37C666GT) 81667646539SMike Smith goto end_detect; 81767646539SMike Smith 81867646539SMike Smith r = inb(cio); 81946f3ff79SMike Smith if ((chipset_mode & (PPB_ECP | PPB_EPP)) == 0) { 82046f3ff79SMike Smith /* do not use ECP when the mode is not forced to */ 82167646539SMike Smith outb(cio, r | SMC_CR1_MODE); 822edcfcf27SNicolas Souchu if (bootverbose) 823edcfcf27SNicolas Souchu printf(" SPP"); 82467646539SMike Smith } else { 82567646539SMike Smith /* an extended mode is selected */ 82667646539SMike Smith outb(cio, r & ~SMC_CR1_MODE); 82767646539SMike Smith 82867646539SMike Smith /* read CR4 register and reset mode field */ 82967646539SMike Smith outb(csr, 0x4); 83067646539SMike Smith r = inb(cio) & ~SMC_CR4_EMODE; 83167646539SMike Smith 83246f3ff79SMike Smith if (chipset_mode & PPB_ECP) { 83346f3ff79SMike Smith if (chipset_mode & PPB_EPP) { 83467646539SMike Smith outb(cio, r | SMC_ECPEPP); 835edcfcf27SNicolas Souchu if (bootverbose) 836edcfcf27SNicolas Souchu printf(" ECP+EPP"); 83746f3ff79SMike Smith } else { 83846f3ff79SMike Smith outb(cio, r | SMC_ECP); 839edcfcf27SNicolas Souchu if (bootverbose) 840edcfcf27SNicolas Souchu printf(" ECP"); 84146f3ff79SMike Smith } 84246f3ff79SMike Smith } else { 84346f3ff79SMike Smith /* PPB_EPP is set */ 84446f3ff79SMike Smith outb(cio, r | SMC_EPPSPP); 845edcfcf27SNicolas Souchu if (bootverbose) 846edcfcf27SNicolas Souchu printf(" EPP SPP"); 84767646539SMike Smith } 84867646539SMike Smith } 84946f3ff79SMike Smith ppc->ppc_avm = chipset_mode; 85067646539SMike Smith } 85167646539SMike Smith 852bc35c174SNicolas Souchu /* set FIFO threshold to 16 */ 853bc35c174SNicolas Souchu if (ppc->ppc_avm & PPB_ECP) { 854bc35c174SNicolas Souchu /* select CRA */ 855bc35c174SNicolas Souchu outb(csr, 0xa); 856bc35c174SNicolas Souchu outb(cio, 16); 857bc35c174SNicolas Souchu } 858bc35c174SNicolas Souchu 85967646539SMike Smith end_detect: 86046f3ff79SMike Smith 86146f3ff79SMike Smith if (bootverbose) 86246f3ff79SMike Smith printf ("\n"); 86346f3ff79SMike Smith 86454ad6085SNicolas Souchu if (ppc->ppc_avm & PPB_EPP) { 86567646539SMike Smith /* select CR4 */ 86667646539SMike Smith outb(csr, 0x4); 86767646539SMike Smith r = inb(cio); 86867646539SMike Smith 86967646539SMike Smith /* 87067646539SMike Smith * Set the EPP protocol... 87167646539SMike Smith * Low=EPP 1.9 (1284 standard) and High=EPP 1.7 87267646539SMike Smith */ 87367646539SMike Smith if (ppc->ppc_epp == EPP_1_9) 87467646539SMike Smith outb(cio, (r & ~SMC_CR4_EPPTYPE)); 87567646539SMike Smith else 87667646539SMike Smith outb(cio, (r | SMC_CR4_EPPTYPE)); 87767646539SMike Smith } 87867646539SMike Smith 87967646539SMike Smith /* end config mode */ 88067646539SMike Smith outb(csr, 0xaa); 88167646539SMike Smith 8820f210c92SNicolas Souchu ppc->ppc_type = PPC_TYPE_SMCLIKE; 8830f210c92SNicolas Souchu ppc_smclike_setmode(ppc, chipset_mode); 88467646539SMike Smith 88546f3ff79SMike Smith return (chipset_mode); 88667646539SMike Smith } 88767646539SMike Smith 88846f3ff79SMike Smith /* 88946f3ff79SMike Smith * Winbond W83877F stuff 89046f3ff79SMike Smith * 89146f3ff79SMike Smith * EFER: extended function enable register 89246f3ff79SMike Smith * EFIR: extended function index register 89346f3ff79SMike Smith * EFDR: extended function data register 89446f3ff79SMike Smith */ 89546f3ff79SMike Smith #define efir ((efer == 0x250) ? 0x251 : 0x3f0) 89646f3ff79SMike Smith #define efdr ((efer == 0x250) ? 0x252 : 0x3f1) 89746f3ff79SMike Smith 89846f3ff79SMike Smith static int w83877f_efers[] = { 0x250, 0x3f0, 0x3f0, 0x250 }; 89946f3ff79SMike Smith static int w83877f_keys[] = { 0x89, 0x86, 0x87, 0x88 }; 90046f3ff79SMike Smith static int w83877f_keyiter[] = { 1, 2, 2, 1 }; 90146f3ff79SMike Smith static int w83877f_hefs[] = { WINB_HEFERE, WINB_HEFRAS, WINB_HEFERE | WINB_HEFRAS, 0 }; 90267646539SMike Smith 90367646539SMike Smith static int 90446f3ff79SMike Smith ppc_w83877f_detect(struct ppc_data *ppc, int chipset_mode) 90567646539SMike Smith { 906f1d19042SArchie Cobbs int i, j, efer; 90746f3ff79SMike Smith unsigned char r, hefere, hefras; 90867646539SMike Smith 90946f3ff79SMike Smith for (i = 0; i < 4; i ++) { 91046f3ff79SMike Smith /* first try to enable configuration registers */ 91146f3ff79SMike Smith efer = w83877f_efers[i]; 91267646539SMike Smith 91346f3ff79SMike Smith /* write the key to the EFER */ 91446f3ff79SMike Smith for (j = 0; j < w83877f_keyiter[i]; j ++) 91546f3ff79SMike Smith outb (efer, w83877f_keys[i]); 91646f3ff79SMike Smith 91746f3ff79SMike Smith /* then check HEFERE and HEFRAS bits */ 91846f3ff79SMike Smith outb (efir, 0x0c); 91946f3ff79SMike Smith hefere = inb(efdr) & WINB_HEFERE; 92046f3ff79SMike Smith 92146f3ff79SMike Smith outb (efir, 0x16); 92246f3ff79SMike Smith hefras = inb(efdr) & WINB_HEFRAS; 92346f3ff79SMike Smith 92446f3ff79SMike Smith /* 92546f3ff79SMike Smith * HEFRAS HEFERE 92646f3ff79SMike Smith * 0 1 write 89h to 250h (power-on default) 92746f3ff79SMike Smith * 1 0 write 86h twice to 3f0h 92846f3ff79SMike Smith * 1 1 write 87h twice to 3f0h 92946f3ff79SMike Smith * 0 0 write 88h to 250h 93046f3ff79SMike Smith */ 93146f3ff79SMike Smith if ((hefere | hefras) == w83877f_hefs[i]) 93246f3ff79SMike Smith goto found; 93367646539SMike Smith } 93467646539SMike Smith 93546f3ff79SMike Smith return (-1); /* failed */ 93667646539SMike Smith 93746f3ff79SMike Smith found: 93846f3ff79SMike Smith /* check base port address - read from CR23 */ 93946f3ff79SMike Smith outb(efir, 0x23); 94046f3ff79SMike Smith if (ppc->ppc_base != inb(efdr) * 4) /* 4 bytes boundaries */ 94146f3ff79SMike Smith return (-1); 94246f3ff79SMike Smith 94346f3ff79SMike Smith /* read CHIP ID from CR9/bits0-3 */ 94446f3ff79SMike Smith outb(efir, 0x9); 94546f3ff79SMike Smith 94646f3ff79SMike Smith switch (inb(efdr) & WINB_CHIPID) { 94746f3ff79SMike Smith case WINB_W83877F_ID: 9480f210c92SNicolas Souchu ppc->ppc_model = WINB_W83877F; 94946f3ff79SMike Smith break; 95046f3ff79SMike Smith 95146f3ff79SMike Smith case WINB_W83877AF_ID: 9520f210c92SNicolas Souchu ppc->ppc_model = WINB_W83877AF; 95346f3ff79SMike Smith break; 95446f3ff79SMike Smith 95546f3ff79SMike Smith default: 9560f210c92SNicolas Souchu ppc->ppc_model = WINB_UNKNOWN; 95746f3ff79SMike Smith } 95846f3ff79SMike Smith 95946f3ff79SMike Smith if (bootverbose) { 96046f3ff79SMike Smith /* dump of registers */ 96146f3ff79SMike Smith printf("ppc%d: 0x%x - ", ppc->ppc_unit, w83877f_keys[i]); 96246f3ff79SMike Smith for (i = 0; i <= 0xd; i ++) { 96346f3ff79SMike Smith outb(efir, i); 96446f3ff79SMike Smith printf("0x%x ", inb(efdr)); 96546f3ff79SMike Smith } 96646f3ff79SMike Smith for (i = 0x10; i <= 0x17; i ++) { 96746f3ff79SMike Smith outb(efir, i); 96846f3ff79SMike Smith printf("0x%x ", inb(efdr)); 96946f3ff79SMike Smith } 97046f3ff79SMike Smith outb(efir, 0x1e); 97146f3ff79SMike Smith printf("0x%x ", inb(efdr)); 97246f3ff79SMike Smith for (i = 0x20; i <= 0x29; i ++) { 97346f3ff79SMike Smith outb(efir, i); 97446f3ff79SMike Smith printf("0x%x ", inb(efdr)); 97546f3ff79SMike Smith } 97646f3ff79SMike Smith printf("\n"); 977edcfcf27SNicolas Souchu printf("ppc%d:", ppc->ppc_unit); 97846f3ff79SMike Smith } 97946f3ff79SMike Smith 9800f210c92SNicolas Souchu ppc->ppc_type = PPC_TYPE_GENERIC; 981edcfcf27SNicolas Souchu 98246f3ff79SMike Smith if (!chipset_mode) { 98346f3ff79SMike Smith /* autodetect mode */ 98446f3ff79SMike Smith 98546f3ff79SMike Smith /* select CR0 */ 98646f3ff79SMike Smith outb(efir, 0x0); 98746f3ff79SMike Smith r = inb(efdr) & (WINB_PRTMODS0 | WINB_PRTMODS1); 98846f3ff79SMike Smith 98946f3ff79SMike Smith /* select CR9 */ 99046f3ff79SMike Smith outb(efir, 0x9); 99146f3ff79SMike Smith r |= (inb(efdr) & WINB_PRTMODS2); 99246f3ff79SMike Smith 99346f3ff79SMike Smith switch (r) { 99446f3ff79SMike Smith case WINB_W83757: 99546f3ff79SMike Smith if (bootverbose) 99646f3ff79SMike Smith printf("ppc%d: W83757 compatible mode\n", 99746f3ff79SMike Smith ppc->ppc_unit); 99846f3ff79SMike Smith return (-1); /* generic or SMC-like */ 99946f3ff79SMike Smith 100046f3ff79SMike Smith case WINB_EXTFDC: 100146f3ff79SMike Smith case WINB_EXTADP: 100246f3ff79SMike Smith case WINB_EXT2FDD: 100346f3ff79SMike Smith case WINB_JOYSTICK: 100446f3ff79SMike Smith if (bootverbose) 1005edcfcf27SNicolas Souchu printf(" not in parallel port mode\n"); 100646f3ff79SMike Smith return (-1); 100746f3ff79SMike Smith 100846f3ff79SMike Smith case (WINB_PARALLEL | WINB_EPP_SPP): 100946f3ff79SMike Smith ppc->ppc_avm |= PPB_EPP | PPB_SPP; 1010edcfcf27SNicolas Souchu if (bootverbose) 1011edcfcf27SNicolas Souchu printf(" EPP SPP"); 101246f3ff79SMike Smith break; 101346f3ff79SMike Smith 101446f3ff79SMike Smith case (WINB_PARALLEL | WINB_ECP): 101546f3ff79SMike Smith ppc->ppc_avm |= PPB_ECP | PPB_SPP; 1016edcfcf27SNicolas Souchu if (bootverbose) 1017edcfcf27SNicolas Souchu printf(" ECP SPP"); 101846f3ff79SMike Smith break; 101946f3ff79SMike Smith 102046f3ff79SMike Smith case (WINB_PARALLEL | WINB_ECP_EPP): 102146f3ff79SMike Smith ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP; 10220f210c92SNicolas Souchu ppc->ppc_type = PPC_TYPE_SMCLIKE; 1023edcfcf27SNicolas Souchu 1024edcfcf27SNicolas Souchu if (bootverbose) 1025edcfcf27SNicolas Souchu printf(" ECP+EPP SPP"); 102646f3ff79SMike Smith break; 102746f3ff79SMike Smith default: 102846f3ff79SMike Smith printf("%s: unknown case (0x%x)!\n", __FUNCTION__, r); 102946f3ff79SMike Smith } 103046f3ff79SMike Smith 103146f3ff79SMike Smith } else { 103246f3ff79SMike Smith /* mode forced */ 103346f3ff79SMike Smith 103446f3ff79SMike Smith /* select CR9 and set PRTMODS2 bit */ 103546f3ff79SMike Smith outb(efir, 0x9); 103646f3ff79SMike Smith outb(efdr, inb(efdr) & ~WINB_PRTMODS2); 103746f3ff79SMike Smith 103846f3ff79SMike Smith /* select CR0 and reset PRTMODSx bits */ 103946f3ff79SMike Smith outb(efir, 0x0); 104046f3ff79SMike Smith outb(efdr, inb(efdr) & ~(WINB_PRTMODS0 | WINB_PRTMODS1)); 104146f3ff79SMike Smith 104246f3ff79SMike Smith if (chipset_mode & PPB_ECP) { 1043edcfcf27SNicolas Souchu if (chipset_mode & PPB_EPP) { 104446f3ff79SMike Smith outb(efdr, inb(efdr) | WINB_ECP_EPP); 1045edcfcf27SNicolas Souchu if (bootverbose) 1046edcfcf27SNicolas Souchu printf(" ECP+EPP"); 1047edcfcf27SNicolas Souchu 10480f210c92SNicolas Souchu ppc->ppc_type = PPC_TYPE_SMCLIKE; 1049edcfcf27SNicolas Souchu 1050edcfcf27SNicolas Souchu } else { 105146f3ff79SMike Smith outb(efdr, inb(efdr) | WINB_ECP); 1052edcfcf27SNicolas Souchu if (bootverbose) 1053edcfcf27SNicolas Souchu printf(" ECP"); 1054edcfcf27SNicolas Souchu } 105546f3ff79SMike Smith } else { 105646f3ff79SMike Smith /* select EPP_SPP otherwise */ 105746f3ff79SMike Smith outb(efdr, inb(efdr) | WINB_EPP_SPP); 1058edcfcf27SNicolas Souchu if (bootverbose) 1059edcfcf27SNicolas Souchu printf(" EPP SPP"); 106046f3ff79SMike Smith } 106146f3ff79SMike Smith ppc->ppc_avm = chipset_mode; 106246f3ff79SMike Smith } 106346f3ff79SMike Smith 1064edcfcf27SNicolas Souchu if (bootverbose) 1065edcfcf27SNicolas Souchu printf("\n"); 1066edcfcf27SNicolas Souchu 106746f3ff79SMike Smith /* exit configuration mode */ 106846f3ff79SMike Smith outb(efer, 0xaa); 106946f3ff79SMike Smith 10700f210c92SNicolas Souchu switch (ppc->ppc_type) { 10710f210c92SNicolas Souchu case PPC_TYPE_SMCLIKE: 10720f210c92SNicolas Souchu ppc_smclike_setmode(ppc, chipset_mode); 10730f210c92SNicolas Souchu break; 10740f210c92SNicolas Souchu default: 10750f210c92SNicolas Souchu ppc_generic_setmode(ppc, chipset_mode); 10760f210c92SNicolas Souchu break; 10770f210c92SNicolas Souchu } 107846f3ff79SMike Smith 107946f3ff79SMike Smith return (chipset_mode); 108067646539SMike Smith } 10810f210c92SNicolas Souchu #endif 108267646539SMike Smith 108367646539SMike Smith /* 108467646539SMike Smith * ppc_generic_detect 108567646539SMike Smith */ 108667646539SMike Smith static int 108746f3ff79SMike Smith ppc_generic_detect(struct ppc_data *ppc, int chipset_mode) 108867646539SMike Smith { 1089edcfcf27SNicolas Souchu /* default to generic */ 10900f210c92SNicolas Souchu ppc->ppc_type = PPC_TYPE_GENERIC; 1091edcfcf27SNicolas Souchu 1092edcfcf27SNicolas Souchu if (bootverbose) 1093edcfcf27SNicolas Souchu printf("ppc%d:", ppc->ppc_unit); 1094edcfcf27SNicolas Souchu 109546f3ff79SMike Smith if (!chipset_mode) { 109646f3ff79SMike Smith /* first, check for ECP */ 1097bc35c174SNicolas Souchu w_ecr(ppc, PPC_ECR_PS2); 1098bc35c174SNicolas Souchu if ((r_ecr(ppc) & 0xe0) == PPC_ECR_PS2) { 109946f3ff79SMike Smith ppc->ppc_avm |= PPB_ECP | PPB_SPP; 1100edcfcf27SNicolas Souchu if (bootverbose) 1101edcfcf27SNicolas Souchu printf(" ECP SPP"); 110246f3ff79SMike Smith 110346f3ff79SMike Smith /* search for SMC style ECP+EPP mode */ 1104bc35c174SNicolas Souchu w_ecr(ppc, PPC_ECR_EPP); 110546f3ff79SMike Smith } 110667646539SMike Smith 110767646539SMike Smith /* try to reset EPP timeout bit */ 110846f3ff79SMike Smith if (ppc_check_epp_timeout(ppc)) { 110946f3ff79SMike Smith ppc->ppc_avm |= PPB_EPP; 111067646539SMike Smith 1111edcfcf27SNicolas Souchu if (ppc->ppc_avm & PPB_ECP) { 111246f3ff79SMike Smith /* SMC like chipset found */ 11130f210c92SNicolas Souchu ppc->ppc_model = SMC_LIKE; 11140f210c92SNicolas Souchu ppc->ppc_type = PPC_TYPE_SMCLIKE; 1115edcfcf27SNicolas Souchu 1116edcfcf27SNicolas Souchu if (bootverbose) 1117edcfcf27SNicolas Souchu printf(" ECP+EPP"); 1118edcfcf27SNicolas Souchu } else { 1119edcfcf27SNicolas Souchu if (bootverbose) 1120edcfcf27SNicolas Souchu printf(" EPP"); 1121edcfcf27SNicolas Souchu } 1122edcfcf27SNicolas Souchu } else { 1123edcfcf27SNicolas Souchu /* restore to standard mode */ 1124bc35c174SNicolas Souchu w_ecr(ppc, PPC_ECR_STD); 112567646539SMike Smith } 112667646539SMike Smith 1127edcfcf27SNicolas Souchu /* XXX try to detect NIBBLE and PS2 modes */ 112846f3ff79SMike Smith ppc->ppc_avm |= PPB_NIBBLE; 112967646539SMike Smith 1130edcfcf27SNicolas Souchu if (bootverbose) 1131edcfcf27SNicolas Souchu printf(" SPP"); 113267646539SMike Smith 1133edcfcf27SNicolas Souchu } else { 1134edcfcf27SNicolas Souchu ppc->ppc_avm = chipset_mode; 1135edcfcf27SNicolas Souchu } 1136edcfcf27SNicolas Souchu 1137edcfcf27SNicolas Souchu if (bootverbose) 1138edcfcf27SNicolas Souchu printf("\n"); 1139edcfcf27SNicolas Souchu 11400f210c92SNicolas Souchu switch (ppc->ppc_type) { 11410f210c92SNicolas Souchu case PPC_TYPE_SMCLIKE: 11420f210c92SNicolas Souchu ppc_smclike_setmode(ppc, chipset_mode); 11430f210c92SNicolas Souchu break; 11440f210c92SNicolas Souchu default: 11450f210c92SNicolas Souchu ppc_generic_setmode(ppc, chipset_mode); 11460f210c92SNicolas Souchu break; 11470f210c92SNicolas Souchu } 114846f3ff79SMike Smith 114946f3ff79SMike Smith return (chipset_mode); 115067646539SMike Smith } 115167646539SMike Smith 115267646539SMike Smith /* 115367646539SMike Smith * ppc_detect() 115467646539SMike Smith * 115567646539SMike Smith * mode is the mode suggested at boot 115667646539SMike Smith */ 115767646539SMike Smith static int 115846f3ff79SMike Smith ppc_detect(struct ppc_data *ppc, int chipset_mode) { 115967646539SMike Smith 11600f210c92SNicolas Souchu #ifdef PPC_PROBE_CHIPSET 116146f3ff79SMike Smith int i, mode; 116267646539SMike Smith 116346f3ff79SMike Smith /* list of supported chipsets */ 116446f3ff79SMike Smith int (*chipset_detect[])(struct ppc_data *, int) = { 116546f3ff79SMike Smith ppc_pc873xx_detect, 116646f3ff79SMike Smith ppc_smc37c66xgt_detect, 116746f3ff79SMike Smith ppc_w83877f_detect, 116846f3ff79SMike Smith ppc_generic_detect, 116946f3ff79SMike Smith NULL 117046f3ff79SMike Smith }; 11710f210c92SNicolas Souchu #endif 117267646539SMike Smith 117346f3ff79SMike Smith /* if can't find the port and mode not forced return error */ 117446f3ff79SMike Smith if (!ppc_detect_port(ppc) && chipset_mode == 0) 117546f3ff79SMike Smith return (EIO); /* failed, port not present */ 117667646539SMike Smith 117746f3ff79SMike Smith /* assume centronics compatible mode is supported */ 117846f3ff79SMike Smith ppc->ppc_avm = PPB_COMPATIBLE; 117967646539SMike Smith 11800f210c92SNicolas Souchu #ifdef PPC_PROBE_CHIPSET 118146f3ff79SMike Smith /* we have to differenciate available chipset modes, 118246f3ff79SMike Smith * chipset running modes and IEEE-1284 operating modes 118346f3ff79SMike Smith * 118446f3ff79SMike Smith * after detection, the port must support running in compatible mode 118546f3ff79SMike Smith */ 1186af548787SNicolas Souchu if (ppc->ppc_flags & 0x40) { 1187af548787SNicolas Souchu if (bootverbose) 1188af548787SNicolas Souchu printf("ppc: chipset forced to generic\n"); 11890f210c92SNicolas Souchu #endif 1190af548787SNicolas Souchu 1191af548787SNicolas Souchu ppc->ppc_mode = ppc_generic_detect(ppc, chipset_mode); 1192af548787SNicolas Souchu 11930f210c92SNicolas Souchu #ifdef PPC_PROBE_CHIPSET 1194af548787SNicolas Souchu } else { 119546f3ff79SMike Smith for (i=0; chipset_detect[i] != NULL; i++) { 119646f3ff79SMike Smith if ((mode = chipset_detect[i](ppc, chipset_mode)) != -1) { 119746f3ff79SMike Smith ppc->ppc_mode = mode; 119846f3ff79SMike Smith break; 119946f3ff79SMike Smith } 120046f3ff79SMike Smith } 1201af548787SNicolas Souchu } 12020f210c92SNicolas Souchu #endif 120346f3ff79SMike Smith 1204bc35c174SNicolas Souchu /* configure/detect ECP FIFO */ 1205bc35c174SNicolas Souchu if ((ppc->ppc_avm & PPB_ECP) && !(ppc->ppc_flags & 0x80)) 1206bc35c174SNicolas Souchu ppc_detect_fifo(ppc); 1207bc35c174SNicolas Souchu 120846f3ff79SMike Smith return (0); 120946f3ff79SMike Smith } 121046f3ff79SMike Smith 121146f3ff79SMike Smith /* 121246f3ff79SMike Smith * ppc_exec_microseq() 121346f3ff79SMike Smith * 121446f3ff79SMike Smith * Execute a microsequence. 121546f3ff79SMike Smith * Microsequence mechanism is supposed to handle fast I/O operations. 121646f3ff79SMike Smith */ 121746f3ff79SMike Smith static int 12180f210c92SNicolas Souchu ppc_exec_microseq(device_t dev, struct ppb_microseq **p_msq) 121946f3ff79SMike Smith { 12200f210c92SNicolas Souchu struct ppc_data *ppc = DEVTOSOFTC(dev); 12210a40e22aSNicolas Souchu struct ppb_microseq *mi; 122246f3ff79SMike Smith char cc, *p; 122354ad6085SNicolas Souchu int i, iter, len; 122446f3ff79SMike Smith int error; 122546f3ff79SMike Smith 122654ad6085SNicolas Souchu register int reg; 122754ad6085SNicolas Souchu register char mask; 122854ad6085SNicolas Souchu register int accum = 0; 122954ad6085SNicolas Souchu register char *ptr = 0; 123046f3ff79SMike Smith 12310a40e22aSNicolas Souchu struct ppb_microseq *stack = 0; 123246f3ff79SMike Smith 123346f3ff79SMike Smith /* microsequence registers are equivalent to PC-like port registers */ 1234a7006f89SNicolas Souchu #define r_reg(register,ppc) (inb((ppc)->ppc_base + register)) 123546f3ff79SMike Smith #define w_reg(register,ppc,byte) outb((ppc)->ppc_base + register, byte) 123646f3ff79SMike Smith 12370a40e22aSNicolas Souchu #define INCR_PC (mi ++) /* increment program counter */ 123846f3ff79SMike Smith 12390a40e22aSNicolas Souchu mi = *p_msq; 124046f3ff79SMike Smith for (;;) { 124146f3ff79SMike Smith switch (mi->opcode) { 124246f3ff79SMike Smith case MS_OP_RSET: 124346f3ff79SMike Smith cc = r_reg(mi->arg[0].i, ppc); 124454ad6085SNicolas Souchu cc &= (char)mi->arg[2].i; /* clear mask */ 124554ad6085SNicolas Souchu cc |= (char)mi->arg[1].i; /* assert mask */ 124646f3ff79SMike Smith w_reg(mi->arg[0].i, ppc, cc); 124746f3ff79SMike Smith INCR_PC; 124846f3ff79SMike Smith break; 124946f3ff79SMike Smith 125046f3ff79SMike Smith case MS_OP_RASSERT_P: 125154ad6085SNicolas Souchu reg = mi->arg[1].i; 125254ad6085SNicolas Souchu ptr = ppc->ppc_ptr; 125354ad6085SNicolas Souchu 125454ad6085SNicolas Souchu if ((len = mi->arg[0].i) == MS_ACCUM) { 125554ad6085SNicolas Souchu accum = ppc->ppc_accum; 125654ad6085SNicolas Souchu for (; accum; accum--) 125754ad6085SNicolas Souchu w_reg(reg, ppc, *ptr++); 125854ad6085SNicolas Souchu ppc->ppc_accum = accum; 125954ad6085SNicolas Souchu } else 126054ad6085SNicolas Souchu for (i=0; i<len; i++) 126154ad6085SNicolas Souchu w_reg(reg, ppc, *ptr++); 126254ad6085SNicolas Souchu ppc->ppc_ptr = ptr; 126354ad6085SNicolas Souchu 126446f3ff79SMike Smith INCR_PC; 126546f3ff79SMike Smith break; 126646f3ff79SMike Smith 126746f3ff79SMike Smith case MS_OP_RFETCH_P: 126854ad6085SNicolas Souchu reg = mi->arg[1].i; 126954ad6085SNicolas Souchu mask = (char)mi->arg[2].i; 127054ad6085SNicolas Souchu ptr = ppc->ppc_ptr; 127154ad6085SNicolas Souchu 127254ad6085SNicolas Souchu if ((len = mi->arg[0].i) == MS_ACCUM) { 127354ad6085SNicolas Souchu accum = ppc->ppc_accum; 127454ad6085SNicolas Souchu for (; accum; accum--) 127554ad6085SNicolas Souchu *ptr++ = r_reg(reg, ppc) & mask; 127654ad6085SNicolas Souchu ppc->ppc_accum = accum; 127754ad6085SNicolas Souchu } else 127854ad6085SNicolas Souchu for (i=0; i<len; i++) 127954ad6085SNicolas Souchu *ptr++ = r_reg(reg, ppc) & mask; 128054ad6085SNicolas Souchu ppc->ppc_ptr = ptr; 128154ad6085SNicolas Souchu 128246f3ff79SMike Smith INCR_PC; 128346f3ff79SMike Smith break; 128446f3ff79SMike Smith 128546f3ff79SMike Smith case MS_OP_RFETCH: 128646f3ff79SMike Smith *((char *) mi->arg[2].p) = r_reg(mi->arg[0].i, ppc) & 128754ad6085SNicolas Souchu (char)mi->arg[1].i; 128846f3ff79SMike Smith INCR_PC; 128946f3ff79SMike Smith break; 129046f3ff79SMike Smith 129146f3ff79SMike Smith case MS_OP_RASSERT: 129254ad6085SNicolas Souchu case MS_OP_DELAY: 129346f3ff79SMike Smith 129446f3ff79SMike Smith /* let's suppose the next instr. is the same */ 129546f3ff79SMike Smith prefetch: 129646f3ff79SMike Smith for (;mi->opcode == MS_OP_RASSERT; INCR_PC) 129754ad6085SNicolas Souchu w_reg(mi->arg[0].i, ppc, (char)mi->arg[1].i); 129846f3ff79SMike Smith 129946f3ff79SMike Smith if (mi->opcode == MS_OP_DELAY) { 130046f3ff79SMike Smith DELAY(mi->arg[0].i); 130146f3ff79SMike Smith INCR_PC; 130246f3ff79SMike Smith goto prefetch; 130346f3ff79SMike Smith } 130446f3ff79SMike Smith break; 130546f3ff79SMike Smith 130654ad6085SNicolas Souchu case MS_OP_ADELAY: 130754ad6085SNicolas Souchu if (mi->arg[0].i) 130854ad6085SNicolas Souchu tsleep(NULL, PPBPRI, "ppbdelay", 130954ad6085SNicolas Souchu mi->arg[0].i * (hz/1000)); 131046f3ff79SMike Smith INCR_PC; 131146f3ff79SMike Smith break; 131246f3ff79SMike Smith 131346f3ff79SMike Smith case MS_OP_TRIG: 131446f3ff79SMike Smith reg = mi->arg[0].i; 131546f3ff79SMike Smith iter = mi->arg[1].i; 131646f3ff79SMike Smith p = (char *)mi->arg[2].p; 131746f3ff79SMike Smith 131854ad6085SNicolas Souchu /* XXX delay limited to 255 us */ 131946f3ff79SMike Smith for (i=0; i<iter; i++) { 132046f3ff79SMike Smith w_reg(reg, ppc, *p++); 132146f3ff79SMike Smith DELAY((unsigned char)*p++); 132246f3ff79SMike Smith } 132346f3ff79SMike Smith INCR_PC; 132446f3ff79SMike Smith break; 132546f3ff79SMike Smith 132646f3ff79SMike Smith case MS_OP_SET: 132754ad6085SNicolas Souchu ppc->ppc_accum = mi->arg[0].i; 132846f3ff79SMike Smith INCR_PC; 132946f3ff79SMike Smith break; 133046f3ff79SMike Smith 133146f3ff79SMike Smith case MS_OP_DBRA: 133254ad6085SNicolas Souchu if (--ppc->ppc_accum > 0) 13330a40e22aSNicolas Souchu mi += mi->arg[0].i; 133446f3ff79SMike Smith INCR_PC; 133546f3ff79SMike Smith break; 133646f3ff79SMike Smith 133746f3ff79SMike Smith case MS_OP_BRSET: 133846f3ff79SMike Smith cc = r_str(ppc); 133954ad6085SNicolas Souchu if ((cc & (char)mi->arg[0].i) == (char)mi->arg[0].i) 13400a40e22aSNicolas Souchu mi += mi->arg[1].i; 134146f3ff79SMike Smith INCR_PC; 134246f3ff79SMike Smith break; 134346f3ff79SMike Smith 134446f3ff79SMike Smith case MS_OP_BRCLEAR: 134546f3ff79SMike Smith cc = r_str(ppc); 134654ad6085SNicolas Souchu if ((cc & (char)mi->arg[0].i) == 0) 13470a40e22aSNicolas Souchu mi += mi->arg[1].i; 134846f3ff79SMike Smith INCR_PC; 134946f3ff79SMike Smith break; 135046f3ff79SMike Smith 135154ad6085SNicolas Souchu case MS_OP_BRSTAT: 135254ad6085SNicolas Souchu cc = r_str(ppc); 135354ad6085SNicolas Souchu if ((cc & ((char)mi->arg[0].i | (char)mi->arg[1].i)) == 135454ad6085SNicolas Souchu (char)mi->arg[0].i) 13550a40e22aSNicolas Souchu mi += mi->arg[2].i; 135654ad6085SNicolas Souchu INCR_PC; 135754ad6085SNicolas Souchu break; 135854ad6085SNicolas Souchu 135946f3ff79SMike Smith case MS_OP_C_CALL: 136046f3ff79SMike Smith /* 136146f3ff79SMike Smith * If the C call returns !0 then end the microseq. 136246f3ff79SMike Smith * The current state of ptr is passed to the C function 136346f3ff79SMike Smith */ 136454ad6085SNicolas Souchu if ((error = mi->arg[0].f(mi->arg[1].p, ppc->ppc_ptr))) 136546f3ff79SMike Smith return (error); 136646f3ff79SMike Smith 136746f3ff79SMike Smith INCR_PC; 136846f3ff79SMike Smith break; 136946f3ff79SMike Smith 137046f3ff79SMike Smith case MS_OP_PTR: 137154ad6085SNicolas Souchu ppc->ppc_ptr = (char *)mi->arg[0].p; 137246f3ff79SMike Smith INCR_PC; 137346f3ff79SMike Smith break; 137446f3ff79SMike Smith 137546f3ff79SMike Smith case MS_OP_CALL: 13760a40e22aSNicolas Souchu if (stack) 137746f3ff79SMike Smith panic("%s: too much calls", __FUNCTION__); 137846f3ff79SMike Smith 137946f3ff79SMike Smith if (mi->arg[0].p) { 138046f3ff79SMike Smith /* store the state of the actual 138146f3ff79SMike Smith * microsequence 138246f3ff79SMike Smith */ 13830a40e22aSNicolas Souchu stack = mi; 138446f3ff79SMike Smith 138546f3ff79SMike Smith /* jump to the new microsequence */ 13860a40e22aSNicolas Souchu mi = (struct ppb_microseq *)mi->arg[0].p; 138746f3ff79SMike Smith } else 138846f3ff79SMike Smith INCR_PC; 138946f3ff79SMike Smith 139046f3ff79SMike Smith break; 139146f3ff79SMike Smith 139246f3ff79SMike Smith case MS_OP_SUBRET: 139346f3ff79SMike Smith /* retrieve microseq and pc state before the call */ 13940a40e22aSNicolas Souchu mi = stack; 139546f3ff79SMike Smith 139646f3ff79SMike Smith /* reset the stack */ 13970a40e22aSNicolas Souchu stack = 0; 139846f3ff79SMike Smith 139946f3ff79SMike Smith /* XXX return code */ 140046f3ff79SMike Smith 140146f3ff79SMike Smith INCR_PC; 140246f3ff79SMike Smith break; 140346f3ff79SMike Smith 140446f3ff79SMike Smith case MS_OP_PUT: 140546f3ff79SMike Smith case MS_OP_GET: 140646f3ff79SMike Smith case MS_OP_RET: 140746f3ff79SMike Smith /* can't return to ppb level during the execution 140846f3ff79SMike Smith * of a submicrosequence */ 14090a40e22aSNicolas Souchu if (stack) 141046f3ff79SMike Smith panic("%s: can't return to ppb level", 141146f3ff79SMike Smith __FUNCTION__); 141246f3ff79SMike Smith 141346f3ff79SMike Smith /* update pc for ppb level of execution */ 14140a40e22aSNicolas Souchu *p_msq = mi; 141546f3ff79SMike Smith 141646f3ff79SMike Smith /* return to ppb level of execution */ 141746f3ff79SMike Smith return (0); 141846f3ff79SMike Smith 141946f3ff79SMike Smith default: 142046f3ff79SMike Smith panic("%s: unknown microsequence opcode 0x%x", 142146f3ff79SMike Smith __FUNCTION__, mi->opcode); 142246f3ff79SMike Smith } 142346f3ff79SMike Smith } 142446f3ff79SMike Smith 142546f3ff79SMike Smith /* unreached */ 142646f3ff79SMike Smith } 142746f3ff79SMike Smith 1428bc35c174SNicolas Souchu static void 14290f210c92SNicolas Souchu ppcintr(void *arg) 1430bc35c174SNicolas Souchu { 14310f210c92SNicolas Souchu device_t dev = (device_t)arg; 14320f210c92SNicolas Souchu struct ppc_data *ppc = (struct ppc_data *)device_get_softc(dev); 14333ab971c1SNicolas Souchu u_char ctr, ecr, str; 1434bc35c174SNicolas Souchu 14353ab971c1SNicolas Souchu str = r_str(ppc); 1436bc35c174SNicolas Souchu ctr = r_ctr(ppc); 1437bc35c174SNicolas Souchu ecr = r_ecr(ppc); 1438bc35c174SNicolas Souchu 14393ab971c1SNicolas Souchu #if PPC_DEBUG > 1 14403ab971c1SNicolas Souchu printf("![%x/%x/%x]", ctr, ecr, str); 1441bc35c174SNicolas Souchu #endif 1442bc35c174SNicolas Souchu 1443bc35c174SNicolas Souchu /* don't use ecp mode with IRQENABLE set */ 1444bc35c174SNicolas Souchu if (ctr & IRQENABLE) { 1445bc35c174SNicolas Souchu return; 1446bc35c174SNicolas Souchu } 1447bc35c174SNicolas Souchu 14483ab971c1SNicolas Souchu /* interrupts are generated by nFault signal 14493ab971c1SNicolas Souchu * only in ECP mode */ 14503ab971c1SNicolas Souchu if ((str & nFAULT) && (ppc->ppc_mode & PPB_ECP)) { 14513ab971c1SNicolas Souchu /* check if ppc driver has programmed the 14523ab971c1SNicolas Souchu * nFault interrupt */ 1453bc35c174SNicolas Souchu if (ppc->ppc_irqstat & PPC_IRQ_nFAULT) { 1454bc35c174SNicolas Souchu 1455bc35c174SNicolas Souchu w_ecr(ppc, ecr | PPC_nFAULT_INTR); 1456bc35c174SNicolas Souchu ppc->ppc_irqstat &= ~PPC_IRQ_nFAULT; 1457bc35c174SNicolas Souchu } else { 14580f210c92SNicolas Souchu /* shall be handled by underlying layers XXX */ 1459bc35c174SNicolas Souchu return; 1460bc35c174SNicolas Souchu } 1461bc35c174SNicolas Souchu } 1462bc35c174SNicolas Souchu 1463bc35c174SNicolas Souchu if (ppc->ppc_irqstat & PPC_IRQ_DMA) { 1464bc35c174SNicolas Souchu /* disable interrupts (should be done by hardware though) */ 1465bc35c174SNicolas Souchu w_ecr(ppc, ecr | PPC_SERVICE_INTR); 1466bc35c174SNicolas Souchu ppc->ppc_irqstat &= ~PPC_IRQ_DMA; 1467bc35c174SNicolas Souchu ecr = r_ecr(ppc); 1468bc35c174SNicolas Souchu 1469bc35c174SNicolas Souchu /* check if DMA completed */ 1470bc35c174SNicolas Souchu if ((ppc->ppc_avm & PPB_ECP) && (ecr & PPC_ENABLE_DMA)) { 1471bc35c174SNicolas Souchu #ifdef PPC_DEBUG 1472bc35c174SNicolas Souchu printf("a"); 1473bc35c174SNicolas Souchu #endif 1474bc35c174SNicolas Souchu /* stop DMA */ 1475bc35c174SNicolas Souchu w_ecr(ppc, ecr & ~PPC_ENABLE_DMA); 1476bc35c174SNicolas Souchu ecr = r_ecr(ppc); 1477bc35c174SNicolas Souchu 1478bc35c174SNicolas Souchu if (ppc->ppc_dmastat == PPC_DMA_STARTED) { 1479bc35c174SNicolas Souchu #ifdef PPC_DEBUG 1480bc35c174SNicolas Souchu printf("d"); 1481bc35c174SNicolas Souchu #endif 1482bc35c174SNicolas Souchu isa_dmadone( 1483bc35c174SNicolas Souchu ppc->ppc_dmaflags, 1484bc35c174SNicolas Souchu ppc->ppc_dmaddr, 1485bc35c174SNicolas Souchu ppc->ppc_dmacnt, 1486bc35c174SNicolas Souchu ppc->ppc_dmachan); 1487bc35c174SNicolas Souchu 1488bc35c174SNicolas Souchu ppc->ppc_dmastat = PPC_DMA_COMPLETE; 1489bc35c174SNicolas Souchu 1490bc35c174SNicolas Souchu /* wakeup the waiting process */ 1491bc35c174SNicolas Souchu wakeup((caddr_t)ppc); 1492bc35c174SNicolas Souchu } 1493bc35c174SNicolas Souchu } 1494bc35c174SNicolas Souchu } else if (ppc->ppc_irqstat & PPC_IRQ_FIFO) { 1495bc35c174SNicolas Souchu 1496bc35c174SNicolas Souchu /* classic interrupt I/O */ 1497bc35c174SNicolas Souchu ppc->ppc_irqstat &= ~PPC_IRQ_FIFO; 1498bc35c174SNicolas Souchu } 1499bc35c174SNicolas Souchu 1500bc35c174SNicolas Souchu return; 1501bc35c174SNicolas Souchu } 1502bc35c174SNicolas Souchu 1503bc35c174SNicolas Souchu static int 15040f210c92SNicolas Souchu ppc_read(device_t dev, char *buf, int len, int mode) 1505bc35c174SNicolas Souchu { 1506bc35c174SNicolas Souchu return (EINVAL); 1507bc35c174SNicolas Souchu } 1508bc35c174SNicolas Souchu 1509bc35c174SNicolas Souchu /* 1510bc35c174SNicolas Souchu * Call this function if you want to send data in any advanced mode 1511bc35c174SNicolas Souchu * of your parallel port: FIFO, DMA 1512bc35c174SNicolas Souchu * 1513bc35c174SNicolas Souchu * If what you want is not possible (no ECP, no DMA...), 1514bc35c174SNicolas Souchu * EINVAL is returned 1515bc35c174SNicolas Souchu */ 1516bc35c174SNicolas Souchu static int 15170f210c92SNicolas Souchu ppc_write(device_t dev, char *buf, int len, int how) 1518bc35c174SNicolas Souchu { 15190f210c92SNicolas Souchu struct ppc_data *ppc = DEVTOSOFTC(dev); 1520bc35c174SNicolas Souchu char ecr, ecr_sav, ctr, ctr_sav; 1521bc35c174SNicolas Souchu int s, error = 0; 1522bc35c174SNicolas Souchu int spin; 1523bc35c174SNicolas Souchu 1524bc35c174SNicolas Souchu #ifdef PPC_DEBUG 1525bc35c174SNicolas Souchu printf("w"); 1526bc35c174SNicolas Souchu #endif 1527bc35c174SNicolas Souchu 1528bc35c174SNicolas Souchu ecr_sav = r_ecr(ppc); 1529bc35c174SNicolas Souchu ctr_sav = r_ctr(ppc); 1530bc35c174SNicolas Souchu 1531bc35c174SNicolas Souchu /* 1532bc35c174SNicolas Souchu * Send buffer with DMA, FIFO and interrupts 1533bc35c174SNicolas Souchu */ 15340f210c92SNicolas Souchu if ((ppc->ppc_avm & PPB_ECP) && (ppc->ppc_registered)) { 1535bc35c174SNicolas Souchu 1536bc35c174SNicolas Souchu if (ppc->ppc_dmachan >= 0) { 1537bc35c174SNicolas Souchu 1538bc35c174SNicolas Souchu /* byte mode, no intr, no DMA, dir=0, flush fifo 1539bc35c174SNicolas Souchu */ 1540bc35c174SNicolas Souchu ecr = PPC_ECR_STD | PPC_DISABLE_INTR; 1541bc35c174SNicolas Souchu w_ecr(ppc, ecr); 1542bc35c174SNicolas Souchu 1543bc35c174SNicolas Souchu /* disable nAck interrupts */ 1544bc35c174SNicolas Souchu ctr = r_ctr(ppc); 1545bc35c174SNicolas Souchu ctr &= ~IRQENABLE; 1546bc35c174SNicolas Souchu w_ctr(ppc, ctr); 1547bc35c174SNicolas Souchu 1548bc35c174SNicolas Souchu ppc->ppc_dmaflags = 0; 1549bc35c174SNicolas Souchu ppc->ppc_dmaddr = (caddr_t)buf; 1550bc35c174SNicolas Souchu ppc->ppc_dmacnt = (u_int)len; 1551bc35c174SNicolas Souchu 1552bc35c174SNicolas Souchu switch (ppc->ppc_mode) { 1553bc35c174SNicolas Souchu case PPB_COMPATIBLE: 1554bc35c174SNicolas Souchu /* compatible mode with FIFO, no intr, DMA, dir=0 */ 1555bc35c174SNicolas Souchu ecr = PPC_ECR_FIFO | PPC_DISABLE_INTR | PPC_ENABLE_DMA; 1556bc35c174SNicolas Souchu break; 1557bc35c174SNicolas Souchu case PPB_ECP: 1558bc35c174SNicolas Souchu ecr = PPC_ECR_ECP | PPC_DISABLE_INTR | PPC_ENABLE_DMA; 1559bc35c174SNicolas Souchu break; 1560bc35c174SNicolas Souchu default: 1561bc35c174SNicolas Souchu error = EINVAL; 1562bc35c174SNicolas Souchu goto error; 1563bc35c174SNicolas Souchu } 1564bc35c174SNicolas Souchu 1565bc35c174SNicolas Souchu w_ecr(ppc, ecr); 1566bc35c174SNicolas Souchu ecr = r_ecr(ppc); 1567bc35c174SNicolas Souchu 1568bc35c174SNicolas Souchu /* enter splhigh() not to be preempted 1569bc35c174SNicolas Souchu * by the dma interrupt, we may miss 1570bc35c174SNicolas Souchu * the wakeup otherwise 1571bc35c174SNicolas Souchu */ 1572bc35c174SNicolas Souchu s = splhigh(); 1573bc35c174SNicolas Souchu 1574bc35c174SNicolas Souchu ppc->ppc_dmastat = PPC_DMA_INIT; 1575bc35c174SNicolas Souchu 1576bc35c174SNicolas Souchu /* enable interrupts */ 1577bc35c174SNicolas Souchu ecr &= ~PPC_SERVICE_INTR; 1578bc35c174SNicolas Souchu ppc->ppc_irqstat = PPC_IRQ_DMA; 1579bc35c174SNicolas Souchu w_ecr(ppc, ecr); 1580bc35c174SNicolas Souchu 1581bc35c174SNicolas Souchu isa_dmastart( 1582bc35c174SNicolas Souchu ppc->ppc_dmaflags, 1583bc35c174SNicolas Souchu ppc->ppc_dmaddr, 1584bc35c174SNicolas Souchu ppc->ppc_dmacnt, 1585bc35c174SNicolas Souchu ppc->ppc_dmachan); 1586bc35c174SNicolas Souchu #ifdef PPC_DEBUG 1587bc35c174SNicolas Souchu printf("s%d", ppc->ppc_dmacnt); 1588bc35c174SNicolas Souchu #endif 1589bc35c174SNicolas Souchu ppc->ppc_dmastat = PPC_DMA_STARTED; 1590bc35c174SNicolas Souchu 1591bc35c174SNicolas Souchu /* Wait for the DMA completed interrupt. We hope we won't 1592bc35c174SNicolas Souchu * miss it, otherwise a signal will be necessary to unlock the 1593bc35c174SNicolas Souchu * process. 1594bc35c174SNicolas Souchu */ 1595bc35c174SNicolas Souchu do { 1596bc35c174SNicolas Souchu /* release CPU */ 1597bc35c174SNicolas Souchu error = tsleep((caddr_t)ppc, 1598bc35c174SNicolas Souchu PPBPRI | PCATCH, "ppcdma", 0); 1599bc35c174SNicolas Souchu 1600bc35c174SNicolas Souchu } while (error == EWOULDBLOCK); 1601bc35c174SNicolas Souchu 1602bc35c174SNicolas Souchu splx(s); 1603bc35c174SNicolas Souchu 1604bc35c174SNicolas Souchu if (error) { 1605bc35c174SNicolas Souchu #ifdef PPC_DEBUG 1606bc35c174SNicolas Souchu printf("i"); 1607bc35c174SNicolas Souchu #endif 1608bc35c174SNicolas Souchu /* stop DMA */ 1609bc35c174SNicolas Souchu isa_dmadone( 1610bc35c174SNicolas Souchu ppc->ppc_dmaflags, ppc->ppc_dmaddr, 1611bc35c174SNicolas Souchu ppc->ppc_dmacnt, ppc->ppc_dmachan); 1612bc35c174SNicolas Souchu 1613bc35c174SNicolas Souchu /* no dma, no interrupt, flush the fifo */ 1614bc35c174SNicolas Souchu w_ecr(ppc, PPC_ECR_RESET); 1615bc35c174SNicolas Souchu 1616bc35c174SNicolas Souchu ppc->ppc_dmastat = PPC_DMA_INTERRUPTED; 1617bc35c174SNicolas Souchu goto error; 1618bc35c174SNicolas Souchu } 1619bc35c174SNicolas Souchu 1620bc35c174SNicolas Souchu /* wait for an empty fifo */ 1621bc35c174SNicolas Souchu while (!(r_ecr(ppc) & PPC_FIFO_EMPTY)) { 1622bc35c174SNicolas Souchu 1623bc35c174SNicolas Souchu for (spin=100; spin; spin--) 1624bc35c174SNicolas Souchu if (r_ecr(ppc) & PPC_FIFO_EMPTY) 1625bc35c174SNicolas Souchu goto fifo_empty; 1626bc35c174SNicolas Souchu #ifdef PPC_DEBUG 1627bc35c174SNicolas Souchu printf("Z"); 1628bc35c174SNicolas Souchu #endif 1629bc35c174SNicolas Souchu error = tsleep((caddr_t)ppc, PPBPRI | PCATCH, "ppcfifo", hz/100); 1630bc35c174SNicolas Souchu if (error != EWOULDBLOCK) { 1631bc35c174SNicolas Souchu #ifdef PPC_DEBUG 1632bc35c174SNicolas Souchu printf("I"); 1633bc35c174SNicolas Souchu #endif 1634bc35c174SNicolas Souchu /* no dma, no interrupt, flush the fifo */ 1635bc35c174SNicolas Souchu w_ecr(ppc, PPC_ECR_RESET); 1636bc35c174SNicolas Souchu 1637bc35c174SNicolas Souchu ppc->ppc_dmastat = PPC_DMA_INTERRUPTED; 1638bc35c174SNicolas Souchu error = EINTR; 1639bc35c174SNicolas Souchu goto error; 1640bc35c174SNicolas Souchu } 1641bc35c174SNicolas Souchu } 1642bc35c174SNicolas Souchu 1643bc35c174SNicolas Souchu fifo_empty: 1644bc35c174SNicolas Souchu /* no dma, no interrupt, flush the fifo */ 1645bc35c174SNicolas Souchu w_ecr(ppc, PPC_ECR_RESET); 1646bc35c174SNicolas Souchu 1647bc35c174SNicolas Souchu } else 1648bc35c174SNicolas Souchu error = EINVAL; /* XXX we should FIFO and 1649bc35c174SNicolas Souchu * interrupts */ 1650bc35c174SNicolas Souchu } else 1651bc35c174SNicolas Souchu error = EINVAL; 1652bc35c174SNicolas Souchu 1653bc35c174SNicolas Souchu error: 1654bc35c174SNicolas Souchu 1655bc35c174SNicolas Souchu /* PDRQ must be kept unasserted until nPDACK is 1656bc35c174SNicolas Souchu * deasserted for a minimum of 350ns (SMC datasheet) 1657bc35c174SNicolas Souchu * 1658bc35c174SNicolas Souchu * Consequence may be a FIFO that never empty 1659bc35c174SNicolas Souchu */ 1660bc35c174SNicolas Souchu DELAY(1); 1661bc35c174SNicolas Souchu 1662bc35c174SNicolas Souchu w_ecr(ppc, ecr_sav); 1663bc35c174SNicolas Souchu w_ctr(ppc, ctr_sav); 1664bc35c174SNicolas Souchu 1665bc35c174SNicolas Souchu return (error); 1666bc35c174SNicolas Souchu } 1667bc35c174SNicolas Souchu 166867646539SMike Smith static void 16690f210c92SNicolas Souchu ppc_reset_epp(device_t dev) 167067646539SMike Smith { 16710f210c92SNicolas Souchu struct ppc_data *ppc = DEVTOSOFTC(dev); 167267646539SMike Smith 16730f210c92SNicolas Souchu ppc_reset_epp_timeout(ppc); 167467646539SMike Smith 167567646539SMike Smith return; 167667646539SMike Smith } 167767646539SMike Smith 167867646539SMike Smith static int 16790f210c92SNicolas Souchu ppc_setmode(device_t dev, int mode) 16800f210c92SNicolas Souchu { 16810f210c92SNicolas Souchu struct ppc_data *ppc = DEVTOSOFTC(dev); 16820f210c92SNicolas Souchu 16830f210c92SNicolas Souchu switch (ppc->ppc_type) { 16840f210c92SNicolas Souchu case PPC_TYPE_SMCLIKE: 16850f210c92SNicolas Souchu return (ppc_smclike_setmode(ppc, mode)); 16860f210c92SNicolas Souchu break; 16870f210c92SNicolas Souchu 16880f210c92SNicolas Souchu case PPC_TYPE_GENERIC: 16890f210c92SNicolas Souchu default: 16900f210c92SNicolas Souchu return (ppc_generic_setmode(ppc, mode)); 16910f210c92SNicolas Souchu break; 16920f210c92SNicolas Souchu } 16930f210c92SNicolas Souchu 16940f210c92SNicolas Souchu /* not reached */ 16950f210c92SNicolas Souchu return (ENXIO); 16960f210c92SNicolas Souchu } 16970f210c92SNicolas Souchu 16980f210c92SNicolas Souchu static int 16990f210c92SNicolas Souchu ppc_probe(device_t dev) 170067646539SMike Smith { 1701d64d73c9SDoug Rabson #ifdef __i386__ 170267646539SMike Smith static short next_bios_ppc = 0; 1703d64d73c9SDoug Rabson #endif 170467646539SMike Smith struct ppc_data *ppc; 17050f210c92SNicolas Souchu device_t parent; 1706d64d73c9SDoug Rabson int error; 1707d64d73c9SDoug Rabson u_long port; 170867646539SMike Smith 1709a9d565fcSPeter Wemm /* If we are a PNP device, abort. Otherwise we attach to *everthing* */ 17100f210c92SNicolas Souchu if (isa_get_logicalid(dev)) 17110f210c92SNicolas Souchu return ENXIO; 17120f210c92SNicolas Souchu 17130f210c92SNicolas Souchu parent = device_get_parent(dev); 171467646539SMike Smith 1715a9d565fcSPeter Wemm /* XXX shall be set after detection */ 1716a9d565fcSPeter Wemm device_set_desc(dev, "Parallel port"); 1717a9d565fcSPeter Wemm 171867646539SMike Smith /* 171967646539SMike Smith * Allocate the ppc_data structure. 172067646539SMike Smith */ 17210f210c92SNicolas Souchu ppc = DEVTOSOFTC(dev); 172267646539SMike Smith bzero(ppc, sizeof(struct ppc_data)); 172367646539SMike Smith 17240f210c92SNicolas Souchu ppc->rid_irq = ppc->rid_drq = ppc->rid_ioport = 0; 17250f210c92SNicolas Souchu ppc->res_irq = ppc->res_drq = ppc->res_ioport = 0; 172667646539SMike Smith 17270f210c92SNicolas Souchu /* retrieve ISA parameters */ 1728d64d73c9SDoug Rabson error = bus_get_resource(dev, SYS_RES_IOPORT, 0, &port, NULL); 17290f210c92SNicolas Souchu 1730d64d73c9SDoug Rabson #ifdef __i386__ 17310f210c92SNicolas Souchu /* 17320f210c92SNicolas Souchu * If port not specified, use bios list. 17330f210c92SNicolas Souchu */ 1734d64d73c9SDoug Rabson if (error) { 17350f210c92SNicolas Souchu if((next_bios_ppc < BIOS_MAX_PPC) && 17360f210c92SNicolas Souchu (*(BIOS_PORTS+next_bios_ppc) != 0) ) { 17370f210c92SNicolas Souchu port = *(BIOS_PORTS+next_bios_ppc++); 17380f210c92SNicolas Souchu if (bootverbose) 17390f210c92SNicolas Souchu device_printf(dev, "parallel port found at 0x%x\n", 1740d64d73c9SDoug Rabson (int) port); 17410f210c92SNicolas Souchu } else { 17420f210c92SNicolas Souchu device_printf(dev, "parallel port not found.\n"); 17430f210c92SNicolas Souchu return ENXIO; 17440f210c92SNicolas Souchu } 1745d64d73c9SDoug Rabson bus_set_resource(dev, SYS_RES_IOPORT, 0, port, IO_LPTSIZE); 17460f210c92SNicolas Souchu } 1747d64d73c9SDoug Rabson #endif 1748d64d73c9SDoug Rabson #ifdef __alpha__ 1749d64d73c9SDoug Rabson /* 1750d64d73c9SDoug Rabson * There isn't a bios list on alpha. Put it in the usual place. 1751d64d73c9SDoug Rabson */ 1752d64d73c9SDoug Rabson if (error) { 1753d64d73c9SDoug Rabson bus_set_resource(dev, SYS_RES_IOPORT, 0, 0x3bc, IO_LPTSIZE); 1754d64d73c9SDoug Rabson } 1755d64d73c9SDoug Rabson #endif 17560f210c92SNicolas Souchu 17570f210c92SNicolas Souchu /* IO port is mandatory */ 17580f210c92SNicolas Souchu ppc->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT, 1759d64d73c9SDoug Rabson &ppc->rid_ioport, 0, ~0, 17600f210c92SNicolas Souchu IO_LPTSIZE, RF_ACTIVE); 17610f210c92SNicolas Souchu if (ppc->res_ioport == 0) { 17620f210c92SNicolas Souchu device_printf(dev, "cannot reserve I/O port range\n"); 17630f210c92SNicolas Souchu goto error; 17640f210c92SNicolas Souchu } 1765d64d73c9SDoug Rabson ppc->ppc_base = rman_get_start(ppc->res_ioport); 17660f210c92SNicolas Souchu 17670f210c92SNicolas Souchu ppc->ppc_flags = device_get_flags(dev); 17680f210c92SNicolas Souchu 17690f210c92SNicolas Souchu if (!(ppc->ppc_flags & 0x20)) { 17700f210c92SNicolas Souchu ppc->res_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &ppc->rid_irq, 17710f210c92SNicolas Souchu 0ul, ~0ul, 1, RF_SHAREABLE); 17720f210c92SNicolas Souchu ppc->res_drq = bus_alloc_resource(dev, SYS_RES_DRQ, &ppc->rid_drq, 17730f210c92SNicolas Souchu 0ul, ~0ul, 1, RF_ACTIVE); 17740f210c92SNicolas Souchu } 17750f210c92SNicolas Souchu 17760f210c92SNicolas Souchu if (ppc->res_irq) 1777d64d73c9SDoug Rabson ppc->ppc_irq = rman_get_start(ppc->res_irq); 17780f210c92SNicolas Souchu if (ppc->res_drq) 1779d64d73c9SDoug Rabson ppc->ppc_dmachan = rman_get_start(ppc->res_drq); 17800f210c92SNicolas Souchu 17810f210c92SNicolas Souchu ppc->ppc_unit = device_get_unit(dev); 17820f210c92SNicolas Souchu ppc->ppc_model = GENERIC; 1783af548787SNicolas Souchu 178446f3ff79SMike Smith ppc->ppc_mode = PPB_COMPATIBLE; 17850f210c92SNicolas Souchu ppc->ppc_epp = (ppc->ppc_flags & 0x10) >> 4; 178667646539SMike Smith 17870f210c92SNicolas Souchu ppc->ppc_type = PPC_TYPE_GENERIC; 1788edcfcf27SNicolas Souchu 1789edcfcf27SNicolas Souchu /* 1790dc733423SDag-Erling Smørgrav * Try to detect the chipset and its mode. 179167646539SMike Smith */ 17920f210c92SNicolas Souchu if (ppc_detect(ppc, ppc->ppc_flags & 0xf)) 179367646539SMike Smith goto error; 179467646539SMike Smith 17950f210c92SNicolas Souchu return (0); 179667646539SMike Smith 179767646539SMike Smith error: 17980f210c92SNicolas Souchu if (ppc->res_irq != 0) { 17990f210c92SNicolas Souchu bus_release_resource(dev, SYS_RES_IRQ, ppc->rid_irq, 18000f210c92SNicolas Souchu ppc->res_irq); 18010f210c92SNicolas Souchu } 18020f210c92SNicolas Souchu if (ppc->res_ioport != 0) { 18030f210c92SNicolas Souchu bus_deactivate_resource(dev, SYS_RES_IOPORT, ppc->rid_ioport, 18040f210c92SNicolas Souchu ppc->res_ioport); 18050f210c92SNicolas Souchu bus_release_resource(dev, SYS_RES_IOPORT, ppc->rid_ioport, 18060f210c92SNicolas Souchu ppc->res_ioport); 18070f210c92SNicolas Souchu } 18080f210c92SNicolas Souchu if (ppc->res_drq != 0) { 18090f210c92SNicolas Souchu bus_deactivate_resource(dev, SYS_RES_DRQ, ppc->rid_drq, 18100f210c92SNicolas Souchu ppc->res_drq); 18110f210c92SNicolas Souchu bus_release_resource(dev, SYS_RES_DRQ, ppc->rid_drq, 18120f210c92SNicolas Souchu ppc->res_drq); 18130f210c92SNicolas Souchu } 18140f210c92SNicolas Souchu return (ENXIO); 181567646539SMike Smith } 181667646539SMike Smith 181767646539SMike Smith static int 18180f210c92SNicolas Souchu ppc_attach(device_t dev) 181967646539SMike Smith { 18200f210c92SNicolas Souchu struct ppc_data *ppc = DEVTOSOFTC(dev); 182167646539SMike Smith 18220f210c92SNicolas Souchu device_t ppbus; 18230f210c92SNicolas Souchu device_t parent = device_get_parent(dev); 18240f210c92SNicolas Souchu 18250f210c92SNicolas Souchu device_printf(dev, "%s chipset (%s) in %s mode%s\n", 18260f210c92SNicolas Souchu ppc_models[ppc->ppc_model], ppc_avms[ppc->ppc_avm], 182746f3ff79SMike Smith ppc_modes[ppc->ppc_mode], (PPB_IS_EPP(ppc->ppc_mode)) ? 182867646539SMike Smith ppc_epp_protocol[ppc->ppc_epp] : ""); 182967646539SMike Smith 1830bc35c174SNicolas Souchu if (ppc->ppc_fifo) 18310f210c92SNicolas Souchu device_printf(dev, "FIFO with %d/%d/%d bytes threshold\n", 18320f210c92SNicolas Souchu ppc->ppc_fifo, ppc->ppc_wthr, ppc->ppc_rthr); 183367646539SMike Smith 1834bc35c174SNicolas Souchu if ((ppc->ppc_avm & PPB_ECP) && (ppc->ppc_dmachan > 0)) { 18350f210c92SNicolas Souchu /* acquire the DMA channel forever */ /* XXX */ 1836bc35c174SNicolas Souchu isa_dma_acquire(ppc->ppc_dmachan); 1837bc35c174SNicolas Souchu isa_dmainit(ppc->ppc_dmachan, 1024); /* nlpt.BUFSIZE */ 1838bc35c174SNicolas Souchu } 1839bc35c174SNicolas Souchu 18400f210c92SNicolas Souchu /* add ppbus as a child of this isa to parallel bridge */ 18410f210c92SNicolas Souchu ppbus = device_add_child(dev, "ppbus", -1); 18420f210c92SNicolas Souchu 184367646539SMike Smith /* 184467646539SMike Smith * Probe the ppbus and attach devices found. 184567646539SMike Smith */ 18460f210c92SNicolas Souchu device_probe_and_attach(ppbus); 184767646539SMike Smith 18480f210c92SNicolas Souchu /* register the ppc interrupt handler as default */ 18490f210c92SNicolas Souchu if (ppc->res_irq) { 18500f210c92SNicolas Souchu /* default to the tty mask for registration */ /* XXX */ 18510f210c92SNicolas Souchu if (BUS_SETUP_INTR(parent, dev, ppc->res_irq, INTR_TYPE_TTY, 18520f210c92SNicolas Souchu ppcintr, dev, &ppc->intr_cookie) == 0) { 18530f210c92SNicolas Souchu 18540f210c92SNicolas Souchu /* remember the ppcintr is registered */ 18550f210c92SNicolas Souchu ppc->ppc_registered = 1; 185667646539SMike Smith } 18570f210c92SNicolas Souchu } 18580f210c92SNicolas Souchu 18590f210c92SNicolas Souchu return (0); 18600f210c92SNicolas Souchu } 18610f210c92SNicolas Souchu 18620f210c92SNicolas Souchu static u_char 18630f210c92SNicolas Souchu ppc_io(device_t ppcdev, int iop, u_char *addr, int cnt, u_char byte) 18640f210c92SNicolas Souchu { 18650f210c92SNicolas Souchu struct ppc_data *ppc = DEVTOSOFTC(ppcdev); 18660f210c92SNicolas Souchu switch (iop) { 18670f210c92SNicolas Souchu case PPB_OUTSB_EPP: 18680f210c92SNicolas Souchu outsb(ppc->ppc_base + PPC_EPP_DATA, addr, cnt); 18690f210c92SNicolas Souchu break; 18700f210c92SNicolas Souchu case PPB_OUTSW_EPP: 18710f210c92SNicolas Souchu outsw(ppc->ppc_base + PPC_EPP_DATA, addr, cnt); 18720f210c92SNicolas Souchu break; 18730f210c92SNicolas Souchu case PPB_OUTSL_EPP: 18740f210c92SNicolas Souchu outsl(ppc->ppc_base + PPC_EPP_DATA, addr, cnt); 18750f210c92SNicolas Souchu break; 18760f210c92SNicolas Souchu case PPB_INSB_EPP: 18770f210c92SNicolas Souchu insb(ppc->ppc_base + PPC_EPP_DATA, addr, cnt); 18780f210c92SNicolas Souchu break; 18790f210c92SNicolas Souchu case PPB_INSW_EPP: 18800f210c92SNicolas Souchu insw(ppc->ppc_base + PPC_EPP_DATA, addr, cnt); 18810f210c92SNicolas Souchu break; 18820f210c92SNicolas Souchu case PPB_INSL_EPP: 18830f210c92SNicolas Souchu insl(ppc->ppc_base + PPC_EPP_DATA, addr, cnt); 18840f210c92SNicolas Souchu break; 18850f210c92SNicolas Souchu case PPB_RDTR: 18860f210c92SNicolas Souchu return (r_dtr(ppc)); 18870f210c92SNicolas Souchu break; 18880f210c92SNicolas Souchu case PPB_RSTR: 18890f210c92SNicolas Souchu return (r_str(ppc)); 18900f210c92SNicolas Souchu break; 18910f210c92SNicolas Souchu case PPB_RCTR: 18920f210c92SNicolas Souchu return (r_ctr(ppc)); 18930f210c92SNicolas Souchu break; 18940f210c92SNicolas Souchu case PPB_REPP_A: 18950f210c92SNicolas Souchu return (r_epp_A(ppc)); 18960f210c92SNicolas Souchu break; 18970f210c92SNicolas Souchu case PPB_REPP_D: 18980f210c92SNicolas Souchu return (r_epp_D(ppc)); 18990f210c92SNicolas Souchu break; 19000f210c92SNicolas Souchu case PPB_RECR: 19010f210c92SNicolas Souchu return (r_ecr(ppc)); 19020f210c92SNicolas Souchu break; 19030f210c92SNicolas Souchu case PPB_RFIFO: 19040f210c92SNicolas Souchu return (r_fifo(ppc)); 19050f210c92SNicolas Souchu break; 19060f210c92SNicolas Souchu case PPB_WDTR: 19070f210c92SNicolas Souchu w_dtr(ppc, byte); 19080f210c92SNicolas Souchu break; 19090f210c92SNicolas Souchu case PPB_WSTR: 19100f210c92SNicolas Souchu w_str(ppc, byte); 19110f210c92SNicolas Souchu break; 19120f210c92SNicolas Souchu case PPB_WCTR: 19130f210c92SNicolas Souchu w_ctr(ppc, byte); 19140f210c92SNicolas Souchu break; 19150f210c92SNicolas Souchu case PPB_WEPP_A: 19160f210c92SNicolas Souchu w_epp_A(ppc, byte); 19170f210c92SNicolas Souchu break; 19180f210c92SNicolas Souchu case PPB_WEPP_D: 19190f210c92SNicolas Souchu w_epp_D(ppc, byte); 19200f210c92SNicolas Souchu break; 19210f210c92SNicolas Souchu case PPB_WECR: 19220f210c92SNicolas Souchu w_ecr(ppc, byte); 19230f210c92SNicolas Souchu break; 19240f210c92SNicolas Souchu case PPB_WFIFO: 19250f210c92SNicolas Souchu w_fifo(ppc, byte); 19260f210c92SNicolas Souchu break; 19270f210c92SNicolas Souchu default: 19280f210c92SNicolas Souchu panic("%s: unknown I/O operation", __FUNCTION__); 19290f210c92SNicolas Souchu break; 19300f210c92SNicolas Souchu } 19310f210c92SNicolas Souchu 19320f210c92SNicolas Souchu return (0); /* not significative */ 19330f210c92SNicolas Souchu } 19340f210c92SNicolas Souchu 19350f210c92SNicolas Souchu static int 19360f210c92SNicolas Souchu ppc_read_ivar(device_t bus, device_t dev, int index, uintptr_t *val) 19370f210c92SNicolas Souchu { 19380f210c92SNicolas Souchu struct ppc_data *ppc = (struct ppc_data *)device_get_softc(bus); 19390f210c92SNicolas Souchu 19400f210c92SNicolas Souchu switch (index) { 19410f210c92SNicolas Souchu case PPC_IVAR_EPP_PROTO: 19420f210c92SNicolas Souchu *val = (u_long)ppc->ppc_epp; 19430f210c92SNicolas Souchu break; 19440f210c92SNicolas Souchu case PPC_IVAR_IRQ: 1945d64d73c9SDoug Rabson *val = (u_long)ppc->ppc_irq; 19460f210c92SNicolas Souchu break; 19470f210c92SNicolas Souchu default: 19480f210c92SNicolas Souchu return (ENOENT); 19490f210c92SNicolas Souchu } 19500f210c92SNicolas Souchu 19510f210c92SNicolas Souchu return (0); 19520f210c92SNicolas Souchu } 19530f210c92SNicolas Souchu 19540f210c92SNicolas Souchu /* 19550f210c92SNicolas Souchu * Resource is useless here since ppbus devices' interrupt handlers are 19560f210c92SNicolas Souchu * multiplexed to the same resource initially allocated by ppc 19570f210c92SNicolas Souchu */ 19580f210c92SNicolas Souchu static int 19590f210c92SNicolas Souchu ppc_setup_intr(device_t bus, device_t child, struct resource *r, int flags, 19600f210c92SNicolas Souchu void (*ihand)(void *), void *arg, void **cookiep) 19610f210c92SNicolas Souchu { 19620f210c92SNicolas Souchu int error; 19630f210c92SNicolas Souchu struct ppc_data *ppc = DEVTOSOFTC(bus); 19640f210c92SNicolas Souchu 19650f210c92SNicolas Souchu if (ppc->ppc_registered) { 19660f210c92SNicolas Souchu /* XXX refuse registration if DMA is in progress */ 19670f210c92SNicolas Souchu 19680f210c92SNicolas Souchu /* first, unregister the default interrupt handler */ 19690f210c92SNicolas Souchu if ((error = BUS_TEARDOWN_INTR(device_get_parent(bus), 19700f210c92SNicolas Souchu bus, ppc->res_irq, ppc->intr_cookie))) 19710f210c92SNicolas Souchu return (error); 19720f210c92SNicolas Souchu 19730f210c92SNicolas Souchu /* bus_deactivate_resource(bus, SYS_RES_IRQ, ppc->rid_irq, */ 19740f210c92SNicolas Souchu /* ppc->res_irq); */ 19750f210c92SNicolas Souchu 19760f210c92SNicolas Souchu /* DMA/FIFO operation won't be possible anymore */ 19770f210c92SNicolas Souchu ppc->ppc_registered = 0; 19780f210c92SNicolas Souchu } 19790f210c92SNicolas Souchu 19800f210c92SNicolas Souchu /* pass registration to the upper layer, ignore the incoming resource */ 19810f210c92SNicolas Souchu return (BUS_SETUP_INTR(device_get_parent(bus), child, 19820f210c92SNicolas Souchu r, flags, ihand, arg, cookiep)); 19830f210c92SNicolas Souchu } 19840f210c92SNicolas Souchu 19850f210c92SNicolas Souchu /* 19860f210c92SNicolas Souchu * When no underlying device has a registered interrupt, register the ppc 19870f210c92SNicolas Souchu * layer one 19880f210c92SNicolas Souchu */ 19890f210c92SNicolas Souchu static int 19900f210c92SNicolas Souchu ppc_teardown_intr(device_t bus, device_t child, struct resource *r, void *ih) 19910f210c92SNicolas Souchu { 19920f210c92SNicolas Souchu int error; 19930f210c92SNicolas Souchu struct ppc_data *ppc = DEVTOSOFTC(bus); 19940f210c92SNicolas Souchu device_t parent = device_get_parent(bus); 19950f210c92SNicolas Souchu 19960f210c92SNicolas Souchu /* pass unregistration to the upper layer */ 19970f210c92SNicolas Souchu if ((error = BUS_TEARDOWN_INTR(parent, child, r, ih))) 19980f210c92SNicolas Souchu return (error); 19990f210c92SNicolas Souchu 20000f210c92SNicolas Souchu /* default to the tty mask for registration */ /* XXX */ 20010f210c92SNicolas Souchu if (ppc->ppc_irq && 20020f210c92SNicolas Souchu !(error = BUS_SETUP_INTR(parent, bus, ppc->res_irq, 20030f210c92SNicolas Souchu INTR_TYPE_TTY, ppcintr, bus, &ppc->intr_cookie))) { 20040f210c92SNicolas Souchu 20050f210c92SNicolas Souchu /* remember the ppcintr is registered */ 20060f210c92SNicolas Souchu ppc->ppc_registered = 1; 20070f210c92SNicolas Souchu } 20080f210c92SNicolas Souchu 20090f210c92SNicolas Souchu return (error); 20100f210c92SNicolas Souchu } 20110f210c92SNicolas Souchu 20120f210c92SNicolas Souchu DRIVER_MODULE(ppc, isa, ppc_driver, ppc_devclass, 0, 0); 201367646539SMike Smith #endif 2014