167646539SMike Smith /*- 2ddd22fb7SNicolas Souchu * Copyright (c) 1997-2000 Nicolas Souchu 3c264e80fSNicolas Souchu * Copyright (c) 2001 Alcove - Nicolas Souchu 467646539SMike Smith * All rights reserved. 567646539SMike Smith * 667646539SMike Smith * Redistribution and use in source and binary forms, with or without 767646539SMike Smith * modification, are permitted provided that the following conditions 867646539SMike Smith * are met: 967646539SMike Smith * 1. Redistributions of source code must retain the above copyright 1067646539SMike Smith * notice, this list of conditions and the following disclaimer. 1167646539SMike Smith * 2. Redistributions in binary form must reproduce the above copyright 1267646539SMike Smith * notice, this list of conditions and the following disclaimer in the 1367646539SMike Smith * documentation and/or other materials provided with the distribution. 1467646539SMike Smith * 1567646539SMike Smith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1667646539SMike Smith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1767646539SMike Smith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1867646539SMike Smith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1967646539SMike Smith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2067646539SMike Smith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2167646539SMike Smith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2267646539SMike Smith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2367646539SMike Smith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2467646539SMike Smith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2567646539SMike Smith * SUCH DAMAGE. 2667646539SMike Smith */ 2767646539SMike Smith 288c9bbf48SDavid E. O'Brien #include <sys/cdefs.h> 298c9bbf48SDavid E. O'Brien __FBSDID("$FreeBSD$"); 308c9bbf48SDavid E. O'Brien 310f210c92SNicolas Souchu #include "opt_ppc.h" 320f210c92SNicolas Souchu 3367646539SMike Smith #include <sys/param.h> 3467646539SMike Smith #include <sys/systm.h> 3554ad6085SNicolas Souchu #include <sys/kernel.h> 36fe12f24bSPoul-Henning Kamp #include <sys/module.h> 370f210c92SNicolas Souchu #include <sys/bus.h> 380f210c92SNicolas Souchu #include <sys/malloc.h> 3967646539SMike Smith 400f210c92SNicolas Souchu #include <machine/bus.h> 410f210c92SNicolas Souchu #include <machine/resource.h> 420f210c92SNicolas Souchu #include <sys/rman.h> 4367646539SMike Smith 44cea4d875SMarcel Moolenaar #ifdef __i386__ 45cea4d875SMarcel Moolenaar #include <vm/vm.h> 46cea4d875SMarcel Moolenaar #include <vm/pmap.h> 47cea4d875SMarcel Moolenaar #include <machine/vmparam.h> 48cea4d875SMarcel Moolenaar #endif 4967646539SMike Smith 5067646539SMike Smith #include <dev/ppbus/ppbconf.h> 5146f3ff79SMike Smith #include <dev/ppbus/ppb_msq.h> 5246f3ff79SMike Smith 53a3732274SDoug Ambrisko #include <dev/ppc/ppcvar.h> 54a3732274SDoug Ambrisko #include <dev/ppc/ppcreg.h> 5567646539SMike Smith 560f210c92SNicolas Souchu #include "ppbus_if.h" 57bc35c174SNicolas Souchu 58a3732274SDoug Ambrisko static void ppcintr(void *arg); 59a3732274SDoug Ambrisko 60cea4d875SMarcel Moolenaar #define IO_LPTSIZE_EXTENDED 8 /* "Extended" LPT controllers */ 61cea4d875SMarcel Moolenaar #define IO_LPTSIZE_NORMAL 4 /* "Normal" LPT controllers */ 62cea4d875SMarcel Moolenaar 63bc35c174SNicolas Souchu #define LOG_PPC(function, ppc, string) \ 64bc35c174SNicolas Souchu if (bootverbose) printf("%s: %s\n", function, string) 65bc35c174SNicolas Souchu 66cea4d875SMarcel Moolenaar #if defined(__i386__) && defined(PC98) 67cea4d875SMarcel Moolenaar #define PC98_IEEE_1284_DISABLE 0x100 68cea4d875SMarcel Moolenaar #define PC98_IEEE_1284_PORT 0x140 69cea4d875SMarcel Moolenaar #endif 7067646539SMike Smith 710f210c92SNicolas Souchu #define DEVTOSOFTC(dev) ((struct ppc_data *)device_get_softc(dev)) 720f210c92SNicolas Souchu 73a3732274SDoug Ambrisko devclass_t ppc_devclass; 74cea4d875SMarcel Moolenaar const char ppc_driver_name[] = "ppc"; 7567646539SMike Smith 760f210c92SNicolas Souchu static char *ppc_models[] = { 7746f3ff79SMike Smith "SMC-like", "SMC FDC37C665GT", "SMC FDC37C666GT", "PC87332", "PC87306", 786a5be862SDoug Rabson "82091AA", "Generic", "W83877F", "W83877AF", "Winbond", "PC87334", 79ac7ba926SDoug Rabson "SMC FDC37C935", "PC87303", 0 8067646539SMike Smith }; 8167646539SMike Smith 8246f3ff79SMike Smith /* list of available modes */ 8346f3ff79SMike Smith static char *ppc_avms[] = { 8446f3ff79SMike Smith "COMPATIBLE", "NIBBLE-only", "PS2-only", "PS2/NIBBLE", "EPP-only", 8546f3ff79SMike Smith "EPP/NIBBLE", "EPP/PS2", "EPP/PS2/NIBBLE", "ECP-only", 8646f3ff79SMike Smith "ECP/NIBBLE", "ECP/PS2", "ECP/PS2/NIBBLE", "ECP/EPP", 8746f3ff79SMike Smith "ECP/EPP/NIBBLE", "ECP/EPP/PS2", "ECP/EPP/PS2/NIBBLE", 0 8846f3ff79SMike Smith }; 8946f3ff79SMike Smith 9046f3ff79SMike Smith /* list of current executing modes 9146f3ff79SMike Smith * Note that few modes do not actually exist. 9246f3ff79SMike Smith */ 9367646539SMike Smith static char *ppc_modes[] = { 9446f3ff79SMike Smith "COMPATIBLE", "NIBBLE", "PS/2", "PS/2", "EPP", 9546f3ff79SMike Smith "EPP", "EPP", "EPP", "ECP", 9646f3ff79SMike Smith "ECP", "ECP+PS2", "ECP+PS2", "ECP+EPP", 9746f3ff79SMike Smith "ECP+EPP", "ECP+EPP", "ECP+EPP", 0 9867646539SMike Smith }; 9967646539SMike Smith 10067646539SMike Smith static char *ppc_epp_protocol[] = { " (EPP 1.9)", " (EPP 1.7)", 0 }; 10167646539SMike Smith 102d64d73c9SDoug Rabson #ifdef __i386__ 10367646539SMike Smith /* 10467646539SMike Smith * BIOS printer list - used by BIOS probe. 10567646539SMike Smith */ 10667646539SMike Smith #define BIOS_PPC_PORTS 0x408 10767646539SMike Smith #define BIOS_PORTS (short *)(KERNBASE+BIOS_PPC_PORTS) 10867646539SMike Smith #define BIOS_MAX_PPC 4 109d64d73c9SDoug Rabson #endif 11067646539SMike Smith 11167646539SMike Smith /* 11267646539SMike Smith * ppc_ecp_sync() XXX 11367646539SMike Smith */ 114a3732274SDoug Ambrisko void 1150f210c92SNicolas Souchu ppc_ecp_sync(device_t dev) { 11667646539SMike Smith 11767646539SMike Smith int i, r; 1180f210c92SNicolas Souchu struct ppc_data *ppc = DEVTOSOFTC(dev); 11967646539SMike Smith 120c264e80fSNicolas Souchu if (!(ppc->ppc_avm & PPB_ECP) && !(ppc->ppc_dtm & PPB_ECP)) 121bc35c174SNicolas Souchu return; 122bc35c174SNicolas Souchu 12367646539SMike Smith r = r_ecr(ppc); 124bc35c174SNicolas Souchu if ((r & 0xe0) != PPC_ECR_EPP) 12567646539SMike Smith return; 12667646539SMike Smith 12767646539SMike Smith for (i = 0; i < 100; i++) { 12867646539SMike Smith r = r_ecr(ppc); 12967646539SMike Smith if (r & 0x1) 13067646539SMike Smith return; 13167646539SMike Smith DELAY(100); 13267646539SMike Smith } 13367646539SMike Smith 13446f3ff79SMike Smith printf("ppc%d: ECP sync failed as data still " \ 1350f210c92SNicolas Souchu "present in FIFO.\n", ppc->ppc_unit); 13667646539SMike Smith 13767646539SMike Smith return; 13867646539SMike Smith } 13967646539SMike Smith 140bc35c174SNicolas Souchu /* 141bc35c174SNicolas Souchu * ppc_detect_fifo() 142bc35c174SNicolas Souchu * 143bc35c174SNicolas Souchu * Detect parallel port FIFO 144bc35c174SNicolas Souchu */ 145bc35c174SNicolas Souchu static int 146bc35c174SNicolas Souchu ppc_detect_fifo(struct ppc_data *ppc) 14767646539SMike Smith { 148bc35c174SNicolas Souchu char ecr_sav; 149bc35c174SNicolas Souchu char ctr_sav, ctr, cc; 150bc35c174SNicolas Souchu short i; 15167646539SMike Smith 152bc35c174SNicolas Souchu /* save registers */ 153bc35c174SNicolas Souchu ecr_sav = r_ecr(ppc); 154bc35c174SNicolas Souchu ctr_sav = r_ctr(ppc); 155bc35c174SNicolas Souchu 156bc35c174SNicolas Souchu /* enter ECP configuration mode, no interrupt, no DMA */ 157bc35c174SNicolas Souchu w_ecr(ppc, 0xf4); 158bc35c174SNicolas Souchu 159bc35c174SNicolas Souchu /* read PWord size - transfers in FIFO mode must be PWord aligned */ 160bc35c174SNicolas Souchu ppc->ppc_pword = (r_cnfgA(ppc) & PPC_PWORD_MASK); 161bc35c174SNicolas Souchu 162bc35c174SNicolas Souchu /* XXX 16 and 32 bits implementations not supported */ 163bc35c174SNicolas Souchu if (ppc->ppc_pword != PPC_PWORD_8) { 1646e551fb6SDavid E. O'Brien LOG_PPC(__func__, ppc, "PWord not supported"); 165bc35c174SNicolas Souchu goto error; 166bc35c174SNicolas Souchu } 167bc35c174SNicolas Souchu 168bc35c174SNicolas Souchu w_ecr(ppc, 0x34); /* byte mode, no interrupt, no DMA */ 169bc35c174SNicolas Souchu ctr = r_ctr(ppc); 170bc35c174SNicolas Souchu w_ctr(ppc, ctr | PCD); /* set direction to 1 */ 171bc35c174SNicolas Souchu 172bc35c174SNicolas Souchu /* enter ECP test mode, no interrupt, no DMA */ 173bc35c174SNicolas Souchu w_ecr(ppc, 0xd4); 174bc35c174SNicolas Souchu 175bc35c174SNicolas Souchu /* flush the FIFO */ 176bc35c174SNicolas Souchu for (i=0; i<1024; i++) { 177bc35c174SNicolas Souchu if (r_ecr(ppc) & PPC_FIFO_EMPTY) 178bc35c174SNicolas Souchu break; 179bc35c174SNicolas Souchu cc = r_fifo(ppc); 180bc35c174SNicolas Souchu } 181bc35c174SNicolas Souchu 182bc35c174SNicolas Souchu if (i >= 1024) { 1836e551fb6SDavid E. O'Brien LOG_PPC(__func__, ppc, "can't flush FIFO"); 184bc35c174SNicolas Souchu goto error; 185bc35c174SNicolas Souchu } 186bc35c174SNicolas Souchu 187bc35c174SNicolas Souchu /* enable interrupts, no DMA */ 188bc35c174SNicolas Souchu w_ecr(ppc, 0xd0); 189bc35c174SNicolas Souchu 190bc35c174SNicolas Souchu /* determine readIntrThreshold 191bc35c174SNicolas Souchu * fill the FIFO until serviceIntr is set 192bc35c174SNicolas Souchu */ 193bc35c174SNicolas Souchu for (i=0; i<1024; i++) { 194bc35c174SNicolas Souchu w_fifo(ppc, (char)i); 195bc35c174SNicolas Souchu if (!ppc->ppc_rthr && (r_ecr(ppc) & PPC_SERVICE_INTR)) { 196bc35c174SNicolas Souchu /* readThreshold reached */ 197bc35c174SNicolas Souchu ppc->ppc_rthr = i+1; 198bc35c174SNicolas Souchu } 199bc35c174SNicolas Souchu if (r_ecr(ppc) & PPC_FIFO_FULL) { 200bc35c174SNicolas Souchu ppc->ppc_fifo = i+1; 201bc35c174SNicolas Souchu break; 202bc35c174SNicolas Souchu } 203bc35c174SNicolas Souchu } 204bc35c174SNicolas Souchu 205bc35c174SNicolas Souchu if (i >= 1024) { 2066e551fb6SDavid E. O'Brien LOG_PPC(__func__, ppc, "can't fill FIFO"); 207bc35c174SNicolas Souchu goto error; 208bc35c174SNicolas Souchu } 209bc35c174SNicolas Souchu 210bc35c174SNicolas Souchu w_ecr(ppc, 0xd4); /* test mode, no interrupt, no DMA */ 211bc35c174SNicolas Souchu w_ctr(ppc, ctr & ~PCD); /* set direction to 0 */ 212bc35c174SNicolas Souchu w_ecr(ppc, 0xd0); /* enable interrupts */ 213bc35c174SNicolas Souchu 214bc35c174SNicolas Souchu /* determine writeIntrThreshold 215bc35c174SNicolas Souchu * empty the FIFO until serviceIntr is set 216bc35c174SNicolas Souchu */ 217bc35c174SNicolas Souchu for (i=ppc->ppc_fifo; i>0; i--) { 218bc35c174SNicolas Souchu if (r_fifo(ppc) != (char)(ppc->ppc_fifo-i)) { 2196e551fb6SDavid E. O'Brien LOG_PPC(__func__, ppc, "invalid data in FIFO"); 220bc35c174SNicolas Souchu goto error; 221bc35c174SNicolas Souchu } 222bc35c174SNicolas Souchu if (r_ecr(ppc) & PPC_SERVICE_INTR) { 223bc35c174SNicolas Souchu /* writeIntrThreshold reached */ 224bc35c174SNicolas Souchu ppc->ppc_wthr = ppc->ppc_fifo - i+1; 225bc35c174SNicolas Souchu } 226bc35c174SNicolas Souchu /* if FIFO empty before the last byte, error */ 227bc35c174SNicolas Souchu if (i>1 && (r_ecr(ppc) & PPC_FIFO_EMPTY)) { 2286e551fb6SDavid E. O'Brien LOG_PPC(__func__, ppc, "data lost in FIFO"); 229bc35c174SNicolas Souchu goto error; 230bc35c174SNicolas Souchu } 231bc35c174SNicolas Souchu } 232bc35c174SNicolas Souchu 233bc35c174SNicolas Souchu /* FIFO must be empty after the last byte */ 234bc35c174SNicolas Souchu if (!(r_ecr(ppc) & PPC_FIFO_EMPTY)) { 2356e551fb6SDavid E. O'Brien LOG_PPC(__func__, ppc, "can't empty the FIFO"); 236bc35c174SNicolas Souchu goto error; 237bc35c174SNicolas Souchu } 238bc35c174SNicolas Souchu 239bc35c174SNicolas Souchu w_ctr(ppc, ctr_sav); 240bc35c174SNicolas Souchu w_ecr(ppc, ecr_sav); 241bc35c174SNicolas Souchu 242bc35c174SNicolas Souchu return (0); 243bc35c174SNicolas Souchu 244bc35c174SNicolas Souchu error: 245bc35c174SNicolas Souchu w_ctr(ppc, ctr_sav); 246bc35c174SNicolas Souchu w_ecr(ppc, ecr_sav); 247bc35c174SNicolas Souchu 248bc35c174SNicolas Souchu return (EINVAL); 24967646539SMike Smith } 25067646539SMike Smith 25146f3ff79SMike Smith static int 25246f3ff79SMike Smith ppc_detect_port(struct ppc_data *ppc) 25346f3ff79SMike Smith { 25446f3ff79SMike Smith 25546f3ff79SMike Smith w_ctr(ppc, 0x0c); /* To avoid missing PS2 ports */ 25646f3ff79SMike Smith w_dtr(ppc, 0xaa); 257a7006f89SNicolas Souchu if (r_dtr(ppc) != 0xaa) 25846f3ff79SMike Smith return (0); 25946f3ff79SMike Smith 26046f3ff79SMike Smith return (1); 26146f3ff79SMike Smith } 26246f3ff79SMike Smith 26367646539SMike Smith /* 2640f210c92SNicolas Souchu * EPP timeout, according to the PC87332 manual 2650f210c92SNicolas Souchu * Semantics of clearing EPP timeout bit. 2660f210c92SNicolas Souchu * PC87332 - reading SPP_STR does it... 2670f210c92SNicolas Souchu * SMC - write 1 to EPP timeout bit XXX 2680f210c92SNicolas Souchu * Others - (?) write 0 to EPP timeout bit 2690f210c92SNicolas Souchu */ 2700f210c92SNicolas Souchu static void 2710f210c92SNicolas Souchu ppc_reset_epp_timeout(struct ppc_data *ppc) 2720f210c92SNicolas Souchu { 2730f210c92SNicolas Souchu register char r; 2740f210c92SNicolas Souchu 2750f210c92SNicolas Souchu r = r_str(ppc); 2760f210c92SNicolas Souchu w_str(ppc, r | 0x1); 2770f210c92SNicolas Souchu w_str(ppc, r & 0xfe); 2780f210c92SNicolas Souchu 2790f210c92SNicolas Souchu return; 2800f210c92SNicolas Souchu } 2810f210c92SNicolas Souchu 2820f210c92SNicolas Souchu static int 2830f210c92SNicolas Souchu ppc_check_epp_timeout(struct ppc_data *ppc) 2840f210c92SNicolas Souchu { 2850f210c92SNicolas Souchu ppc_reset_epp_timeout(ppc); 2860f210c92SNicolas Souchu 2870f210c92SNicolas Souchu return (!(r_str(ppc) & TIMEOUT)); 2880f210c92SNicolas Souchu } 2890f210c92SNicolas Souchu 2900f210c92SNicolas Souchu /* 2910f210c92SNicolas Souchu * Configure current operating mode 2920f210c92SNicolas Souchu */ 2930f210c92SNicolas Souchu static int 2940f210c92SNicolas Souchu ppc_generic_setmode(struct ppc_data *ppc, int mode) 2950f210c92SNicolas Souchu { 2960f210c92SNicolas Souchu u_char ecr = 0; 2970f210c92SNicolas Souchu 2980f210c92SNicolas Souchu /* check if mode is available */ 2990f210c92SNicolas Souchu if (mode && !(ppc->ppc_avm & mode)) 3000f210c92SNicolas Souchu return (EINVAL); 3010f210c92SNicolas Souchu 3020f210c92SNicolas Souchu /* if ECP mode, configure ecr register */ 303c264e80fSNicolas Souchu if ((ppc->ppc_avm & PPB_ECP) || (ppc->ppc_dtm & PPB_ECP)) { 3040f210c92SNicolas Souchu /* return to byte mode (keeping direction bit), 3050f210c92SNicolas Souchu * no interrupt, no DMA to be able to change to 3060f210c92SNicolas Souchu * ECP 3070f210c92SNicolas Souchu */ 3080f210c92SNicolas Souchu w_ecr(ppc, PPC_ECR_RESET); 3090f210c92SNicolas Souchu ecr = PPC_DISABLE_INTR; 3100f210c92SNicolas Souchu 3110f210c92SNicolas Souchu if (mode & PPB_EPP) 3120f210c92SNicolas Souchu return (EINVAL); 3130f210c92SNicolas Souchu else if (mode & PPB_ECP) 3140f210c92SNicolas Souchu /* select ECP mode */ 3150f210c92SNicolas Souchu ecr |= PPC_ECR_ECP; 3160f210c92SNicolas Souchu else if (mode & PPB_PS2) 3170f210c92SNicolas Souchu /* select PS2 mode with ECP */ 3180f210c92SNicolas Souchu ecr |= PPC_ECR_PS2; 3190f210c92SNicolas Souchu else 3200f210c92SNicolas Souchu /* select COMPATIBLE/NIBBLE mode */ 3210f210c92SNicolas Souchu ecr |= PPC_ECR_STD; 3220f210c92SNicolas Souchu 3230f210c92SNicolas Souchu w_ecr(ppc, ecr); 3240f210c92SNicolas Souchu } 3250f210c92SNicolas Souchu 3260f210c92SNicolas Souchu ppc->ppc_mode = mode; 3270f210c92SNicolas Souchu 3280f210c92SNicolas Souchu return (0); 3290f210c92SNicolas Souchu } 3300f210c92SNicolas Souchu 3310f210c92SNicolas Souchu /* 3320f210c92SNicolas Souchu * The ppc driver is free to choose options like FIFO or DMA 3330f210c92SNicolas Souchu * if ECP mode is available. 3340f210c92SNicolas Souchu * 3350f210c92SNicolas Souchu * The 'RAW' option allows the upper drivers to force the ppc mode 3360f210c92SNicolas Souchu * even with FIFO, DMA available. 3370f210c92SNicolas Souchu */ 3380f210c92SNicolas Souchu static int 3390f210c92SNicolas Souchu ppc_smclike_setmode(struct ppc_data *ppc, int mode) 3400f210c92SNicolas Souchu { 3410f210c92SNicolas Souchu u_char ecr = 0; 3420f210c92SNicolas Souchu 3430f210c92SNicolas Souchu /* check if mode is available */ 3440f210c92SNicolas Souchu if (mode && !(ppc->ppc_avm & mode)) 3450f210c92SNicolas Souchu return (EINVAL); 3460f210c92SNicolas Souchu 3470f210c92SNicolas Souchu /* if ECP mode, configure ecr register */ 348c264e80fSNicolas Souchu if ((ppc->ppc_avm & PPB_ECP) || (ppc->ppc_dtm & PPB_ECP)) { 3490f210c92SNicolas Souchu /* return to byte mode (keeping direction bit), 3500f210c92SNicolas Souchu * no interrupt, no DMA to be able to change to 3510f210c92SNicolas Souchu * ECP or EPP mode 3520f210c92SNicolas Souchu */ 3530f210c92SNicolas Souchu w_ecr(ppc, PPC_ECR_RESET); 3540f210c92SNicolas Souchu ecr = PPC_DISABLE_INTR; 3550f210c92SNicolas Souchu 3560f210c92SNicolas Souchu if (mode & PPB_EPP) 3570f210c92SNicolas Souchu /* select EPP mode */ 3580f210c92SNicolas Souchu ecr |= PPC_ECR_EPP; 3590f210c92SNicolas Souchu else if (mode & PPB_ECP) 3600f210c92SNicolas Souchu /* select ECP mode */ 3610f210c92SNicolas Souchu ecr |= PPC_ECR_ECP; 3620f210c92SNicolas Souchu else if (mode & PPB_PS2) 3630f210c92SNicolas Souchu /* select PS2 mode with ECP */ 3640f210c92SNicolas Souchu ecr |= PPC_ECR_PS2; 3650f210c92SNicolas Souchu else 3660f210c92SNicolas Souchu /* select COMPATIBLE/NIBBLE mode */ 3670f210c92SNicolas Souchu ecr |= PPC_ECR_STD; 3680f210c92SNicolas Souchu 3690f210c92SNicolas Souchu w_ecr(ppc, ecr); 3700f210c92SNicolas Souchu } 3710f210c92SNicolas Souchu 3720f210c92SNicolas Souchu ppc->ppc_mode = mode; 3730f210c92SNicolas Souchu 3740f210c92SNicolas Souchu return (0); 3750f210c92SNicolas Souchu } 3760f210c92SNicolas Souchu 3770f210c92SNicolas Souchu #ifdef PPC_PROBE_CHIPSET 3780f210c92SNicolas Souchu /* 37967646539SMike Smith * ppc_pc873xx_detect 38067646539SMike Smith * 38167646539SMike Smith * Probe for a Natsemi PC873xx-family part. 38267646539SMike Smith * 38367646539SMike Smith * References in this function are to the National Semiconductor 38467646539SMike Smith * PC87332 datasheet TL/C/11930, May 1995 revision. 38567646539SMike Smith */ 38667646539SMike Smith static int pc873xx_basetab[] = {0x0398, 0x026e, 0x015c, 0x002e, 0}; 38767646539SMike Smith static int pc873xx_porttab[] = {0x0378, 0x03bc, 0x0278, 0}; 388af548787SNicolas Souchu static int pc873xx_irqtab[] = {5, 7, 5, 0}; 389af548787SNicolas Souchu 390af548787SNicolas Souchu static int pc873xx_regstab[] = { 391af548787SNicolas Souchu PC873_FER, PC873_FAR, PC873_PTR, 392af548787SNicolas Souchu PC873_FCR, PC873_PCR, PC873_PMC, 393af548787SNicolas Souchu PC873_TUP, PC873_SID, PC873_PNP0, 394af548787SNicolas Souchu PC873_PNP1, PC873_LPTBA, -1 395af548787SNicolas Souchu }; 396af548787SNicolas Souchu 397af548787SNicolas Souchu static char *pc873xx_rnametab[] = { 398af548787SNicolas Souchu "FER", "FAR", "PTR", "FCR", "PCR", 399af548787SNicolas Souchu "PMC", "TUP", "SID", "PNP0", "PNP1", 400af548787SNicolas Souchu "LPTBA", NULL 401af548787SNicolas Souchu }; 40267646539SMike Smith 40367646539SMike Smith static int 40446f3ff79SMike Smith ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never forced */ 40567646539SMike Smith { 40667646539SMike Smith static int index = 0; 407f1d19042SArchie Cobbs int idport, irq; 408af548787SNicolas Souchu int ptr, pcr, val, i; 40967646539SMike Smith 41067646539SMike Smith while ((idport = pc873xx_basetab[index++])) { 41167646539SMike Smith 41267646539SMike Smith /* XXX should check first to see if this location is already claimed */ 41367646539SMike Smith 41467646539SMike Smith /* 415af548787SNicolas Souchu * Pull the 873xx through the power-on ID cycle (2.2,1.). 416af548787SNicolas Souchu * We can't use this to locate the chip as it may already have 417af548787SNicolas Souchu * been used by the BIOS. 41867646539SMike Smith */ 419af548787SNicolas Souchu (void)inb(idport); (void)inb(idport); 420af548787SNicolas Souchu (void)inb(idport); (void)inb(idport); 42167646539SMike Smith 42267646539SMike Smith /* 42367646539SMike Smith * Read the SID byte. Possible values are : 42467646539SMike Smith * 425af548787SNicolas Souchu * 01010xxx PC87334 42667646539SMike Smith * 0001xxxx PC87332 42767646539SMike Smith * 01110xxx PC87306 428ac7ba926SDoug Rabson * 00110xxx PC87303 42967646539SMike Smith */ 43067646539SMike Smith outb(idport, PC873_SID); 43167646539SMike Smith val = inb(idport + 1); 43267646539SMike Smith if ((val & 0xf0) == 0x10) { 4330f210c92SNicolas Souchu ppc->ppc_model = NS_PC87332; 43467646539SMike Smith } else if ((val & 0xf8) == 0x70) { 4350f210c92SNicolas Souchu ppc->ppc_model = NS_PC87306; 436af548787SNicolas Souchu } else if ((val & 0xf8) == 0x50) { 4370f210c92SNicolas Souchu ppc->ppc_model = NS_PC87334; 438ac7ba926SDoug Rabson } else if ((val & 0xf8) == 0x40) { /* Should be 0x30 by the 439ac7ba926SDoug Rabson documentation, but probing 440ac7ba926SDoug Rabson yielded 0x40... */ 441ac7ba926SDoug Rabson ppc->ppc_model = NS_PC87303; 44267646539SMike Smith } else { 44367646539SMike Smith if (bootverbose && (val != 0xff)) 44467646539SMike Smith printf("PC873xx probe at 0x%x got unknown ID 0x%x\n", idport, val); 44567646539SMike Smith continue ; /* not recognised */ 44667646539SMike Smith } 44767646539SMike Smith 448af548787SNicolas Souchu /* print registers */ 449af548787SNicolas Souchu if (bootverbose) { 450af548787SNicolas Souchu printf("PC873xx"); 451af548787SNicolas Souchu for (i=0; pc873xx_regstab[i] != -1; i++) { 452af548787SNicolas Souchu outb(idport, pc873xx_regstab[i]); 453af548787SNicolas Souchu printf(" %s=0x%x", pc873xx_rnametab[i], 454af548787SNicolas Souchu inb(idport + 1) & 0xff); 455af548787SNicolas Souchu } 456af548787SNicolas Souchu printf("\n"); 457af548787SNicolas Souchu } 458af548787SNicolas Souchu 45967646539SMike Smith /* 46067646539SMike Smith * We think we have one. Is it enabled and where we want it to be? 46167646539SMike Smith */ 46267646539SMike Smith outb(idport, PC873_FER); 46367646539SMike Smith val = inb(idport + 1); 46467646539SMike Smith if (!(val & PC873_PPENABLE)) { 46567646539SMike Smith if (bootverbose) 46667646539SMike Smith printf("PC873xx parallel port disabled\n"); 46767646539SMike Smith continue; 46867646539SMike Smith } 46967646539SMike Smith outb(idport, PC873_FAR); 470ac7ba926SDoug Rabson val = inb(idport + 1); 47167646539SMike Smith /* XXX we should create a driver instance for every port found */ 472ac7ba926SDoug Rabson if (pc873xx_porttab[val & 0x3] != ppc->ppc_base) { 473ac7ba926SDoug Rabson 474ac7ba926SDoug Rabson /* First try to change the port address to that requested... */ 475ac7ba926SDoug Rabson 476ac7ba926SDoug Rabson switch(ppc->ppc_base) { 477ac7ba926SDoug Rabson case 0x378: 478ac7ba926SDoug Rabson val &= 0xfc; 479ac7ba926SDoug Rabson break; 480ac7ba926SDoug Rabson 481ac7ba926SDoug Rabson case 0x3bc: 482ac7ba926SDoug Rabson val &= 0xfd; 483ac7ba926SDoug Rabson break; 484ac7ba926SDoug Rabson 485ac7ba926SDoug Rabson case 0x278: 486ac7ba926SDoug Rabson val &= 0xfe; 487ac7ba926SDoug Rabson break; 488ac7ba926SDoug Rabson 489ac7ba926SDoug Rabson default: 490ac7ba926SDoug Rabson val &= 0xfd; 491ac7ba926SDoug Rabson break; 492ac7ba926SDoug Rabson } 493ac7ba926SDoug Rabson 494ac7ba926SDoug Rabson outb(idport, PC873_FAR); 495ac7ba926SDoug Rabson outb(idport + 1, val); 496ac7ba926SDoug Rabson outb(idport + 1, val); 497ac7ba926SDoug Rabson 498ac7ba926SDoug Rabson /* Check for success by reading back the value we supposedly 499ac7ba926SDoug Rabson wrote and comparing...*/ 500ac7ba926SDoug Rabson 501ac7ba926SDoug Rabson outb(idport, PC873_FAR); 502ac7ba926SDoug Rabson val = inb(idport + 1) & 0x3; 503ac7ba926SDoug Rabson 504ac7ba926SDoug Rabson /* If we fail, report the failure... */ 505ac7ba926SDoug Rabson 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); 510ac7ba926SDoug Rabson } 51167646539SMike Smith continue; 51267646539SMike Smith } 51367646539SMike Smith 51467646539SMike Smith outb(idport, PC873_PTR); 515af548787SNicolas Souchu ptr = inb(idport + 1); 516af548787SNicolas Souchu 517af548787SNicolas Souchu /* get irq settings */ 518af548787SNicolas Souchu if (ppc->ppc_base == 0x378) 519af548787SNicolas Souchu irq = (ptr & PC873_LPTBIRQ7) ? 7 : 5; 520af548787SNicolas Souchu else 521af548787SNicolas Souchu irq = pc873xx_irqtab[val]; 522af548787SNicolas Souchu 52367646539SMike Smith if (bootverbose) 524af548787SNicolas Souchu printf("PC873xx irq %d at 0x%x\n", irq, ppc->ppc_base); 52567646539SMike Smith 526af548787SNicolas Souchu /* 527af548787SNicolas Souchu * Check if irq settings are correct 528af548787SNicolas Souchu */ 529af548787SNicolas Souchu if (irq != ppc->ppc_irq) { 530af548787SNicolas Souchu /* 531af548787SNicolas Souchu * If the chipset is not locked and base address is 0x378, 532af548787SNicolas Souchu * we have another chance 533af548787SNicolas Souchu */ 534af548787SNicolas Souchu if (ppc->ppc_base == 0x378 && !(ptr & PC873_CFGLOCK)) { 535af548787SNicolas Souchu if (ppc->ppc_irq == 7) { 536af548787SNicolas Souchu outb(idport + 1, (ptr | PC873_LPTBIRQ7)); 537af548787SNicolas Souchu outb(idport + 1, (ptr | PC873_LPTBIRQ7)); 538af548787SNicolas Souchu } else { 539af548787SNicolas Souchu outb(idport + 1, (ptr & ~PC873_LPTBIRQ7)); 540af548787SNicolas Souchu outb(idport + 1, (ptr & ~PC873_LPTBIRQ7)); 54167646539SMike Smith } 542af548787SNicolas Souchu if (bootverbose) 543af548787SNicolas Souchu printf("PC873xx irq set to %d\n", ppc->ppc_irq); 544af548787SNicolas Souchu } else { 545af548787SNicolas Souchu if (bootverbose) 546af548787SNicolas Souchu printf("PC873xx sorry, can't change irq setting\n"); 54767646539SMike Smith } 54867646539SMike Smith } else { 54967646539SMike Smith if (bootverbose) 550af548787SNicolas Souchu printf("PC873xx irq settings are correct\n"); 55167646539SMike Smith } 55267646539SMike Smith 55367646539SMike Smith outb(idport, PC873_PCR); 554af548787SNicolas Souchu pcr = inb(idport + 1); 555af548787SNicolas Souchu 556af548787SNicolas Souchu if ((ptr & PC873_CFGLOCK) || !chipset_mode) { 557af548787SNicolas Souchu if (bootverbose) 558af548787SNicolas Souchu printf("PC873xx %s", (ptr & PC873_CFGLOCK)?"locked":"unlocked"); 559af548787SNicolas Souchu 560af548787SNicolas Souchu ppc->ppc_avm |= PPB_NIBBLE; 561af548787SNicolas Souchu if (bootverbose) 562af548787SNicolas Souchu printf(", NIBBLE"); 563af548787SNicolas Souchu 564af548787SNicolas Souchu if (pcr & PC873_EPPEN) { 565af548787SNicolas Souchu ppc->ppc_avm |= PPB_EPP; 566af548787SNicolas Souchu 567af548787SNicolas Souchu if (bootverbose) 568af548787SNicolas Souchu printf(", EPP"); 569af548787SNicolas Souchu 570af548787SNicolas Souchu if (pcr & PC873_EPP19) 571af548787SNicolas Souchu ppc->ppc_epp = EPP_1_9; 572af548787SNicolas Souchu else 573af548787SNicolas Souchu ppc->ppc_epp = EPP_1_7; 574af548787SNicolas Souchu 5750f210c92SNicolas Souchu if ((ppc->ppc_model == NS_PC87332) && bootverbose) { 576af548787SNicolas Souchu outb(idport, PC873_PTR); 577af548787SNicolas Souchu ptr = inb(idport + 1); 578af548787SNicolas Souchu if (ptr & PC873_EPPRDIR) 579af548787SNicolas Souchu printf(", Regular mode"); 580af548787SNicolas Souchu else 581af548787SNicolas Souchu printf(", Automatic mode"); 582af548787SNicolas Souchu } 583af548787SNicolas Souchu } else if (pcr & PC873_ECPEN) { 584af548787SNicolas Souchu ppc->ppc_avm |= PPB_ECP; 585af548787SNicolas Souchu if (bootverbose) 586af548787SNicolas Souchu printf(", ECP"); 587af548787SNicolas Souchu 588af548787SNicolas Souchu if (pcr & PC873_ECPCLK) { /* XXX */ 589af548787SNicolas Souchu ppc->ppc_avm |= PPB_PS2; 590af548787SNicolas Souchu if (bootverbose) 591af548787SNicolas Souchu printf(", PS/2"); 592af548787SNicolas Souchu } 593af548787SNicolas Souchu } else { 594af548787SNicolas Souchu outb(idport, PC873_PTR); 595af548787SNicolas Souchu ptr = inb(idport + 1); 596af548787SNicolas Souchu if (ptr & PC873_EXTENDED) { 597af548787SNicolas Souchu ppc->ppc_avm |= PPB_SPP; 598af548787SNicolas Souchu if (bootverbose) 599af548787SNicolas Souchu printf(", SPP"); 600af548787SNicolas Souchu } 601af548787SNicolas Souchu } 602af548787SNicolas Souchu } else { 603af548787SNicolas Souchu if (bootverbose) 604af548787SNicolas Souchu printf("PC873xx unlocked"); 605af548787SNicolas Souchu 606af548787SNicolas Souchu if (chipset_mode & PPB_ECP) { 607af548787SNicolas Souchu if ((chipset_mode & PPB_EPP) && bootverbose) 608af548787SNicolas Souchu printf(", ECP+EPP not supported"); 609af548787SNicolas Souchu 610af548787SNicolas Souchu pcr &= ~PC873_EPPEN; 611af548787SNicolas Souchu pcr |= (PC873_ECPEN | PC873_ECPCLK); /* XXX */ 612af548787SNicolas Souchu outb(idport + 1, pcr); 613af548787SNicolas Souchu outb(idport + 1, pcr); 614af548787SNicolas Souchu 615af548787SNicolas Souchu if (bootverbose) 616af548787SNicolas Souchu printf(", ECP"); 617af548787SNicolas Souchu 618af548787SNicolas Souchu } else if (chipset_mode & PPB_EPP) { 619af548787SNicolas Souchu pcr &= ~(PC873_ECPEN | PC873_ECPCLK); 620af548787SNicolas Souchu pcr |= (PC873_EPPEN | PC873_EPP19); 621af548787SNicolas Souchu outb(idport + 1, pcr); 622af548787SNicolas Souchu outb(idport + 1, pcr); 623af548787SNicolas Souchu 624af548787SNicolas Souchu ppc->ppc_epp = EPP_1_9; /* XXX */ 625af548787SNicolas Souchu 626af548787SNicolas Souchu if (bootverbose) 627af548787SNicolas Souchu printf(", EPP1.9"); 62867646539SMike Smith 62967646539SMike Smith /* enable automatic direction turnover */ 6300f210c92SNicolas Souchu if (ppc->ppc_model == NS_PC87332) { 63167646539SMike Smith outb(idport, PC873_PTR); 632af548787SNicolas Souchu ptr = inb(idport + 1); 633af548787SNicolas Souchu ptr &= ~PC873_EPPRDIR; 634af548787SNicolas Souchu outb(idport + 1, ptr); 635af548787SNicolas Souchu outb(idport + 1, ptr); 63667646539SMike Smith 63767646539SMike Smith if (bootverbose) 638af548787SNicolas Souchu printf(", Automatic mode"); 63967646539SMike Smith } 640af548787SNicolas Souchu } else { 641af548787SNicolas Souchu pcr &= ~(PC873_ECPEN | PC873_ECPCLK | PC873_EPPEN); 642af548787SNicolas Souchu outb(idport + 1, pcr); 643af548787SNicolas Souchu outb(idport + 1, pcr); 644af548787SNicolas Souchu 645af548787SNicolas Souchu /* configure extended bit in PTR */ 646af548787SNicolas Souchu outb(idport, PC873_PTR); 647af548787SNicolas Souchu ptr = inb(idport + 1); 648af548787SNicolas Souchu 649af548787SNicolas Souchu if (chipset_mode & PPB_PS2) { 650af548787SNicolas Souchu ptr |= PC873_EXTENDED; 651af548787SNicolas Souchu 652af548787SNicolas Souchu if (bootverbose) 653af548787SNicolas Souchu printf(", PS/2"); 654af548787SNicolas Souchu 655af548787SNicolas Souchu } else { 656af548787SNicolas Souchu /* default to NIBBLE mode */ 657af548787SNicolas Souchu ptr &= ~PC873_EXTENDED; 658af548787SNicolas Souchu 659af548787SNicolas Souchu if (bootverbose) 660af548787SNicolas Souchu printf(", NIBBLE"); 66167646539SMike Smith } 662af548787SNicolas Souchu outb(idport + 1, ptr); 663af548787SNicolas Souchu outb(idport + 1, ptr); 664af548787SNicolas Souchu } 665af548787SNicolas Souchu 666af548787SNicolas Souchu ppc->ppc_avm = chipset_mode; 667af548787SNicolas Souchu } 668af548787SNicolas Souchu 669af548787SNicolas Souchu if (bootverbose) 670af548787SNicolas Souchu printf("\n"); 671af548787SNicolas Souchu 6720f210c92SNicolas Souchu ppc->ppc_type = PPC_TYPE_GENERIC; 6730f210c92SNicolas Souchu ppc_generic_setmode(ppc, chipset_mode); 67446f3ff79SMike Smith 67546f3ff79SMike Smith return(chipset_mode); 67667646539SMike Smith } 67746f3ff79SMike Smith return(-1); 67867646539SMike Smith } 67967646539SMike Smith 68067646539SMike Smith /* 68167646539SMike Smith * ppc_smc37c66xgt_detect 68267646539SMike Smith * 68367646539SMike Smith * SMC FDC37C66xGT configuration. 68467646539SMike Smith */ 68567646539SMike Smith static int 68646f3ff79SMike Smith ppc_smc37c66xgt_detect(struct ppc_data *ppc, int chipset_mode) 68767646539SMike Smith { 68867646539SMike Smith int s, i; 689c9ab0738SNicolas Souchu u_char r; 69067646539SMike Smith int type = -1; 69167646539SMike Smith int csr = SMC66x_CSR; /* initial value is 0x3F0 */ 69267646539SMike Smith 69367646539SMike Smith int port_address[] = { -1 /* disabled */ , 0x3bc, 0x378, 0x278 }; 69467646539SMike Smith 69567646539SMike Smith 69667646539SMike Smith #define cio csr+1 /* config IO port is either 0x3F1 or 0x371 */ 69767646539SMike Smith 69867646539SMike Smith /* 69967646539SMike Smith * Detection: enter configuration mode and read CRD register. 70067646539SMike Smith */ 70167646539SMike Smith 70267646539SMike Smith s = splhigh(); 70367646539SMike Smith outb(csr, SMC665_iCODE); 70467646539SMike Smith outb(csr, SMC665_iCODE); 70567646539SMike Smith splx(s); 70667646539SMike Smith 70767646539SMike Smith outb(csr, 0xd); 70867646539SMike Smith if (inb(cio) == 0x65) { 70967646539SMike Smith type = SMC_37C665GT; 71067646539SMike Smith goto config; 71167646539SMike Smith } 71267646539SMike Smith 71367646539SMike Smith for (i = 0; i < 2; i++) { 71467646539SMike Smith s = splhigh(); 71567646539SMike Smith outb(csr, SMC666_iCODE); 71667646539SMike Smith outb(csr, SMC666_iCODE); 71767646539SMike Smith splx(s); 71867646539SMike Smith 71967646539SMike Smith outb(csr, 0xd); 72067646539SMike Smith if (inb(cio) == 0x66) { 72167646539SMike Smith type = SMC_37C666GT; 72267646539SMike Smith break; 72367646539SMike Smith } 72467646539SMike Smith 72567646539SMike Smith /* Another chance, CSR may be hard-configured to be at 0x370 */ 72667646539SMike Smith csr = SMC666_CSR; 72767646539SMike Smith } 72867646539SMike Smith 72967646539SMike Smith config: 73067646539SMike Smith /* 73167646539SMike Smith * If chipset not found, do not continue. 73267646539SMike Smith */ 73367646539SMike Smith if (type == -1) 73446f3ff79SMike Smith return (-1); 73567646539SMike Smith 73667646539SMike Smith /* select CR1 */ 73767646539SMike Smith outb(csr, 0x1); 73867646539SMike Smith 73967646539SMike Smith /* read the port's address: bits 0 and 1 of CR1 */ 74067646539SMike Smith r = inb(cio) & SMC_CR1_ADDR; 741c9ab0738SNicolas Souchu if (port_address[(int)r] != ppc->ppc_base) 74246f3ff79SMike Smith return (-1); 74367646539SMike Smith 7440f210c92SNicolas Souchu ppc->ppc_model = type; 74567646539SMike Smith 74667646539SMike Smith /* 74767646539SMike Smith * CR1 and CR4 registers bits 3 and 0/1 for mode configuration 74846f3ff79SMike Smith * If SPP mode is detected, try to set ECP+EPP mode 74967646539SMike Smith */ 75067646539SMike Smith 75146f3ff79SMike Smith if (bootverbose) { 75246f3ff79SMike Smith outb(csr, 0x1); 75341990851SNicolas Souchu printf("ppc%d: SMC registers CR1=0x%x", ppc->ppc_unit, 75454ad6085SNicolas Souchu inb(cio) & 0xff); 75546f3ff79SMike Smith 75646f3ff79SMike Smith outb(csr, 0x4); 75746f3ff79SMike Smith printf(" CR4=0x%x", inb(cio) & 0xff); 75846f3ff79SMike Smith } 75946f3ff79SMike Smith 76046f3ff79SMike Smith /* select CR1 */ 76167646539SMike Smith outb(csr, 0x1); 76267646539SMike Smith 76346f3ff79SMike Smith if (!chipset_mode) { 76467646539SMike Smith /* autodetect mode */ 76567646539SMike Smith 76646f3ff79SMike Smith /* 666GT is ~certainly~ hardwired to an extended ECP+EPP mode */ 76746f3ff79SMike Smith if (type == SMC_37C666GT) { 76846f3ff79SMike Smith ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP; 769edcfcf27SNicolas Souchu if (bootverbose) 770edcfcf27SNicolas Souchu printf(" configuration hardwired, supposing " \ 771edcfcf27SNicolas Souchu "ECP+EPP SPP"); 77267646539SMike Smith 77346f3ff79SMike Smith } else 77446f3ff79SMike Smith if ((inb(cio) & SMC_CR1_MODE) == 0) { 77567646539SMike Smith /* already in extended parallel port mode, read CR4 */ 77667646539SMike Smith outb(csr, 0x4); 77767646539SMike Smith r = (inb(cio) & SMC_CR4_EMODE); 77867646539SMike Smith 77967646539SMike Smith switch (r) { 78067646539SMike Smith case SMC_SPP: 78146f3ff79SMike Smith ppc->ppc_avm |= PPB_SPP; 782edcfcf27SNicolas Souchu if (bootverbose) 783edcfcf27SNicolas Souchu printf(" SPP"); 78467646539SMike Smith break; 78567646539SMike Smith 78667646539SMike Smith case SMC_EPPSPP: 78746f3ff79SMike Smith ppc->ppc_avm |= PPB_EPP | PPB_SPP; 788edcfcf27SNicolas Souchu if (bootverbose) 789edcfcf27SNicolas Souchu printf(" EPP SPP"); 79067646539SMike Smith break; 79167646539SMike Smith 79267646539SMike Smith case SMC_ECP: 79346f3ff79SMike Smith ppc->ppc_avm |= PPB_ECP | PPB_SPP; 794edcfcf27SNicolas Souchu if (bootverbose) 795edcfcf27SNicolas Souchu printf(" ECP SPP"); 79667646539SMike Smith break; 79767646539SMike Smith 79867646539SMike Smith case SMC_ECPEPP: 79946f3ff79SMike Smith ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP; 800edcfcf27SNicolas Souchu if (bootverbose) 801edcfcf27SNicolas Souchu printf(" ECP+EPP SPP"); 80267646539SMike Smith break; 80367646539SMike Smith } 80446f3ff79SMike Smith } else { 80546f3ff79SMike Smith /* not an extended port mode */ 80646f3ff79SMike Smith ppc->ppc_avm |= PPB_SPP; 807edcfcf27SNicolas Souchu if (bootverbose) 808edcfcf27SNicolas Souchu printf(" SPP"); 80967646539SMike Smith } 81046f3ff79SMike Smith 81167646539SMike Smith } else { 81267646539SMike Smith /* mode forced */ 81354ad6085SNicolas Souchu ppc->ppc_avm = chipset_mode; 81467646539SMike Smith 81546f3ff79SMike Smith /* 666GT is ~certainly~ hardwired to an extended ECP+EPP mode */ 81667646539SMike Smith if (type == SMC_37C666GT) 81767646539SMike Smith goto end_detect; 81867646539SMike Smith 81967646539SMike Smith r = inb(cio); 82046f3ff79SMike Smith if ((chipset_mode & (PPB_ECP | PPB_EPP)) == 0) { 82146f3ff79SMike Smith /* do not use ECP when the mode is not forced to */ 82267646539SMike Smith outb(cio, r | SMC_CR1_MODE); 823edcfcf27SNicolas Souchu if (bootverbose) 824edcfcf27SNicolas Souchu printf(" SPP"); 82567646539SMike Smith } else { 82667646539SMike Smith /* an extended mode is selected */ 82767646539SMike Smith outb(cio, r & ~SMC_CR1_MODE); 82867646539SMike Smith 82967646539SMike Smith /* read CR4 register and reset mode field */ 83067646539SMike Smith outb(csr, 0x4); 83167646539SMike Smith r = inb(cio) & ~SMC_CR4_EMODE; 83267646539SMike Smith 83346f3ff79SMike Smith if (chipset_mode & PPB_ECP) { 83446f3ff79SMike Smith if (chipset_mode & PPB_EPP) { 83567646539SMike Smith outb(cio, r | SMC_ECPEPP); 836edcfcf27SNicolas Souchu if (bootverbose) 837edcfcf27SNicolas Souchu printf(" ECP+EPP"); 83846f3ff79SMike Smith } else { 83946f3ff79SMike Smith outb(cio, r | SMC_ECP); 840edcfcf27SNicolas Souchu if (bootverbose) 841edcfcf27SNicolas Souchu printf(" ECP"); 84246f3ff79SMike Smith } 84346f3ff79SMike Smith } else { 84446f3ff79SMike Smith /* PPB_EPP is set */ 84546f3ff79SMike Smith outb(cio, r | SMC_EPPSPP); 846edcfcf27SNicolas Souchu if (bootverbose) 847edcfcf27SNicolas Souchu printf(" EPP SPP"); 84867646539SMike Smith } 84967646539SMike Smith } 85046f3ff79SMike Smith ppc->ppc_avm = chipset_mode; 85167646539SMike Smith } 85267646539SMike Smith 853bc35c174SNicolas Souchu /* set FIFO threshold to 16 */ 854bc35c174SNicolas Souchu if (ppc->ppc_avm & PPB_ECP) { 855bc35c174SNicolas Souchu /* select CRA */ 856bc35c174SNicolas Souchu outb(csr, 0xa); 857bc35c174SNicolas Souchu outb(cio, 16); 858bc35c174SNicolas Souchu } 859bc35c174SNicolas Souchu 86067646539SMike Smith end_detect: 86146f3ff79SMike Smith 86246f3ff79SMike Smith if (bootverbose) 86346f3ff79SMike Smith printf ("\n"); 86446f3ff79SMike Smith 86554ad6085SNicolas Souchu if (ppc->ppc_avm & PPB_EPP) { 86667646539SMike Smith /* select CR4 */ 86767646539SMike Smith outb(csr, 0x4); 86867646539SMike Smith r = inb(cio); 86967646539SMike Smith 87067646539SMike Smith /* 87167646539SMike Smith * Set the EPP protocol... 87267646539SMike Smith * Low=EPP 1.9 (1284 standard) and High=EPP 1.7 87367646539SMike Smith */ 87467646539SMike Smith if (ppc->ppc_epp == EPP_1_9) 87567646539SMike Smith outb(cio, (r & ~SMC_CR4_EPPTYPE)); 87667646539SMike Smith else 87767646539SMike Smith outb(cio, (r | SMC_CR4_EPPTYPE)); 87867646539SMike Smith } 87967646539SMike Smith 88067646539SMike Smith /* end config mode */ 88167646539SMike Smith outb(csr, 0xaa); 88267646539SMike Smith 8830f210c92SNicolas Souchu ppc->ppc_type = PPC_TYPE_SMCLIKE; 8840f210c92SNicolas Souchu ppc_smclike_setmode(ppc, chipset_mode); 88567646539SMike Smith 88646f3ff79SMike Smith return (chipset_mode); 88767646539SMike Smith } 88867646539SMike Smith 88946f3ff79SMike Smith /* 8906a5be862SDoug Rabson * SMC FDC37C935 configuration 8916a5be862SDoug Rabson * Found on many Alpha machines 8926a5be862SDoug Rabson */ 8936a5be862SDoug Rabson static int 8946a5be862SDoug Rabson ppc_smc37c935_detect(struct ppc_data *ppc, int chipset_mode) 8956a5be862SDoug Rabson { 8966a5be862SDoug Rabson int s; 8976a5be862SDoug Rabson int type = -1; 8986a5be862SDoug Rabson 8996a5be862SDoug Rabson s = splhigh(); 9006a5be862SDoug Rabson outb(SMC935_CFG, 0x55); /* enter config mode */ 9016a5be862SDoug Rabson outb(SMC935_CFG, 0x55); 9026a5be862SDoug Rabson splx(s); 9036a5be862SDoug Rabson 9046a5be862SDoug Rabson outb(SMC935_IND, SMC935_ID); /* check device id */ 9056a5be862SDoug Rabson if (inb(SMC935_DAT) == 0x2) 9066a5be862SDoug Rabson type = SMC_37C935; 9076a5be862SDoug Rabson 9086a5be862SDoug Rabson if (type == -1) { 9096a5be862SDoug Rabson outb(SMC935_CFG, 0xaa); /* exit config mode */ 9106a5be862SDoug Rabson return (-1); 9116a5be862SDoug Rabson } 9126a5be862SDoug Rabson 9136a5be862SDoug Rabson ppc->ppc_model = type; 9146a5be862SDoug Rabson 9156a5be862SDoug Rabson outb(SMC935_IND, SMC935_LOGDEV); /* select parallel port, */ 9166a5be862SDoug Rabson outb(SMC935_DAT, 3); /* which is logical device 3 */ 9176a5be862SDoug Rabson 9186a5be862SDoug Rabson /* set io port base */ 9196a5be862SDoug Rabson outb(SMC935_IND, SMC935_PORTHI); 9206a5be862SDoug Rabson outb(SMC935_DAT, (u_char)((ppc->ppc_base & 0xff00) >> 8)); 9216a5be862SDoug Rabson outb(SMC935_IND, SMC935_PORTLO); 9226a5be862SDoug Rabson outb(SMC935_DAT, (u_char)(ppc->ppc_base & 0xff)); 9236a5be862SDoug Rabson 9246a5be862SDoug Rabson if (!chipset_mode) 9256a5be862SDoug Rabson ppc->ppc_avm = PPB_COMPATIBLE; /* default mode */ 9266a5be862SDoug Rabson else { 9276a5be862SDoug Rabson ppc->ppc_avm = chipset_mode; 9286a5be862SDoug Rabson outb(SMC935_IND, SMC935_PPMODE); 9296a5be862SDoug Rabson outb(SMC935_DAT, SMC935_CENT); /* start in compatible mode */ 9306a5be862SDoug Rabson 9316a5be862SDoug Rabson /* SPP + EPP or just plain SPP */ 9326a5be862SDoug Rabson if (chipset_mode & (PPB_SPP)) { 9336a5be862SDoug Rabson if (chipset_mode & PPB_EPP) { 9346a5be862SDoug Rabson if (ppc->ppc_epp == EPP_1_9) { 9356a5be862SDoug Rabson outb(SMC935_IND, SMC935_PPMODE); 9366a5be862SDoug Rabson outb(SMC935_DAT, SMC935_EPP19SPP); 9376a5be862SDoug Rabson } 9386a5be862SDoug Rabson if (ppc->ppc_epp == EPP_1_7) { 9396a5be862SDoug Rabson outb(SMC935_IND, SMC935_PPMODE); 9406a5be862SDoug Rabson outb(SMC935_DAT, SMC935_EPP17SPP); 9416a5be862SDoug Rabson } 9426a5be862SDoug Rabson } else { 9436a5be862SDoug Rabson outb(SMC935_IND, SMC935_PPMODE); 9446a5be862SDoug Rabson outb(SMC935_DAT, SMC935_SPP); 9456a5be862SDoug Rabson } 9466a5be862SDoug Rabson } 9476a5be862SDoug Rabson 9486a5be862SDoug Rabson /* ECP + EPP or just plain ECP */ 9496a5be862SDoug Rabson if (chipset_mode & PPB_ECP) { 9506a5be862SDoug Rabson if (chipset_mode & PPB_EPP) { 9516a5be862SDoug Rabson if (ppc->ppc_epp == EPP_1_9) { 9526a5be862SDoug Rabson outb(SMC935_IND, SMC935_PPMODE); 9536a5be862SDoug Rabson outb(SMC935_DAT, SMC935_ECPEPP19); 9546a5be862SDoug Rabson } 9556a5be862SDoug Rabson if (ppc->ppc_epp == EPP_1_7) { 9566a5be862SDoug Rabson outb(SMC935_IND, SMC935_PPMODE); 9576a5be862SDoug Rabson outb(SMC935_DAT, SMC935_ECPEPP17); 9586a5be862SDoug Rabson } 9596a5be862SDoug Rabson } else { 9606a5be862SDoug Rabson outb(SMC935_IND, SMC935_PPMODE); 9616a5be862SDoug Rabson outb(SMC935_DAT, SMC935_ECP); 9626a5be862SDoug Rabson } 9636a5be862SDoug Rabson } 9646a5be862SDoug Rabson } 9656a5be862SDoug Rabson 9666a5be862SDoug Rabson outb(SMC935_CFG, 0xaa); /* exit config mode */ 9676a5be862SDoug Rabson 9686a5be862SDoug Rabson ppc->ppc_type = PPC_TYPE_SMCLIKE; 9696a5be862SDoug Rabson ppc_smclike_setmode(ppc, chipset_mode); 9706a5be862SDoug Rabson 9716a5be862SDoug Rabson return (chipset_mode); 9726a5be862SDoug Rabson } 9736a5be862SDoug Rabson 9746a5be862SDoug Rabson /* 97546f3ff79SMike Smith * Winbond W83877F stuff 97646f3ff79SMike Smith * 97746f3ff79SMike Smith * EFER: extended function enable register 97846f3ff79SMike Smith * EFIR: extended function index register 97946f3ff79SMike Smith * EFDR: extended function data register 98046f3ff79SMike Smith */ 98146f3ff79SMike Smith #define efir ((efer == 0x250) ? 0x251 : 0x3f0) 98246f3ff79SMike Smith #define efdr ((efer == 0x250) ? 0x252 : 0x3f1) 98346f3ff79SMike Smith 98446f3ff79SMike Smith static int w83877f_efers[] = { 0x250, 0x3f0, 0x3f0, 0x250 }; 98546f3ff79SMike Smith static int w83877f_keys[] = { 0x89, 0x86, 0x87, 0x88 }; 98646f3ff79SMike Smith static int w83877f_keyiter[] = { 1, 2, 2, 1 }; 98746f3ff79SMike Smith static int w83877f_hefs[] = { WINB_HEFERE, WINB_HEFRAS, WINB_HEFERE | WINB_HEFRAS, 0 }; 98867646539SMike Smith 98967646539SMike Smith static int 99046f3ff79SMike Smith ppc_w83877f_detect(struct ppc_data *ppc, int chipset_mode) 99167646539SMike Smith { 992f1d19042SArchie Cobbs int i, j, efer; 99346f3ff79SMike Smith unsigned char r, hefere, hefras; 99467646539SMike Smith 99546f3ff79SMike Smith for (i = 0; i < 4; i ++) { 99646f3ff79SMike Smith /* first try to enable configuration registers */ 99746f3ff79SMike Smith efer = w83877f_efers[i]; 99867646539SMike Smith 99946f3ff79SMike Smith /* write the key to the EFER */ 100046f3ff79SMike Smith for (j = 0; j < w83877f_keyiter[i]; j ++) 100146f3ff79SMike Smith outb (efer, w83877f_keys[i]); 100246f3ff79SMike Smith 100346f3ff79SMike Smith /* then check HEFERE and HEFRAS bits */ 100446f3ff79SMike Smith outb (efir, 0x0c); 100546f3ff79SMike Smith hefere = inb(efdr) & WINB_HEFERE; 100646f3ff79SMike Smith 100746f3ff79SMike Smith outb (efir, 0x16); 100846f3ff79SMike Smith hefras = inb(efdr) & WINB_HEFRAS; 100946f3ff79SMike Smith 101046f3ff79SMike Smith /* 101146f3ff79SMike Smith * HEFRAS HEFERE 101246f3ff79SMike Smith * 0 1 write 89h to 250h (power-on default) 101346f3ff79SMike Smith * 1 0 write 86h twice to 3f0h 101446f3ff79SMike Smith * 1 1 write 87h twice to 3f0h 101546f3ff79SMike Smith * 0 0 write 88h to 250h 101646f3ff79SMike Smith */ 101746f3ff79SMike Smith if ((hefere | hefras) == w83877f_hefs[i]) 101846f3ff79SMike Smith goto found; 101967646539SMike Smith } 102067646539SMike Smith 102146f3ff79SMike Smith return (-1); /* failed */ 102267646539SMike Smith 102346f3ff79SMike Smith found: 102446f3ff79SMike Smith /* check base port address - read from CR23 */ 102546f3ff79SMike Smith outb(efir, 0x23); 102646f3ff79SMike Smith if (ppc->ppc_base != inb(efdr) * 4) /* 4 bytes boundaries */ 102746f3ff79SMike Smith return (-1); 102846f3ff79SMike Smith 102946f3ff79SMike Smith /* read CHIP ID from CR9/bits0-3 */ 103046f3ff79SMike Smith outb(efir, 0x9); 103146f3ff79SMike Smith 103246f3ff79SMike Smith switch (inb(efdr) & WINB_CHIPID) { 103346f3ff79SMike Smith case WINB_W83877F_ID: 10340f210c92SNicolas Souchu ppc->ppc_model = WINB_W83877F; 103546f3ff79SMike Smith break; 103646f3ff79SMike Smith 103746f3ff79SMike Smith case WINB_W83877AF_ID: 10380f210c92SNicolas Souchu ppc->ppc_model = WINB_W83877AF; 103946f3ff79SMike Smith break; 104046f3ff79SMike Smith 104146f3ff79SMike Smith default: 10420f210c92SNicolas Souchu ppc->ppc_model = WINB_UNKNOWN; 104346f3ff79SMike Smith } 104446f3ff79SMike Smith 104546f3ff79SMike Smith if (bootverbose) { 104646f3ff79SMike Smith /* dump of registers */ 104746f3ff79SMike Smith printf("ppc%d: 0x%x - ", ppc->ppc_unit, w83877f_keys[i]); 104846f3ff79SMike Smith for (i = 0; i <= 0xd; i ++) { 104946f3ff79SMike Smith outb(efir, i); 105046f3ff79SMike Smith printf("0x%x ", inb(efdr)); 105146f3ff79SMike Smith } 105246f3ff79SMike Smith for (i = 0x10; i <= 0x17; i ++) { 105346f3ff79SMike Smith outb(efir, i); 105446f3ff79SMike Smith printf("0x%x ", inb(efdr)); 105546f3ff79SMike Smith } 105646f3ff79SMike Smith outb(efir, 0x1e); 105746f3ff79SMike Smith printf("0x%x ", inb(efdr)); 105846f3ff79SMike Smith for (i = 0x20; i <= 0x29; i ++) { 105946f3ff79SMike Smith outb(efir, i); 106046f3ff79SMike Smith printf("0x%x ", inb(efdr)); 106146f3ff79SMike Smith } 106246f3ff79SMike Smith printf("\n"); 1063edcfcf27SNicolas Souchu printf("ppc%d:", ppc->ppc_unit); 106446f3ff79SMike Smith } 106546f3ff79SMike Smith 10660f210c92SNicolas Souchu ppc->ppc_type = PPC_TYPE_GENERIC; 1067edcfcf27SNicolas Souchu 106846f3ff79SMike Smith if (!chipset_mode) { 106946f3ff79SMike Smith /* autodetect mode */ 107046f3ff79SMike Smith 107146f3ff79SMike Smith /* select CR0 */ 107246f3ff79SMike Smith outb(efir, 0x0); 107346f3ff79SMike Smith r = inb(efdr) & (WINB_PRTMODS0 | WINB_PRTMODS1); 107446f3ff79SMike Smith 107546f3ff79SMike Smith /* select CR9 */ 107646f3ff79SMike Smith outb(efir, 0x9); 107746f3ff79SMike Smith r |= (inb(efdr) & WINB_PRTMODS2); 107846f3ff79SMike Smith 107946f3ff79SMike Smith switch (r) { 108046f3ff79SMike Smith case WINB_W83757: 108146f3ff79SMike Smith if (bootverbose) 108246f3ff79SMike Smith printf("ppc%d: W83757 compatible mode\n", 108346f3ff79SMike Smith ppc->ppc_unit); 108446f3ff79SMike Smith return (-1); /* generic or SMC-like */ 108546f3ff79SMike Smith 108646f3ff79SMike Smith case WINB_EXTFDC: 108746f3ff79SMike Smith case WINB_EXTADP: 108846f3ff79SMike Smith case WINB_EXT2FDD: 108946f3ff79SMike Smith case WINB_JOYSTICK: 109046f3ff79SMike Smith if (bootverbose) 1091edcfcf27SNicolas Souchu printf(" not in parallel port mode\n"); 109246f3ff79SMike Smith return (-1); 109346f3ff79SMike Smith 109446f3ff79SMike Smith case (WINB_PARALLEL | WINB_EPP_SPP): 109546f3ff79SMike Smith ppc->ppc_avm |= PPB_EPP | PPB_SPP; 1096edcfcf27SNicolas Souchu if (bootverbose) 1097edcfcf27SNicolas Souchu printf(" EPP SPP"); 109846f3ff79SMike Smith break; 109946f3ff79SMike Smith 110046f3ff79SMike Smith case (WINB_PARALLEL | WINB_ECP): 110146f3ff79SMike Smith ppc->ppc_avm |= PPB_ECP | PPB_SPP; 1102edcfcf27SNicolas Souchu if (bootverbose) 1103edcfcf27SNicolas Souchu printf(" ECP SPP"); 110446f3ff79SMike Smith break; 110546f3ff79SMike Smith 110646f3ff79SMike Smith case (WINB_PARALLEL | WINB_ECP_EPP): 110746f3ff79SMike Smith ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP; 11080f210c92SNicolas Souchu ppc->ppc_type = PPC_TYPE_SMCLIKE; 1109edcfcf27SNicolas Souchu 1110edcfcf27SNicolas Souchu if (bootverbose) 1111edcfcf27SNicolas Souchu printf(" ECP+EPP SPP"); 111246f3ff79SMike Smith break; 111346f3ff79SMike Smith default: 11146e551fb6SDavid E. O'Brien printf("%s: unknown case (0x%x)!\n", __func__, r); 111546f3ff79SMike Smith } 111646f3ff79SMike Smith 111746f3ff79SMike Smith } else { 111846f3ff79SMike Smith /* mode forced */ 111946f3ff79SMike Smith 112046f3ff79SMike Smith /* select CR9 and set PRTMODS2 bit */ 112146f3ff79SMike Smith outb(efir, 0x9); 112246f3ff79SMike Smith outb(efdr, inb(efdr) & ~WINB_PRTMODS2); 112346f3ff79SMike Smith 112446f3ff79SMike Smith /* select CR0 and reset PRTMODSx bits */ 112546f3ff79SMike Smith outb(efir, 0x0); 112646f3ff79SMike Smith outb(efdr, inb(efdr) & ~(WINB_PRTMODS0 | WINB_PRTMODS1)); 112746f3ff79SMike Smith 112846f3ff79SMike Smith if (chipset_mode & PPB_ECP) { 1129edcfcf27SNicolas Souchu if (chipset_mode & PPB_EPP) { 113046f3ff79SMike Smith outb(efdr, inb(efdr) | WINB_ECP_EPP); 1131edcfcf27SNicolas Souchu if (bootverbose) 1132edcfcf27SNicolas Souchu printf(" ECP+EPP"); 1133edcfcf27SNicolas Souchu 11340f210c92SNicolas Souchu ppc->ppc_type = PPC_TYPE_SMCLIKE; 1135edcfcf27SNicolas Souchu 1136edcfcf27SNicolas Souchu } else { 113746f3ff79SMike Smith outb(efdr, inb(efdr) | WINB_ECP); 1138edcfcf27SNicolas Souchu if (bootverbose) 1139edcfcf27SNicolas Souchu printf(" ECP"); 1140edcfcf27SNicolas Souchu } 114146f3ff79SMike Smith } else { 114246f3ff79SMike Smith /* select EPP_SPP otherwise */ 114346f3ff79SMike Smith outb(efdr, inb(efdr) | WINB_EPP_SPP); 1144edcfcf27SNicolas Souchu if (bootverbose) 1145edcfcf27SNicolas Souchu printf(" EPP SPP"); 114646f3ff79SMike Smith } 114746f3ff79SMike Smith ppc->ppc_avm = chipset_mode; 114846f3ff79SMike Smith } 114946f3ff79SMike Smith 1150edcfcf27SNicolas Souchu if (bootverbose) 1151edcfcf27SNicolas Souchu printf("\n"); 1152edcfcf27SNicolas Souchu 115346f3ff79SMike Smith /* exit configuration mode */ 115446f3ff79SMike Smith outb(efer, 0xaa); 115546f3ff79SMike Smith 11560f210c92SNicolas Souchu switch (ppc->ppc_type) { 11570f210c92SNicolas Souchu case PPC_TYPE_SMCLIKE: 11580f210c92SNicolas Souchu ppc_smclike_setmode(ppc, chipset_mode); 11590f210c92SNicolas Souchu break; 11600f210c92SNicolas Souchu default: 11610f210c92SNicolas Souchu ppc_generic_setmode(ppc, chipset_mode); 11620f210c92SNicolas Souchu break; 11630f210c92SNicolas Souchu } 116446f3ff79SMike Smith 116546f3ff79SMike Smith return (chipset_mode); 116667646539SMike Smith } 11670f210c92SNicolas Souchu #endif 116867646539SMike Smith 116967646539SMike Smith /* 117067646539SMike Smith * ppc_generic_detect 117167646539SMike Smith */ 117267646539SMike Smith static int 117346f3ff79SMike Smith ppc_generic_detect(struct ppc_data *ppc, int chipset_mode) 117467646539SMike Smith { 1175edcfcf27SNicolas Souchu /* default to generic */ 11760f210c92SNicolas Souchu ppc->ppc_type = PPC_TYPE_GENERIC; 1177edcfcf27SNicolas Souchu 1178edcfcf27SNicolas Souchu if (bootverbose) 1179edcfcf27SNicolas Souchu printf("ppc%d:", ppc->ppc_unit); 1180edcfcf27SNicolas Souchu 118146f3ff79SMike Smith /* first, check for ECP */ 1182bc35c174SNicolas Souchu w_ecr(ppc, PPC_ECR_PS2); 1183bc35c174SNicolas Souchu if ((r_ecr(ppc) & 0xe0) == PPC_ECR_PS2) { 1184c264e80fSNicolas Souchu ppc->ppc_dtm |= PPB_ECP | PPB_SPP; 1185edcfcf27SNicolas Souchu if (bootverbose) 1186edcfcf27SNicolas Souchu printf(" ECP SPP"); 118746f3ff79SMike Smith 118846f3ff79SMike Smith /* search for SMC style ECP+EPP mode */ 1189bc35c174SNicolas Souchu w_ecr(ppc, PPC_ECR_EPP); 119046f3ff79SMike Smith } 119167646539SMike Smith 119267646539SMike Smith /* try to reset EPP timeout bit */ 119346f3ff79SMike Smith if (ppc_check_epp_timeout(ppc)) { 1194c264e80fSNicolas Souchu ppc->ppc_dtm |= PPB_EPP; 119567646539SMike Smith 1196c264e80fSNicolas Souchu if (ppc->ppc_dtm & PPB_ECP) { 119746f3ff79SMike Smith /* SMC like chipset found */ 11980f210c92SNicolas Souchu ppc->ppc_model = SMC_LIKE; 11990f210c92SNicolas Souchu ppc->ppc_type = PPC_TYPE_SMCLIKE; 1200edcfcf27SNicolas Souchu 1201edcfcf27SNicolas Souchu if (bootverbose) 1202edcfcf27SNicolas Souchu printf(" ECP+EPP"); 1203edcfcf27SNicolas Souchu } else { 1204edcfcf27SNicolas Souchu if (bootverbose) 1205edcfcf27SNicolas Souchu printf(" EPP"); 1206edcfcf27SNicolas Souchu } 1207edcfcf27SNicolas Souchu } else { 1208edcfcf27SNicolas Souchu /* restore to standard mode */ 1209bc35c174SNicolas Souchu w_ecr(ppc, PPC_ECR_STD); 121067646539SMike Smith } 121167646539SMike Smith 1212edcfcf27SNicolas Souchu /* XXX try to detect NIBBLE and PS2 modes */ 1213c264e80fSNicolas Souchu ppc->ppc_dtm |= PPB_NIBBLE; 121467646539SMike Smith 1215edcfcf27SNicolas Souchu if (bootverbose) 1216edcfcf27SNicolas Souchu printf(" SPP"); 121767646539SMike Smith 1218c264e80fSNicolas Souchu if (chipset_mode) 1219edcfcf27SNicolas Souchu ppc->ppc_avm = chipset_mode; 1220c264e80fSNicolas Souchu else 1221c264e80fSNicolas Souchu ppc->ppc_avm = ppc->ppc_dtm; 1222edcfcf27SNicolas Souchu 1223edcfcf27SNicolas Souchu if (bootverbose) 1224edcfcf27SNicolas Souchu printf("\n"); 1225edcfcf27SNicolas Souchu 12260f210c92SNicolas Souchu switch (ppc->ppc_type) { 12270f210c92SNicolas Souchu case PPC_TYPE_SMCLIKE: 12280f210c92SNicolas Souchu ppc_smclike_setmode(ppc, chipset_mode); 12290f210c92SNicolas Souchu break; 12300f210c92SNicolas Souchu default: 12310f210c92SNicolas Souchu ppc_generic_setmode(ppc, chipset_mode); 12320f210c92SNicolas Souchu break; 12330f210c92SNicolas Souchu } 123446f3ff79SMike Smith 123546f3ff79SMike Smith return (chipset_mode); 123667646539SMike Smith } 123767646539SMike Smith 123867646539SMike Smith /* 123967646539SMike Smith * ppc_detect() 124067646539SMike Smith * 124167646539SMike Smith * mode is the mode suggested at boot 124267646539SMike Smith */ 124367646539SMike Smith static int 124446f3ff79SMike Smith ppc_detect(struct ppc_data *ppc, int chipset_mode) { 124567646539SMike Smith 12460f210c92SNicolas Souchu #ifdef PPC_PROBE_CHIPSET 124746f3ff79SMike Smith int i, mode; 124867646539SMike Smith 124946f3ff79SMike Smith /* list of supported chipsets */ 125046f3ff79SMike Smith int (*chipset_detect[])(struct ppc_data *, int) = { 125146f3ff79SMike Smith ppc_pc873xx_detect, 125246f3ff79SMike Smith ppc_smc37c66xgt_detect, 125346f3ff79SMike Smith ppc_w83877f_detect, 12546a5be862SDoug Rabson ppc_smc37c935_detect, 125546f3ff79SMike Smith ppc_generic_detect, 125646f3ff79SMike Smith NULL 125746f3ff79SMike Smith }; 12580f210c92SNicolas Souchu #endif 125967646539SMike Smith 126046f3ff79SMike Smith /* if can't find the port and mode not forced return error */ 126146f3ff79SMike Smith if (!ppc_detect_port(ppc) && chipset_mode == 0) 126246f3ff79SMike Smith return (EIO); /* failed, port not present */ 126367646539SMike Smith 126446f3ff79SMike Smith /* assume centronics compatible mode is supported */ 126546f3ff79SMike Smith ppc->ppc_avm = PPB_COMPATIBLE; 126667646539SMike Smith 12670f210c92SNicolas Souchu #ifdef PPC_PROBE_CHIPSET 126846f3ff79SMike Smith /* we have to differenciate available chipset modes, 126946f3ff79SMike Smith * chipset running modes and IEEE-1284 operating modes 127046f3ff79SMike Smith * 127146f3ff79SMike Smith * after detection, the port must support running in compatible mode 127246f3ff79SMike Smith */ 1273af548787SNicolas Souchu if (ppc->ppc_flags & 0x40) { 1274af548787SNicolas Souchu if (bootverbose) 1275af548787SNicolas Souchu printf("ppc: chipset forced to generic\n"); 12760f210c92SNicolas Souchu #endif 1277af548787SNicolas Souchu 1278af548787SNicolas Souchu ppc->ppc_mode = ppc_generic_detect(ppc, chipset_mode); 1279af548787SNicolas Souchu 12800f210c92SNicolas Souchu #ifdef PPC_PROBE_CHIPSET 1281af548787SNicolas Souchu } else { 128246f3ff79SMike Smith for (i=0; chipset_detect[i] != NULL; i++) { 128346f3ff79SMike Smith if ((mode = chipset_detect[i](ppc, chipset_mode)) != -1) { 128446f3ff79SMike Smith ppc->ppc_mode = mode; 128546f3ff79SMike Smith break; 128646f3ff79SMike Smith } 128746f3ff79SMike Smith } 1288af548787SNicolas Souchu } 12890f210c92SNicolas Souchu #endif 129046f3ff79SMike Smith 1291bc35c174SNicolas Souchu /* configure/detect ECP FIFO */ 1292bc35c174SNicolas Souchu if ((ppc->ppc_avm & PPB_ECP) && !(ppc->ppc_flags & 0x80)) 1293bc35c174SNicolas Souchu ppc_detect_fifo(ppc); 1294bc35c174SNicolas Souchu 129546f3ff79SMike Smith return (0); 129646f3ff79SMike Smith } 129746f3ff79SMike Smith 129846f3ff79SMike Smith /* 129946f3ff79SMike Smith * ppc_exec_microseq() 130046f3ff79SMike Smith * 130146f3ff79SMike Smith * Execute a microsequence. 130246f3ff79SMike Smith * Microsequence mechanism is supposed to handle fast I/O operations. 130346f3ff79SMike Smith */ 1304a3732274SDoug Ambrisko int 13050f210c92SNicolas Souchu ppc_exec_microseq(device_t dev, struct ppb_microseq **p_msq) 130646f3ff79SMike Smith { 13070f210c92SNicolas Souchu struct ppc_data *ppc = DEVTOSOFTC(dev); 13080a40e22aSNicolas Souchu struct ppb_microseq *mi; 130946f3ff79SMike Smith char cc, *p; 131054ad6085SNicolas Souchu int i, iter, len; 131146f3ff79SMike Smith int error; 131246f3ff79SMike Smith 131354ad6085SNicolas Souchu register int reg; 131454ad6085SNicolas Souchu register char mask; 131554ad6085SNicolas Souchu register int accum = 0; 131654ad6085SNicolas Souchu register char *ptr = 0; 131746f3ff79SMike Smith 13180a40e22aSNicolas Souchu struct ppb_microseq *stack = 0; 131946f3ff79SMike Smith 132046f3ff79SMike Smith /* microsequence registers are equivalent to PC-like port registers */ 13213ae3f8b0SNicolas Souchu 13228fd40d8aSJohn Baldwin #define r_reg(reg,ppc) (bus_read_1((ppc)->res_ioport, reg)) 13238fd40d8aSJohn Baldwin #define w_reg(reg, ppc, byte) (bus_write_1((ppc)->res_ioport, reg, byte)) 132446f3ff79SMike Smith 13250a40e22aSNicolas Souchu #define INCR_PC (mi ++) /* increment program counter */ 132646f3ff79SMike Smith 13270a40e22aSNicolas Souchu mi = *p_msq; 132846f3ff79SMike Smith for (;;) { 132946f3ff79SMike Smith switch (mi->opcode) { 133046f3ff79SMike Smith case MS_OP_RSET: 133146f3ff79SMike Smith cc = r_reg(mi->arg[0].i, ppc); 133254ad6085SNicolas Souchu cc &= (char)mi->arg[2].i; /* clear mask */ 133354ad6085SNicolas Souchu cc |= (char)mi->arg[1].i; /* assert mask */ 133446f3ff79SMike Smith w_reg(mi->arg[0].i, ppc, cc); 133546f3ff79SMike Smith INCR_PC; 133646f3ff79SMike Smith break; 133746f3ff79SMike Smith 133846f3ff79SMike Smith case MS_OP_RASSERT_P: 133954ad6085SNicolas Souchu reg = mi->arg[1].i; 134054ad6085SNicolas Souchu ptr = ppc->ppc_ptr; 134154ad6085SNicolas Souchu 134254ad6085SNicolas Souchu if ((len = mi->arg[0].i) == MS_ACCUM) { 134354ad6085SNicolas Souchu accum = ppc->ppc_accum; 134454ad6085SNicolas Souchu for (; accum; accum--) 134554ad6085SNicolas Souchu w_reg(reg, ppc, *ptr++); 134654ad6085SNicolas Souchu ppc->ppc_accum = accum; 134754ad6085SNicolas Souchu } else 134854ad6085SNicolas Souchu for (i=0; i<len; i++) 134954ad6085SNicolas Souchu w_reg(reg, ppc, *ptr++); 135054ad6085SNicolas Souchu ppc->ppc_ptr = ptr; 135154ad6085SNicolas Souchu 135246f3ff79SMike Smith INCR_PC; 135346f3ff79SMike Smith break; 135446f3ff79SMike Smith 135546f3ff79SMike Smith case MS_OP_RFETCH_P: 135654ad6085SNicolas Souchu reg = mi->arg[1].i; 135754ad6085SNicolas Souchu mask = (char)mi->arg[2].i; 135854ad6085SNicolas Souchu ptr = ppc->ppc_ptr; 135954ad6085SNicolas Souchu 136054ad6085SNicolas Souchu if ((len = mi->arg[0].i) == MS_ACCUM) { 136154ad6085SNicolas Souchu accum = ppc->ppc_accum; 136254ad6085SNicolas Souchu for (; accum; accum--) 136354ad6085SNicolas Souchu *ptr++ = r_reg(reg, ppc) & mask; 136454ad6085SNicolas Souchu ppc->ppc_accum = accum; 136554ad6085SNicolas Souchu } else 136654ad6085SNicolas Souchu for (i=0; i<len; i++) 136754ad6085SNicolas Souchu *ptr++ = r_reg(reg, ppc) & mask; 136854ad6085SNicolas Souchu ppc->ppc_ptr = ptr; 136954ad6085SNicolas Souchu 137046f3ff79SMike Smith INCR_PC; 137146f3ff79SMike Smith break; 137246f3ff79SMike Smith 137346f3ff79SMike Smith case MS_OP_RFETCH: 137446f3ff79SMike Smith *((char *) mi->arg[2].p) = r_reg(mi->arg[0].i, ppc) & 137554ad6085SNicolas Souchu (char)mi->arg[1].i; 137646f3ff79SMike Smith INCR_PC; 137746f3ff79SMike Smith break; 137846f3ff79SMike Smith 137946f3ff79SMike Smith case MS_OP_RASSERT: 138054ad6085SNicolas Souchu case MS_OP_DELAY: 138146f3ff79SMike Smith 138246f3ff79SMike Smith /* let's suppose the next instr. is the same */ 138346f3ff79SMike Smith prefetch: 138446f3ff79SMike Smith for (;mi->opcode == MS_OP_RASSERT; INCR_PC) 138554ad6085SNicolas Souchu w_reg(mi->arg[0].i, ppc, (char)mi->arg[1].i); 138646f3ff79SMike Smith 138746f3ff79SMike Smith if (mi->opcode == MS_OP_DELAY) { 138846f3ff79SMike Smith DELAY(mi->arg[0].i); 138946f3ff79SMike Smith INCR_PC; 139046f3ff79SMike Smith goto prefetch; 139146f3ff79SMike Smith } 139246f3ff79SMike Smith break; 139346f3ff79SMike Smith 139454ad6085SNicolas Souchu case MS_OP_ADELAY: 139554ad6085SNicolas Souchu if (mi->arg[0].i) 1396a96255b6SJohn Baldwin pause("ppbdelay", mi->arg[0].i * (hz/1000)); 139746f3ff79SMike Smith INCR_PC; 139846f3ff79SMike Smith break; 139946f3ff79SMike Smith 140046f3ff79SMike Smith case MS_OP_TRIG: 140146f3ff79SMike Smith reg = mi->arg[0].i; 140246f3ff79SMike Smith iter = mi->arg[1].i; 140346f3ff79SMike Smith p = (char *)mi->arg[2].p; 140446f3ff79SMike Smith 140554ad6085SNicolas Souchu /* XXX delay limited to 255 us */ 140646f3ff79SMike Smith for (i=0; i<iter; i++) { 140746f3ff79SMike Smith w_reg(reg, ppc, *p++); 140846f3ff79SMike Smith DELAY((unsigned char)*p++); 140946f3ff79SMike Smith } 141046f3ff79SMike Smith INCR_PC; 141146f3ff79SMike Smith break; 141246f3ff79SMike Smith 141346f3ff79SMike Smith case MS_OP_SET: 141454ad6085SNicolas Souchu ppc->ppc_accum = mi->arg[0].i; 141546f3ff79SMike Smith INCR_PC; 141646f3ff79SMike Smith break; 141746f3ff79SMike Smith 141846f3ff79SMike Smith case MS_OP_DBRA: 141954ad6085SNicolas Souchu if (--ppc->ppc_accum > 0) 14200a40e22aSNicolas Souchu mi += mi->arg[0].i; 142146f3ff79SMike Smith INCR_PC; 142246f3ff79SMike Smith break; 142346f3ff79SMike Smith 142446f3ff79SMike Smith case MS_OP_BRSET: 142546f3ff79SMike Smith cc = r_str(ppc); 142654ad6085SNicolas Souchu if ((cc & (char)mi->arg[0].i) == (char)mi->arg[0].i) 14270a40e22aSNicolas Souchu mi += mi->arg[1].i; 142846f3ff79SMike Smith INCR_PC; 142946f3ff79SMike Smith break; 143046f3ff79SMike Smith 143146f3ff79SMike Smith case MS_OP_BRCLEAR: 143246f3ff79SMike Smith cc = r_str(ppc); 143354ad6085SNicolas Souchu if ((cc & (char)mi->arg[0].i) == 0) 14340a40e22aSNicolas Souchu mi += mi->arg[1].i; 143546f3ff79SMike Smith INCR_PC; 143646f3ff79SMike Smith break; 143746f3ff79SMike Smith 143854ad6085SNicolas Souchu case MS_OP_BRSTAT: 143954ad6085SNicolas Souchu cc = r_str(ppc); 144054ad6085SNicolas Souchu if ((cc & ((char)mi->arg[0].i | (char)mi->arg[1].i)) == 144154ad6085SNicolas Souchu (char)mi->arg[0].i) 14420a40e22aSNicolas Souchu mi += mi->arg[2].i; 144354ad6085SNicolas Souchu INCR_PC; 144454ad6085SNicolas Souchu break; 144554ad6085SNicolas Souchu 144646f3ff79SMike Smith case MS_OP_C_CALL: 144746f3ff79SMike Smith /* 144846f3ff79SMike Smith * If the C call returns !0 then end the microseq. 144946f3ff79SMike Smith * The current state of ptr is passed to the C function 145046f3ff79SMike Smith */ 145154ad6085SNicolas Souchu if ((error = mi->arg[0].f(mi->arg[1].p, ppc->ppc_ptr))) 145246f3ff79SMike Smith return (error); 145346f3ff79SMike Smith 145446f3ff79SMike Smith INCR_PC; 145546f3ff79SMike Smith break; 145646f3ff79SMike Smith 145746f3ff79SMike Smith case MS_OP_PTR: 145854ad6085SNicolas Souchu ppc->ppc_ptr = (char *)mi->arg[0].p; 145946f3ff79SMike Smith INCR_PC; 146046f3ff79SMike Smith break; 146146f3ff79SMike Smith 146246f3ff79SMike Smith case MS_OP_CALL: 14630a40e22aSNicolas Souchu if (stack) 14646e551fb6SDavid E. O'Brien panic("%s: too much calls", __func__); 146546f3ff79SMike Smith 146646f3ff79SMike Smith if (mi->arg[0].p) { 146746f3ff79SMike Smith /* store the state of the actual 146846f3ff79SMike Smith * microsequence 146946f3ff79SMike Smith */ 14700a40e22aSNicolas Souchu stack = mi; 147146f3ff79SMike Smith 147246f3ff79SMike Smith /* jump to the new microsequence */ 14730a40e22aSNicolas Souchu mi = (struct ppb_microseq *)mi->arg[0].p; 147446f3ff79SMike Smith } else 147546f3ff79SMike Smith INCR_PC; 147646f3ff79SMike Smith 147746f3ff79SMike Smith break; 147846f3ff79SMike Smith 147946f3ff79SMike Smith case MS_OP_SUBRET: 148046f3ff79SMike Smith /* retrieve microseq and pc state before the call */ 14810a40e22aSNicolas Souchu mi = stack; 148246f3ff79SMike Smith 148346f3ff79SMike Smith /* reset the stack */ 14840a40e22aSNicolas Souchu stack = 0; 148546f3ff79SMike Smith 148646f3ff79SMike Smith /* XXX return code */ 148746f3ff79SMike Smith 148846f3ff79SMike Smith INCR_PC; 148946f3ff79SMike Smith break; 149046f3ff79SMike Smith 149146f3ff79SMike Smith case MS_OP_PUT: 149246f3ff79SMike Smith case MS_OP_GET: 149346f3ff79SMike Smith case MS_OP_RET: 149446f3ff79SMike Smith /* can't return to ppb level during the execution 149546f3ff79SMike Smith * of a submicrosequence */ 14960a40e22aSNicolas Souchu if (stack) 149746f3ff79SMike Smith panic("%s: can't return to ppb level", 14986e551fb6SDavid E. O'Brien __func__); 149946f3ff79SMike Smith 150046f3ff79SMike Smith /* update pc for ppb level of execution */ 15010a40e22aSNicolas Souchu *p_msq = mi; 150246f3ff79SMike Smith 150346f3ff79SMike Smith /* return to ppb level of execution */ 150446f3ff79SMike Smith return (0); 150546f3ff79SMike Smith 150646f3ff79SMike Smith default: 150746f3ff79SMike Smith panic("%s: unknown microsequence opcode 0x%x", 15086e551fb6SDavid E. O'Brien __func__, mi->opcode); 150946f3ff79SMike Smith } 151046f3ff79SMike Smith } 151146f3ff79SMike Smith 151246f3ff79SMike Smith /* unreached */ 151346f3ff79SMike Smith } 151446f3ff79SMike Smith 1515bc35c174SNicolas Souchu static void 15160f210c92SNicolas Souchu ppcintr(void *arg) 1517bc35c174SNicolas Souchu { 15180f210c92SNicolas Souchu device_t dev = (device_t)arg; 15190f210c92SNicolas Souchu struct ppc_data *ppc = (struct ppc_data *)device_get_softc(dev); 15203ab971c1SNicolas Souchu u_char ctr, ecr, str; 1521bc35c174SNicolas Souchu 15223ab971c1SNicolas Souchu str = r_str(ppc); 1523bc35c174SNicolas Souchu ctr = r_ctr(ppc); 1524bc35c174SNicolas Souchu ecr = r_ecr(ppc); 1525bc35c174SNicolas Souchu 1526f4e98881SRuslan Ermilov #if defined(PPC_DEBUG) && PPC_DEBUG > 1 15273ab971c1SNicolas Souchu printf("![%x/%x/%x]", ctr, ecr, str); 1528bc35c174SNicolas Souchu #endif 1529bc35c174SNicolas Souchu 1530bc35c174SNicolas Souchu /* don't use ecp mode with IRQENABLE set */ 1531bc35c174SNicolas Souchu if (ctr & IRQENABLE) { 1532bc35c174SNicolas Souchu return; 1533bc35c174SNicolas Souchu } 1534bc35c174SNicolas Souchu 15353ab971c1SNicolas Souchu /* interrupts are generated by nFault signal 15363ab971c1SNicolas Souchu * only in ECP mode */ 15373ab971c1SNicolas Souchu if ((str & nFAULT) && (ppc->ppc_mode & PPB_ECP)) { 15383ab971c1SNicolas Souchu /* check if ppc driver has programmed the 15393ab971c1SNicolas Souchu * nFault interrupt */ 1540bc35c174SNicolas Souchu if (ppc->ppc_irqstat & PPC_IRQ_nFAULT) { 1541bc35c174SNicolas Souchu 1542bc35c174SNicolas Souchu w_ecr(ppc, ecr | PPC_nFAULT_INTR); 1543bc35c174SNicolas Souchu ppc->ppc_irqstat &= ~PPC_IRQ_nFAULT; 1544bc35c174SNicolas Souchu } else { 15450f210c92SNicolas Souchu /* shall be handled by underlying layers XXX */ 1546bc35c174SNicolas Souchu return; 1547bc35c174SNicolas Souchu } 1548bc35c174SNicolas Souchu } 1549bc35c174SNicolas Souchu 1550bc35c174SNicolas Souchu if (ppc->ppc_irqstat & PPC_IRQ_DMA) { 1551bc35c174SNicolas Souchu /* disable interrupts (should be done by hardware though) */ 1552bc35c174SNicolas Souchu w_ecr(ppc, ecr | PPC_SERVICE_INTR); 1553bc35c174SNicolas Souchu ppc->ppc_irqstat &= ~PPC_IRQ_DMA; 1554bc35c174SNicolas Souchu ecr = r_ecr(ppc); 1555bc35c174SNicolas Souchu 1556bc35c174SNicolas Souchu /* check if DMA completed */ 1557bc35c174SNicolas Souchu if ((ppc->ppc_avm & PPB_ECP) && (ecr & PPC_ENABLE_DMA)) { 1558bc35c174SNicolas Souchu #ifdef PPC_DEBUG 1559bc35c174SNicolas Souchu printf("a"); 1560bc35c174SNicolas Souchu #endif 1561bc35c174SNicolas Souchu /* stop DMA */ 1562bc35c174SNicolas Souchu w_ecr(ppc, ecr & ~PPC_ENABLE_DMA); 1563bc35c174SNicolas Souchu ecr = r_ecr(ppc); 1564bc35c174SNicolas Souchu 1565bc35c174SNicolas Souchu if (ppc->ppc_dmastat == PPC_DMA_STARTED) { 1566bc35c174SNicolas Souchu #ifdef PPC_DEBUG 1567bc35c174SNicolas Souchu printf("d"); 1568bc35c174SNicolas Souchu #endif 1569cea4d875SMarcel Moolenaar ppc->ppc_dmadone(ppc); 1570bc35c174SNicolas Souchu ppc->ppc_dmastat = PPC_DMA_COMPLETE; 1571bc35c174SNicolas Souchu 1572bc35c174SNicolas Souchu /* wakeup the waiting process */ 1573521f364bSDag-Erling Smørgrav wakeup(ppc); 1574bc35c174SNicolas Souchu } 1575bc35c174SNicolas Souchu } 1576bc35c174SNicolas Souchu } else if (ppc->ppc_irqstat & PPC_IRQ_FIFO) { 1577bc35c174SNicolas Souchu 1578bc35c174SNicolas Souchu /* classic interrupt I/O */ 1579bc35c174SNicolas Souchu ppc->ppc_irqstat &= ~PPC_IRQ_FIFO; 1580bc35c174SNicolas Souchu } 1581bc35c174SNicolas Souchu 1582bc35c174SNicolas Souchu return; 1583bc35c174SNicolas Souchu } 1584bc35c174SNicolas Souchu 1585a3732274SDoug Ambrisko int 15860f210c92SNicolas Souchu ppc_read(device_t dev, char *buf, int len, int mode) 1587bc35c174SNicolas Souchu { 1588bc35c174SNicolas Souchu return (EINVAL); 1589bc35c174SNicolas Souchu } 1590bc35c174SNicolas Souchu 1591a3732274SDoug Ambrisko int 15920f210c92SNicolas Souchu ppc_write(device_t dev, char *buf, int len, int how) 1593bc35c174SNicolas Souchu { 1594cea4d875SMarcel Moolenaar return (EINVAL); 1595bc35c174SNicolas Souchu } 1596bc35c174SNicolas Souchu 1597a3732274SDoug Ambrisko void 15980f210c92SNicolas Souchu ppc_reset_epp(device_t dev) 159967646539SMike Smith { 16000f210c92SNicolas Souchu struct ppc_data *ppc = DEVTOSOFTC(dev); 160167646539SMike Smith 16020f210c92SNicolas Souchu ppc_reset_epp_timeout(ppc); 160367646539SMike Smith 160467646539SMike Smith return; 160567646539SMike Smith } 160667646539SMike Smith 1607a3732274SDoug Ambrisko int 16080f210c92SNicolas Souchu ppc_setmode(device_t dev, int mode) 16090f210c92SNicolas Souchu { 16100f210c92SNicolas Souchu struct ppc_data *ppc = DEVTOSOFTC(dev); 16110f210c92SNicolas Souchu 16120f210c92SNicolas Souchu switch (ppc->ppc_type) { 16130f210c92SNicolas Souchu case PPC_TYPE_SMCLIKE: 16140f210c92SNicolas Souchu return (ppc_smclike_setmode(ppc, mode)); 16150f210c92SNicolas Souchu break; 16160f210c92SNicolas Souchu 16170f210c92SNicolas Souchu case PPC_TYPE_GENERIC: 16180f210c92SNicolas Souchu default: 16190f210c92SNicolas Souchu return (ppc_generic_setmode(ppc, mode)); 16200f210c92SNicolas Souchu break; 16210f210c92SNicolas Souchu } 16220f210c92SNicolas Souchu 16230f210c92SNicolas Souchu /* not reached */ 16240f210c92SNicolas Souchu return (ENXIO); 16250f210c92SNicolas Souchu } 16260f210c92SNicolas Souchu 1627a3732274SDoug Ambrisko int 1628cea4d875SMarcel Moolenaar ppc_probe(device_t dev, int rid) 1629a3732274SDoug Ambrisko { 1630a3732274SDoug Ambrisko #ifdef __i386__ 1631a3732274SDoug Ambrisko static short next_bios_ppc = 0; 1632cea4d875SMarcel Moolenaar #ifdef PC98 1633cea4d875SMarcel Moolenaar unsigned int pc98_ieee_mode = 0x00; 1634cea4d875SMarcel Moolenaar unsigned int tmp; 1635cea4d875SMarcel Moolenaar #endif 1636a3732274SDoug Ambrisko #endif 1637a3732274SDoug Ambrisko struct ppc_data *ppc; 1638a3732274SDoug Ambrisko int error; 1639a3732274SDoug Ambrisko u_long port; 1640a3732274SDoug Ambrisko 164167646539SMike Smith /* 164267646539SMike Smith * Allocate the ppc_data structure. 164367646539SMike Smith */ 16440f210c92SNicolas Souchu ppc = DEVTOSOFTC(dev); 164567646539SMike Smith bzero(ppc, sizeof(struct ppc_data)); 164667646539SMike Smith 1647cea4d875SMarcel Moolenaar ppc->rid_ioport = rid; 164867646539SMike Smith 16490f210c92SNicolas Souchu /* retrieve ISA parameters */ 1650cea4d875SMarcel Moolenaar error = bus_get_resource(dev, SYS_RES_IOPORT, rid, &port, NULL); 16510f210c92SNicolas Souchu 1652d64d73c9SDoug Rabson #ifdef __i386__ 16530f210c92SNicolas Souchu /* 16540f210c92SNicolas Souchu * If port not specified, use bios list. 16550f210c92SNicolas Souchu */ 1656d64d73c9SDoug Rabson if (error) { 1657cea4d875SMarcel Moolenaar #ifdef PC98 1658cea4d875SMarcel Moolenaar if (next_bios_ppc == 0) { 1659cea4d875SMarcel Moolenaar /* Use default IEEE-1284 port of NEC PC-98x1 */ 1660cea4d875SMarcel Moolenaar port = PC98_IEEE_1284_PORT; 1661cea4d875SMarcel Moolenaar next_bios_ppc += 1; 1662cea4d875SMarcel Moolenaar if (bootverbose) 1663cea4d875SMarcel Moolenaar device_printf(dev, 1664cea4d875SMarcel Moolenaar "parallel port found at 0x%x\n", 1665cea4d875SMarcel Moolenaar (int) port); 1666cea4d875SMarcel Moolenaar } 1667cea4d875SMarcel Moolenaar #else 16680f210c92SNicolas Souchu if((next_bios_ppc < BIOS_MAX_PPC) && 16690f210c92SNicolas Souchu (*(BIOS_PORTS+next_bios_ppc) != 0) ) { 16700f210c92SNicolas Souchu port = *(BIOS_PORTS+next_bios_ppc++); 16710f210c92SNicolas Souchu if (bootverbose) 16720f210c92SNicolas Souchu device_printf(dev, "parallel port found at 0x%x\n", 1673d64d73c9SDoug Rabson (int) port); 16740f210c92SNicolas Souchu } else { 16750f210c92SNicolas Souchu device_printf(dev, "parallel port not found.\n"); 16760f210c92SNicolas Souchu return ENXIO; 16770f210c92SNicolas Souchu } 1678cea4d875SMarcel Moolenaar #endif /* PC98 */ 1679cea4d875SMarcel Moolenaar bus_set_resource(dev, SYS_RES_IOPORT, rid, port, 16806a5be862SDoug Rabson IO_LPTSIZE_EXTENDED); 16810f210c92SNicolas Souchu } 1682d64d73c9SDoug Rabson #endif 16830f210c92SNicolas Souchu 16840f210c92SNicolas Souchu /* IO port is mandatory */ 16856a5be862SDoug Rabson 16866a5be862SDoug Rabson /* Try "extended" IO port range...*/ 16870f210c92SNicolas Souchu ppc->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT, 1688d64d73c9SDoug Rabson &ppc->rid_ioport, 0, ~0, 16896a5be862SDoug Rabson IO_LPTSIZE_EXTENDED, RF_ACTIVE); 16906a5be862SDoug Rabson 16916a5be862SDoug Rabson if (ppc->res_ioport != 0) { 16926a5be862SDoug Rabson if (bootverbose) 16936a5be862SDoug Rabson device_printf(dev, "using extended I/O port range\n"); 16946a5be862SDoug Rabson } else { 16956a5be862SDoug Rabson /* Failed? If so, then try the "normal" IO port range... */ 16966a5be862SDoug Rabson ppc->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT, 16976a5be862SDoug Rabson &ppc->rid_ioport, 0, ~0, 16986a5be862SDoug Rabson IO_LPTSIZE_NORMAL, 16996a5be862SDoug Rabson RF_ACTIVE); 17006a5be862SDoug Rabson if (ppc->res_ioport != 0) { 17016a5be862SDoug Rabson if (bootverbose) 17026a5be862SDoug Rabson device_printf(dev, "using normal I/O port range\n"); 17036a5be862SDoug Rabson } else { 17040f210c92SNicolas Souchu device_printf(dev, "cannot reserve I/O port range\n"); 17050f210c92SNicolas Souchu goto error; 17060f210c92SNicolas Souchu } 17075c885c3fSDoug Rabson } 17085c885c3fSDoug Rabson 1709d64d73c9SDoug Rabson ppc->ppc_base = rman_get_start(ppc->res_ioport); 17100f210c92SNicolas Souchu 17110f210c92SNicolas Souchu ppc->ppc_flags = device_get_flags(dev); 17120f210c92SNicolas Souchu 17130f210c92SNicolas Souchu if (!(ppc->ppc_flags & 0x20)) { 17145f96beb9SNate Lawson ppc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 17155f96beb9SNate Lawson &ppc->rid_irq, 17165f96beb9SNate Lawson RF_SHAREABLE); 17175f96beb9SNate Lawson ppc->res_drq = bus_alloc_resource_any(dev, SYS_RES_DRQ, 17185f96beb9SNate Lawson &ppc->rid_drq, 17195f96beb9SNate Lawson RF_ACTIVE); 17200f210c92SNicolas Souchu } 17210f210c92SNicolas Souchu 17220f210c92SNicolas Souchu if (ppc->res_irq) 1723d64d73c9SDoug Rabson ppc->ppc_irq = rman_get_start(ppc->res_irq); 17240f210c92SNicolas Souchu if (ppc->res_drq) 1725d64d73c9SDoug Rabson ppc->ppc_dmachan = rman_get_start(ppc->res_drq); 17260f210c92SNicolas Souchu 17270f210c92SNicolas Souchu ppc->ppc_unit = device_get_unit(dev); 17280f210c92SNicolas Souchu ppc->ppc_model = GENERIC; 1729af548787SNicolas Souchu 173046f3ff79SMike Smith ppc->ppc_mode = PPB_COMPATIBLE; 17310f210c92SNicolas Souchu ppc->ppc_epp = (ppc->ppc_flags & 0x10) >> 4; 173267646539SMike Smith 17330f210c92SNicolas Souchu ppc->ppc_type = PPC_TYPE_GENERIC; 1734edcfcf27SNicolas Souchu 1735cea4d875SMarcel Moolenaar #if defined(__i386__) && defined(PC98) 1736cea4d875SMarcel Moolenaar /* 1737cea4d875SMarcel Moolenaar * IEEE STD 1284 Function Check and Enable 1738cea4d875SMarcel Moolenaar * for default IEEE-1284 port of NEC PC-98x1 1739cea4d875SMarcel Moolenaar */ 1740cea4d875SMarcel Moolenaar if (ppc->ppc_base == PC98_IEEE_1284_PORT && 1741cea4d875SMarcel Moolenaar !(ppc->ppc_flags & PC98_IEEE_1284_DISABLE)) { 1742cea4d875SMarcel Moolenaar tmp = inb(ppc->ppc_base + PPC_1284_ENABLE); 1743cea4d875SMarcel Moolenaar pc98_ieee_mode = tmp; 1744cea4d875SMarcel Moolenaar if ((tmp & 0x10) == 0x10) { 1745cea4d875SMarcel Moolenaar outb(ppc->ppc_base + PPC_1284_ENABLE, tmp & ~0x10); 1746cea4d875SMarcel Moolenaar tmp = inb(ppc->ppc_base + PPC_1284_ENABLE); 1747cea4d875SMarcel Moolenaar if ((tmp & 0x10) == 0x10) 1748cea4d875SMarcel Moolenaar goto error; 1749cea4d875SMarcel Moolenaar } else { 1750cea4d875SMarcel Moolenaar outb(ppc->ppc_base + PPC_1284_ENABLE, tmp | 0x10); 1751cea4d875SMarcel Moolenaar tmp = inb(ppc->ppc_base + PPC_1284_ENABLE); 1752cea4d875SMarcel Moolenaar if ((tmp & 0x10) != 0x10) 1753cea4d875SMarcel Moolenaar goto error; 1754cea4d875SMarcel Moolenaar } 1755cea4d875SMarcel Moolenaar outb(ppc->ppc_base + PPC_1284_ENABLE, pc98_ieee_mode | 0x10); 1756cea4d875SMarcel Moolenaar } 1757cea4d875SMarcel Moolenaar #endif 1758cea4d875SMarcel Moolenaar 1759edcfcf27SNicolas Souchu /* 1760dc733423SDag-Erling Smørgrav * Try to detect the chipset and its mode. 176167646539SMike Smith */ 17620f210c92SNicolas Souchu if (ppc_detect(ppc, ppc->ppc_flags & 0xf)) 176367646539SMike Smith goto error; 176467646539SMike Smith 17650f210c92SNicolas Souchu return (0); 176667646539SMike Smith 176767646539SMike Smith error: 1768cea4d875SMarcel Moolenaar #if defined(__i386__) && defined(PC98) 1769cea4d875SMarcel Moolenaar if (ppc->ppc_base == PC98_IEEE_1284_PORT && 1770cea4d875SMarcel Moolenaar !(ppc->ppc_flags & PC98_IEEE_1284_DISABLE)) { 1771cea4d875SMarcel Moolenaar outb(ppc->ppc_base + PPC_1284_ENABLE, pc98_ieee_mode); 1772cea4d875SMarcel Moolenaar } 1773cea4d875SMarcel Moolenaar #endif 17740f210c92SNicolas Souchu if (ppc->res_irq != 0) { 17750f210c92SNicolas Souchu bus_release_resource(dev, SYS_RES_IRQ, ppc->rid_irq, 17760f210c92SNicolas Souchu ppc->res_irq); 17770f210c92SNicolas Souchu } 17780f210c92SNicolas Souchu if (ppc->res_ioport != 0) { 17790f210c92SNicolas Souchu bus_release_resource(dev, SYS_RES_IOPORT, ppc->rid_ioport, 17800f210c92SNicolas Souchu ppc->res_ioport); 17810f210c92SNicolas Souchu } 17820f210c92SNicolas Souchu if (ppc->res_drq != 0) { 17830f210c92SNicolas Souchu bus_release_resource(dev, SYS_RES_DRQ, ppc->rid_drq, 17840f210c92SNicolas Souchu ppc->res_drq); 17850f210c92SNicolas Souchu } 17860f210c92SNicolas Souchu return (ENXIO); 178767646539SMike Smith } 178867646539SMike Smith 1789a3732274SDoug Ambrisko int 17900f210c92SNicolas Souchu ppc_attach(device_t dev) 179167646539SMike Smith { 17920f210c92SNicolas Souchu struct ppc_data *ppc = DEVTOSOFTC(dev); 179367646539SMike Smith 17940f210c92SNicolas Souchu device_t ppbus; 17950f210c92SNicolas Souchu 17960f210c92SNicolas Souchu device_printf(dev, "%s chipset (%s) in %s mode%s\n", 17970f210c92SNicolas Souchu ppc_models[ppc->ppc_model], ppc_avms[ppc->ppc_avm], 179846f3ff79SMike Smith ppc_modes[ppc->ppc_mode], (PPB_IS_EPP(ppc->ppc_mode)) ? 179967646539SMike Smith ppc_epp_protocol[ppc->ppc_epp] : ""); 180067646539SMike Smith 1801bc35c174SNicolas Souchu if (ppc->ppc_fifo) 18020f210c92SNicolas Souchu device_printf(dev, "FIFO with %d/%d/%d bytes threshold\n", 18030f210c92SNicolas Souchu ppc->ppc_fifo, ppc->ppc_wthr, ppc->ppc_rthr); 180467646539SMike Smith 18050f210c92SNicolas Souchu /* add ppbus as a child of this isa to parallel bridge */ 18060f210c92SNicolas Souchu ppbus = device_add_child(dev, "ppbus", -1); 18070f210c92SNicolas Souchu 180867646539SMike Smith /* 180967646539SMike Smith * Probe the ppbus and attach devices found. 181067646539SMike Smith */ 18110f210c92SNicolas Souchu device_probe_and_attach(ppbus); 181267646539SMike Smith 18130f210c92SNicolas Souchu /* register the ppc interrupt handler as default */ 18140f210c92SNicolas Souchu if (ppc->res_irq) { 18150f210c92SNicolas Souchu /* default to the tty mask for registration */ /* XXX */ 181657fb5e60SJohn Baldwin if (bus_setup_intr(dev, ppc->res_irq, INTR_TYPE_TTY, 1817ef544f63SPaolo Pisati NULL, ppcintr, dev, &ppc->intr_cookie) == 0) { 18180f210c92SNicolas Souchu 18190f210c92SNicolas Souchu /* remember the ppcintr is registered */ 18200f210c92SNicolas Souchu ppc->ppc_registered = 1; 182167646539SMike Smith } 18220f210c92SNicolas Souchu } 18230f210c92SNicolas Souchu 18240f210c92SNicolas Souchu return (0); 18250f210c92SNicolas Souchu } 18260f210c92SNicolas Souchu 1827858a52f4SMitsuru IWASAKI int 1828858a52f4SMitsuru IWASAKI ppc_detach(device_t dev) 1829858a52f4SMitsuru IWASAKI { 1830858a52f4SMitsuru IWASAKI struct ppc_data *ppc = DEVTOSOFTC(dev); 1831858a52f4SMitsuru IWASAKI device_t *children; 1832858a52f4SMitsuru IWASAKI int nchildren, i; 1833858a52f4SMitsuru IWASAKI 1834858a52f4SMitsuru IWASAKI if (ppc->res_irq == 0) { 1835858a52f4SMitsuru IWASAKI return (ENXIO); 1836858a52f4SMitsuru IWASAKI } 1837858a52f4SMitsuru IWASAKI 1838858a52f4SMitsuru IWASAKI /* detach & delete all children */ 1839858a52f4SMitsuru IWASAKI if (!device_get_children(dev, &children, &nchildren)) { 1840858a52f4SMitsuru IWASAKI for (i = 0; i < nchildren; i++) 1841858a52f4SMitsuru IWASAKI if (children[i]) 1842858a52f4SMitsuru IWASAKI device_delete_child(dev, children[i]); 1843858a52f4SMitsuru IWASAKI free(children, M_TEMP); 1844858a52f4SMitsuru IWASAKI } 1845858a52f4SMitsuru IWASAKI 1846858a52f4SMitsuru IWASAKI if (ppc->res_irq != 0) { 1847858a52f4SMitsuru IWASAKI bus_teardown_intr(dev, ppc->res_irq, ppc->intr_cookie); 1848858a52f4SMitsuru IWASAKI bus_release_resource(dev, SYS_RES_IRQ, ppc->rid_irq, 1849858a52f4SMitsuru IWASAKI ppc->res_irq); 1850858a52f4SMitsuru IWASAKI } 1851858a52f4SMitsuru IWASAKI if (ppc->res_ioport != 0) { 1852858a52f4SMitsuru IWASAKI bus_release_resource(dev, SYS_RES_IOPORT, ppc->rid_ioport, 1853858a52f4SMitsuru IWASAKI ppc->res_ioport); 1854858a52f4SMitsuru IWASAKI } 1855858a52f4SMitsuru IWASAKI if (ppc->res_drq != 0) { 1856858a52f4SMitsuru IWASAKI bus_release_resource(dev, SYS_RES_DRQ, ppc->rid_drq, 1857858a52f4SMitsuru IWASAKI ppc->res_drq); 1858858a52f4SMitsuru IWASAKI } 1859858a52f4SMitsuru IWASAKI 1860858a52f4SMitsuru IWASAKI return (0); 1861858a52f4SMitsuru IWASAKI } 1862858a52f4SMitsuru IWASAKI 1863a3732274SDoug Ambrisko u_char 18640f210c92SNicolas Souchu ppc_io(device_t ppcdev, int iop, u_char *addr, int cnt, u_char byte) 18650f210c92SNicolas Souchu { 18660f210c92SNicolas Souchu struct ppc_data *ppc = DEVTOSOFTC(ppcdev); 18670f210c92SNicolas Souchu switch (iop) { 18680f210c92SNicolas Souchu case PPB_OUTSB_EPP: 18698fd40d8aSJohn Baldwin bus_write_multi_1(ppc->res_ioport, PPC_EPP_DATA, addr, cnt); 18700f210c92SNicolas Souchu break; 18710f210c92SNicolas Souchu case PPB_OUTSW_EPP: 18728fd40d8aSJohn Baldwin bus_write_multi_2(ppc->res_ioport, PPC_EPP_DATA, (u_int16_t *)addr, cnt); 18730f210c92SNicolas Souchu break; 18740f210c92SNicolas Souchu case PPB_OUTSL_EPP: 18758fd40d8aSJohn Baldwin bus_write_multi_4(ppc->res_ioport, PPC_EPP_DATA, (u_int32_t *)addr, cnt); 18760f210c92SNicolas Souchu break; 18770f210c92SNicolas Souchu case PPB_INSB_EPP: 18788fd40d8aSJohn Baldwin bus_read_multi_1(ppc->res_ioport, PPC_EPP_DATA, addr, cnt); 18790f210c92SNicolas Souchu break; 18800f210c92SNicolas Souchu case PPB_INSW_EPP: 18818fd40d8aSJohn Baldwin bus_read_multi_2(ppc->res_ioport, PPC_EPP_DATA, (u_int16_t *)addr, cnt); 18820f210c92SNicolas Souchu break; 18830f210c92SNicolas Souchu case PPB_INSL_EPP: 18848fd40d8aSJohn Baldwin bus_read_multi_4(ppc->res_ioport, PPC_EPP_DATA, (u_int32_t *)addr, cnt); 18850f210c92SNicolas Souchu break; 18860f210c92SNicolas Souchu case PPB_RDTR: 18870f210c92SNicolas Souchu return (r_dtr(ppc)); 18880f210c92SNicolas Souchu case PPB_RSTR: 18890f210c92SNicolas Souchu return (r_str(ppc)); 18900f210c92SNicolas Souchu case PPB_RCTR: 18910f210c92SNicolas Souchu return (r_ctr(ppc)); 18920f210c92SNicolas Souchu case PPB_REPP_A: 18930f210c92SNicolas Souchu return (r_epp_A(ppc)); 18940f210c92SNicolas Souchu case PPB_REPP_D: 18950f210c92SNicolas Souchu return (r_epp_D(ppc)); 18960f210c92SNicolas Souchu case PPB_RECR: 18970f210c92SNicolas Souchu return (r_ecr(ppc)); 18980f210c92SNicolas Souchu case PPB_RFIFO: 18990f210c92SNicolas Souchu return (r_fifo(ppc)); 19000f210c92SNicolas Souchu case PPB_WDTR: 19010f210c92SNicolas Souchu w_dtr(ppc, byte); 19020f210c92SNicolas Souchu break; 19030f210c92SNicolas Souchu case PPB_WSTR: 19040f210c92SNicolas Souchu w_str(ppc, byte); 19050f210c92SNicolas Souchu break; 19060f210c92SNicolas Souchu case PPB_WCTR: 19070f210c92SNicolas Souchu w_ctr(ppc, byte); 19080f210c92SNicolas Souchu break; 19090f210c92SNicolas Souchu case PPB_WEPP_A: 19100f210c92SNicolas Souchu w_epp_A(ppc, byte); 19110f210c92SNicolas Souchu break; 19120f210c92SNicolas Souchu case PPB_WEPP_D: 19130f210c92SNicolas Souchu w_epp_D(ppc, byte); 19140f210c92SNicolas Souchu break; 19150f210c92SNicolas Souchu case PPB_WECR: 19160f210c92SNicolas Souchu w_ecr(ppc, byte); 19170f210c92SNicolas Souchu break; 19180f210c92SNicolas Souchu case PPB_WFIFO: 19190f210c92SNicolas Souchu w_fifo(ppc, byte); 19200f210c92SNicolas Souchu break; 19210f210c92SNicolas Souchu default: 19226e551fb6SDavid E. O'Brien panic("%s: unknown I/O operation", __func__); 19230f210c92SNicolas Souchu break; 19240f210c92SNicolas Souchu } 19250f210c92SNicolas Souchu 19260f210c92SNicolas Souchu return (0); /* not significative */ 19270f210c92SNicolas Souchu } 19280f210c92SNicolas Souchu 1929a3732274SDoug Ambrisko int 19300f210c92SNicolas Souchu ppc_read_ivar(device_t bus, device_t dev, int index, uintptr_t *val) 19310f210c92SNicolas Souchu { 19320f210c92SNicolas Souchu struct ppc_data *ppc = (struct ppc_data *)device_get_softc(bus); 19330f210c92SNicolas Souchu 19340f210c92SNicolas Souchu switch (index) { 19350f210c92SNicolas Souchu case PPC_IVAR_EPP_PROTO: 19360f210c92SNicolas Souchu *val = (u_long)ppc->ppc_epp; 19370f210c92SNicolas Souchu break; 19380f210c92SNicolas Souchu case PPC_IVAR_IRQ: 1939d64d73c9SDoug Rabson *val = (u_long)ppc->ppc_irq; 19400f210c92SNicolas Souchu break; 19410f210c92SNicolas Souchu default: 19420f210c92SNicolas Souchu return (ENOENT); 19430f210c92SNicolas Souchu } 19440f210c92SNicolas Souchu 19450f210c92SNicolas Souchu return (0); 19460f210c92SNicolas Souchu } 19470f210c92SNicolas Souchu 19480f210c92SNicolas Souchu /* 19490f210c92SNicolas Souchu * Resource is useless here since ppbus devices' interrupt handlers are 19500f210c92SNicolas Souchu * multiplexed to the same resource initially allocated by ppc 19510f210c92SNicolas Souchu */ 1952a3732274SDoug Ambrisko int 19530f210c92SNicolas Souchu ppc_setup_intr(device_t bus, device_t child, struct resource *r, int flags, 1954ef544f63SPaolo Pisati driver_filter_t *filt, void (*ihand)(void *), void *arg, void **cookiep) 19550f210c92SNicolas Souchu { 19560f210c92SNicolas Souchu int error; 19570f210c92SNicolas Souchu struct ppc_data *ppc = DEVTOSOFTC(bus); 19580f210c92SNicolas Souchu 19590f210c92SNicolas Souchu if (ppc->ppc_registered) { 19600f210c92SNicolas Souchu /* XXX refuse registration if DMA is in progress */ 19610f210c92SNicolas Souchu 19620f210c92SNicolas Souchu /* first, unregister the default interrupt handler */ 19630f210c92SNicolas Souchu if ((error = BUS_TEARDOWN_INTR(device_get_parent(bus), 19640f210c92SNicolas Souchu bus, ppc->res_irq, ppc->intr_cookie))) 19650f210c92SNicolas Souchu return (error); 19660f210c92SNicolas Souchu 19670f210c92SNicolas Souchu /* bus_deactivate_resource(bus, SYS_RES_IRQ, ppc->rid_irq, */ 19680f210c92SNicolas Souchu /* ppc->res_irq); */ 19690f210c92SNicolas Souchu 19700f210c92SNicolas Souchu /* DMA/FIFO operation won't be possible anymore */ 19710f210c92SNicolas Souchu ppc->ppc_registered = 0; 19720f210c92SNicolas Souchu } 19730f210c92SNicolas Souchu 197472565ac3SPaolo Pisati /* 197572565ac3SPaolo Pisati * pass registration to the upper layer, ignore the incoming 197672565ac3SPaolo Pisati * resource 197772565ac3SPaolo Pisati */ 19780f210c92SNicolas Souchu return (BUS_SETUP_INTR(device_get_parent(bus), child, 1979ef544f63SPaolo Pisati r, flags, filt, ihand, arg, cookiep)); 19800f210c92SNicolas Souchu } 19810f210c92SNicolas Souchu 19820f210c92SNicolas Souchu /* 19830f210c92SNicolas Souchu * When no underlying device has a registered interrupt, register the ppc 19840f210c92SNicolas Souchu * layer one 19850f210c92SNicolas Souchu */ 1986a3732274SDoug Ambrisko int 19870f210c92SNicolas Souchu ppc_teardown_intr(device_t bus, device_t child, struct resource *r, void *ih) 19880f210c92SNicolas Souchu { 19890f210c92SNicolas Souchu int error; 19900f210c92SNicolas Souchu struct ppc_data *ppc = DEVTOSOFTC(bus); 19910f210c92SNicolas Souchu device_t parent = device_get_parent(bus); 19920f210c92SNicolas Souchu 19930f210c92SNicolas Souchu /* pass unregistration to the upper layer */ 19940f210c92SNicolas Souchu if ((error = BUS_TEARDOWN_INTR(parent, child, r, ih))) 19950f210c92SNicolas Souchu return (error); 19960f210c92SNicolas Souchu 19970f210c92SNicolas Souchu /* default to the tty mask for registration */ /* XXX */ 19980f210c92SNicolas Souchu if (ppc->ppc_irq && 19990f210c92SNicolas Souchu !(error = BUS_SETUP_INTR(parent, bus, ppc->res_irq, 2000ef544f63SPaolo Pisati INTR_TYPE_TTY, NULL, ppcintr, bus, &ppc->intr_cookie))) { 20010f210c92SNicolas Souchu 20020f210c92SNicolas Souchu /* remember the ppcintr is registered */ 20030f210c92SNicolas Souchu ppc->ppc_registered = 1; 20040f210c92SNicolas Souchu } 20050f210c92SNicolas Souchu 20060f210c92SNicolas Souchu return (error); 20070f210c92SNicolas Souchu } 20080f210c92SNicolas Souchu 2009f5fd5611SRuslan Ermilov MODULE_DEPEND(ppc, ppbus, 1, 1, 1); 2010