167646539SMike Smith /*- 2718cf2ccSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3718cf2ccSPedro F. Giffuni * 4ddd22fb7SNicolas Souchu * Copyright (c) 1997-2000 Nicolas Souchu 5c264e80fSNicolas Souchu * Copyright (c) 2001 Alcove - Nicolas Souchu 667646539SMike Smith * All rights reserved. 767646539SMike Smith * 867646539SMike Smith * Redistribution and use in source and binary forms, with or without 967646539SMike Smith * modification, are permitted provided that the following conditions 1067646539SMike Smith * are met: 1167646539SMike Smith * 1. Redistributions of source code must retain the above copyright 1267646539SMike Smith * notice, this list of conditions and the following disclaimer. 1367646539SMike Smith * 2. Redistributions in binary form must reproduce the above copyright 1467646539SMike Smith * notice, this list of conditions and the following disclaimer in the 1567646539SMike Smith * documentation and/or other materials provided with the distribution. 1667646539SMike Smith * 1767646539SMike Smith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1867646539SMike Smith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1967646539SMike Smith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2067646539SMike Smith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2167646539SMike Smith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2267646539SMike Smith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2367646539SMike Smith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2467646539SMike Smith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2567646539SMike Smith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2667646539SMike Smith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2767646539SMike Smith * SUCH DAMAGE. 2867646539SMike Smith */ 2967646539SMike Smith 308c9bbf48SDavid E. O'Brien #include <sys/cdefs.h> 318c9bbf48SDavid E. O'Brien __FBSDID("$FreeBSD$"); 328c9bbf48SDavid E. O'Brien 330f210c92SNicolas Souchu #include "opt_ppc.h" 340f210c92SNicolas Souchu 3567646539SMike Smith #include <sys/param.h> 3667646539SMike Smith #include <sys/systm.h> 370f210c92SNicolas Souchu #include <sys/bus.h> 38ca3d3795SJohn Baldwin #include <sys/kernel.h> 392067d312SJohn Baldwin #include <sys/lock.h> 40ca3d3795SJohn Baldwin #include <sys/interrupt.h> 41ca3d3795SJohn Baldwin #include <sys/module.h> 420f210c92SNicolas Souchu #include <sys/malloc.h> 432067d312SJohn Baldwin #include <sys/mutex.h> 44ca3d3795SJohn Baldwin #include <sys/proc.h> 4567646539SMike Smith 460f210c92SNicolas Souchu #include <machine/bus.h> 470f210c92SNicolas Souchu #include <machine/resource.h> 480f210c92SNicolas Souchu #include <sys/rman.h> 4967646539SMike Smith 50cea4d875SMarcel Moolenaar #ifdef __i386__ 51cea4d875SMarcel Moolenaar #include <vm/vm.h> 52cea4d875SMarcel Moolenaar #include <vm/pmap.h> 53cea4d875SMarcel Moolenaar #include <machine/vmparam.h> 54*d86c1f0dSKonstantin Belousov #include <machine/pc/bios.h> 55cea4d875SMarcel Moolenaar #endif 5667646539SMike Smith 5767646539SMike Smith #include <dev/ppbus/ppbconf.h> 5846f3ff79SMike Smith #include <dev/ppbus/ppb_msq.h> 5946f3ff79SMike Smith 60a3732274SDoug Ambrisko #include <dev/ppc/ppcvar.h> 61a3732274SDoug Ambrisko #include <dev/ppc/ppcreg.h> 6267646539SMike Smith 630f210c92SNicolas Souchu #include "ppbus_if.h" 64bc35c174SNicolas Souchu 65a3732274SDoug Ambrisko static void ppcintr(void *arg); 66a3732274SDoug Ambrisko 67cea4d875SMarcel Moolenaar #define IO_LPTSIZE_EXTENDED 8 /* "Extended" LPT controllers */ 68cea4d875SMarcel Moolenaar #define IO_LPTSIZE_NORMAL 4 /* "Normal" LPT controllers */ 69cea4d875SMarcel Moolenaar 70bc35c174SNicolas Souchu #define LOG_PPC(function, ppc, string) \ 71bc35c174SNicolas Souchu if (bootverbose) printf("%s: %s\n", function, string) 72bc35c174SNicolas Souchu 730f210c92SNicolas Souchu #define DEVTOSOFTC(dev) ((struct ppc_data *)device_get_softc(dev)) 740f210c92SNicolas Souchu 751eb7e5feSWarner Losh /* 76d0741ed4SGleb Smirnoff * We use critical enter/exit for the simple config locking needed to 771eb7e5feSWarner Losh * detect the devices. We just want to make sure that both of our writes 781eb7e5feSWarner Losh * happen without someone else also writing to those config registers. Since 791eb7e5feSWarner Losh * we just do this at startup, Giant keeps multiple threads from executing, 801eb7e5feSWarner Losh * and critical_enter() then is all that's needed to keep us from being preempted 811eb7e5feSWarner Losh * during the critical sequences with the hardware. 821eb7e5feSWarner Losh * 831eb7e5feSWarner Losh * Note: this doesn't prevent multiple threads from putting the chips into 841eb7e5feSWarner Losh * config mode, but since we only do that to detect the type at startup the 851eb7e5feSWarner Losh * extra overhead isn't needed since Giant protects us from multiple entry 861eb7e5feSWarner Losh * and no other code changes these registers. 871eb7e5feSWarner Losh */ 881eb7e5feSWarner Losh #define PPC_CONFIG_LOCK(ppc) critical_enter() 89d0741ed4SGleb Smirnoff #define PPC_CONFIG_UNLOCK(ppc) critical_exit() 901eb7e5feSWarner Losh 91a3732274SDoug Ambrisko devclass_t ppc_devclass; 92cea4d875SMarcel Moolenaar const char ppc_driver_name[] = "ppc"; 9367646539SMike Smith 940f210c92SNicolas Souchu static char *ppc_models[] = { 9546f3ff79SMike Smith "SMC-like", "SMC FDC37C665GT", "SMC FDC37C666GT", "PC87332", "PC87306", 966a5be862SDoug Rabson "82091AA", "Generic", "W83877F", "W83877AF", "Winbond", "PC87334", 97ac7ba926SDoug Rabson "SMC FDC37C935", "PC87303", 0 9867646539SMike Smith }; 9967646539SMike Smith 10046f3ff79SMike Smith /* list of available modes */ 10146f3ff79SMike Smith static char *ppc_avms[] = { 10246f3ff79SMike Smith "COMPATIBLE", "NIBBLE-only", "PS2-only", "PS2/NIBBLE", "EPP-only", 10346f3ff79SMike Smith "EPP/NIBBLE", "EPP/PS2", "EPP/PS2/NIBBLE", "ECP-only", 10446f3ff79SMike Smith "ECP/NIBBLE", "ECP/PS2", "ECP/PS2/NIBBLE", "ECP/EPP", 10546f3ff79SMike Smith "ECP/EPP/NIBBLE", "ECP/EPP/PS2", "ECP/EPP/PS2/NIBBLE", 0 10646f3ff79SMike Smith }; 10746f3ff79SMike Smith 10846f3ff79SMike Smith /* list of current executing modes 10946f3ff79SMike Smith * Note that few modes do not actually exist. 11046f3ff79SMike Smith */ 11167646539SMike Smith static char *ppc_modes[] = { 11246f3ff79SMike Smith "COMPATIBLE", "NIBBLE", "PS/2", "PS/2", "EPP", 11346f3ff79SMike Smith "EPP", "EPP", "EPP", "ECP", 11446f3ff79SMike Smith "ECP", "ECP+PS2", "ECP+PS2", "ECP+EPP", 11546f3ff79SMike Smith "ECP+EPP", "ECP+EPP", "ECP+EPP", 0 11667646539SMike Smith }; 11767646539SMike Smith 11867646539SMike Smith static char *ppc_epp_protocol[] = { " (EPP 1.9)", " (EPP 1.7)", 0 }; 11967646539SMike Smith 120d64d73c9SDoug Rabson #ifdef __i386__ 12167646539SMike Smith /* 12267646539SMike Smith * BIOS printer list - used by BIOS probe. 12367646539SMike Smith */ 12467646539SMike Smith #define BIOS_PPC_PORTS 0x408 125*d86c1f0dSKonstantin Belousov #define BIOS_PORTS ((short *)BIOS_PADDRTOVADDR(BIOS_PPC_PORTS)) 12667646539SMike Smith #define BIOS_MAX_PPC 4 127d64d73c9SDoug Rabson #endif 12867646539SMike Smith 12967646539SMike Smith /* 13067646539SMike Smith * ppc_ecp_sync() XXX 13167646539SMike Smith */ 1323fd85273SWarner Losh int 133284c87f6SJohn Baldwin ppc_ecp_sync(device_t dev) 134284c87f6SJohn Baldwin { 13567646539SMike Smith int i, r; 1360f210c92SNicolas Souchu struct ppc_data *ppc = DEVTOSOFTC(dev); 13767646539SMike Smith 1382067d312SJohn Baldwin PPC_ASSERT_LOCKED(ppc); 139c264e80fSNicolas Souchu if (!(ppc->ppc_avm & PPB_ECP) && !(ppc->ppc_dtm & PPB_ECP)) 1403fd85273SWarner Losh return 0; 141bc35c174SNicolas Souchu 14267646539SMike Smith r = r_ecr(ppc); 143bc35c174SNicolas Souchu if ((r & 0xe0) != PPC_ECR_EPP) 1443fd85273SWarner Losh return 0; 14567646539SMike Smith 14667646539SMike Smith for (i = 0; i < 100; i++) { 14767646539SMike Smith r = r_ecr(ppc); 14867646539SMike Smith if (r & 0x1) 1493fd85273SWarner Losh return 0; 15067646539SMike Smith DELAY(100); 15167646539SMike Smith } 15267646539SMike Smith 153ae6b868aSJohn Baldwin device_printf(dev, "ECP sync failed as data still present in FIFO.\n"); 15467646539SMike Smith 1553fd85273SWarner Losh return 0; 15667646539SMike Smith } 15767646539SMike Smith 158bc35c174SNicolas Souchu /* 159bc35c174SNicolas Souchu * ppc_detect_fifo() 160bc35c174SNicolas Souchu * 161bc35c174SNicolas Souchu * Detect parallel port FIFO 162bc35c174SNicolas Souchu */ 163bc35c174SNicolas Souchu static int 164bc35c174SNicolas Souchu ppc_detect_fifo(struct ppc_data *ppc) 16567646539SMike Smith { 166bc35c174SNicolas Souchu char ecr_sav; 167bc35c174SNicolas Souchu char ctr_sav, ctr, cc; 168bc35c174SNicolas Souchu short i; 16967646539SMike Smith 170bc35c174SNicolas Souchu /* save registers */ 171bc35c174SNicolas Souchu ecr_sav = r_ecr(ppc); 172bc35c174SNicolas Souchu ctr_sav = r_ctr(ppc); 173bc35c174SNicolas Souchu 174bc35c174SNicolas Souchu /* enter ECP configuration mode, no interrupt, no DMA */ 175bc35c174SNicolas Souchu w_ecr(ppc, 0xf4); 176bc35c174SNicolas Souchu 177bc35c174SNicolas Souchu /* read PWord size - transfers in FIFO mode must be PWord aligned */ 178bc35c174SNicolas Souchu ppc->ppc_pword = (r_cnfgA(ppc) & PPC_PWORD_MASK); 179bc35c174SNicolas Souchu 180bc35c174SNicolas Souchu /* XXX 16 and 32 bits implementations not supported */ 181bc35c174SNicolas Souchu if (ppc->ppc_pword != PPC_PWORD_8) { 1826e551fb6SDavid E. O'Brien LOG_PPC(__func__, ppc, "PWord not supported"); 183bc35c174SNicolas Souchu goto error; 184bc35c174SNicolas Souchu } 185bc35c174SNicolas Souchu 186bc35c174SNicolas Souchu w_ecr(ppc, 0x34); /* byte mode, no interrupt, no DMA */ 187bc35c174SNicolas Souchu ctr = r_ctr(ppc); 188bc35c174SNicolas Souchu w_ctr(ppc, ctr | PCD); /* set direction to 1 */ 189bc35c174SNicolas Souchu 190bc35c174SNicolas Souchu /* enter ECP test mode, no interrupt, no DMA */ 191bc35c174SNicolas Souchu w_ecr(ppc, 0xd4); 192bc35c174SNicolas Souchu 193bc35c174SNicolas Souchu /* flush the FIFO */ 194bc35c174SNicolas Souchu for (i=0; i<1024; i++) { 195bc35c174SNicolas Souchu if (r_ecr(ppc) & PPC_FIFO_EMPTY) 196bc35c174SNicolas Souchu break; 197bc35c174SNicolas Souchu cc = r_fifo(ppc); 198bc35c174SNicolas Souchu } 199bc35c174SNicolas Souchu 200bc35c174SNicolas Souchu if (i >= 1024) { 2016e551fb6SDavid E. O'Brien LOG_PPC(__func__, ppc, "can't flush FIFO"); 202bc35c174SNicolas Souchu goto error; 203bc35c174SNicolas Souchu } 204bc35c174SNicolas Souchu 205bc35c174SNicolas Souchu /* enable interrupts, no DMA */ 206bc35c174SNicolas Souchu w_ecr(ppc, 0xd0); 207bc35c174SNicolas Souchu 208bc35c174SNicolas Souchu /* determine readIntrThreshold 209bc35c174SNicolas Souchu * fill the FIFO until serviceIntr is set 210bc35c174SNicolas Souchu */ 211bc35c174SNicolas Souchu for (i=0; i<1024; i++) { 212bc35c174SNicolas Souchu w_fifo(ppc, (char)i); 213bc35c174SNicolas Souchu if (!ppc->ppc_rthr && (r_ecr(ppc) & PPC_SERVICE_INTR)) { 214bc35c174SNicolas Souchu /* readThreshold reached */ 215bc35c174SNicolas Souchu ppc->ppc_rthr = i+1; 216bc35c174SNicolas Souchu } 217bc35c174SNicolas Souchu if (r_ecr(ppc) & PPC_FIFO_FULL) { 218bc35c174SNicolas Souchu ppc->ppc_fifo = i+1; 219bc35c174SNicolas Souchu break; 220bc35c174SNicolas Souchu } 221bc35c174SNicolas Souchu } 222bc35c174SNicolas Souchu 223bc35c174SNicolas Souchu if (i >= 1024) { 2246e551fb6SDavid E. O'Brien LOG_PPC(__func__, ppc, "can't fill FIFO"); 225bc35c174SNicolas Souchu goto error; 226bc35c174SNicolas Souchu } 227bc35c174SNicolas Souchu 228bc35c174SNicolas Souchu w_ecr(ppc, 0xd4); /* test mode, no interrupt, no DMA */ 229bc35c174SNicolas Souchu w_ctr(ppc, ctr & ~PCD); /* set direction to 0 */ 230bc35c174SNicolas Souchu w_ecr(ppc, 0xd0); /* enable interrupts */ 231bc35c174SNicolas Souchu 232bc35c174SNicolas Souchu /* determine writeIntrThreshold 233bc35c174SNicolas Souchu * empty the FIFO until serviceIntr is set 234bc35c174SNicolas Souchu */ 235bc35c174SNicolas Souchu for (i=ppc->ppc_fifo; i>0; i--) { 236bc35c174SNicolas Souchu if (r_fifo(ppc) != (char)(ppc->ppc_fifo-i)) { 2376e551fb6SDavid E. O'Brien LOG_PPC(__func__, ppc, "invalid data in FIFO"); 238bc35c174SNicolas Souchu goto error; 239bc35c174SNicolas Souchu } 240bc35c174SNicolas Souchu if (r_ecr(ppc) & PPC_SERVICE_INTR) { 241bc35c174SNicolas Souchu /* writeIntrThreshold reached */ 242bc35c174SNicolas Souchu ppc->ppc_wthr = ppc->ppc_fifo - i+1; 243bc35c174SNicolas Souchu } 244bc35c174SNicolas Souchu /* if FIFO empty before the last byte, error */ 245bc35c174SNicolas Souchu if (i>1 && (r_ecr(ppc) & PPC_FIFO_EMPTY)) { 2466e551fb6SDavid E. O'Brien LOG_PPC(__func__, ppc, "data lost in FIFO"); 247bc35c174SNicolas Souchu goto error; 248bc35c174SNicolas Souchu } 249bc35c174SNicolas Souchu } 250bc35c174SNicolas Souchu 251bc35c174SNicolas Souchu /* FIFO must be empty after the last byte */ 252bc35c174SNicolas Souchu if (!(r_ecr(ppc) & PPC_FIFO_EMPTY)) { 2536e551fb6SDavid E. O'Brien LOG_PPC(__func__, ppc, "can't empty the FIFO"); 254bc35c174SNicolas Souchu goto error; 255bc35c174SNicolas Souchu } 256bc35c174SNicolas Souchu 257bc35c174SNicolas Souchu w_ctr(ppc, ctr_sav); 258bc35c174SNicolas Souchu w_ecr(ppc, ecr_sav); 259bc35c174SNicolas Souchu 260bc35c174SNicolas Souchu return (0); 261bc35c174SNicolas Souchu 262bc35c174SNicolas Souchu error: 263bc35c174SNicolas Souchu w_ctr(ppc, ctr_sav); 264bc35c174SNicolas Souchu w_ecr(ppc, ecr_sav); 265bc35c174SNicolas Souchu 266bc35c174SNicolas Souchu return (EINVAL); 26767646539SMike Smith } 26867646539SMike Smith 26946f3ff79SMike Smith static int 27046f3ff79SMike Smith ppc_detect_port(struct ppc_data *ppc) 27146f3ff79SMike Smith { 27246f3ff79SMike Smith 27346f3ff79SMike Smith w_ctr(ppc, 0x0c); /* To avoid missing PS2 ports */ 27446f3ff79SMike Smith w_dtr(ppc, 0xaa); 275a7006f89SNicolas Souchu if (r_dtr(ppc) != 0xaa) 27646f3ff79SMike Smith return (0); 27746f3ff79SMike Smith 27846f3ff79SMike Smith return (1); 27946f3ff79SMike Smith } 28046f3ff79SMike Smith 28167646539SMike Smith /* 2820f210c92SNicolas Souchu * EPP timeout, according to the PC87332 manual 2830f210c92SNicolas Souchu * Semantics of clearing EPP timeout bit. 2840f210c92SNicolas Souchu * PC87332 - reading SPP_STR does it... 2850f210c92SNicolas Souchu * SMC - write 1 to EPP timeout bit XXX 2860f210c92SNicolas Souchu * Others - (?) write 0 to EPP timeout bit 2870f210c92SNicolas Souchu */ 2880f210c92SNicolas Souchu static void 2890f210c92SNicolas Souchu ppc_reset_epp_timeout(struct ppc_data *ppc) 2900f210c92SNicolas Souchu { 2913e85b721SEd Maste char r; 2920f210c92SNicolas Souchu 2930f210c92SNicolas Souchu r = r_str(ppc); 2940f210c92SNicolas Souchu w_str(ppc, r | 0x1); 2950f210c92SNicolas Souchu w_str(ppc, r & 0xfe); 2960f210c92SNicolas Souchu 2970f210c92SNicolas Souchu return; 2980f210c92SNicolas Souchu } 2990f210c92SNicolas Souchu 3000f210c92SNicolas Souchu static int 3010f210c92SNicolas Souchu ppc_check_epp_timeout(struct ppc_data *ppc) 3020f210c92SNicolas Souchu { 3030f210c92SNicolas Souchu ppc_reset_epp_timeout(ppc); 3040f210c92SNicolas Souchu 3050f210c92SNicolas Souchu return (!(r_str(ppc) & TIMEOUT)); 3060f210c92SNicolas Souchu } 3070f210c92SNicolas Souchu 3080f210c92SNicolas Souchu /* 3090f210c92SNicolas Souchu * Configure current operating mode 3100f210c92SNicolas Souchu */ 3110f210c92SNicolas Souchu static int 3120f210c92SNicolas Souchu ppc_generic_setmode(struct ppc_data *ppc, int mode) 3130f210c92SNicolas Souchu { 3140f210c92SNicolas Souchu u_char ecr = 0; 3150f210c92SNicolas Souchu 3160f210c92SNicolas Souchu /* check if mode is available */ 3170f210c92SNicolas Souchu if (mode && !(ppc->ppc_avm & mode)) 3180f210c92SNicolas Souchu return (EINVAL); 3190f210c92SNicolas Souchu 3200f210c92SNicolas Souchu /* if ECP mode, configure ecr register */ 321c264e80fSNicolas Souchu if ((ppc->ppc_avm & PPB_ECP) || (ppc->ppc_dtm & PPB_ECP)) { 3220f210c92SNicolas Souchu /* return to byte mode (keeping direction bit), 3230f210c92SNicolas Souchu * no interrupt, no DMA to be able to change to 3240f210c92SNicolas Souchu * ECP 3250f210c92SNicolas Souchu */ 3260f210c92SNicolas Souchu w_ecr(ppc, PPC_ECR_RESET); 3270f210c92SNicolas Souchu ecr = PPC_DISABLE_INTR; 3280f210c92SNicolas Souchu 3290f210c92SNicolas Souchu if (mode & PPB_EPP) 3300f210c92SNicolas Souchu return (EINVAL); 3310f210c92SNicolas Souchu else if (mode & PPB_ECP) 3320f210c92SNicolas Souchu /* select ECP mode */ 3330f210c92SNicolas Souchu ecr |= PPC_ECR_ECP; 3340f210c92SNicolas Souchu else if (mode & PPB_PS2) 3350f210c92SNicolas Souchu /* select PS2 mode with ECP */ 3360f210c92SNicolas Souchu ecr |= PPC_ECR_PS2; 3370f210c92SNicolas Souchu else 3380f210c92SNicolas Souchu /* select COMPATIBLE/NIBBLE mode */ 3390f210c92SNicolas Souchu ecr |= PPC_ECR_STD; 3400f210c92SNicolas Souchu 3410f210c92SNicolas Souchu w_ecr(ppc, ecr); 3420f210c92SNicolas Souchu } 3430f210c92SNicolas Souchu 3440f210c92SNicolas Souchu ppc->ppc_mode = mode; 3450f210c92SNicolas Souchu 3460f210c92SNicolas Souchu return (0); 3470f210c92SNicolas Souchu } 3480f210c92SNicolas Souchu 3490f210c92SNicolas Souchu /* 3500f210c92SNicolas Souchu * The ppc driver is free to choose options like FIFO or DMA 3510f210c92SNicolas Souchu * if ECP mode is available. 3520f210c92SNicolas Souchu * 3530f210c92SNicolas Souchu * The 'RAW' option allows the upper drivers to force the ppc mode 3540f210c92SNicolas Souchu * even with FIFO, DMA available. 3550f210c92SNicolas Souchu */ 3560f210c92SNicolas Souchu static int 3570f210c92SNicolas Souchu ppc_smclike_setmode(struct ppc_data *ppc, int mode) 3580f210c92SNicolas Souchu { 3590f210c92SNicolas Souchu u_char ecr = 0; 3600f210c92SNicolas Souchu 3610f210c92SNicolas Souchu /* check if mode is available */ 3620f210c92SNicolas Souchu if (mode && !(ppc->ppc_avm & mode)) 3630f210c92SNicolas Souchu return (EINVAL); 3640f210c92SNicolas Souchu 3650f210c92SNicolas Souchu /* if ECP mode, configure ecr register */ 366c264e80fSNicolas Souchu if ((ppc->ppc_avm & PPB_ECP) || (ppc->ppc_dtm & PPB_ECP)) { 3670f210c92SNicolas Souchu /* return to byte mode (keeping direction bit), 3680f210c92SNicolas Souchu * no interrupt, no DMA to be able to change to 3690f210c92SNicolas Souchu * ECP or EPP mode 3700f210c92SNicolas Souchu */ 3710f210c92SNicolas Souchu w_ecr(ppc, PPC_ECR_RESET); 3720f210c92SNicolas Souchu ecr = PPC_DISABLE_INTR; 3730f210c92SNicolas Souchu 3740f210c92SNicolas Souchu if (mode & PPB_EPP) 3750f210c92SNicolas Souchu /* select EPP mode */ 3760f210c92SNicolas Souchu ecr |= PPC_ECR_EPP; 3770f210c92SNicolas Souchu else if (mode & PPB_ECP) 3780f210c92SNicolas Souchu /* select ECP mode */ 3790f210c92SNicolas Souchu ecr |= PPC_ECR_ECP; 3800f210c92SNicolas Souchu else if (mode & PPB_PS2) 3810f210c92SNicolas Souchu /* select PS2 mode with ECP */ 3820f210c92SNicolas Souchu ecr |= PPC_ECR_PS2; 3830f210c92SNicolas Souchu else 3840f210c92SNicolas Souchu /* select COMPATIBLE/NIBBLE mode */ 3850f210c92SNicolas Souchu ecr |= PPC_ECR_STD; 3860f210c92SNicolas Souchu 3870f210c92SNicolas Souchu w_ecr(ppc, ecr); 3880f210c92SNicolas Souchu } 3890f210c92SNicolas Souchu 3900f210c92SNicolas Souchu ppc->ppc_mode = mode; 3910f210c92SNicolas Souchu 3920f210c92SNicolas Souchu return (0); 3930f210c92SNicolas Souchu } 3940f210c92SNicolas Souchu 3950f210c92SNicolas Souchu #ifdef PPC_PROBE_CHIPSET 3960f210c92SNicolas Souchu /* 39767646539SMike Smith * ppc_pc873xx_detect 39867646539SMike Smith * 39967646539SMike Smith * Probe for a Natsemi PC873xx-family part. 40067646539SMike Smith * 40167646539SMike Smith * References in this function are to the National Semiconductor 40267646539SMike Smith * PC87332 datasheet TL/C/11930, May 1995 revision. 40367646539SMike Smith */ 40467646539SMike Smith static int pc873xx_basetab[] = {0x0398, 0x026e, 0x015c, 0x002e, 0}; 40567646539SMike Smith static int pc873xx_porttab[] = {0x0378, 0x03bc, 0x0278, 0}; 406af548787SNicolas Souchu static int pc873xx_irqtab[] = {5, 7, 5, 0}; 407af548787SNicolas Souchu 408af548787SNicolas Souchu static int pc873xx_regstab[] = { 409af548787SNicolas Souchu PC873_FER, PC873_FAR, PC873_PTR, 410af548787SNicolas Souchu PC873_FCR, PC873_PCR, PC873_PMC, 411af548787SNicolas Souchu PC873_TUP, PC873_SID, PC873_PNP0, 412af548787SNicolas Souchu PC873_PNP1, PC873_LPTBA, -1 413af548787SNicolas Souchu }; 414af548787SNicolas Souchu 415af548787SNicolas Souchu static char *pc873xx_rnametab[] = { 416af548787SNicolas Souchu "FER", "FAR", "PTR", "FCR", "PCR", 417af548787SNicolas Souchu "PMC", "TUP", "SID", "PNP0", "PNP1", 418af548787SNicolas Souchu "LPTBA", NULL 419af548787SNicolas Souchu }; 42067646539SMike Smith 42167646539SMike Smith static int 42246f3ff79SMike Smith ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never forced */ 42367646539SMike Smith { 42467646539SMike Smith static int index = 0; 425f1d19042SArchie Cobbs int idport, irq; 426af548787SNicolas Souchu int ptr, pcr, val, i; 42767646539SMike Smith 42867646539SMike Smith while ((idport = pc873xx_basetab[index++])) { 42967646539SMike Smith 43067646539SMike Smith /* XXX should check first to see if this location is already claimed */ 43167646539SMike Smith 43267646539SMike Smith /* 433af548787SNicolas Souchu * Pull the 873xx through the power-on ID cycle (2.2,1.). 434af548787SNicolas Souchu * We can't use this to locate the chip as it may already have 435af548787SNicolas Souchu * been used by the BIOS. 43667646539SMike Smith */ 437af548787SNicolas Souchu (void)inb(idport); (void)inb(idport); 438af548787SNicolas Souchu (void)inb(idport); (void)inb(idport); 43967646539SMike Smith 44067646539SMike Smith /* 44167646539SMike Smith * Read the SID byte. Possible values are : 44267646539SMike Smith * 443af548787SNicolas Souchu * 01010xxx PC87334 44467646539SMike Smith * 0001xxxx PC87332 44567646539SMike Smith * 01110xxx PC87306 446ac7ba926SDoug Rabson * 00110xxx PC87303 44767646539SMike Smith */ 44867646539SMike Smith outb(idport, PC873_SID); 44967646539SMike Smith val = inb(idport + 1); 45067646539SMike Smith if ((val & 0xf0) == 0x10) { 4510f210c92SNicolas Souchu ppc->ppc_model = NS_PC87332; 45267646539SMike Smith } else if ((val & 0xf8) == 0x70) { 4530f210c92SNicolas Souchu ppc->ppc_model = NS_PC87306; 454af548787SNicolas Souchu } else if ((val & 0xf8) == 0x50) { 4550f210c92SNicolas Souchu ppc->ppc_model = NS_PC87334; 456ac7ba926SDoug Rabson } else if ((val & 0xf8) == 0x40) { /* Should be 0x30 by the 457ac7ba926SDoug Rabson documentation, but probing 458ac7ba926SDoug Rabson yielded 0x40... */ 459ac7ba926SDoug Rabson ppc->ppc_model = NS_PC87303; 46067646539SMike Smith } else { 46167646539SMike Smith if (bootverbose && (val != 0xff)) 46267646539SMike Smith printf("PC873xx probe at 0x%x got unknown ID 0x%x\n", idport, val); 46367646539SMike Smith continue ; /* not recognised */ 46467646539SMike Smith } 46567646539SMike Smith 466af548787SNicolas Souchu /* print registers */ 467af548787SNicolas Souchu if (bootverbose) { 468af548787SNicolas Souchu printf("PC873xx"); 469af548787SNicolas Souchu for (i=0; pc873xx_regstab[i] != -1; i++) { 470af548787SNicolas Souchu outb(idport, pc873xx_regstab[i]); 471af548787SNicolas Souchu printf(" %s=0x%x", pc873xx_rnametab[i], 472af548787SNicolas Souchu inb(idport + 1) & 0xff); 473af548787SNicolas Souchu } 474af548787SNicolas Souchu printf("\n"); 475af548787SNicolas Souchu } 476af548787SNicolas Souchu 47767646539SMike Smith /* 47867646539SMike Smith * We think we have one. Is it enabled and where we want it to be? 47967646539SMike Smith */ 48067646539SMike Smith outb(idport, PC873_FER); 48167646539SMike Smith val = inb(idport + 1); 48267646539SMike Smith if (!(val & PC873_PPENABLE)) { 48367646539SMike Smith if (bootverbose) 48467646539SMike Smith printf("PC873xx parallel port disabled\n"); 48567646539SMike Smith continue; 48667646539SMike Smith } 48767646539SMike Smith outb(idport, PC873_FAR); 488ac7ba926SDoug Rabson val = inb(idport + 1); 48967646539SMike Smith /* XXX we should create a driver instance for every port found */ 490ac7ba926SDoug Rabson if (pc873xx_porttab[val & 0x3] != ppc->ppc_base) { 491ac7ba926SDoug Rabson 492ac7ba926SDoug Rabson /* First try to change the port address to that requested... */ 493ac7ba926SDoug Rabson 494ac7ba926SDoug Rabson switch (ppc->ppc_base) { 495ac7ba926SDoug Rabson case 0x378: 496ac7ba926SDoug Rabson val &= 0xfc; 497ac7ba926SDoug Rabson break; 498ac7ba926SDoug Rabson 499ac7ba926SDoug Rabson case 0x3bc: 500ac7ba926SDoug Rabson val &= 0xfd; 501ac7ba926SDoug Rabson break; 502ac7ba926SDoug Rabson 503ac7ba926SDoug Rabson case 0x278: 504ac7ba926SDoug Rabson val &= 0xfe; 505ac7ba926SDoug Rabson break; 506ac7ba926SDoug Rabson 507ac7ba926SDoug Rabson default: 508ac7ba926SDoug Rabson val &= 0xfd; 509ac7ba926SDoug Rabson break; 510ac7ba926SDoug Rabson } 511ac7ba926SDoug Rabson 512ac7ba926SDoug Rabson outb(idport, PC873_FAR); 513ac7ba926SDoug Rabson outb(idport + 1, val); 514ac7ba926SDoug Rabson outb(idport + 1, val); 515ac7ba926SDoug Rabson 516ac7ba926SDoug Rabson /* Check for success by reading back the value we supposedly 517ac7ba926SDoug Rabson wrote and comparing...*/ 518ac7ba926SDoug Rabson 519ac7ba926SDoug Rabson outb(idport, PC873_FAR); 520ac7ba926SDoug Rabson val = inb(idport + 1) & 0x3; 521ac7ba926SDoug Rabson 522ac7ba926SDoug Rabson /* If we fail, report the failure... */ 523ac7ba926SDoug Rabson 52467646539SMike Smith if (pc873xx_porttab[val] != ppc->ppc_base) { 52567646539SMike Smith if (bootverbose) 52667646539SMike Smith printf("PC873xx at 0x%x not for driver at port 0x%x\n", 52767646539SMike Smith pc873xx_porttab[val], ppc->ppc_base); 528ac7ba926SDoug Rabson } 52967646539SMike Smith continue; 53067646539SMike Smith } 53167646539SMike Smith 53267646539SMike Smith outb(idport, PC873_PTR); 533af548787SNicolas Souchu ptr = inb(idport + 1); 534af548787SNicolas Souchu 535af548787SNicolas Souchu /* get irq settings */ 536af548787SNicolas Souchu if (ppc->ppc_base == 0x378) 537af548787SNicolas Souchu irq = (ptr & PC873_LPTBIRQ7) ? 7 : 5; 538af548787SNicolas Souchu else 539af548787SNicolas Souchu irq = pc873xx_irqtab[val]; 540af548787SNicolas Souchu 54167646539SMike Smith if (bootverbose) 542af548787SNicolas Souchu printf("PC873xx irq %d at 0x%x\n", irq, ppc->ppc_base); 54367646539SMike Smith 544af548787SNicolas Souchu /* 545af548787SNicolas Souchu * Check if irq settings are correct 546af548787SNicolas Souchu */ 547af548787SNicolas Souchu if (irq != ppc->ppc_irq) { 548af548787SNicolas Souchu /* 549af548787SNicolas Souchu * If the chipset is not locked and base address is 0x378, 550af548787SNicolas Souchu * we have another chance 551af548787SNicolas Souchu */ 552af548787SNicolas Souchu if (ppc->ppc_base == 0x378 && !(ptr & PC873_CFGLOCK)) { 553af548787SNicolas Souchu if (ppc->ppc_irq == 7) { 554af548787SNicolas Souchu outb(idport + 1, (ptr | PC873_LPTBIRQ7)); 555af548787SNicolas Souchu outb(idport + 1, (ptr | PC873_LPTBIRQ7)); 556af548787SNicolas Souchu } else { 557af548787SNicolas Souchu outb(idport + 1, (ptr & ~PC873_LPTBIRQ7)); 558af548787SNicolas Souchu outb(idport + 1, (ptr & ~PC873_LPTBIRQ7)); 55967646539SMike Smith } 560af548787SNicolas Souchu if (bootverbose) 561af548787SNicolas Souchu printf("PC873xx irq set to %d\n", ppc->ppc_irq); 562af548787SNicolas Souchu } else { 563af548787SNicolas Souchu if (bootverbose) 564af548787SNicolas Souchu printf("PC873xx sorry, can't change irq setting\n"); 56567646539SMike Smith } 56667646539SMike Smith } else { 56767646539SMike Smith if (bootverbose) 568af548787SNicolas Souchu printf("PC873xx irq settings are correct\n"); 56967646539SMike Smith } 57067646539SMike Smith 57167646539SMike Smith outb(idport, PC873_PCR); 572af548787SNicolas Souchu pcr = inb(idport + 1); 573af548787SNicolas Souchu 574af548787SNicolas Souchu if ((ptr & PC873_CFGLOCK) || !chipset_mode) { 575af548787SNicolas Souchu if (bootverbose) 576af548787SNicolas Souchu printf("PC873xx %s", (ptr & PC873_CFGLOCK)?"locked":"unlocked"); 577af548787SNicolas Souchu 578af548787SNicolas Souchu ppc->ppc_avm |= PPB_NIBBLE; 579af548787SNicolas Souchu if (bootverbose) 580af548787SNicolas Souchu printf(", NIBBLE"); 581af548787SNicolas Souchu 582af548787SNicolas Souchu if (pcr & PC873_EPPEN) { 583af548787SNicolas Souchu ppc->ppc_avm |= PPB_EPP; 584af548787SNicolas Souchu 585af548787SNicolas Souchu if (bootverbose) 586af548787SNicolas Souchu printf(", EPP"); 587af548787SNicolas Souchu 588af548787SNicolas Souchu if (pcr & PC873_EPP19) 589af548787SNicolas Souchu ppc->ppc_epp = EPP_1_9; 590af548787SNicolas Souchu else 591af548787SNicolas Souchu ppc->ppc_epp = EPP_1_7; 592af548787SNicolas Souchu 5930f210c92SNicolas Souchu if ((ppc->ppc_model == NS_PC87332) && bootverbose) { 594af548787SNicolas Souchu outb(idport, PC873_PTR); 595af548787SNicolas Souchu ptr = inb(idport + 1); 596af548787SNicolas Souchu if (ptr & PC873_EPPRDIR) 597af548787SNicolas Souchu printf(", Regular mode"); 598af548787SNicolas Souchu else 599af548787SNicolas Souchu printf(", Automatic mode"); 600af548787SNicolas Souchu } 601af548787SNicolas Souchu } else if (pcr & PC873_ECPEN) { 602af548787SNicolas Souchu ppc->ppc_avm |= PPB_ECP; 603af548787SNicolas Souchu if (bootverbose) 604af548787SNicolas Souchu printf(", ECP"); 605af548787SNicolas Souchu 606af548787SNicolas Souchu if (pcr & PC873_ECPCLK) { /* XXX */ 607af548787SNicolas Souchu ppc->ppc_avm |= PPB_PS2; 608af548787SNicolas Souchu if (bootverbose) 609af548787SNicolas Souchu printf(", PS/2"); 610af548787SNicolas Souchu } 611af548787SNicolas Souchu } else { 612af548787SNicolas Souchu outb(idport, PC873_PTR); 613af548787SNicolas Souchu ptr = inb(idport + 1); 614af548787SNicolas Souchu if (ptr & PC873_EXTENDED) { 615af548787SNicolas Souchu ppc->ppc_avm |= PPB_SPP; 616af548787SNicolas Souchu if (bootverbose) 617af548787SNicolas Souchu printf(", SPP"); 618af548787SNicolas Souchu } 619af548787SNicolas Souchu } 620af548787SNicolas Souchu } else { 621af548787SNicolas Souchu if (bootverbose) 622af548787SNicolas Souchu printf("PC873xx unlocked"); 623af548787SNicolas Souchu 624af548787SNicolas Souchu if (chipset_mode & PPB_ECP) { 625af548787SNicolas Souchu if ((chipset_mode & PPB_EPP) && bootverbose) 626af548787SNicolas Souchu printf(", ECP+EPP not supported"); 627af548787SNicolas Souchu 628af548787SNicolas Souchu pcr &= ~PC873_EPPEN; 629af548787SNicolas Souchu pcr |= (PC873_ECPEN | PC873_ECPCLK); /* XXX */ 630af548787SNicolas Souchu outb(idport + 1, pcr); 631af548787SNicolas Souchu outb(idport + 1, pcr); 632af548787SNicolas Souchu 633af548787SNicolas Souchu if (bootverbose) 634af548787SNicolas Souchu printf(", ECP"); 635af548787SNicolas Souchu 636af548787SNicolas Souchu } else if (chipset_mode & PPB_EPP) { 637af548787SNicolas Souchu pcr &= ~(PC873_ECPEN | PC873_ECPCLK); 638af548787SNicolas Souchu pcr |= (PC873_EPPEN | PC873_EPP19); 639af548787SNicolas Souchu outb(idport + 1, pcr); 640af548787SNicolas Souchu outb(idport + 1, pcr); 641af548787SNicolas Souchu 642af548787SNicolas Souchu ppc->ppc_epp = EPP_1_9; /* XXX */ 643af548787SNicolas Souchu 644af548787SNicolas Souchu if (bootverbose) 645af548787SNicolas Souchu printf(", EPP1.9"); 64667646539SMike Smith 64767646539SMike Smith /* enable automatic direction turnover */ 6480f210c92SNicolas Souchu if (ppc->ppc_model == NS_PC87332) { 64967646539SMike Smith outb(idport, PC873_PTR); 650af548787SNicolas Souchu ptr = inb(idport + 1); 651af548787SNicolas Souchu ptr &= ~PC873_EPPRDIR; 652af548787SNicolas Souchu outb(idport + 1, ptr); 653af548787SNicolas Souchu outb(idport + 1, ptr); 65467646539SMike Smith 65567646539SMike Smith if (bootverbose) 656af548787SNicolas Souchu printf(", Automatic mode"); 65767646539SMike Smith } 658af548787SNicolas Souchu } else { 659af548787SNicolas Souchu pcr &= ~(PC873_ECPEN | PC873_ECPCLK | PC873_EPPEN); 660af548787SNicolas Souchu outb(idport + 1, pcr); 661af548787SNicolas Souchu outb(idport + 1, pcr); 662af548787SNicolas Souchu 663af548787SNicolas Souchu /* configure extended bit in PTR */ 664af548787SNicolas Souchu outb(idport, PC873_PTR); 665af548787SNicolas Souchu ptr = inb(idport + 1); 666af548787SNicolas Souchu 667af548787SNicolas Souchu if (chipset_mode & PPB_PS2) { 668af548787SNicolas Souchu ptr |= PC873_EXTENDED; 669af548787SNicolas Souchu 670af548787SNicolas Souchu if (bootverbose) 671af548787SNicolas Souchu printf(", PS/2"); 672af548787SNicolas Souchu 673af548787SNicolas Souchu } else { 674af548787SNicolas Souchu /* default to NIBBLE mode */ 675af548787SNicolas Souchu ptr &= ~PC873_EXTENDED; 676af548787SNicolas Souchu 677af548787SNicolas Souchu if (bootverbose) 678af548787SNicolas Souchu printf(", NIBBLE"); 67967646539SMike Smith } 680af548787SNicolas Souchu outb(idport + 1, ptr); 681af548787SNicolas Souchu outb(idport + 1, ptr); 682af548787SNicolas Souchu } 683af548787SNicolas Souchu 684af548787SNicolas Souchu ppc->ppc_avm = chipset_mode; 685af548787SNicolas Souchu } 686af548787SNicolas Souchu 687af548787SNicolas Souchu if (bootverbose) 688af548787SNicolas Souchu printf("\n"); 689af548787SNicolas Souchu 6900f210c92SNicolas Souchu ppc->ppc_type = PPC_TYPE_GENERIC; 6910f210c92SNicolas Souchu ppc_generic_setmode(ppc, chipset_mode); 69246f3ff79SMike Smith 69346f3ff79SMike Smith return(chipset_mode); 69467646539SMike Smith } 69546f3ff79SMike Smith return(-1); 69667646539SMike Smith } 69767646539SMike Smith 69867646539SMike Smith /* 69967646539SMike Smith * ppc_smc37c66xgt_detect 70067646539SMike Smith * 70167646539SMike Smith * SMC FDC37C66xGT configuration. 70267646539SMike Smith */ 70367646539SMike Smith static int 70446f3ff79SMike Smith ppc_smc37c66xgt_detect(struct ppc_data *ppc, int chipset_mode) 70567646539SMike Smith { 7061eb7e5feSWarner Losh int i; 707c9ab0738SNicolas Souchu u_char r; 70867646539SMike Smith int type = -1; 70967646539SMike Smith int csr = SMC66x_CSR; /* initial value is 0x3F0 */ 71067646539SMike Smith 71167646539SMike Smith int port_address[] = { -1 /* disabled */ , 0x3bc, 0x378, 0x278 }; 71267646539SMike Smith 71367646539SMike Smith 71467646539SMike Smith #define cio csr+1 /* config IO port is either 0x3F1 or 0x371 */ 71567646539SMike Smith 71667646539SMike Smith /* 71767646539SMike Smith * Detection: enter configuration mode and read CRD register. 71867646539SMike Smith */ 7191eb7e5feSWarner Losh PPC_CONFIG_LOCK(ppc); 72067646539SMike Smith outb(csr, SMC665_iCODE); 72167646539SMike Smith outb(csr, SMC665_iCODE); 7221eb7e5feSWarner Losh PPC_CONFIG_UNLOCK(ppc); 72367646539SMike Smith 72467646539SMike Smith outb(csr, 0xd); 72567646539SMike Smith if (inb(cio) == 0x65) { 72667646539SMike Smith type = SMC_37C665GT; 72767646539SMike Smith goto config; 72867646539SMike Smith } 72967646539SMike Smith 73067646539SMike Smith for (i = 0; i < 2; i++) { 7311eb7e5feSWarner Losh PPC_CONFIG_LOCK(ppc); 73267646539SMike Smith outb(csr, SMC666_iCODE); 73367646539SMike Smith outb(csr, SMC666_iCODE); 7341eb7e5feSWarner Losh PPC_CONFIG_UNLOCK(ppc); 73567646539SMike Smith 73667646539SMike Smith outb(csr, 0xd); 73767646539SMike Smith if (inb(cio) == 0x66) { 73867646539SMike Smith type = SMC_37C666GT; 73967646539SMike Smith break; 74067646539SMike Smith } 74167646539SMike Smith 74267646539SMike Smith /* Another chance, CSR may be hard-configured to be at 0x370 */ 74367646539SMike Smith csr = SMC666_CSR; 74467646539SMike Smith } 74567646539SMike Smith 74667646539SMike Smith config: 74767646539SMike Smith /* 74867646539SMike Smith * If chipset not found, do not continue. 74967646539SMike Smith */ 7501eb7e5feSWarner Losh if (type == -1) { 7511eb7e5feSWarner Losh outb(csr, 0xaa); /* end config mode */ 75246f3ff79SMike Smith return (-1); 7531eb7e5feSWarner Losh } 75467646539SMike Smith 75567646539SMike Smith /* select CR1 */ 75667646539SMike Smith outb(csr, 0x1); 75767646539SMike Smith 75867646539SMike Smith /* read the port's address: bits 0 and 1 of CR1 */ 75967646539SMike Smith r = inb(cio) & SMC_CR1_ADDR; 7601eb7e5feSWarner Losh if (port_address[(int)r] != ppc->ppc_base) { 7611eb7e5feSWarner Losh outb(csr, 0xaa); /* end config mode */ 76246f3ff79SMike Smith return (-1); 7631eb7e5feSWarner Losh } 76467646539SMike Smith 7650f210c92SNicolas Souchu ppc->ppc_model = type; 76667646539SMike Smith 76767646539SMike Smith /* 76867646539SMike Smith * CR1 and CR4 registers bits 3 and 0/1 for mode configuration 76946f3ff79SMike Smith * If SPP mode is detected, try to set ECP+EPP mode 77067646539SMike Smith */ 77167646539SMike Smith 77246f3ff79SMike Smith if (bootverbose) { 77346f3ff79SMike Smith outb(csr, 0x1); 774ff809674SJohn Baldwin device_printf(ppc->ppc_dev, "SMC registers CR1=0x%x", 775ff809674SJohn Baldwin inb(cio) & 0xff); 77646f3ff79SMike Smith 77746f3ff79SMike Smith outb(csr, 0x4); 77846f3ff79SMike Smith printf(" CR4=0x%x", inb(cio) & 0xff); 77946f3ff79SMike Smith } 78046f3ff79SMike Smith 78146f3ff79SMike Smith /* select CR1 */ 78267646539SMike Smith outb(csr, 0x1); 78367646539SMike Smith 78446f3ff79SMike Smith if (!chipset_mode) { 78567646539SMike Smith /* autodetect mode */ 78667646539SMike Smith 78746f3ff79SMike Smith /* 666GT is ~certainly~ hardwired to an extended ECP+EPP mode */ 78846f3ff79SMike Smith if (type == SMC_37C666GT) { 78946f3ff79SMike Smith ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP; 790edcfcf27SNicolas Souchu if (bootverbose) 791edcfcf27SNicolas Souchu printf(" configuration hardwired, supposing " \ 792edcfcf27SNicolas Souchu "ECP+EPP SPP"); 79367646539SMike Smith 79446f3ff79SMike Smith } else 79546f3ff79SMike Smith if ((inb(cio) & SMC_CR1_MODE) == 0) { 79667646539SMike Smith /* already in extended parallel port mode, read CR4 */ 79767646539SMike Smith outb(csr, 0x4); 79867646539SMike Smith r = (inb(cio) & SMC_CR4_EMODE); 79967646539SMike Smith 80067646539SMike Smith switch (r) { 80167646539SMike Smith case SMC_SPP: 80246f3ff79SMike Smith ppc->ppc_avm |= PPB_SPP; 803edcfcf27SNicolas Souchu if (bootverbose) 804edcfcf27SNicolas Souchu printf(" SPP"); 80567646539SMike Smith break; 80667646539SMike Smith 80767646539SMike Smith case SMC_EPPSPP: 80846f3ff79SMike Smith ppc->ppc_avm |= PPB_EPP | PPB_SPP; 809edcfcf27SNicolas Souchu if (bootverbose) 810edcfcf27SNicolas Souchu printf(" EPP SPP"); 81167646539SMike Smith break; 81267646539SMike Smith 81367646539SMike Smith case SMC_ECP: 81446f3ff79SMike Smith ppc->ppc_avm |= PPB_ECP | PPB_SPP; 815edcfcf27SNicolas Souchu if (bootverbose) 816edcfcf27SNicolas Souchu printf(" ECP SPP"); 81767646539SMike Smith break; 81867646539SMike Smith 81967646539SMike Smith case SMC_ECPEPP: 82046f3ff79SMike Smith ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP; 821edcfcf27SNicolas Souchu if (bootverbose) 822edcfcf27SNicolas Souchu printf(" ECP+EPP SPP"); 82367646539SMike Smith break; 82467646539SMike Smith } 82546f3ff79SMike Smith } else { 82646f3ff79SMike Smith /* not an extended port mode */ 82746f3ff79SMike Smith ppc->ppc_avm |= PPB_SPP; 828edcfcf27SNicolas Souchu if (bootverbose) 829edcfcf27SNicolas Souchu printf(" SPP"); 83067646539SMike Smith } 83146f3ff79SMike Smith 83267646539SMike Smith } else { 83367646539SMike Smith /* mode forced */ 83454ad6085SNicolas Souchu ppc->ppc_avm = chipset_mode; 83567646539SMike Smith 83646f3ff79SMike Smith /* 666GT is ~certainly~ hardwired to an extended ECP+EPP mode */ 83767646539SMike Smith if (type == SMC_37C666GT) 83867646539SMike Smith goto end_detect; 83967646539SMike Smith 84067646539SMike Smith r = inb(cio); 84146f3ff79SMike Smith if ((chipset_mode & (PPB_ECP | PPB_EPP)) == 0) { 84246f3ff79SMike Smith /* do not use ECP when the mode is not forced to */ 84367646539SMike Smith outb(cio, r | SMC_CR1_MODE); 844edcfcf27SNicolas Souchu if (bootverbose) 845edcfcf27SNicolas Souchu printf(" SPP"); 84667646539SMike Smith } else { 84767646539SMike Smith /* an extended mode is selected */ 84867646539SMike Smith outb(cio, r & ~SMC_CR1_MODE); 84967646539SMike Smith 85067646539SMike Smith /* read CR4 register and reset mode field */ 85167646539SMike Smith outb(csr, 0x4); 85267646539SMike Smith r = inb(cio) & ~SMC_CR4_EMODE; 85367646539SMike Smith 85446f3ff79SMike Smith if (chipset_mode & PPB_ECP) { 85546f3ff79SMike Smith if (chipset_mode & PPB_EPP) { 85667646539SMike Smith outb(cio, r | SMC_ECPEPP); 857edcfcf27SNicolas Souchu if (bootverbose) 858edcfcf27SNicolas Souchu printf(" ECP+EPP"); 85946f3ff79SMike Smith } else { 86046f3ff79SMike Smith outb(cio, r | SMC_ECP); 861edcfcf27SNicolas Souchu if (bootverbose) 862edcfcf27SNicolas Souchu printf(" ECP"); 86346f3ff79SMike Smith } 86446f3ff79SMike Smith } else { 86546f3ff79SMike Smith /* PPB_EPP is set */ 86646f3ff79SMike Smith outb(cio, r | SMC_EPPSPP); 867edcfcf27SNicolas Souchu if (bootverbose) 868edcfcf27SNicolas Souchu printf(" EPP SPP"); 86967646539SMike Smith } 87067646539SMike Smith } 87146f3ff79SMike Smith ppc->ppc_avm = chipset_mode; 87267646539SMike Smith } 87367646539SMike Smith 874bc35c174SNicolas Souchu /* set FIFO threshold to 16 */ 875bc35c174SNicolas Souchu if (ppc->ppc_avm & PPB_ECP) { 876bc35c174SNicolas Souchu /* select CRA */ 877bc35c174SNicolas Souchu outb(csr, 0xa); 878bc35c174SNicolas Souchu outb(cio, 16); 879bc35c174SNicolas Souchu } 880bc35c174SNicolas Souchu 88167646539SMike Smith end_detect: 88246f3ff79SMike Smith 88346f3ff79SMike Smith if (bootverbose) 88446f3ff79SMike Smith printf ("\n"); 88546f3ff79SMike Smith 88654ad6085SNicolas Souchu if (ppc->ppc_avm & PPB_EPP) { 88767646539SMike Smith /* select CR4 */ 88867646539SMike Smith outb(csr, 0x4); 88967646539SMike Smith r = inb(cio); 89067646539SMike Smith 89167646539SMike Smith /* 89267646539SMike Smith * Set the EPP protocol... 89367646539SMike Smith * Low=EPP 1.9 (1284 standard) and High=EPP 1.7 89467646539SMike Smith */ 89567646539SMike Smith if (ppc->ppc_epp == EPP_1_9) 89667646539SMike Smith outb(cio, (r & ~SMC_CR4_EPPTYPE)); 89767646539SMike Smith else 89867646539SMike Smith outb(cio, (r | SMC_CR4_EPPTYPE)); 89967646539SMike Smith } 90067646539SMike Smith 9011eb7e5feSWarner Losh outb(csr, 0xaa); /* end config mode */ 90267646539SMike Smith 9030f210c92SNicolas Souchu ppc->ppc_type = PPC_TYPE_SMCLIKE; 9040f210c92SNicolas Souchu ppc_smclike_setmode(ppc, chipset_mode); 90567646539SMike Smith 90646f3ff79SMike Smith return (chipset_mode); 90767646539SMike Smith } 90867646539SMike Smith 90946f3ff79SMike Smith /* 9106a5be862SDoug Rabson * SMC FDC37C935 configuration 9116a5be862SDoug Rabson * Found on many Alpha machines 9126a5be862SDoug Rabson */ 9136a5be862SDoug Rabson static int 9146a5be862SDoug Rabson ppc_smc37c935_detect(struct ppc_data *ppc, int chipset_mode) 9156a5be862SDoug Rabson { 9166a5be862SDoug Rabson int type = -1; 9176a5be862SDoug Rabson 9181eb7e5feSWarner Losh PPC_CONFIG_LOCK(ppc); 9196a5be862SDoug Rabson outb(SMC935_CFG, 0x55); /* enter config mode */ 9206a5be862SDoug Rabson outb(SMC935_CFG, 0x55); 9211eb7e5feSWarner Losh PPC_CONFIG_UNLOCK(ppc); 9226a5be862SDoug Rabson 9236a5be862SDoug Rabson outb(SMC935_IND, SMC935_ID); /* check device id */ 9246a5be862SDoug Rabson if (inb(SMC935_DAT) == 0x2) 9256a5be862SDoug Rabson type = SMC_37C935; 9266a5be862SDoug Rabson 9276a5be862SDoug Rabson if (type == -1) { 9286a5be862SDoug Rabson outb(SMC935_CFG, 0xaa); /* exit config mode */ 9296a5be862SDoug Rabson return (-1); 9306a5be862SDoug Rabson } 9316a5be862SDoug Rabson 9326a5be862SDoug Rabson ppc->ppc_model = type; 9336a5be862SDoug Rabson 9346a5be862SDoug Rabson outb(SMC935_IND, SMC935_LOGDEV); /* select parallel port, */ 9356a5be862SDoug Rabson outb(SMC935_DAT, 3); /* which is logical device 3 */ 9366a5be862SDoug Rabson 9376a5be862SDoug Rabson /* set io port base */ 9386a5be862SDoug Rabson outb(SMC935_IND, SMC935_PORTHI); 9396a5be862SDoug Rabson outb(SMC935_DAT, (u_char)((ppc->ppc_base & 0xff00) >> 8)); 9406a5be862SDoug Rabson outb(SMC935_IND, SMC935_PORTLO); 9416a5be862SDoug Rabson outb(SMC935_DAT, (u_char)(ppc->ppc_base & 0xff)); 9426a5be862SDoug Rabson 9436a5be862SDoug Rabson if (!chipset_mode) 9446a5be862SDoug Rabson ppc->ppc_avm = PPB_COMPATIBLE; /* default mode */ 9456a5be862SDoug Rabson else { 9466a5be862SDoug Rabson ppc->ppc_avm = chipset_mode; 9476a5be862SDoug Rabson outb(SMC935_IND, SMC935_PPMODE); 9486a5be862SDoug Rabson outb(SMC935_DAT, SMC935_CENT); /* start in compatible mode */ 9496a5be862SDoug Rabson 9506a5be862SDoug Rabson /* SPP + EPP or just plain SPP */ 9516a5be862SDoug Rabson if (chipset_mode & (PPB_SPP)) { 9526a5be862SDoug Rabson if (chipset_mode & PPB_EPP) { 9536a5be862SDoug Rabson if (ppc->ppc_epp == EPP_1_9) { 9546a5be862SDoug Rabson outb(SMC935_IND, SMC935_PPMODE); 9556a5be862SDoug Rabson outb(SMC935_DAT, SMC935_EPP19SPP); 9566a5be862SDoug Rabson } 9576a5be862SDoug Rabson if (ppc->ppc_epp == EPP_1_7) { 9586a5be862SDoug Rabson outb(SMC935_IND, SMC935_PPMODE); 9596a5be862SDoug Rabson outb(SMC935_DAT, SMC935_EPP17SPP); 9606a5be862SDoug Rabson } 9616a5be862SDoug Rabson } else { 9626a5be862SDoug Rabson outb(SMC935_IND, SMC935_PPMODE); 9636a5be862SDoug Rabson outb(SMC935_DAT, SMC935_SPP); 9646a5be862SDoug Rabson } 9656a5be862SDoug Rabson } 9666a5be862SDoug Rabson 9676a5be862SDoug Rabson /* ECP + EPP or just plain ECP */ 9686a5be862SDoug Rabson if (chipset_mode & PPB_ECP) { 9696a5be862SDoug Rabson if (chipset_mode & PPB_EPP) { 9706a5be862SDoug Rabson if (ppc->ppc_epp == EPP_1_9) { 9716a5be862SDoug Rabson outb(SMC935_IND, SMC935_PPMODE); 9726a5be862SDoug Rabson outb(SMC935_DAT, SMC935_ECPEPP19); 9736a5be862SDoug Rabson } 9746a5be862SDoug Rabson if (ppc->ppc_epp == EPP_1_7) { 9756a5be862SDoug Rabson outb(SMC935_IND, SMC935_PPMODE); 9766a5be862SDoug Rabson outb(SMC935_DAT, SMC935_ECPEPP17); 9776a5be862SDoug Rabson } 9786a5be862SDoug Rabson } else { 9796a5be862SDoug Rabson outb(SMC935_IND, SMC935_PPMODE); 9806a5be862SDoug Rabson outb(SMC935_DAT, SMC935_ECP); 9816a5be862SDoug Rabson } 9826a5be862SDoug Rabson } 9836a5be862SDoug Rabson } 9846a5be862SDoug Rabson 9856a5be862SDoug Rabson outb(SMC935_CFG, 0xaa); /* exit config mode */ 9866a5be862SDoug Rabson 9876a5be862SDoug Rabson ppc->ppc_type = PPC_TYPE_SMCLIKE; 9886a5be862SDoug Rabson ppc_smclike_setmode(ppc, chipset_mode); 9896a5be862SDoug Rabson 9906a5be862SDoug Rabson return (chipset_mode); 9916a5be862SDoug Rabson } 9926a5be862SDoug Rabson 9936a5be862SDoug Rabson /* 99446f3ff79SMike Smith * Winbond W83877F stuff 99546f3ff79SMike Smith * 99646f3ff79SMike Smith * EFER: extended function enable register 99746f3ff79SMike Smith * EFIR: extended function index register 99846f3ff79SMike Smith * EFDR: extended function data register 99946f3ff79SMike Smith */ 100046f3ff79SMike Smith #define efir ((efer == 0x250) ? 0x251 : 0x3f0) 100146f3ff79SMike Smith #define efdr ((efer == 0x250) ? 0x252 : 0x3f1) 100246f3ff79SMike Smith 100346f3ff79SMike Smith static int w83877f_efers[] = { 0x250, 0x3f0, 0x3f0, 0x250 }; 100446f3ff79SMike Smith static int w83877f_keys[] = { 0x89, 0x86, 0x87, 0x88 }; 100546f3ff79SMike Smith static int w83877f_keyiter[] = { 1, 2, 2, 1 }; 100646f3ff79SMike Smith static int w83877f_hefs[] = { WINB_HEFERE, WINB_HEFRAS, WINB_HEFERE | WINB_HEFRAS, 0 }; 100767646539SMike Smith 100867646539SMike Smith static int 100946f3ff79SMike Smith ppc_w83877f_detect(struct ppc_data *ppc, int chipset_mode) 101067646539SMike Smith { 1011f1d19042SArchie Cobbs int i, j, efer; 101246f3ff79SMike Smith unsigned char r, hefere, hefras; 101367646539SMike Smith 101446f3ff79SMike Smith for (i = 0; i < 4; i ++) { 101546f3ff79SMike Smith /* first try to enable configuration registers */ 101646f3ff79SMike Smith efer = w83877f_efers[i]; 101767646539SMike Smith 101846f3ff79SMike Smith /* write the key to the EFER */ 101946f3ff79SMike Smith for (j = 0; j < w83877f_keyiter[i]; j ++) 102046f3ff79SMike Smith outb (efer, w83877f_keys[i]); 102146f3ff79SMike Smith 102246f3ff79SMike Smith /* then check HEFERE and HEFRAS bits */ 102346f3ff79SMike Smith outb (efir, 0x0c); 102446f3ff79SMike Smith hefere = inb(efdr) & WINB_HEFERE; 102546f3ff79SMike Smith 102646f3ff79SMike Smith outb (efir, 0x16); 102746f3ff79SMike Smith hefras = inb(efdr) & WINB_HEFRAS; 102846f3ff79SMike Smith 102946f3ff79SMike Smith /* 103046f3ff79SMike Smith * HEFRAS HEFERE 103146f3ff79SMike Smith * 0 1 write 89h to 250h (power-on default) 103246f3ff79SMike Smith * 1 0 write 86h twice to 3f0h 103346f3ff79SMike Smith * 1 1 write 87h twice to 3f0h 103446f3ff79SMike Smith * 0 0 write 88h to 250h 103546f3ff79SMike Smith */ 103646f3ff79SMike Smith if ((hefere | hefras) == w83877f_hefs[i]) 103746f3ff79SMike Smith goto found; 103867646539SMike Smith } 103967646539SMike Smith 104046f3ff79SMike Smith return (-1); /* failed */ 104167646539SMike Smith 104246f3ff79SMike Smith found: 104346f3ff79SMike Smith /* check base port address - read from CR23 */ 104446f3ff79SMike Smith outb(efir, 0x23); 104546f3ff79SMike Smith if (ppc->ppc_base != inb(efdr) * 4) /* 4 bytes boundaries */ 104646f3ff79SMike Smith return (-1); 104746f3ff79SMike Smith 104846f3ff79SMike Smith /* read CHIP ID from CR9/bits0-3 */ 104946f3ff79SMike Smith outb(efir, 0x9); 105046f3ff79SMike Smith 105146f3ff79SMike Smith switch (inb(efdr) & WINB_CHIPID) { 105246f3ff79SMike Smith case WINB_W83877F_ID: 10530f210c92SNicolas Souchu ppc->ppc_model = WINB_W83877F; 105446f3ff79SMike Smith break; 105546f3ff79SMike Smith 105646f3ff79SMike Smith case WINB_W83877AF_ID: 10570f210c92SNicolas Souchu ppc->ppc_model = WINB_W83877AF; 105846f3ff79SMike Smith break; 105946f3ff79SMike Smith 106046f3ff79SMike Smith default: 10610f210c92SNicolas Souchu ppc->ppc_model = WINB_UNKNOWN; 106246f3ff79SMike Smith } 106346f3ff79SMike Smith 106446f3ff79SMike Smith if (bootverbose) { 106546f3ff79SMike Smith /* dump of registers */ 1066ff809674SJohn Baldwin device_printf(ppc->ppc_dev, "0x%x - ", w83877f_keys[i]); 106746f3ff79SMike Smith for (i = 0; i <= 0xd; i ++) { 106846f3ff79SMike Smith outb(efir, i); 106946f3ff79SMike Smith printf("0x%x ", inb(efdr)); 107046f3ff79SMike Smith } 107146f3ff79SMike Smith for (i = 0x10; i <= 0x17; i ++) { 107246f3ff79SMike Smith outb(efir, i); 107346f3ff79SMike Smith printf("0x%x ", inb(efdr)); 107446f3ff79SMike Smith } 107546f3ff79SMike Smith outb(efir, 0x1e); 107646f3ff79SMike Smith printf("0x%x ", inb(efdr)); 107746f3ff79SMike Smith for (i = 0x20; i <= 0x29; i ++) { 107846f3ff79SMike Smith outb(efir, i); 107946f3ff79SMike Smith printf("0x%x ", inb(efdr)); 108046f3ff79SMike Smith } 108146f3ff79SMike Smith printf("\n"); 108246f3ff79SMike Smith } 108346f3ff79SMike Smith 10840f210c92SNicolas Souchu ppc->ppc_type = PPC_TYPE_GENERIC; 1085edcfcf27SNicolas Souchu 108646f3ff79SMike Smith if (!chipset_mode) { 108746f3ff79SMike Smith /* autodetect mode */ 108846f3ff79SMike Smith 108946f3ff79SMike Smith /* select CR0 */ 109046f3ff79SMike Smith outb(efir, 0x0); 109146f3ff79SMike Smith r = inb(efdr) & (WINB_PRTMODS0 | WINB_PRTMODS1); 109246f3ff79SMike Smith 109346f3ff79SMike Smith /* select CR9 */ 109446f3ff79SMike Smith outb(efir, 0x9); 109546f3ff79SMike Smith r |= (inb(efdr) & WINB_PRTMODS2); 109646f3ff79SMike Smith 109746f3ff79SMike Smith switch (r) { 109846f3ff79SMike Smith case WINB_W83757: 109946f3ff79SMike Smith if (bootverbose) 1100ff809674SJohn Baldwin device_printf(ppc->ppc_dev, 1101ff809674SJohn Baldwin "W83757 compatible mode\n"); 110246f3ff79SMike Smith return (-1); /* generic or SMC-like */ 110346f3ff79SMike Smith 110446f3ff79SMike Smith case WINB_EXTFDC: 110546f3ff79SMike Smith case WINB_EXTADP: 110646f3ff79SMike Smith case WINB_EXT2FDD: 110746f3ff79SMike Smith case WINB_JOYSTICK: 110846f3ff79SMike Smith if (bootverbose) 1109ff809674SJohn Baldwin device_printf(ppc->ppc_dev, 1110ae6b868aSJohn Baldwin "not in parallel port mode\n"); 111146f3ff79SMike Smith return (-1); 111246f3ff79SMike Smith 111346f3ff79SMike Smith case (WINB_PARALLEL | WINB_EPP_SPP): 111446f3ff79SMike Smith ppc->ppc_avm |= PPB_EPP | PPB_SPP; 1115edcfcf27SNicolas Souchu if (bootverbose) 1116ff809674SJohn Baldwin device_printf(ppc->ppc_dev, "EPP SPP\n"); 111746f3ff79SMike Smith break; 111846f3ff79SMike Smith 111946f3ff79SMike Smith case (WINB_PARALLEL | WINB_ECP): 112046f3ff79SMike Smith ppc->ppc_avm |= PPB_ECP | PPB_SPP; 1121edcfcf27SNicolas Souchu if (bootverbose) 1122ff809674SJohn Baldwin device_printf(ppc->ppc_dev, "ECP SPP\n"); 112346f3ff79SMike Smith break; 112446f3ff79SMike Smith 112546f3ff79SMike Smith case (WINB_PARALLEL | WINB_ECP_EPP): 112646f3ff79SMike Smith ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP; 11270f210c92SNicolas Souchu ppc->ppc_type = PPC_TYPE_SMCLIKE; 1128edcfcf27SNicolas Souchu 1129edcfcf27SNicolas Souchu if (bootverbose) 1130ff809674SJohn Baldwin device_printf(ppc->ppc_dev, "ECP+EPP SPP\n"); 113146f3ff79SMike Smith break; 113246f3ff79SMike Smith default: 11336e551fb6SDavid E. O'Brien printf("%s: unknown case (0x%x)!\n", __func__, r); 113446f3ff79SMike Smith } 113546f3ff79SMike Smith 113646f3ff79SMike Smith } else { 113746f3ff79SMike Smith /* mode forced */ 113846f3ff79SMike Smith 113946f3ff79SMike Smith /* select CR9 and set PRTMODS2 bit */ 114046f3ff79SMike Smith outb(efir, 0x9); 114146f3ff79SMike Smith outb(efdr, inb(efdr) & ~WINB_PRTMODS2); 114246f3ff79SMike Smith 114346f3ff79SMike Smith /* select CR0 and reset PRTMODSx bits */ 114446f3ff79SMike Smith outb(efir, 0x0); 114546f3ff79SMike Smith outb(efdr, inb(efdr) & ~(WINB_PRTMODS0 | WINB_PRTMODS1)); 114646f3ff79SMike Smith 114746f3ff79SMike Smith if (chipset_mode & PPB_ECP) { 1148edcfcf27SNicolas Souchu if (chipset_mode & PPB_EPP) { 114946f3ff79SMike Smith outb(efdr, inb(efdr) | WINB_ECP_EPP); 1150edcfcf27SNicolas Souchu if (bootverbose) 1151ff809674SJohn Baldwin device_printf(ppc->ppc_dev, 1152ff809674SJohn Baldwin "ECP+EPP\n"); 1153edcfcf27SNicolas Souchu 11540f210c92SNicolas Souchu ppc->ppc_type = PPC_TYPE_SMCLIKE; 1155edcfcf27SNicolas Souchu 1156edcfcf27SNicolas Souchu } else { 115746f3ff79SMike Smith outb(efdr, inb(efdr) | WINB_ECP); 1158edcfcf27SNicolas Souchu if (bootverbose) 1159ff809674SJohn Baldwin device_printf(ppc->ppc_dev, "ECP\n"); 1160edcfcf27SNicolas Souchu } 116146f3ff79SMike Smith } else { 116246f3ff79SMike Smith /* select EPP_SPP otherwise */ 116346f3ff79SMike Smith outb(efdr, inb(efdr) | WINB_EPP_SPP); 1164edcfcf27SNicolas Souchu if (bootverbose) 1165ff809674SJohn Baldwin device_printf(ppc->ppc_dev, "EPP SPP\n"); 116646f3ff79SMike Smith } 116746f3ff79SMike Smith ppc->ppc_avm = chipset_mode; 116846f3ff79SMike Smith } 116946f3ff79SMike Smith 117046f3ff79SMike Smith /* exit configuration mode */ 117146f3ff79SMike Smith outb(efer, 0xaa); 117246f3ff79SMike Smith 11730f210c92SNicolas Souchu switch (ppc->ppc_type) { 11740f210c92SNicolas Souchu case PPC_TYPE_SMCLIKE: 11750f210c92SNicolas Souchu ppc_smclike_setmode(ppc, chipset_mode); 11760f210c92SNicolas Souchu break; 11770f210c92SNicolas Souchu default: 11780f210c92SNicolas Souchu ppc_generic_setmode(ppc, chipset_mode); 11790f210c92SNicolas Souchu break; 11800f210c92SNicolas Souchu } 118146f3ff79SMike Smith 118246f3ff79SMike Smith return (chipset_mode); 118367646539SMike Smith } 11840f210c92SNicolas Souchu #endif 118567646539SMike Smith 118667646539SMike Smith /* 118767646539SMike Smith * ppc_generic_detect 118867646539SMike Smith */ 118967646539SMike Smith static int 119046f3ff79SMike Smith ppc_generic_detect(struct ppc_data *ppc, int chipset_mode) 119167646539SMike Smith { 1192edcfcf27SNicolas Souchu /* default to generic */ 11930f210c92SNicolas Souchu ppc->ppc_type = PPC_TYPE_GENERIC; 1194edcfcf27SNicolas Souchu 1195edcfcf27SNicolas Souchu if (bootverbose) 1196ae6b868aSJohn Baldwin device_printf(ppc->ppc_dev, "SPP"); 1197edcfcf27SNicolas Souchu 119846f3ff79SMike Smith /* first, check for ECP */ 1199bc35c174SNicolas Souchu w_ecr(ppc, PPC_ECR_PS2); 1200bc35c174SNicolas Souchu if ((r_ecr(ppc) & 0xe0) == PPC_ECR_PS2) { 1201c264e80fSNicolas Souchu ppc->ppc_dtm |= PPB_ECP | PPB_SPP; 1202edcfcf27SNicolas Souchu if (bootverbose) 1203ae6b868aSJohn Baldwin printf(" ECP "); 120446f3ff79SMike Smith 120546f3ff79SMike Smith /* search for SMC style ECP+EPP mode */ 1206bc35c174SNicolas Souchu w_ecr(ppc, PPC_ECR_EPP); 120746f3ff79SMike Smith } 120867646539SMike Smith 120967646539SMike Smith /* try to reset EPP timeout bit */ 121046f3ff79SMike Smith if (ppc_check_epp_timeout(ppc)) { 1211c264e80fSNicolas Souchu ppc->ppc_dtm |= PPB_EPP; 121267646539SMike Smith 1213c264e80fSNicolas Souchu if (ppc->ppc_dtm & PPB_ECP) { 121446f3ff79SMike Smith /* SMC like chipset found */ 12150f210c92SNicolas Souchu ppc->ppc_model = SMC_LIKE; 12160f210c92SNicolas Souchu ppc->ppc_type = PPC_TYPE_SMCLIKE; 1217edcfcf27SNicolas Souchu 1218edcfcf27SNicolas Souchu if (bootverbose) 1219edcfcf27SNicolas Souchu printf(" ECP+EPP"); 1220edcfcf27SNicolas Souchu } else { 1221edcfcf27SNicolas Souchu if (bootverbose) 1222edcfcf27SNicolas Souchu printf(" EPP"); 1223edcfcf27SNicolas Souchu } 1224edcfcf27SNicolas Souchu } else { 1225edcfcf27SNicolas Souchu /* restore to standard mode */ 1226bc35c174SNicolas Souchu w_ecr(ppc, PPC_ECR_STD); 122767646539SMike Smith } 122867646539SMike Smith 1229edcfcf27SNicolas Souchu /* XXX try to detect NIBBLE and PS2 modes */ 1230c264e80fSNicolas Souchu ppc->ppc_dtm |= PPB_NIBBLE; 123167646539SMike Smith 1232c264e80fSNicolas Souchu if (chipset_mode) 1233edcfcf27SNicolas Souchu ppc->ppc_avm = chipset_mode; 1234c264e80fSNicolas Souchu else 1235c264e80fSNicolas Souchu ppc->ppc_avm = ppc->ppc_dtm; 1236edcfcf27SNicolas Souchu 1237edcfcf27SNicolas Souchu if (bootverbose) 1238edcfcf27SNicolas Souchu printf("\n"); 1239edcfcf27SNicolas Souchu 12400f210c92SNicolas Souchu switch (ppc->ppc_type) { 12410f210c92SNicolas Souchu case PPC_TYPE_SMCLIKE: 12420f210c92SNicolas Souchu ppc_smclike_setmode(ppc, chipset_mode); 12430f210c92SNicolas Souchu break; 12440f210c92SNicolas Souchu default: 12450f210c92SNicolas Souchu ppc_generic_setmode(ppc, chipset_mode); 12460f210c92SNicolas Souchu break; 12470f210c92SNicolas Souchu } 124846f3ff79SMike Smith 124946f3ff79SMike Smith return (chipset_mode); 125067646539SMike Smith } 125167646539SMike Smith 125267646539SMike Smith /* 125367646539SMike Smith * ppc_detect() 125467646539SMike Smith * 125567646539SMike Smith * mode is the mode suggested at boot 125667646539SMike Smith */ 125767646539SMike Smith static int 125846f3ff79SMike Smith ppc_detect(struct ppc_data *ppc, int chipset_mode) { 125967646539SMike Smith 12600f210c92SNicolas Souchu #ifdef PPC_PROBE_CHIPSET 126146f3ff79SMike Smith int i, mode; 126267646539SMike Smith 126346f3ff79SMike Smith /* list of supported chipsets */ 126446f3ff79SMike Smith int (*chipset_detect[])(struct ppc_data *, int) = { 126546f3ff79SMike Smith ppc_pc873xx_detect, 126646f3ff79SMike Smith ppc_smc37c66xgt_detect, 126746f3ff79SMike Smith ppc_w83877f_detect, 12686a5be862SDoug Rabson ppc_smc37c935_detect, 126946f3ff79SMike Smith ppc_generic_detect, 127046f3ff79SMike Smith NULL 127146f3ff79SMike Smith }; 12720f210c92SNicolas Souchu #endif 127367646539SMike Smith 127446f3ff79SMike Smith /* if can't find the port and mode not forced return error */ 127546f3ff79SMike Smith if (!ppc_detect_port(ppc) && chipset_mode == 0) 127646f3ff79SMike Smith return (EIO); /* failed, port not present */ 127767646539SMike Smith 127846f3ff79SMike Smith /* assume centronics compatible mode is supported */ 127946f3ff79SMike Smith ppc->ppc_avm = PPB_COMPATIBLE; 128067646539SMike Smith 12810f210c92SNicolas Souchu #ifdef PPC_PROBE_CHIPSET 128246f3ff79SMike Smith /* we have to differenciate available chipset modes, 128346f3ff79SMike Smith * chipset running modes and IEEE-1284 operating modes 128446f3ff79SMike Smith * 128546f3ff79SMike Smith * after detection, the port must support running in compatible mode 128646f3ff79SMike Smith */ 1287af548787SNicolas Souchu if (ppc->ppc_flags & 0x40) { 1288af548787SNicolas Souchu if (bootverbose) 1289af548787SNicolas Souchu printf("ppc: chipset forced to generic\n"); 12900f210c92SNicolas Souchu #endif 1291af548787SNicolas Souchu 1292af548787SNicolas Souchu ppc->ppc_mode = ppc_generic_detect(ppc, chipset_mode); 1293af548787SNicolas Souchu 12940f210c92SNicolas Souchu #ifdef PPC_PROBE_CHIPSET 1295af548787SNicolas Souchu } else { 129646f3ff79SMike Smith for (i=0; chipset_detect[i] != NULL; i++) { 129746f3ff79SMike Smith if ((mode = chipset_detect[i](ppc, chipset_mode)) != -1) { 129846f3ff79SMike Smith ppc->ppc_mode = mode; 129946f3ff79SMike Smith break; 130046f3ff79SMike Smith } 130146f3ff79SMike Smith } 1302af548787SNicolas Souchu } 13030f210c92SNicolas Souchu #endif 130446f3ff79SMike Smith 1305bc35c174SNicolas Souchu /* configure/detect ECP FIFO */ 1306bc35c174SNicolas Souchu if ((ppc->ppc_avm & PPB_ECP) && !(ppc->ppc_flags & 0x80)) 1307bc35c174SNicolas Souchu ppc_detect_fifo(ppc); 1308bc35c174SNicolas Souchu 130946f3ff79SMike Smith return (0); 131046f3ff79SMike Smith } 131146f3ff79SMike Smith 131246f3ff79SMike Smith /* 131346f3ff79SMike Smith * ppc_exec_microseq() 131446f3ff79SMike Smith * 131546f3ff79SMike Smith * Execute a microsequence. 131646f3ff79SMike Smith * Microsequence mechanism is supposed to handle fast I/O operations. 131746f3ff79SMike Smith */ 1318a3732274SDoug Ambrisko int 13190f210c92SNicolas Souchu ppc_exec_microseq(device_t dev, struct ppb_microseq **p_msq) 132046f3ff79SMike Smith { 13210f210c92SNicolas Souchu struct ppc_data *ppc = DEVTOSOFTC(dev); 13220a40e22aSNicolas Souchu struct ppb_microseq *mi; 132346f3ff79SMike Smith char cc, *p; 132454ad6085SNicolas Souchu int i, iter, len; 132546f3ff79SMike Smith int error; 132646f3ff79SMike Smith 13273e85b721SEd Maste int reg; 13283e85b721SEd Maste char mask; 13293e85b721SEd Maste int accum = 0; 13303e85b721SEd Maste char *ptr = NULL; 133146f3ff79SMike Smith 13324d24901aSPedro F. Giffuni struct ppb_microseq *stack = NULL; 133346f3ff79SMike Smith 133446f3ff79SMike Smith /* microsequence registers are equivalent to PC-like port registers */ 13353ae3f8b0SNicolas Souchu 13368fd40d8aSJohn Baldwin #define r_reg(reg,ppc) (bus_read_1((ppc)->res_ioport, reg)) 13378fd40d8aSJohn Baldwin #define w_reg(reg, ppc, byte) (bus_write_1((ppc)->res_ioport, reg, byte)) 133846f3ff79SMike Smith 13390a40e22aSNicolas Souchu #define INCR_PC (mi ++) /* increment program counter */ 134046f3ff79SMike Smith 13412067d312SJohn Baldwin PPC_ASSERT_LOCKED(ppc); 13420a40e22aSNicolas Souchu mi = *p_msq; 134346f3ff79SMike Smith for (;;) { 134446f3ff79SMike Smith switch (mi->opcode) { 134546f3ff79SMike Smith case MS_OP_RSET: 134646f3ff79SMike Smith cc = r_reg(mi->arg[0].i, ppc); 134754ad6085SNicolas Souchu cc &= (char)mi->arg[2].i; /* clear mask */ 134854ad6085SNicolas Souchu cc |= (char)mi->arg[1].i; /* assert mask */ 134946f3ff79SMike Smith w_reg(mi->arg[0].i, ppc, cc); 135046f3ff79SMike Smith INCR_PC; 135146f3ff79SMike Smith break; 135246f3ff79SMike Smith 135346f3ff79SMike Smith case MS_OP_RASSERT_P: 135454ad6085SNicolas Souchu reg = mi->arg[1].i; 135554ad6085SNicolas Souchu ptr = ppc->ppc_ptr; 135654ad6085SNicolas Souchu 135754ad6085SNicolas Souchu if ((len = mi->arg[0].i) == MS_ACCUM) { 135854ad6085SNicolas Souchu accum = ppc->ppc_accum; 135954ad6085SNicolas Souchu for (; accum; accum--) 136054ad6085SNicolas Souchu w_reg(reg, ppc, *ptr++); 136154ad6085SNicolas Souchu ppc->ppc_accum = accum; 136254ad6085SNicolas Souchu } else 136354ad6085SNicolas Souchu for (i=0; i<len; i++) 136454ad6085SNicolas Souchu w_reg(reg, ppc, *ptr++); 136554ad6085SNicolas Souchu ppc->ppc_ptr = ptr; 136654ad6085SNicolas Souchu 136746f3ff79SMike Smith INCR_PC; 136846f3ff79SMike Smith break; 136946f3ff79SMike Smith 137046f3ff79SMike Smith case MS_OP_RFETCH_P: 137154ad6085SNicolas Souchu reg = mi->arg[1].i; 137254ad6085SNicolas Souchu mask = (char)mi->arg[2].i; 137354ad6085SNicolas Souchu ptr = ppc->ppc_ptr; 137454ad6085SNicolas Souchu 137554ad6085SNicolas Souchu if ((len = mi->arg[0].i) == MS_ACCUM) { 137654ad6085SNicolas Souchu accum = ppc->ppc_accum; 137754ad6085SNicolas Souchu for (; accum; accum--) 137854ad6085SNicolas Souchu *ptr++ = r_reg(reg, ppc) & mask; 137954ad6085SNicolas Souchu ppc->ppc_accum = accum; 138054ad6085SNicolas Souchu } else 138154ad6085SNicolas Souchu for (i=0; i<len; i++) 138254ad6085SNicolas Souchu *ptr++ = r_reg(reg, ppc) & mask; 138354ad6085SNicolas Souchu ppc->ppc_ptr = ptr; 138454ad6085SNicolas Souchu 138546f3ff79SMike Smith INCR_PC; 138646f3ff79SMike Smith break; 138746f3ff79SMike Smith 138846f3ff79SMike Smith case MS_OP_RFETCH: 138946f3ff79SMike Smith *((char *) mi->arg[2].p) = r_reg(mi->arg[0].i, ppc) & 139054ad6085SNicolas Souchu (char)mi->arg[1].i; 139146f3ff79SMike Smith INCR_PC; 139246f3ff79SMike Smith break; 139346f3ff79SMike Smith 139446f3ff79SMike Smith case MS_OP_RASSERT: 139554ad6085SNicolas Souchu case MS_OP_DELAY: 139646f3ff79SMike Smith 139746f3ff79SMike Smith /* let's suppose the next instr. is the same */ 139846f3ff79SMike Smith prefetch: 139946f3ff79SMike Smith for (;mi->opcode == MS_OP_RASSERT; INCR_PC) 140054ad6085SNicolas Souchu w_reg(mi->arg[0].i, ppc, (char)mi->arg[1].i); 140146f3ff79SMike Smith 140246f3ff79SMike Smith if (mi->opcode == MS_OP_DELAY) { 140346f3ff79SMike Smith DELAY(mi->arg[0].i); 140446f3ff79SMike Smith INCR_PC; 140546f3ff79SMike Smith goto prefetch; 140646f3ff79SMike Smith } 140746f3ff79SMike Smith break; 140846f3ff79SMike Smith 140954ad6085SNicolas Souchu case MS_OP_ADELAY: 14102067d312SJohn Baldwin if (mi->arg[0].i) { 14112067d312SJohn Baldwin PPC_UNLOCK(ppc); 1412a96255b6SJohn Baldwin pause("ppbdelay", mi->arg[0].i * (hz/1000)); 14132067d312SJohn Baldwin PPC_LOCK(ppc); 14142067d312SJohn Baldwin } 141546f3ff79SMike Smith INCR_PC; 141646f3ff79SMike Smith break; 141746f3ff79SMike Smith 141846f3ff79SMike Smith case MS_OP_TRIG: 141946f3ff79SMike Smith reg = mi->arg[0].i; 142046f3ff79SMike Smith iter = mi->arg[1].i; 142146f3ff79SMike Smith p = (char *)mi->arg[2].p; 142246f3ff79SMike Smith 142354ad6085SNicolas Souchu /* XXX delay limited to 255 us */ 142446f3ff79SMike Smith for (i=0; i<iter; i++) { 142546f3ff79SMike Smith w_reg(reg, ppc, *p++); 142646f3ff79SMike Smith DELAY((unsigned char)*p++); 142746f3ff79SMike Smith } 142846f3ff79SMike Smith INCR_PC; 142946f3ff79SMike Smith break; 143046f3ff79SMike Smith 143146f3ff79SMike Smith case MS_OP_SET: 143254ad6085SNicolas Souchu ppc->ppc_accum = mi->arg[0].i; 143346f3ff79SMike Smith INCR_PC; 143446f3ff79SMike Smith break; 143546f3ff79SMike Smith 143646f3ff79SMike Smith case MS_OP_DBRA: 143754ad6085SNicolas Souchu if (--ppc->ppc_accum > 0) 14380a40e22aSNicolas Souchu mi += mi->arg[0].i; 143946f3ff79SMike Smith INCR_PC; 144046f3ff79SMike Smith break; 144146f3ff79SMike Smith 144246f3ff79SMike Smith case MS_OP_BRSET: 144346f3ff79SMike Smith cc = r_str(ppc); 144454ad6085SNicolas Souchu if ((cc & (char)mi->arg[0].i) == (char)mi->arg[0].i) 14450a40e22aSNicolas Souchu mi += mi->arg[1].i; 144646f3ff79SMike Smith INCR_PC; 144746f3ff79SMike Smith break; 144846f3ff79SMike Smith 144946f3ff79SMike Smith case MS_OP_BRCLEAR: 145046f3ff79SMike Smith cc = r_str(ppc); 145154ad6085SNicolas Souchu if ((cc & (char)mi->arg[0].i) == 0) 14520a40e22aSNicolas Souchu mi += mi->arg[1].i; 145346f3ff79SMike Smith INCR_PC; 145446f3ff79SMike Smith break; 145546f3ff79SMike Smith 145654ad6085SNicolas Souchu case MS_OP_BRSTAT: 145754ad6085SNicolas Souchu cc = r_str(ppc); 145854ad6085SNicolas Souchu if ((cc & ((char)mi->arg[0].i | (char)mi->arg[1].i)) == 145954ad6085SNicolas Souchu (char)mi->arg[0].i) 14600a40e22aSNicolas Souchu mi += mi->arg[2].i; 146154ad6085SNicolas Souchu INCR_PC; 146254ad6085SNicolas Souchu break; 146354ad6085SNicolas Souchu 146446f3ff79SMike Smith case MS_OP_C_CALL: 146546f3ff79SMike Smith /* 146646f3ff79SMike Smith * If the C call returns !0 then end the microseq. 146746f3ff79SMike Smith * The current state of ptr is passed to the C function 146846f3ff79SMike Smith */ 146954ad6085SNicolas Souchu if ((error = mi->arg[0].f(mi->arg[1].p, ppc->ppc_ptr))) 147046f3ff79SMike Smith return (error); 147146f3ff79SMike Smith 147246f3ff79SMike Smith INCR_PC; 147346f3ff79SMike Smith break; 147446f3ff79SMike Smith 147546f3ff79SMike Smith case MS_OP_PTR: 147654ad6085SNicolas Souchu ppc->ppc_ptr = (char *)mi->arg[0].p; 147746f3ff79SMike Smith INCR_PC; 147846f3ff79SMike Smith break; 147946f3ff79SMike Smith 148046f3ff79SMike Smith case MS_OP_CALL: 14810a40e22aSNicolas Souchu if (stack) 14826e551fb6SDavid E. O'Brien panic("%s: too much calls", __func__); 148346f3ff79SMike Smith 148446f3ff79SMike Smith if (mi->arg[0].p) { 148546f3ff79SMike Smith /* store the state of the actual 148646f3ff79SMike Smith * microsequence 148746f3ff79SMike Smith */ 14880a40e22aSNicolas Souchu stack = mi; 148946f3ff79SMike Smith 149046f3ff79SMike Smith /* jump to the new microsequence */ 14910a40e22aSNicolas Souchu mi = (struct ppb_microseq *)mi->arg[0].p; 149246f3ff79SMike Smith } else 149346f3ff79SMike Smith INCR_PC; 149446f3ff79SMike Smith 149546f3ff79SMike Smith break; 149646f3ff79SMike Smith 149746f3ff79SMike Smith case MS_OP_SUBRET: 149846f3ff79SMike Smith /* retrieve microseq and pc state before the call */ 14990a40e22aSNicolas Souchu mi = stack; 150046f3ff79SMike Smith 150146f3ff79SMike Smith /* reset the stack */ 15024d24901aSPedro F. Giffuni stack = NULL; 150346f3ff79SMike Smith 150446f3ff79SMike Smith /* XXX return code */ 150546f3ff79SMike Smith 150646f3ff79SMike Smith INCR_PC; 150746f3ff79SMike Smith break; 150846f3ff79SMike Smith 150946f3ff79SMike Smith case MS_OP_PUT: 151046f3ff79SMike Smith case MS_OP_GET: 151146f3ff79SMike Smith case MS_OP_RET: 151246f3ff79SMike Smith /* can't return to ppb level during the execution 151346f3ff79SMike Smith * of a submicrosequence */ 15140a40e22aSNicolas Souchu if (stack) 151546f3ff79SMike Smith panic("%s: can't return to ppb level", 15166e551fb6SDavid E. O'Brien __func__); 151746f3ff79SMike Smith 151846f3ff79SMike Smith /* update pc for ppb level of execution */ 15190a40e22aSNicolas Souchu *p_msq = mi; 152046f3ff79SMike Smith 152146f3ff79SMike Smith /* return to ppb level of execution */ 152246f3ff79SMike Smith return (0); 152346f3ff79SMike Smith 152446f3ff79SMike Smith default: 152546f3ff79SMike Smith panic("%s: unknown microsequence opcode 0x%x", 15266e551fb6SDavid E. O'Brien __func__, mi->opcode); 152746f3ff79SMike Smith } 152846f3ff79SMike Smith } 152946f3ff79SMike Smith 153046f3ff79SMike Smith /* unreached */ 153146f3ff79SMike Smith } 153246f3ff79SMike Smith 1533bc35c174SNicolas Souchu static void 15340f210c92SNicolas Souchu ppcintr(void *arg) 1535bc35c174SNicolas Souchu { 1536ca3d3795SJohn Baldwin struct ppc_data *ppc = arg; 15373ab971c1SNicolas Souchu u_char ctr, ecr, str; 1538bc35c174SNicolas Souchu 1539ca3d3795SJohn Baldwin /* 1540ca3d3795SJohn Baldwin * If we have any child interrupt handlers registered, let 1541ca3d3795SJohn Baldwin * them handle this interrupt. 1542ca3d3795SJohn Baldwin * 1543ca3d3795SJohn Baldwin * XXX: If DMA is in progress should we just complete that w/o 1544ca3d3795SJohn Baldwin * doing this? 1545ca3d3795SJohn Baldwin */ 15462067d312SJohn Baldwin PPC_LOCK(ppc); 15472067d312SJohn Baldwin if (ppc->ppc_intr_hook != NULL && 15482067d312SJohn Baldwin ppc->ppc_intr_hook(ppc->ppc_intr_arg) == 0) { 15492067d312SJohn Baldwin PPC_UNLOCK(ppc); 1550ca3d3795SJohn Baldwin return; 1551ca3d3795SJohn Baldwin } 1552ca3d3795SJohn Baldwin 15533ab971c1SNicolas Souchu str = r_str(ppc); 1554bc35c174SNicolas Souchu ctr = r_ctr(ppc); 1555bc35c174SNicolas Souchu ecr = r_ecr(ppc); 1556bc35c174SNicolas Souchu 1557f4e98881SRuslan Ermilov #if defined(PPC_DEBUG) && PPC_DEBUG > 1 15583ab971c1SNicolas Souchu printf("![%x/%x/%x]", ctr, ecr, str); 1559bc35c174SNicolas Souchu #endif 1560bc35c174SNicolas Souchu 1561bc35c174SNicolas Souchu /* don't use ecp mode with IRQENABLE set */ 1562bc35c174SNicolas Souchu if (ctr & IRQENABLE) { 15632067d312SJohn Baldwin PPC_UNLOCK(ppc); 1564bc35c174SNicolas Souchu return; 1565bc35c174SNicolas Souchu } 1566bc35c174SNicolas Souchu 15673ab971c1SNicolas Souchu /* interrupts are generated by nFault signal 15683ab971c1SNicolas Souchu * only in ECP mode */ 15693ab971c1SNicolas Souchu if ((str & nFAULT) && (ppc->ppc_mode & PPB_ECP)) { 15703ab971c1SNicolas Souchu /* check if ppc driver has programmed the 15713ab971c1SNicolas Souchu * nFault interrupt */ 1572bc35c174SNicolas Souchu if (ppc->ppc_irqstat & PPC_IRQ_nFAULT) { 1573bc35c174SNicolas Souchu 1574bc35c174SNicolas Souchu w_ecr(ppc, ecr | PPC_nFAULT_INTR); 1575bc35c174SNicolas Souchu ppc->ppc_irqstat &= ~PPC_IRQ_nFAULT; 1576bc35c174SNicolas Souchu } else { 15770f210c92SNicolas Souchu /* shall be handled by underlying layers XXX */ 15782067d312SJohn Baldwin PPC_UNLOCK(ppc); 1579bc35c174SNicolas Souchu return; 1580bc35c174SNicolas Souchu } 1581bc35c174SNicolas Souchu } 1582bc35c174SNicolas Souchu 1583bc35c174SNicolas Souchu if (ppc->ppc_irqstat & PPC_IRQ_DMA) { 1584bc35c174SNicolas Souchu /* disable interrupts (should be done by hardware though) */ 1585bc35c174SNicolas Souchu w_ecr(ppc, ecr | PPC_SERVICE_INTR); 1586bc35c174SNicolas Souchu ppc->ppc_irqstat &= ~PPC_IRQ_DMA; 1587bc35c174SNicolas Souchu ecr = r_ecr(ppc); 1588bc35c174SNicolas Souchu 1589bc35c174SNicolas Souchu /* check if DMA completed */ 1590bc35c174SNicolas Souchu if ((ppc->ppc_avm & PPB_ECP) && (ecr & PPC_ENABLE_DMA)) { 1591bc35c174SNicolas Souchu #ifdef PPC_DEBUG 1592bc35c174SNicolas Souchu printf("a"); 1593bc35c174SNicolas Souchu #endif 1594bc35c174SNicolas Souchu /* stop DMA */ 1595bc35c174SNicolas Souchu w_ecr(ppc, ecr & ~PPC_ENABLE_DMA); 1596bc35c174SNicolas Souchu ecr = r_ecr(ppc); 1597bc35c174SNicolas Souchu 1598bc35c174SNicolas Souchu if (ppc->ppc_dmastat == PPC_DMA_STARTED) { 1599bc35c174SNicolas Souchu #ifdef PPC_DEBUG 1600bc35c174SNicolas Souchu printf("d"); 1601bc35c174SNicolas Souchu #endif 1602cea4d875SMarcel Moolenaar ppc->ppc_dmadone(ppc); 1603bc35c174SNicolas Souchu ppc->ppc_dmastat = PPC_DMA_COMPLETE; 1604bc35c174SNicolas Souchu 1605bc35c174SNicolas Souchu /* wakeup the waiting process */ 1606521f364bSDag-Erling Smørgrav wakeup(ppc); 1607bc35c174SNicolas Souchu } 1608bc35c174SNicolas Souchu } 1609bc35c174SNicolas Souchu } else if (ppc->ppc_irqstat & PPC_IRQ_FIFO) { 1610bc35c174SNicolas Souchu 1611bc35c174SNicolas Souchu /* classic interrupt I/O */ 1612bc35c174SNicolas Souchu ppc->ppc_irqstat &= ~PPC_IRQ_FIFO; 1613bc35c174SNicolas Souchu } 16142067d312SJohn Baldwin PPC_UNLOCK(ppc); 1615bc35c174SNicolas Souchu 1616bc35c174SNicolas Souchu return; 1617bc35c174SNicolas Souchu } 1618bc35c174SNicolas Souchu 1619a3732274SDoug Ambrisko int 16200f210c92SNicolas Souchu ppc_read(device_t dev, char *buf, int len, int mode) 1621bc35c174SNicolas Souchu { 1622bc35c174SNicolas Souchu return (EINVAL); 1623bc35c174SNicolas Souchu } 1624bc35c174SNicolas Souchu 1625a3732274SDoug Ambrisko int 16260f210c92SNicolas Souchu ppc_write(device_t dev, char *buf, int len, int how) 1627bc35c174SNicolas Souchu { 1628cea4d875SMarcel Moolenaar return (EINVAL); 1629bc35c174SNicolas Souchu } 1630bc35c174SNicolas Souchu 16313fd85273SWarner Losh int 16320f210c92SNicolas Souchu ppc_reset_epp(device_t dev) 163367646539SMike Smith { 16340f210c92SNicolas Souchu struct ppc_data *ppc = DEVTOSOFTC(dev); 163567646539SMike Smith 16362067d312SJohn Baldwin PPC_ASSERT_LOCKED(ppc); 16370f210c92SNicolas Souchu ppc_reset_epp_timeout(ppc); 163867646539SMike Smith 16393fd85273SWarner Losh return 0; 164067646539SMike Smith } 164167646539SMike Smith 1642a3732274SDoug Ambrisko int 16430f210c92SNicolas Souchu ppc_setmode(device_t dev, int mode) 16440f210c92SNicolas Souchu { 16450f210c92SNicolas Souchu struct ppc_data *ppc = DEVTOSOFTC(dev); 16460f210c92SNicolas Souchu 16472067d312SJohn Baldwin PPC_ASSERT_LOCKED(ppc); 16480f210c92SNicolas Souchu switch (ppc->ppc_type) { 16490f210c92SNicolas Souchu case PPC_TYPE_SMCLIKE: 16500f210c92SNicolas Souchu return (ppc_smclike_setmode(ppc, mode)); 16510f210c92SNicolas Souchu break; 16520f210c92SNicolas Souchu 16530f210c92SNicolas Souchu case PPC_TYPE_GENERIC: 16540f210c92SNicolas Souchu default: 16550f210c92SNicolas Souchu return (ppc_generic_setmode(ppc, mode)); 16560f210c92SNicolas Souchu break; 16570f210c92SNicolas Souchu } 16580f210c92SNicolas Souchu 16590f210c92SNicolas Souchu /* not reached */ 16600f210c92SNicolas Souchu return (ENXIO); 16610f210c92SNicolas Souchu } 16620f210c92SNicolas Souchu 1663a3732274SDoug Ambrisko int 1664cea4d875SMarcel Moolenaar ppc_probe(device_t dev, int rid) 1665a3732274SDoug Ambrisko { 1666a3732274SDoug Ambrisko #ifdef __i386__ 1667a3732274SDoug Ambrisko static short next_bios_ppc = 0; 1668a3732274SDoug Ambrisko #endif 1669a3732274SDoug Ambrisko struct ppc_data *ppc; 1670a3732274SDoug Ambrisko int error; 16712dd1bdf1SJustin Hibbits rman_res_t port; 1672a3732274SDoug Ambrisko 167367646539SMike Smith /* 167467646539SMike Smith * Allocate the ppc_data structure. 167567646539SMike Smith */ 16760f210c92SNicolas Souchu ppc = DEVTOSOFTC(dev); 167767646539SMike Smith bzero(ppc, sizeof(struct ppc_data)); 167867646539SMike Smith 1679cea4d875SMarcel Moolenaar ppc->rid_ioport = rid; 168067646539SMike Smith 16810f210c92SNicolas Souchu /* retrieve ISA parameters */ 1682cea4d875SMarcel Moolenaar error = bus_get_resource(dev, SYS_RES_IOPORT, rid, &port, NULL); 16830f210c92SNicolas Souchu 1684d64d73c9SDoug Rabson #ifdef __i386__ 16850f210c92SNicolas Souchu /* 16860f210c92SNicolas Souchu * If port not specified, use bios list. 16870f210c92SNicolas Souchu */ 1688d64d73c9SDoug Rabson if (error) { 16890f210c92SNicolas Souchu if ((next_bios_ppc < BIOS_MAX_PPC) && 16900f210c92SNicolas Souchu (*(BIOS_PORTS + next_bios_ppc) != 0)) { 16910f210c92SNicolas Souchu port = *(BIOS_PORTS + next_bios_ppc++); 16920f210c92SNicolas Souchu if (bootverbose) 1693284c87f6SJohn Baldwin device_printf(dev, 1694da1b038aSJustin Hibbits "parallel port found at 0x%jx\n", port); 16950f210c92SNicolas Souchu } else { 16960f210c92SNicolas Souchu device_printf(dev, "parallel port not found.\n"); 1697284c87f6SJohn Baldwin return (ENXIO); 16980f210c92SNicolas Souchu } 1699cea4d875SMarcel Moolenaar bus_set_resource(dev, SYS_RES_IOPORT, rid, port, 17006a5be862SDoug Rabson IO_LPTSIZE_EXTENDED); 17010f210c92SNicolas Souchu } 1702d64d73c9SDoug Rabson #endif 17030f210c92SNicolas Souchu 17040f210c92SNicolas Souchu /* IO port is mandatory */ 17056a5be862SDoug Rabson 17066a5be862SDoug Rabson /* Try "extended" IO port range...*/ 1707c47476d7SJustin Hibbits ppc->res_ioport = bus_alloc_resource_anywhere(dev, SYS_RES_IOPORT, 1708c47476d7SJustin Hibbits &ppc->rid_ioport, 1709c47476d7SJustin Hibbits IO_LPTSIZE_EXTENDED, 1710c47476d7SJustin Hibbits RF_ACTIVE); 17116a5be862SDoug Rabson 17126a5be862SDoug Rabson if (ppc->res_ioport != 0) { 17136a5be862SDoug Rabson if (bootverbose) 17146a5be862SDoug Rabson device_printf(dev, "using extended I/O port range\n"); 17156a5be862SDoug Rabson } else { 17166a5be862SDoug Rabson /* Failed? If so, then try the "normal" IO port range... */ 1717c47476d7SJustin Hibbits ppc->res_ioport = bus_alloc_resource_anywhere(dev, 1718c47476d7SJustin Hibbits SYS_RES_IOPORT, 1719c47476d7SJustin Hibbits &ppc->rid_ioport, 17206a5be862SDoug Rabson IO_LPTSIZE_NORMAL, 17216a5be862SDoug Rabson RF_ACTIVE); 17226a5be862SDoug Rabson if (ppc->res_ioport != 0) { 17236a5be862SDoug Rabson if (bootverbose) 17246a5be862SDoug Rabson device_printf(dev, "using normal I/O port range\n"); 17256a5be862SDoug Rabson } else { 17261ab9094cSScott Long if (bootverbose) 17270f210c92SNicolas Souchu device_printf(dev, "cannot reserve I/O port range\n"); 17280f210c92SNicolas Souchu goto error; 17290f210c92SNicolas Souchu } 17305c885c3fSDoug Rabson } 17315c885c3fSDoug Rabson 1732d64d73c9SDoug Rabson ppc->ppc_base = rman_get_start(ppc->res_ioport); 17330f210c92SNicolas Souchu 17340f210c92SNicolas Souchu ppc->ppc_flags = device_get_flags(dev); 17350f210c92SNicolas Souchu 17360f210c92SNicolas Souchu if (!(ppc->ppc_flags & 0x20)) { 17375f96beb9SNate Lawson ppc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 17385f96beb9SNate Lawson &ppc->rid_irq, 17395f96beb9SNate Lawson RF_SHAREABLE); 17405f96beb9SNate Lawson ppc->res_drq = bus_alloc_resource_any(dev, SYS_RES_DRQ, 17415f96beb9SNate Lawson &ppc->rid_drq, 17425f96beb9SNate Lawson RF_ACTIVE); 17430f210c92SNicolas Souchu } 17440f210c92SNicolas Souchu 17450f210c92SNicolas Souchu if (ppc->res_irq) 1746d64d73c9SDoug Rabson ppc->ppc_irq = rman_get_start(ppc->res_irq); 17470f210c92SNicolas Souchu if (ppc->res_drq) 1748d64d73c9SDoug Rabson ppc->ppc_dmachan = rman_get_start(ppc->res_drq); 17490f210c92SNicolas Souchu 1750ae6b868aSJohn Baldwin ppc->ppc_dev = dev; 17510f210c92SNicolas Souchu ppc->ppc_model = GENERIC; 1752af548787SNicolas Souchu 175346f3ff79SMike Smith ppc->ppc_mode = PPB_COMPATIBLE; 17540f210c92SNicolas Souchu ppc->ppc_epp = (ppc->ppc_flags & 0x10) >> 4; 175567646539SMike Smith 17560f210c92SNicolas Souchu ppc->ppc_type = PPC_TYPE_GENERIC; 1757edcfcf27SNicolas Souchu 1758edcfcf27SNicolas Souchu /* 1759dc733423SDag-Erling Smørgrav * Try to detect the chipset and its mode. 176067646539SMike Smith */ 17610f210c92SNicolas Souchu if (ppc_detect(ppc, ppc->ppc_flags & 0xf)) 176267646539SMike Smith goto error; 176367646539SMike Smith 17640f210c92SNicolas Souchu return (0); 176567646539SMike Smith 176667646539SMike Smith error: 17670f210c92SNicolas Souchu if (ppc->res_irq != 0) { 17680f210c92SNicolas Souchu bus_release_resource(dev, SYS_RES_IRQ, ppc->rid_irq, 17690f210c92SNicolas Souchu ppc->res_irq); 17700f210c92SNicolas Souchu } 17710f210c92SNicolas Souchu if (ppc->res_ioport != 0) { 17720f210c92SNicolas Souchu bus_release_resource(dev, SYS_RES_IOPORT, ppc->rid_ioport, 17730f210c92SNicolas Souchu ppc->res_ioport); 17740f210c92SNicolas Souchu } 17750f210c92SNicolas Souchu if (ppc->res_drq != 0) { 17760f210c92SNicolas Souchu bus_release_resource(dev, SYS_RES_DRQ, ppc->rid_drq, 17770f210c92SNicolas Souchu ppc->res_drq); 17780f210c92SNicolas Souchu } 17790f210c92SNicolas Souchu return (ENXIO); 178067646539SMike Smith } 178167646539SMike Smith 1782a3732274SDoug Ambrisko int 17830f210c92SNicolas Souchu ppc_attach(device_t dev) 178467646539SMike Smith { 17850f210c92SNicolas Souchu struct ppc_data *ppc = DEVTOSOFTC(dev); 1786ca3d3795SJohn Baldwin int error; 17870f210c92SNicolas Souchu 17882067d312SJohn Baldwin mtx_init(&ppc->ppc_lock, device_get_nameunit(dev), "ppc", MTX_DEF); 17892067d312SJohn Baldwin 17900f210c92SNicolas Souchu device_printf(dev, "%s chipset (%s) in %s mode%s\n", 17910f210c92SNicolas Souchu ppc_models[ppc->ppc_model], ppc_avms[ppc->ppc_avm], 179246f3ff79SMike Smith ppc_modes[ppc->ppc_mode], (PPB_IS_EPP(ppc->ppc_mode)) ? 179367646539SMike Smith ppc_epp_protocol[ppc->ppc_epp] : ""); 179467646539SMike Smith 1795bc35c174SNicolas Souchu if (ppc->ppc_fifo) 17960f210c92SNicolas Souchu device_printf(dev, "FIFO with %d/%d/%d bytes threshold\n", 17970f210c92SNicolas Souchu ppc->ppc_fifo, ppc->ppc_wthr, ppc->ppc_rthr); 179867646539SMike Smith 1799ca3d3795SJohn Baldwin if (ppc->res_irq) { 1800ca3d3795SJohn Baldwin /* default to the tty mask for registration */ /* XXX */ 18012067d312SJohn Baldwin error = bus_setup_intr(dev, ppc->res_irq, INTR_TYPE_TTY | 18022067d312SJohn Baldwin INTR_MPSAFE, NULL, ppcintr, ppc, &ppc->intr_cookie); 1803ca3d3795SJohn Baldwin if (error) { 1804ca3d3795SJohn Baldwin device_printf(dev, 1805ca3d3795SJohn Baldwin "failed to register interrupt handler: %d\n", 1806ca3d3795SJohn Baldwin error); 18072067d312SJohn Baldwin mtx_destroy(&ppc->ppc_lock); 1808ca3d3795SJohn Baldwin return (error); 1809ca3d3795SJohn Baldwin } 1810ca3d3795SJohn Baldwin } 1811ca3d3795SJohn Baldwin 18120f210c92SNicolas Souchu /* add ppbus as a child of this isa to parallel bridge */ 18132067d312SJohn Baldwin ppc->ppbus = device_add_child(dev, "ppbus", -1); 18140f210c92SNicolas Souchu 181567646539SMike Smith /* 181667646539SMike Smith * Probe the ppbus and attach devices found. 181767646539SMike Smith */ 18182067d312SJohn Baldwin device_probe_and_attach(ppc->ppbus); 181967646539SMike Smith 18200f210c92SNicolas Souchu return (0); 18210f210c92SNicolas Souchu } 18220f210c92SNicolas Souchu 1823858a52f4SMitsuru IWASAKI int 1824858a52f4SMitsuru IWASAKI ppc_detach(device_t dev) 1825858a52f4SMitsuru IWASAKI { 1826858a52f4SMitsuru IWASAKI struct ppc_data *ppc = DEVTOSOFTC(dev); 1827858a52f4SMitsuru IWASAKI 1828858a52f4SMitsuru IWASAKI if (ppc->res_irq == 0) { 1829858a52f4SMitsuru IWASAKI return (ENXIO); 1830858a52f4SMitsuru IWASAKI } 1831858a52f4SMitsuru IWASAKI 1832858a52f4SMitsuru IWASAKI /* detach & delete all children */ 18333b12bdb5SHans Petter Selasky device_delete_children(dev); 1834858a52f4SMitsuru IWASAKI 1835858a52f4SMitsuru IWASAKI if (ppc->res_irq != 0) { 1836858a52f4SMitsuru IWASAKI bus_teardown_intr(dev, ppc->res_irq, ppc->intr_cookie); 1837858a52f4SMitsuru IWASAKI bus_release_resource(dev, SYS_RES_IRQ, ppc->rid_irq, 1838858a52f4SMitsuru IWASAKI ppc->res_irq); 1839858a52f4SMitsuru IWASAKI } 1840858a52f4SMitsuru IWASAKI if (ppc->res_ioport != 0) { 1841858a52f4SMitsuru IWASAKI bus_release_resource(dev, SYS_RES_IOPORT, ppc->rid_ioport, 1842858a52f4SMitsuru IWASAKI ppc->res_ioport); 1843858a52f4SMitsuru IWASAKI } 1844858a52f4SMitsuru IWASAKI if (ppc->res_drq != 0) { 1845858a52f4SMitsuru IWASAKI bus_release_resource(dev, SYS_RES_DRQ, ppc->rid_drq, 1846858a52f4SMitsuru IWASAKI ppc->res_drq); 1847858a52f4SMitsuru IWASAKI } 1848858a52f4SMitsuru IWASAKI 18492067d312SJohn Baldwin mtx_destroy(&ppc->ppc_lock); 18502067d312SJohn Baldwin 1851858a52f4SMitsuru IWASAKI return (0); 1852858a52f4SMitsuru IWASAKI } 1853858a52f4SMitsuru IWASAKI 1854a3732274SDoug Ambrisko u_char 18550f210c92SNicolas Souchu ppc_io(device_t ppcdev, int iop, u_char *addr, int cnt, u_char byte) 18560f210c92SNicolas Souchu { 18570f210c92SNicolas Souchu struct ppc_data *ppc = DEVTOSOFTC(ppcdev); 1858284c87f6SJohn Baldwin 18592067d312SJohn Baldwin PPC_ASSERT_LOCKED(ppc); 18600f210c92SNicolas Souchu switch (iop) { 18610f210c92SNicolas Souchu case PPB_OUTSB_EPP: 18628fd40d8aSJohn Baldwin bus_write_multi_1(ppc->res_ioport, PPC_EPP_DATA, addr, cnt); 18630f210c92SNicolas Souchu break; 18640f210c92SNicolas Souchu case PPB_OUTSW_EPP: 18658fd40d8aSJohn Baldwin bus_write_multi_2(ppc->res_ioport, PPC_EPP_DATA, (u_int16_t *)addr, cnt); 18660f210c92SNicolas Souchu break; 18670f210c92SNicolas Souchu case PPB_OUTSL_EPP: 18688fd40d8aSJohn Baldwin bus_write_multi_4(ppc->res_ioport, PPC_EPP_DATA, (u_int32_t *)addr, cnt); 18690f210c92SNicolas Souchu break; 18700f210c92SNicolas Souchu case PPB_INSB_EPP: 18718fd40d8aSJohn Baldwin bus_read_multi_1(ppc->res_ioport, PPC_EPP_DATA, addr, cnt); 18720f210c92SNicolas Souchu break; 18730f210c92SNicolas Souchu case PPB_INSW_EPP: 18748fd40d8aSJohn Baldwin bus_read_multi_2(ppc->res_ioport, PPC_EPP_DATA, (u_int16_t *)addr, cnt); 18750f210c92SNicolas Souchu break; 18760f210c92SNicolas Souchu case PPB_INSL_EPP: 18778fd40d8aSJohn Baldwin bus_read_multi_4(ppc->res_ioport, PPC_EPP_DATA, (u_int32_t *)addr, cnt); 18780f210c92SNicolas Souchu break; 18790f210c92SNicolas Souchu case PPB_RDTR: 18800f210c92SNicolas Souchu return (r_dtr(ppc)); 18810f210c92SNicolas Souchu case PPB_RSTR: 18820f210c92SNicolas Souchu return (r_str(ppc)); 18830f210c92SNicolas Souchu case PPB_RCTR: 18840f210c92SNicolas Souchu return (r_ctr(ppc)); 18850f210c92SNicolas Souchu case PPB_REPP_A: 18860f210c92SNicolas Souchu return (r_epp_A(ppc)); 18870f210c92SNicolas Souchu case PPB_REPP_D: 18880f210c92SNicolas Souchu return (r_epp_D(ppc)); 18890f210c92SNicolas Souchu case PPB_RECR: 18900f210c92SNicolas Souchu return (r_ecr(ppc)); 18910f210c92SNicolas Souchu case PPB_RFIFO: 18920f210c92SNicolas Souchu return (r_fifo(ppc)); 18930f210c92SNicolas Souchu case PPB_WDTR: 18940f210c92SNicolas Souchu w_dtr(ppc, byte); 18950f210c92SNicolas Souchu break; 18960f210c92SNicolas Souchu case PPB_WSTR: 18970f210c92SNicolas Souchu w_str(ppc, byte); 18980f210c92SNicolas Souchu break; 18990f210c92SNicolas Souchu case PPB_WCTR: 19000f210c92SNicolas Souchu w_ctr(ppc, byte); 19010f210c92SNicolas Souchu break; 19020f210c92SNicolas Souchu case PPB_WEPP_A: 19030f210c92SNicolas Souchu w_epp_A(ppc, byte); 19040f210c92SNicolas Souchu break; 19050f210c92SNicolas Souchu case PPB_WEPP_D: 19060f210c92SNicolas Souchu w_epp_D(ppc, byte); 19070f210c92SNicolas Souchu break; 19080f210c92SNicolas Souchu case PPB_WECR: 19090f210c92SNicolas Souchu w_ecr(ppc, byte); 19100f210c92SNicolas Souchu break; 19110f210c92SNicolas Souchu case PPB_WFIFO: 19120f210c92SNicolas Souchu w_fifo(ppc, byte); 19130f210c92SNicolas Souchu break; 19140f210c92SNicolas Souchu default: 19156e551fb6SDavid E. O'Brien panic("%s: unknown I/O operation", __func__); 19160f210c92SNicolas Souchu break; 19170f210c92SNicolas Souchu } 19180f210c92SNicolas Souchu 19190f210c92SNicolas Souchu return (0); /* not significative */ 19200f210c92SNicolas Souchu } 19210f210c92SNicolas Souchu 1922a3732274SDoug Ambrisko int 19230f210c92SNicolas Souchu ppc_read_ivar(device_t bus, device_t dev, int index, uintptr_t *val) 19240f210c92SNicolas Souchu { 19250f210c92SNicolas Souchu struct ppc_data *ppc = (struct ppc_data *)device_get_softc(bus); 19260f210c92SNicolas Souchu 19270f210c92SNicolas Souchu switch (index) { 19280f210c92SNicolas Souchu case PPC_IVAR_EPP_PROTO: 19292067d312SJohn Baldwin PPC_ASSERT_LOCKED(ppc); 19300f210c92SNicolas Souchu *val = (u_long)ppc->ppc_epp; 19310f210c92SNicolas Souchu break; 19322067d312SJohn Baldwin case PPC_IVAR_LOCK: 19332067d312SJohn Baldwin *val = (uintptr_t)&ppc->ppc_lock; 19342067d312SJohn Baldwin break; 19352067d312SJohn Baldwin default: 19362067d312SJohn Baldwin return (ENOENT); 19372067d312SJohn Baldwin } 19382067d312SJohn Baldwin 19392067d312SJohn Baldwin return (0); 19402067d312SJohn Baldwin } 19412067d312SJohn Baldwin 19422067d312SJohn Baldwin int 19432067d312SJohn Baldwin ppc_write_ivar(device_t bus, device_t dev, int index, uintptr_t val) 19442067d312SJohn Baldwin { 19452067d312SJohn Baldwin struct ppc_data *ppc = (struct ppc_data *)device_get_softc(bus); 19462067d312SJohn Baldwin 19472067d312SJohn Baldwin switch (index) { 19482067d312SJohn Baldwin case PPC_IVAR_INTR_HANDLER: 19492067d312SJohn Baldwin PPC_ASSERT_LOCKED(ppc); 19502067d312SJohn Baldwin if (dev != ppc->ppbus) 19512067d312SJohn Baldwin return (EINVAL); 19522067d312SJohn Baldwin if (val == 0) { 19532067d312SJohn Baldwin ppc->ppc_intr_hook = NULL; 19542067d312SJohn Baldwin break; 19552067d312SJohn Baldwin } 19562067d312SJohn Baldwin if (ppc->ppc_intr_hook != NULL) 19572067d312SJohn Baldwin return (EBUSY); 19582067d312SJohn Baldwin ppc->ppc_intr_hook = (void *)val; 19592067d312SJohn Baldwin ppc->ppc_intr_arg = device_get_softc(dev); 19602067d312SJohn Baldwin break; 19610f210c92SNicolas Souchu default: 19620f210c92SNicolas Souchu return (ENOENT); 19630f210c92SNicolas Souchu } 19640f210c92SNicolas Souchu 19650f210c92SNicolas Souchu return (0); 19660f210c92SNicolas Souchu } 19670f210c92SNicolas Souchu 19680f210c92SNicolas Souchu /* 1969ca3d3795SJohn Baldwin * We allow child devices to allocate an IRQ resource at rid 0 for their 1970ca3d3795SJohn Baldwin * interrupt handlers. 1971ca3d3795SJohn Baldwin */ 1972ca3d3795SJohn Baldwin struct resource * 1973ca3d3795SJohn Baldwin ppc_alloc_resource(device_t bus, device_t child, int type, int *rid, 19742dd1bdf1SJustin Hibbits rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 1975ca3d3795SJohn Baldwin { 1976ca3d3795SJohn Baldwin struct ppc_data *ppc = DEVTOSOFTC(bus); 1977ca3d3795SJohn Baldwin 1978ca3d3795SJohn Baldwin switch (type) { 1979ca3d3795SJohn Baldwin case SYS_RES_IRQ: 1980ca3d3795SJohn Baldwin if (*rid == 0) 1981ca3d3795SJohn Baldwin return (ppc->res_irq); 1982ca3d3795SJohn Baldwin break; 1983ca3d3795SJohn Baldwin } 1984ca3d3795SJohn Baldwin return (NULL); 1985ca3d3795SJohn Baldwin } 1986ca3d3795SJohn Baldwin 1987ca3d3795SJohn Baldwin int 1988ca3d3795SJohn Baldwin ppc_release_resource(device_t bus, device_t child, int type, int rid, 1989ca3d3795SJohn Baldwin struct resource *r) 1990ca3d3795SJohn Baldwin { 1991ca3d3795SJohn Baldwin #ifdef INVARIANTS 1992ca3d3795SJohn Baldwin struct ppc_data *ppc = DEVTOSOFTC(bus); 1993ca3d3795SJohn Baldwin #endif 1994ca3d3795SJohn Baldwin 1995ca3d3795SJohn Baldwin switch (type) { 1996ca3d3795SJohn Baldwin case SYS_RES_IRQ: 1997ca3d3795SJohn Baldwin if (rid == 0) { 1998ca3d3795SJohn Baldwin KASSERT(r == ppc->res_irq, 1999ca3d3795SJohn Baldwin ("ppc child IRQ resource mismatch")); 2000ca3d3795SJohn Baldwin return (0); 2001ca3d3795SJohn Baldwin } 2002ca3d3795SJohn Baldwin break; 2003ca3d3795SJohn Baldwin } 2004ca3d3795SJohn Baldwin return (EINVAL); 2005ca3d3795SJohn Baldwin } 2006ca3d3795SJohn Baldwin 2007f5fd5611SRuslan Ermilov MODULE_DEPEND(ppc, ppbus, 1, 1, 1); 2008