128221Smsmith/*- 293021Snsouch * Copyright (c) 1997-2000 Nicolas Souchu 371622Snsouch * Copyright (c) 2001 Alcove - Nicolas Souchu 428221Smsmith * All rights reserved. 528221Smsmith * 628221Smsmith * Redistribution and use in source and binary forms, with or without 728221Smsmith * modification, are permitted provided that the following conditions 828221Smsmith * are met: 928221Smsmith * 1. Redistributions of source code must retain the above copyright 1028221Smsmith * notice, this list of conditions and the following disclaimer. 1128221Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1228221Smsmith * notice, this list of conditions and the following disclaimer in the 1328221Smsmith * documentation and/or other materials provided with the distribution. 1428221Smsmith * 1528221Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1628221Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1728221Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1828221Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1928221Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2028221Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2128221Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2228221Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2328221Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2428221Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2528221Smsmith * SUCH DAMAGE. 2628221Smsmith */ 2728221Smsmith 28116181Sobrien#include <sys/cdefs.h> 29116181Sobrien__FBSDID("$FreeBSD$"); 30116181Sobrien 3155939Snsouch#include "opt_ppc.h" 3255939Snsouch 3328221Smsmith#include <sys/param.h> 3428221Smsmith#include <sys/systm.h> 35183053Sjhb#include <sys/bus.h> 3655939Snsouch#include <sys/kernel.h> 37187576Sjhb#include <sys/lock.h> 38183053Sjhb#include <sys/interrupt.h> 39129879Sphk#include <sys/module.h> 4028221Smsmith#include <sys/malloc.h> 41187576Sjhb#include <sys/mutex.h> 42183053Sjhb#include <sys/proc.h> 43185003Sjhb 4455939Snsouch#include <machine/bus.h> 4555939Snsouch#include <machine/resource.h> 4655939Snsouch#include <sys/rman.h> 4728221Smsmith 48158005Smarcel#ifdef __i386__ 49158005Smarcel#include <vm/vm.h> 50158005Smarcel#include <vm/pmap.h> 51158005Smarcel#include <machine/vmparam.h> 52158005Smarcel#endif 5328221Smsmith 5428221Smsmith#include <dev/ppbus/ppbconf.h> 5538061Smsmith#include <dev/ppbus/ppb_msq.h> 5638061Smsmith 57118292Sambrisko#include <dev/ppc/ppcvar.h> 58118292Sambrisko#include <dev/ppc/ppcreg.h> 5928221Smsmith 6055939Snsouch#include "ppbus_if.h" 6142475Snsouch 62118292Sambriskostatic void ppcintr(void *arg); 63118292Sambrisko 64158005Smarcel#define IO_LPTSIZE_EXTENDED 8 /* "Extended" LPT controllers */ 65158005Smarcel#define IO_LPTSIZE_NORMAL 4 /* "Normal" LPT controllers */ 66158005Smarcel 6742475Snsouch#define LOG_PPC(function, ppc, string) \ 6842475Snsouch if (bootverbose) printf("%s: %s\n", function, string) 6942475Snsouch 70158005Smarcel#if defined(__i386__) && defined(PC98) 71158005Smarcel#define PC98_IEEE_1284_DISABLE 0x100 72158005Smarcel#define PC98_IEEE_1284_PORT 0x140 73158005Smarcel#endif 7428221Smsmith 7555939Snsouch#define DEVTOSOFTC(dev) ((struct ppc_data *)device_get_softc(dev)) 76118292Sambrisko 77247066Simp/* 78247094Sglebius * We use critical enter/exit for the simple config locking needed to 79247066Simp * detect the devices. We just want to make sure that both of our writes 80247066Simp * happen without someone else also writing to those config registers. Since 81247066Simp * we just do this at startup, Giant keeps multiple threads from executing, 82247066Simp * and critical_enter() then is all that's needed to keep us from being preempted 83247066Simp * during the critical sequences with the hardware. 84247066Simp * 85247066Simp * Note: this doesn't prevent multiple threads from putting the chips into 86247066Simp * config mode, but since we only do that to detect the type at startup the 87247066Simp * extra overhead isn't needed since Giant protects us from multiple entry 88247066Simp * and no other code changes these registers. 89247066Simp */ 90247066Simp#define PPC_CONFIG_LOCK(ppc) critical_enter() 91247094Sglebius#define PPC_CONFIG_UNLOCK(ppc) critical_exit() 92247066Simp 93118292Sambriskodevclass_t ppc_devclass; 94166933Sjhbconst char ppc_driver_name[] = "ppc"; 9555939Snsouch 9655939Snsouchstatic char *ppc_models[] = { 9738061Smsmith "SMC-like", "SMC FDC37C665GT", "SMC FDC37C666GT", "PC87332", "PC87306", 9863403Sdfr "82091AA", "Generic", "W83877F", "W83877AF", "Winbond", "PC87334", 9963624Sdfr "SMC FDC37C935", "PC87303", 0 10028221Smsmith}; 10128221Smsmith 10238061Smsmith/* list of available modes */ 10338061Smsmithstatic char *ppc_avms[] = { 10438061Smsmith "COMPATIBLE", "NIBBLE-only", "PS2-only", "PS2/NIBBLE", "EPP-only", 10538061Smsmith "EPP/NIBBLE", "EPP/PS2", "EPP/PS2/NIBBLE", "ECP-only", 10638061Smsmith "ECP/NIBBLE", "ECP/PS2", "ECP/PS2/NIBBLE", "ECP/EPP", 10738061Smsmith "ECP/EPP/NIBBLE", "ECP/EPP/PS2", "ECP/EPP/PS2/NIBBLE", 0 10838061Smsmith}; 10938061Smsmith 11038061Smsmith/* list of current executing modes 11138061Smsmith * Note that few modes do not actually exist. 11238061Smsmith */ 11328221Smsmithstatic char *ppc_modes[] = { 11438061Smsmith "COMPATIBLE", "NIBBLE", "PS/2", "PS/2", "EPP", 11538061Smsmith "EPP", "EPP", "EPP", "ECP", 11638061Smsmith "ECP", "ECP+PS2", "ECP+PS2", "ECP+EPP", 11738061Smsmith "ECP+EPP", "ECP+EPP", "ECP+EPP", 0 11828221Smsmith}; 11928221Smsmith 12028221Smsmithstatic char *ppc_epp_protocol[] = { " (EPP 1.9)", " (EPP 1.7)", 0 }; 12128221Smsmith 12256617Sdfr#ifdef __i386__ 12328221Smsmith/* 12428221Smsmith * BIOS printer list - used by BIOS probe. 12528221Smsmith */ 12628221Smsmith#define BIOS_PPC_PORTS 0x408 12728221Smsmith#define BIOS_PORTS (short *)(KERNBASE+BIOS_PPC_PORTS) 12828221Smsmith#define BIOS_MAX_PPC 4 12956617Sdfr#endif 13028221Smsmith 13128221Smsmith/* 13228221Smsmith * ppc_ecp_sync() XXX 13328221Smsmith */ 134188173Simpint 135185003Sjhbppc_ecp_sync(device_t dev) 136185003Sjhb{ 13728221Smsmith int i, r; 13855939Snsouch struct ppc_data *ppc = DEVTOSOFTC(dev); 13928221Smsmith 140187576Sjhb PPC_ASSERT_LOCKED(ppc); 14171622Snsouch if (!(ppc->ppc_avm & PPB_ECP) && !(ppc->ppc_dtm & PPB_ECP)) 142188173Simp return 0; 14342475Snsouch 14428221Smsmith r = r_ecr(ppc); 14542475Snsouch if ((r & 0xe0) != PPC_ECR_EPP) 146188173Simp return 0; 14728221Smsmith 14828221Smsmith for (i = 0; i < 100; i++) { 14928221Smsmith r = r_ecr(ppc); 15028221Smsmith if (r & 0x1) 151188173Simp return 0; 15228221Smsmith DELAY(100); 15328221Smsmith } 15428221Smsmith 155184130Sjhb device_printf(dev, "ECP sync failed as data still present in FIFO.\n"); 15628221Smsmith 157188173Simp return 0; 15828221Smsmith} 15928221Smsmith 16042475Snsouch/* 16142475Snsouch * ppc_detect_fifo() 16242475Snsouch * 16342475Snsouch * Detect parallel port FIFO 16442475Snsouch */ 16542475Snsouchstatic int 16642475Snsouchppc_detect_fifo(struct ppc_data *ppc) 16728221Smsmith{ 16842475Snsouch char ecr_sav; 16942475Snsouch char ctr_sav, ctr, cc; 17042475Snsouch short i; 171185003Sjhb 17242475Snsouch /* save registers */ 17342475Snsouch ecr_sav = r_ecr(ppc); 17442475Snsouch ctr_sav = r_ctr(ppc); 17528221Smsmith 17642475Snsouch /* enter ECP configuration mode, no interrupt, no DMA */ 17742475Snsouch w_ecr(ppc, 0xf4); 17842475Snsouch 17942475Snsouch /* read PWord size - transfers in FIFO mode must be PWord aligned */ 18042475Snsouch ppc->ppc_pword = (r_cnfgA(ppc) & PPC_PWORD_MASK); 18142475Snsouch 18242475Snsouch /* XXX 16 and 32 bits implementations not supported */ 18342475Snsouch if (ppc->ppc_pword != PPC_PWORD_8) { 18487599Sobrien LOG_PPC(__func__, ppc, "PWord not supported"); 18542475Snsouch goto error; 18642475Snsouch } 18742475Snsouch 18842475Snsouch w_ecr(ppc, 0x34); /* byte mode, no interrupt, no DMA */ 18942475Snsouch ctr = r_ctr(ppc); 19042475Snsouch w_ctr(ppc, ctr | PCD); /* set direction to 1 */ 19142475Snsouch 19242475Snsouch /* enter ECP test mode, no interrupt, no DMA */ 19342475Snsouch w_ecr(ppc, 0xd4); 19442475Snsouch 19542475Snsouch /* flush the FIFO */ 19642475Snsouch for (i=0; i<1024; i++) { 19742475Snsouch if (r_ecr(ppc) & PPC_FIFO_EMPTY) 19842475Snsouch break; 19942475Snsouch cc = r_fifo(ppc); 20042475Snsouch } 20142475Snsouch 20242475Snsouch if (i >= 1024) { 20387599Sobrien LOG_PPC(__func__, ppc, "can't flush FIFO"); 20442475Snsouch goto error; 20542475Snsouch } 20642475Snsouch 20742475Snsouch /* enable interrupts, no DMA */ 20842475Snsouch w_ecr(ppc, 0xd0); 20942475Snsouch 21042475Snsouch /* determine readIntrThreshold 21142475Snsouch * fill the FIFO until serviceIntr is set 21242475Snsouch */ 21342475Snsouch for (i=0; i<1024; i++) { 21442475Snsouch w_fifo(ppc, (char)i); 21542475Snsouch if (!ppc->ppc_rthr && (r_ecr(ppc) & PPC_SERVICE_INTR)) { 21642475Snsouch /* readThreshold reached */ 21742475Snsouch ppc->ppc_rthr = i+1; 21842475Snsouch } 21942475Snsouch if (r_ecr(ppc) & PPC_FIFO_FULL) { 22042475Snsouch ppc->ppc_fifo = i+1; 22142475Snsouch break; 22242475Snsouch } 22342475Snsouch } 22442475Snsouch 22542475Snsouch if (i >= 1024) { 22687599Sobrien LOG_PPC(__func__, ppc, "can't fill FIFO"); 22742475Snsouch goto error; 22842475Snsouch } 22942475Snsouch 23042475Snsouch w_ecr(ppc, 0xd4); /* test mode, no interrupt, no DMA */ 23142475Snsouch w_ctr(ppc, ctr & ~PCD); /* set direction to 0 */ 23242475Snsouch w_ecr(ppc, 0xd0); /* enable interrupts */ 23342475Snsouch 23442475Snsouch /* determine writeIntrThreshold 23542475Snsouch * empty the FIFO until serviceIntr is set 23642475Snsouch */ 23742475Snsouch for (i=ppc->ppc_fifo; i>0; i--) { 23842475Snsouch if (r_fifo(ppc) != (char)(ppc->ppc_fifo-i)) { 23987599Sobrien LOG_PPC(__func__, ppc, "invalid data in FIFO"); 24042475Snsouch goto error; 24142475Snsouch } 24242475Snsouch if (r_ecr(ppc) & PPC_SERVICE_INTR) { 24342475Snsouch /* writeIntrThreshold reached */ 24442475Snsouch ppc->ppc_wthr = ppc->ppc_fifo - i+1; 24542475Snsouch } 24642475Snsouch /* if FIFO empty before the last byte, error */ 24742475Snsouch if (i>1 && (r_ecr(ppc) & PPC_FIFO_EMPTY)) { 24887599Sobrien LOG_PPC(__func__, ppc, "data lost in FIFO"); 24942475Snsouch goto error; 25042475Snsouch } 25142475Snsouch } 25242475Snsouch 25342475Snsouch /* FIFO must be empty after the last byte */ 25442475Snsouch if (!(r_ecr(ppc) & PPC_FIFO_EMPTY)) { 25587599Sobrien LOG_PPC(__func__, ppc, "can't empty the FIFO"); 25642475Snsouch goto error; 25742475Snsouch } 258185003Sjhb 25942475Snsouch w_ctr(ppc, ctr_sav); 26042475Snsouch w_ecr(ppc, ecr_sav); 26142475Snsouch 26242475Snsouch return (0); 26342475Snsouch 26442475Snsoucherror: 26542475Snsouch w_ctr(ppc, ctr_sav); 26642475Snsouch w_ecr(ppc, ecr_sav); 26742475Snsouch 26842475Snsouch return (EINVAL); 26928221Smsmith} 27028221Smsmith 27138061Smsmithstatic int 27238061Smsmithppc_detect_port(struct ppc_data *ppc) 27338061Smsmith{ 27438061Smsmith 27538061Smsmith w_ctr(ppc, 0x0c); /* To avoid missing PS2 ports */ 27638061Smsmith w_dtr(ppc, 0xaa); 27742482Snsouch if (r_dtr(ppc) != 0xaa) 27838061Smsmith return (0); 27938061Smsmith 28038061Smsmith return (1); 28138061Smsmith} 28238061Smsmith 28328221Smsmith/* 28455939Snsouch * EPP timeout, according to the PC87332 manual 28555939Snsouch * Semantics of clearing EPP timeout bit. 28655939Snsouch * PC87332 - reading SPP_STR does it... 28755939Snsouch * SMC - write 1 to EPP timeout bit XXX 28855939Snsouch * Others - (?) write 0 to EPP timeout bit 28955939Snsouch */ 29055939Snsouchstatic void 29155939Snsouchppc_reset_epp_timeout(struct ppc_data *ppc) 29255939Snsouch{ 29355939Snsouch register char r; 29455939Snsouch 29555939Snsouch r = r_str(ppc); 29655939Snsouch w_str(ppc, r | 0x1); 29755939Snsouch w_str(ppc, r & 0xfe); 29855939Snsouch 29955939Snsouch return; 30055939Snsouch} 30155939Snsouch 30255939Snsouchstatic int 30355939Snsouchppc_check_epp_timeout(struct ppc_data *ppc) 30455939Snsouch{ 30555939Snsouch ppc_reset_epp_timeout(ppc); 30655939Snsouch 30755939Snsouch return (!(r_str(ppc) & TIMEOUT)); 30855939Snsouch} 30955939Snsouch 31055939Snsouch/* 31155939Snsouch * Configure current operating mode 31255939Snsouch */ 31355939Snsouchstatic int 31455939Snsouchppc_generic_setmode(struct ppc_data *ppc, int mode) 31555939Snsouch{ 31655939Snsouch u_char ecr = 0; 31755939Snsouch 31855939Snsouch /* check if mode is available */ 31955939Snsouch if (mode && !(ppc->ppc_avm & mode)) 32055939Snsouch return (EINVAL); 32155939Snsouch 32255939Snsouch /* if ECP mode, configure ecr register */ 32371622Snsouch if ((ppc->ppc_avm & PPB_ECP) || (ppc->ppc_dtm & PPB_ECP)) { 32455939Snsouch /* return to byte mode (keeping direction bit), 32555939Snsouch * no interrupt, no DMA to be able to change to 32655939Snsouch * ECP 32755939Snsouch */ 32855939Snsouch w_ecr(ppc, PPC_ECR_RESET); 32955939Snsouch ecr = PPC_DISABLE_INTR; 33055939Snsouch 33155939Snsouch if (mode & PPB_EPP) 33255939Snsouch return (EINVAL); 33355939Snsouch else if (mode & PPB_ECP) 33455939Snsouch /* select ECP mode */ 33555939Snsouch ecr |= PPC_ECR_ECP; 33655939Snsouch else if (mode & PPB_PS2) 33755939Snsouch /* select PS2 mode with ECP */ 33855939Snsouch ecr |= PPC_ECR_PS2; 33955939Snsouch else 34055939Snsouch /* select COMPATIBLE/NIBBLE mode */ 34155939Snsouch ecr |= PPC_ECR_STD; 34255939Snsouch 34355939Snsouch w_ecr(ppc, ecr); 34455939Snsouch } 34555939Snsouch 34655939Snsouch ppc->ppc_mode = mode; 34755939Snsouch 34855939Snsouch return (0); 34955939Snsouch} 35055939Snsouch 35155939Snsouch/* 35255939Snsouch * The ppc driver is free to choose options like FIFO or DMA 35355939Snsouch * if ECP mode is available. 35455939Snsouch * 35555939Snsouch * The 'RAW' option allows the upper drivers to force the ppc mode 35655939Snsouch * even with FIFO, DMA available. 35755939Snsouch */ 35855939Snsouchstatic int 35955939Snsouchppc_smclike_setmode(struct ppc_data *ppc, int mode) 36055939Snsouch{ 36155939Snsouch u_char ecr = 0; 36255939Snsouch 36355939Snsouch /* check if mode is available */ 36455939Snsouch if (mode && !(ppc->ppc_avm & mode)) 36555939Snsouch return (EINVAL); 36655939Snsouch 36755939Snsouch /* if ECP mode, configure ecr register */ 36871622Snsouch if ((ppc->ppc_avm & PPB_ECP) || (ppc->ppc_dtm & PPB_ECP)) { 36955939Snsouch /* return to byte mode (keeping direction bit), 37055939Snsouch * no interrupt, no DMA to be able to change to 37155939Snsouch * ECP or EPP mode 37255939Snsouch */ 37355939Snsouch w_ecr(ppc, PPC_ECR_RESET); 37455939Snsouch ecr = PPC_DISABLE_INTR; 37555939Snsouch 37655939Snsouch if (mode & PPB_EPP) 37755939Snsouch /* select EPP mode */ 37855939Snsouch ecr |= PPC_ECR_EPP; 37955939Snsouch else if (mode & PPB_ECP) 38055939Snsouch /* select ECP mode */ 38155939Snsouch ecr |= PPC_ECR_ECP; 38255939Snsouch else if (mode & PPB_PS2) 38355939Snsouch /* select PS2 mode with ECP */ 38455939Snsouch ecr |= PPC_ECR_PS2; 38555939Snsouch else 38655939Snsouch /* select COMPATIBLE/NIBBLE mode */ 38755939Snsouch ecr |= PPC_ECR_STD; 38855939Snsouch 38955939Snsouch w_ecr(ppc, ecr); 39055939Snsouch } 39155939Snsouch 39255939Snsouch ppc->ppc_mode = mode; 39355939Snsouch 39455939Snsouch return (0); 39555939Snsouch} 39655939Snsouch 39755939Snsouch#ifdef PPC_PROBE_CHIPSET 39855939Snsouch/* 39928221Smsmith * ppc_pc873xx_detect 40028221Smsmith * 40128221Smsmith * Probe for a Natsemi PC873xx-family part. 40228221Smsmith * 40328221Smsmith * References in this function are to the National Semiconductor 40428221Smsmith * PC87332 datasheet TL/C/11930, May 1995 revision. 40528221Smsmith */ 40628221Smsmithstatic int pc873xx_basetab[] = {0x0398, 0x026e, 0x015c, 0x002e, 0}; 40728221Smsmithstatic int pc873xx_porttab[] = {0x0378, 0x03bc, 0x0278, 0}; 40840784Snsouchstatic int pc873xx_irqtab[] = {5, 7, 5, 0}; 40928221Smsmith 41040784Snsouchstatic int pc873xx_regstab[] = { 41140784Snsouch PC873_FER, PC873_FAR, PC873_PTR, 41240784Snsouch PC873_FCR, PC873_PCR, PC873_PMC, 41340784Snsouch PC873_TUP, PC873_SID, PC873_PNP0, 41440784Snsouch PC873_PNP1, PC873_LPTBA, -1 41540784Snsouch}; 41640784Snsouch 41740784Snsouchstatic char *pc873xx_rnametab[] = { 41840784Snsouch "FER", "FAR", "PTR", "FCR", "PCR", 41940784Snsouch "PMC", "TUP", "SID", "PNP0", "PNP1", 42040784Snsouch "LPTBA", NULL 42140784Snsouch}; 42240784Snsouch 42328221Smsmithstatic int 42438061Smsmithppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never forced */ 42528221Smsmith{ 42628221Smsmith static int index = 0; 42741591Sarchie int idport, irq; 42840784Snsouch int ptr, pcr, val, i; 429185003Sjhb 43028221Smsmith while ((idport = pc873xx_basetab[index++])) { 431185003Sjhb 43228221Smsmith /* XXX should check first to see if this location is already claimed */ 43328221Smsmith 43428221Smsmith /* 43540784Snsouch * Pull the 873xx through the power-on ID cycle (2.2,1.). 43640784Snsouch * We can't use this to locate the chip as it may already have 43740784Snsouch * been used by the BIOS. 43828221Smsmith */ 43940784Snsouch (void)inb(idport); (void)inb(idport); 44040784Snsouch (void)inb(idport); (void)inb(idport); 44128221Smsmith 44228221Smsmith /* 44328221Smsmith * Read the SID byte. Possible values are : 44428221Smsmith * 44540784Snsouch * 01010xxx PC87334 44628221Smsmith * 0001xxxx PC87332 44728221Smsmith * 01110xxx PC87306 44863624Sdfr * 00110xxx PC87303 44928221Smsmith */ 45028221Smsmith outb(idport, PC873_SID); 45128221Smsmith val = inb(idport + 1); 45228221Smsmith if ((val & 0xf0) == 0x10) { 45355939Snsouch ppc->ppc_model = NS_PC87332; 45428221Smsmith } else if ((val & 0xf8) == 0x70) { 45555939Snsouch ppc->ppc_model = NS_PC87306; 45640784Snsouch } else if ((val & 0xf8) == 0x50) { 45755939Snsouch ppc->ppc_model = NS_PC87334; 45863624Sdfr } else if ((val & 0xf8) == 0x40) { /* Should be 0x30 by the 45963624Sdfr documentation, but probing 46063624Sdfr yielded 0x40... */ 46163624Sdfr ppc->ppc_model = NS_PC87303; 46228221Smsmith } else { 46328221Smsmith if (bootverbose && (val != 0xff)) 46428221Smsmith printf("PC873xx probe at 0x%x got unknown ID 0x%x\n", idport, val); 46528221Smsmith continue ; /* not recognised */ 46628221Smsmith } 46740784Snsouch 46840784Snsouch /* print registers */ 46940784Snsouch if (bootverbose) { 47040784Snsouch printf("PC873xx"); 47140784Snsouch for (i=0; pc873xx_regstab[i] != -1; i++) { 47240784Snsouch outb(idport, pc873xx_regstab[i]); 47340784Snsouch printf(" %s=0x%x", pc873xx_rnametab[i], 47440784Snsouch inb(idport + 1) & 0xff); 47540784Snsouch } 47640784Snsouch printf("\n"); 47740784Snsouch } 478185003Sjhb 47928221Smsmith /* 48040784Snsouch * We think we have one. Is it enabled and where we want it to be? 48128221Smsmith */ 48228221Smsmith outb(idport, PC873_FER); 48328221Smsmith val = inb(idport + 1); 48428221Smsmith if (!(val & PC873_PPENABLE)) { 48528221Smsmith if (bootverbose) 48628221Smsmith printf("PC873xx parallel port disabled\n"); 48728221Smsmith continue; 48828221Smsmith } 48928221Smsmith outb(idport, PC873_FAR); 49063624Sdfr val = inb(idport + 1); 49128221Smsmith /* XXX we should create a driver instance for every port found */ 49263624Sdfr if (pc873xx_porttab[val & 0x3] != ppc->ppc_base) { 49363624Sdfr 49463624Sdfr /* First try to change the port address to that requested... */ 49563624Sdfr 496187576Sjhb switch (ppc->ppc_base) { 49763624Sdfr case 0x378: 49863624Sdfr val &= 0xfc; 49963624Sdfr break; 50063624Sdfr 50163624Sdfr case 0x3bc: 50263624Sdfr val &= 0xfd; 50363624Sdfr break; 50463624Sdfr 50563624Sdfr case 0x278: 50663624Sdfr val &= 0xfe; 50763624Sdfr break; 50863624Sdfr 50963624Sdfr default: 51063624Sdfr val &= 0xfd; 51163624Sdfr break; 51263624Sdfr } 51363624Sdfr 51463624Sdfr outb(idport, PC873_FAR); 51563624Sdfr outb(idport + 1, val); 51663624Sdfr outb(idport + 1, val); 51763624Sdfr 51863624Sdfr /* Check for success by reading back the value we supposedly 51963624Sdfr wrote and comparing...*/ 52063624Sdfr 52163624Sdfr outb(idport, PC873_FAR); 52263624Sdfr val = inb(idport + 1) & 0x3; 52363624Sdfr 52463624Sdfr /* If we fail, report the failure... */ 52563624Sdfr 52663624Sdfr if (pc873xx_porttab[val] != ppc->ppc_base) { 52763624Sdfr if (bootverbose) 52863624Sdfr printf("PC873xx at 0x%x not for driver at port 0x%x\n", 52963624Sdfr pc873xx_porttab[val], ppc->ppc_base); 53063624Sdfr } 53128221Smsmith continue; 53228221Smsmith } 53340784Snsouch 53440784Snsouch outb(idport, PC873_PTR); 535185003Sjhb ptr = inb(idport + 1); 53640784Snsouch 53740784Snsouch /* get irq settings */ 53840784Snsouch if (ppc->ppc_base == 0x378) 53940784Snsouch irq = (ptr & PC873_LPTBIRQ7) ? 7 : 5; 54040784Snsouch else 54140784Snsouch irq = pc873xx_irqtab[val]; 54240784Snsouch 54340784Snsouch if (bootverbose) 54440784Snsouch printf("PC873xx irq %d at 0x%x\n", irq, ppc->ppc_base); 545185003Sjhb 54640784Snsouch /* 54740784Snsouch * Check if irq settings are correct 54828221Smsmith */ 54940784Snsouch if (irq != ppc->ppc_irq) { 55040784Snsouch /* 55140784Snsouch * If the chipset is not locked and base address is 0x378, 55240784Snsouch * we have another chance 55340784Snsouch */ 55440784Snsouch if (ppc->ppc_base == 0x378 && !(ptr & PC873_CFGLOCK)) { 55540784Snsouch if (ppc->ppc_irq == 7) { 55640784Snsouch outb(idport + 1, (ptr | PC873_LPTBIRQ7)); 55740784Snsouch outb(idport + 1, (ptr | PC873_LPTBIRQ7)); 55840784Snsouch } else { 55940784Snsouch outb(idport + 1, (ptr & ~PC873_LPTBIRQ7)); 56040784Snsouch outb(idport + 1, (ptr & ~PC873_LPTBIRQ7)); 56140784Snsouch } 56240784Snsouch if (bootverbose) 56340784Snsouch printf("PC873xx irq set to %d\n", ppc->ppc_irq); 56440784Snsouch } else { 56540784Snsouch if (bootverbose) 56640784Snsouch printf("PC873xx sorry, can't change irq setting\n"); 56728221Smsmith } 56828221Smsmith } else { 56940784Snsouch if (bootverbose) 57040784Snsouch printf("PC873xx irq settings are correct\n"); 57140784Snsouch } 57240784Snsouch 57340784Snsouch outb(idport, PC873_PCR); 57440784Snsouch pcr = inb(idport + 1); 575185003Sjhb 57640784Snsouch if ((ptr & PC873_CFGLOCK) || !chipset_mode) { 57728221Smsmith if (bootverbose) 57840784Snsouch printf("PC873xx %s", (ptr & PC873_CFGLOCK)?"locked":"unlocked"); 57928221Smsmith 58040784Snsouch ppc->ppc_avm |= PPB_NIBBLE; 58140784Snsouch if (bootverbose) 58240784Snsouch printf(", NIBBLE"); 58340784Snsouch 58440784Snsouch if (pcr & PC873_EPPEN) { 585185003Sjhb ppc->ppc_avm |= PPB_EPP; 58640784Snsouch 58728221Smsmith if (bootverbose) 58840784Snsouch printf(", EPP"); 58928221Smsmith 59040784Snsouch if (pcr & PC873_EPP19) 59140784Snsouch ppc->ppc_epp = EPP_1_9; 59240784Snsouch else 59340784Snsouch ppc->ppc_epp = EPP_1_7; 59440784Snsouch 59555939Snsouch if ((ppc->ppc_model == NS_PC87332) && bootverbose) { 59640784Snsouch outb(idport, PC873_PTR); 59740784Snsouch ptr = inb(idport + 1); 59840784Snsouch if (ptr & PC873_EPPRDIR) 59940784Snsouch printf(", Regular mode"); 60040784Snsouch else 60140784Snsouch printf(", Automatic mode"); 60240784Snsouch } 60340784Snsouch } else if (pcr & PC873_ECPEN) { 60440784Snsouch ppc->ppc_avm |= PPB_ECP; 60528221Smsmith if (bootverbose) 60640784Snsouch printf(", ECP"); 60728221Smsmith 60840784Snsouch if (pcr & PC873_ECPCLK) { /* XXX */ 60940784Snsouch ppc->ppc_avm |= PPB_PS2; 61040784Snsouch if (bootverbose) 61140784Snsouch printf(", PS/2"); 61240784Snsouch } 61340784Snsouch } else { 61428221Smsmith outb(idport, PC873_PTR); 61540784Snsouch ptr = inb(idport + 1); 61640784Snsouch if (ptr & PC873_EXTENDED) { 61740784Snsouch ppc->ppc_avm |= PPB_SPP; 618185003Sjhb if (bootverbose) 619185003Sjhb printf(", SPP"); 62040784Snsouch } 62140784Snsouch } 62240784Snsouch } else { 62328221Smsmith if (bootverbose) 62440784Snsouch printf("PC873xx unlocked"); 62528221Smsmith 62640784Snsouch if (chipset_mode & PPB_ECP) { 62740784Snsouch if ((chipset_mode & PPB_EPP) && bootverbose) 62840784Snsouch printf(", ECP+EPP not supported"); 62940784Snsouch 63040784Snsouch pcr &= ~PC873_EPPEN; 63140784Snsouch pcr |= (PC873_ECPEN | PC873_ECPCLK); /* XXX */ 63240784Snsouch outb(idport + 1, pcr); 63340784Snsouch outb(idport + 1, pcr); 63440784Snsouch 63540784Snsouch if (bootverbose) 63640784Snsouch printf(", ECP"); 63740784Snsouch 63840784Snsouch } else if (chipset_mode & PPB_EPP) { 63940784Snsouch pcr &= ~(PC873_ECPEN | PC873_ECPCLK); 64040784Snsouch pcr |= (PC873_EPPEN | PC873_EPP19); 64140784Snsouch outb(idport + 1, pcr); 64240784Snsouch outb(idport + 1, pcr); 64340784Snsouch 64440784Snsouch ppc->ppc_epp = EPP_1_9; /* XXX */ 64540784Snsouch 64640784Snsouch if (bootverbose) 64740784Snsouch printf(", EPP1.9"); 64840784Snsouch 64940784Snsouch /* enable automatic direction turnover */ 65055939Snsouch if (ppc->ppc_model == NS_PC87332) { 65140784Snsouch outb(idport, PC873_PTR); 65240784Snsouch ptr = inb(idport + 1); 65340784Snsouch ptr &= ~PC873_EPPRDIR; 65440784Snsouch outb(idport + 1, ptr); 65540784Snsouch outb(idport + 1, ptr); 65640784Snsouch 65740784Snsouch if (bootverbose) 65840784Snsouch printf(", Automatic mode"); 65940784Snsouch } 66040784Snsouch } else { 66140784Snsouch pcr &= ~(PC873_ECPEN | PC873_ECPCLK | PC873_EPPEN); 66240784Snsouch outb(idport + 1, pcr); 66340784Snsouch outb(idport + 1, pcr); 66440784Snsouch 66540784Snsouch /* configure extended bit in PTR */ 66640784Snsouch outb(idport, PC873_PTR); 66740784Snsouch ptr = inb(idport + 1); 66840784Snsouch 66940784Snsouch if (chipset_mode & PPB_PS2) { 67040784Snsouch ptr |= PC873_EXTENDED; 67140784Snsouch 67240784Snsouch if (bootverbose) 67340784Snsouch printf(", PS/2"); 674185003Sjhb 67540784Snsouch } else { 67640784Snsouch /* default to NIBBLE mode */ 67740784Snsouch ptr &= ~PC873_EXTENDED; 67840784Snsouch 67940784Snsouch if (bootverbose) 68040784Snsouch printf(", NIBBLE"); 68140784Snsouch } 68240784Snsouch outb(idport + 1, ptr); 68340784Snsouch outb(idport + 1, ptr); 68440784Snsouch } 68540784Snsouch 68640784Snsouch ppc->ppc_avm = chipset_mode; 68728221Smsmith } 68838061Smsmith 68940784Snsouch if (bootverbose) 69040784Snsouch printf("\n"); 69140784Snsouch 69255939Snsouch ppc->ppc_type = PPC_TYPE_GENERIC; 69355939Snsouch ppc_generic_setmode(ppc, chipset_mode); 69440784Snsouch 69538061Smsmith return(chipset_mode); 69628221Smsmith } 69738061Smsmith return(-1); 69828221Smsmith} 69928221Smsmith 70028221Smsmith/* 70128221Smsmith * ppc_smc37c66xgt_detect 70228221Smsmith * 70328221Smsmith * SMC FDC37C66xGT configuration. 70428221Smsmith */ 70528221Smsmithstatic int 70638061Smsmithppc_smc37c66xgt_detect(struct ppc_data *ppc, int chipset_mode) 70728221Smsmith{ 708247066Simp int i; 70943460Snsouch u_char r; 71028221Smsmith int type = -1; 71128221Smsmith int csr = SMC66x_CSR; /* initial value is 0x3F0 */ 71228221Smsmith 71328221Smsmith int port_address[] = { -1 /* disabled */ , 0x3bc, 0x378, 0x278 }; 71428221Smsmith 71528221Smsmith 71628221Smsmith#define cio csr+1 /* config IO port is either 0x3F1 or 0x371 */ 71728221Smsmith 71828221Smsmith /* 71928221Smsmith * Detection: enter configuration mode and read CRD register. 72028221Smsmith */ 721247066Simp PPC_CONFIG_LOCK(ppc); 72228221Smsmith outb(csr, SMC665_iCODE); 72328221Smsmith outb(csr, SMC665_iCODE); 724247066Simp PPC_CONFIG_UNLOCK(ppc); 72528221Smsmith 72628221Smsmith outb(csr, 0xd); 72728221Smsmith if (inb(cio) == 0x65) { 72828221Smsmith type = SMC_37C665GT; 72928221Smsmith goto config; 73028221Smsmith } 73128221Smsmith 73228221Smsmith for (i = 0; i < 2; i++) { 733247066Simp PPC_CONFIG_LOCK(ppc); 73428221Smsmith outb(csr, SMC666_iCODE); 73528221Smsmith outb(csr, SMC666_iCODE); 736247066Simp PPC_CONFIG_UNLOCK(ppc); 73728221Smsmith 73828221Smsmith outb(csr, 0xd); 73928221Smsmith if (inb(cio) == 0x66) { 74028221Smsmith type = SMC_37C666GT; 74128221Smsmith break; 74228221Smsmith } 74328221Smsmith 74428221Smsmith /* Another chance, CSR may be hard-configured to be at 0x370 */ 74528221Smsmith csr = SMC666_CSR; 74628221Smsmith } 74728221Smsmith 74828221Smsmithconfig: 74928221Smsmith /* 75028221Smsmith * If chipset not found, do not continue. 75128221Smsmith */ 752247066Simp if (type == -1) { 753247066Simp outb(csr, 0xaa); /* end config mode */ 75438061Smsmith return (-1); 755247066Simp } 75628221Smsmith 75728221Smsmith /* select CR1 */ 75828221Smsmith outb(csr, 0x1); 75928221Smsmith 76028221Smsmith /* read the port's address: bits 0 and 1 of CR1 */ 76128221Smsmith r = inb(cio) & SMC_CR1_ADDR; 762247066Simp if (port_address[(int)r] != ppc->ppc_base) { 763247066Simp outb(csr, 0xaa); /* end config mode */ 76438061Smsmith return (-1); 765247066Simp } 76628221Smsmith 76755939Snsouch ppc->ppc_model = type; 76828221Smsmith 76928221Smsmith /* 77028221Smsmith * CR1 and CR4 registers bits 3 and 0/1 for mode configuration 77138061Smsmith * If SPP mode is detected, try to set ECP+EPP mode 77228221Smsmith */ 77328221Smsmith 77438061Smsmith if (bootverbose) { 77538061Smsmith outb(csr, 0x1); 776184176Sjhb device_printf(ppc->ppc_dev, "SMC registers CR1=0x%x", 777184176Sjhb inb(cio) & 0xff); 77838061Smsmith 77938061Smsmith outb(csr, 0x4); 78038061Smsmith printf(" CR4=0x%x", inb(cio) & 0xff); 78138061Smsmith } 78238061Smsmith 78338061Smsmith /* select CR1 */ 78428221Smsmith outb(csr, 0x1); 78528221Smsmith 78638061Smsmith if (!chipset_mode) { 78728221Smsmith /* autodetect mode */ 78828221Smsmith 78938061Smsmith /* 666GT is ~certainly~ hardwired to an extended ECP+EPP mode */ 79038061Smsmith if (type == SMC_37C666GT) { 79138061Smsmith ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP; 79238761Snsouch if (bootverbose) 79338761Snsouch printf(" configuration hardwired, supposing " \ 79438761Snsouch "ECP+EPP SPP"); 79528221Smsmith 79638061Smsmith } else 79738061Smsmith if ((inb(cio) & SMC_CR1_MODE) == 0) { 79828221Smsmith /* already in extended parallel port mode, read CR4 */ 79928221Smsmith outb(csr, 0x4); 80028221Smsmith r = (inb(cio) & SMC_CR4_EMODE); 80128221Smsmith 80228221Smsmith switch (r) { 80328221Smsmith case SMC_SPP: 80438061Smsmith ppc->ppc_avm |= PPB_SPP; 80538761Snsouch if (bootverbose) 80638761Snsouch printf(" SPP"); 80728221Smsmith break; 80828221Smsmith 80928221Smsmith case SMC_EPPSPP: 81038061Smsmith ppc->ppc_avm |= PPB_EPP | PPB_SPP; 81138761Snsouch if (bootverbose) 81238761Snsouch printf(" EPP SPP"); 81328221Smsmith break; 81428221Smsmith 81528221Smsmith case SMC_ECP: 81638061Smsmith ppc->ppc_avm |= PPB_ECP | PPB_SPP; 81738761Snsouch if (bootverbose) 81838761Snsouch printf(" ECP SPP"); 81928221Smsmith break; 82028221Smsmith 82128221Smsmith case SMC_ECPEPP: 82238061Smsmith ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP; 82338761Snsouch if (bootverbose) 82438761Snsouch printf(" ECP+EPP SPP"); 82528221Smsmith break; 82628221Smsmith } 82738061Smsmith } else { 82838061Smsmith /* not an extended port mode */ 82938061Smsmith ppc->ppc_avm |= PPB_SPP; 83038761Snsouch if (bootverbose) 83138761Snsouch printf(" SPP"); 83238061Smsmith } 83338061Smsmith 83428221Smsmith } else { 83528221Smsmith /* mode forced */ 83639135Snsouch ppc->ppc_avm = chipset_mode; 83728221Smsmith 83838061Smsmith /* 666GT is ~certainly~ hardwired to an extended ECP+EPP mode */ 83928221Smsmith if (type == SMC_37C666GT) 84028221Smsmith goto end_detect; 84128221Smsmith 84228221Smsmith r = inb(cio); 84338061Smsmith if ((chipset_mode & (PPB_ECP | PPB_EPP)) == 0) { 84438061Smsmith /* do not use ECP when the mode is not forced to */ 84528221Smsmith outb(cio, r | SMC_CR1_MODE); 84638761Snsouch if (bootverbose) 84738761Snsouch printf(" SPP"); 84828221Smsmith } else { 84928221Smsmith /* an extended mode is selected */ 85028221Smsmith outb(cio, r & ~SMC_CR1_MODE); 85128221Smsmith 85228221Smsmith /* read CR4 register and reset mode field */ 85328221Smsmith outb(csr, 0x4); 85428221Smsmith r = inb(cio) & ~SMC_CR4_EMODE; 85528221Smsmith 85638061Smsmith if (chipset_mode & PPB_ECP) { 85738061Smsmith if (chipset_mode & PPB_EPP) { 85838061Smsmith outb(cio, r | SMC_ECPEPP); 85938761Snsouch if (bootverbose) 86038761Snsouch printf(" ECP+EPP"); 86138061Smsmith } else { 86238061Smsmith outb(cio, r | SMC_ECP); 86338761Snsouch if (bootverbose) 86438761Snsouch printf(" ECP"); 86538061Smsmith } 86638061Smsmith } else { 86738061Smsmith /* PPB_EPP is set */ 86828221Smsmith outb(cio, r | SMC_EPPSPP); 86938761Snsouch if (bootverbose) 87038761Snsouch printf(" EPP SPP"); 87128221Smsmith } 87228221Smsmith } 87338061Smsmith ppc->ppc_avm = chipset_mode; 87428221Smsmith } 87528221Smsmith 87642475Snsouch /* set FIFO threshold to 16 */ 87742475Snsouch if (ppc->ppc_avm & PPB_ECP) { 87842475Snsouch /* select CRA */ 87942475Snsouch outb(csr, 0xa); 88042475Snsouch outb(cio, 16); 88142475Snsouch } 88242475Snsouch 88328221Smsmithend_detect: 88438061Smsmith 88538061Smsmith if (bootverbose) 88638061Smsmith printf ("\n"); 88738061Smsmith 88839135Snsouch if (ppc->ppc_avm & PPB_EPP) { 88928221Smsmith /* select CR4 */ 89028221Smsmith outb(csr, 0x4); 89128221Smsmith r = inb(cio); 89228221Smsmith 89328221Smsmith /* 89428221Smsmith * Set the EPP protocol... 89528221Smsmith * Low=EPP 1.9 (1284 standard) and High=EPP 1.7 89628221Smsmith */ 89728221Smsmith if (ppc->ppc_epp == EPP_1_9) 89828221Smsmith outb(cio, (r & ~SMC_CR4_EPPTYPE)); 89928221Smsmith else 90028221Smsmith outb(cio, (r | SMC_CR4_EPPTYPE)); 90128221Smsmith } 90228221Smsmith 903247066Simp outb(csr, 0xaa); /* end config mode */ 90428221Smsmith 90555939Snsouch ppc->ppc_type = PPC_TYPE_SMCLIKE; 90655939Snsouch ppc_smclike_setmode(ppc, chipset_mode); 90728221Smsmith 90838061Smsmith return (chipset_mode); 90938061Smsmith} 91028221Smsmith 91138061Smsmith/* 91263403Sdfr * SMC FDC37C935 configuration 91363403Sdfr * Found on many Alpha machines 91463403Sdfr */ 91563403Sdfrstatic int 91663403Sdfrppc_smc37c935_detect(struct ppc_data *ppc, int chipset_mode) 91763403Sdfr{ 91863403Sdfr int type = -1; 91963403Sdfr 920247066Simp PPC_CONFIG_LOCK(ppc); 92163403Sdfr outb(SMC935_CFG, 0x55); /* enter config mode */ 92263403Sdfr outb(SMC935_CFG, 0x55); 923247066Simp PPC_CONFIG_UNLOCK(ppc); 92463403Sdfr 92563403Sdfr outb(SMC935_IND, SMC935_ID); /* check device id */ 92663403Sdfr if (inb(SMC935_DAT) == 0x2) 92763403Sdfr type = SMC_37C935; 92863403Sdfr 92963403Sdfr if (type == -1) { 93063403Sdfr outb(SMC935_CFG, 0xaa); /* exit config mode */ 93163403Sdfr return (-1); 93263403Sdfr } 93363403Sdfr 93463403Sdfr ppc->ppc_model = type; 93563403Sdfr 93663403Sdfr outb(SMC935_IND, SMC935_LOGDEV); /* select parallel port, */ 937185003Sjhb outb(SMC935_DAT, 3); /* which is logical device 3 */ 93863403Sdfr 93963403Sdfr /* set io port base */ 94063403Sdfr outb(SMC935_IND, SMC935_PORTHI); 94163403Sdfr outb(SMC935_DAT, (u_char)((ppc->ppc_base & 0xff00) >> 8)); 94263403Sdfr outb(SMC935_IND, SMC935_PORTLO); 94363403Sdfr outb(SMC935_DAT, (u_char)(ppc->ppc_base & 0xff)); 94463403Sdfr 94563403Sdfr if (!chipset_mode) 94663403Sdfr ppc->ppc_avm = PPB_COMPATIBLE; /* default mode */ 94763403Sdfr else { 94863403Sdfr ppc->ppc_avm = chipset_mode; 94963403Sdfr outb(SMC935_IND, SMC935_PPMODE); 95063403Sdfr outb(SMC935_DAT, SMC935_CENT); /* start in compatible mode */ 95163403Sdfr 95263403Sdfr /* SPP + EPP or just plain SPP */ 95363403Sdfr if (chipset_mode & (PPB_SPP)) { 95463403Sdfr if (chipset_mode & PPB_EPP) { 95563403Sdfr if (ppc->ppc_epp == EPP_1_9) { 95663403Sdfr outb(SMC935_IND, SMC935_PPMODE); 95763403Sdfr outb(SMC935_DAT, SMC935_EPP19SPP); 95863403Sdfr } 95963403Sdfr if (ppc->ppc_epp == EPP_1_7) { 96063403Sdfr outb(SMC935_IND, SMC935_PPMODE); 96163403Sdfr outb(SMC935_DAT, SMC935_EPP17SPP); 96263403Sdfr } 96363403Sdfr } else { 96463403Sdfr outb(SMC935_IND, SMC935_PPMODE); 96563403Sdfr outb(SMC935_DAT, SMC935_SPP); 96663403Sdfr } 96763403Sdfr } 96863403Sdfr 96963403Sdfr /* ECP + EPP or just plain ECP */ 97063403Sdfr if (chipset_mode & PPB_ECP) { 97163403Sdfr if (chipset_mode & PPB_EPP) { 97263403Sdfr if (ppc->ppc_epp == EPP_1_9) { 97363403Sdfr outb(SMC935_IND, SMC935_PPMODE); 97463403Sdfr outb(SMC935_DAT, SMC935_ECPEPP19); 97563403Sdfr } 97663403Sdfr if (ppc->ppc_epp == EPP_1_7) { 97763403Sdfr outb(SMC935_IND, SMC935_PPMODE); 97863403Sdfr outb(SMC935_DAT, SMC935_ECPEPP17); 97963403Sdfr } 98063403Sdfr } else { 98163403Sdfr outb(SMC935_IND, SMC935_PPMODE); 98263403Sdfr outb(SMC935_DAT, SMC935_ECP); 98363403Sdfr } 98463403Sdfr } 98563403Sdfr } 98663403Sdfr 98763403Sdfr outb(SMC935_CFG, 0xaa); /* exit config mode */ 98863403Sdfr 98963403Sdfr ppc->ppc_type = PPC_TYPE_SMCLIKE; 99063403Sdfr ppc_smclike_setmode(ppc, chipset_mode); 99163403Sdfr 99263403Sdfr return (chipset_mode); 99363403Sdfr} 99463403Sdfr 99563403Sdfr/* 99638061Smsmith * Winbond W83877F stuff 99738061Smsmith * 99838061Smsmith * EFER: extended function enable register 99938061Smsmith * EFIR: extended function index register 100038061Smsmith * EFDR: extended function data register 100138061Smsmith */ 100238061Smsmith#define efir ((efer == 0x250) ? 0x251 : 0x3f0) 100338061Smsmith#define efdr ((efer == 0x250) ? 0x252 : 0x3f1) 100438061Smsmith 100538061Smsmithstatic int w83877f_efers[] = { 0x250, 0x3f0, 0x3f0, 0x250 }; 1006185003Sjhbstatic int w83877f_keys[] = { 0x89, 0x86, 0x87, 0x88 }; 100738061Smsmithstatic int w83877f_keyiter[] = { 1, 2, 2, 1 }; 100838061Smsmithstatic int w83877f_hefs[] = { WINB_HEFERE, WINB_HEFRAS, WINB_HEFERE | WINB_HEFRAS, 0 }; 100938061Smsmith 101038061Smsmithstatic int 101138061Smsmithppc_w83877f_detect(struct ppc_data *ppc, int chipset_mode) 101238061Smsmith{ 101341591Sarchie int i, j, efer; 101438061Smsmith unsigned char r, hefere, hefras; 101538061Smsmith 101638061Smsmith for (i = 0; i < 4; i ++) { 101738061Smsmith /* first try to enable configuration registers */ 101838061Smsmith efer = w83877f_efers[i]; 101938061Smsmith 102038061Smsmith /* write the key to the EFER */ 102138061Smsmith for (j = 0; j < w83877f_keyiter[i]; j ++) 102238061Smsmith outb (efer, w83877f_keys[i]); 102338061Smsmith 102438061Smsmith /* then check HEFERE and HEFRAS bits */ 102538061Smsmith outb (efir, 0x0c); 102638061Smsmith hefere = inb(efdr) & WINB_HEFERE; 102738061Smsmith 102838061Smsmith outb (efir, 0x16); 102938061Smsmith hefras = inb(efdr) & WINB_HEFRAS; 103038061Smsmith 103128221Smsmith /* 103238061Smsmith * HEFRAS HEFERE 103338061Smsmith * 0 1 write 89h to 250h (power-on default) 103438061Smsmith * 1 0 write 86h twice to 3f0h 103538061Smsmith * 1 1 write 87h twice to 3f0h 103638061Smsmith * 0 0 write 88h to 250h 103728221Smsmith */ 103838061Smsmith if ((hefere | hefras) == w83877f_hefs[i]) 103938061Smsmith goto found; 104038061Smsmith } 104128221Smsmith 104238061Smsmith return (-1); /* failed */ 104338061Smsmith 104438061Smsmithfound: 104538061Smsmith /* check base port address - read from CR23 */ 104638061Smsmith outb(efir, 0x23); 104738061Smsmith if (ppc->ppc_base != inb(efdr) * 4) /* 4 bytes boundaries */ 104838061Smsmith return (-1); 104938061Smsmith 105038061Smsmith /* read CHIP ID from CR9/bits0-3 */ 105138061Smsmith outb(efir, 0x9); 105238061Smsmith 105338061Smsmith switch (inb(efdr) & WINB_CHIPID) { 105438061Smsmith case WINB_W83877F_ID: 105555939Snsouch ppc->ppc_model = WINB_W83877F; 105638061Smsmith break; 105738061Smsmith 105838061Smsmith case WINB_W83877AF_ID: 105955939Snsouch ppc->ppc_model = WINB_W83877AF; 106038061Smsmith break; 106138061Smsmith 106238061Smsmith default: 106355939Snsouch ppc->ppc_model = WINB_UNKNOWN; 106428221Smsmith } 106528221Smsmith 106638061Smsmith if (bootverbose) { 106738061Smsmith /* dump of registers */ 1068184176Sjhb device_printf(ppc->ppc_dev, "0x%x - ", w83877f_keys[i]); 106938061Smsmith for (i = 0; i <= 0xd; i ++) { 107038061Smsmith outb(efir, i); 107138061Smsmith printf("0x%x ", inb(efdr)); 107238061Smsmith } 107338061Smsmith for (i = 0x10; i <= 0x17; i ++) { 107438061Smsmith outb(efir, i); 107538061Smsmith printf("0x%x ", inb(efdr)); 107638061Smsmith } 107738061Smsmith outb(efir, 0x1e); 107838061Smsmith printf("0x%x ", inb(efdr)); 107938061Smsmith for (i = 0x20; i <= 0x29; i ++) { 108038061Smsmith outb(efir, i); 108138061Smsmith printf("0x%x ", inb(efdr)); 108238061Smsmith } 108338061Smsmith printf("\n"); 108438061Smsmith } 108528221Smsmith 108655939Snsouch ppc->ppc_type = PPC_TYPE_GENERIC; 108738761Snsouch 108838061Smsmith if (!chipset_mode) { 108938061Smsmith /* autodetect mode */ 109028221Smsmith 109138061Smsmith /* select CR0 */ 109238061Smsmith outb(efir, 0x0); 109338061Smsmith r = inb(efdr) & (WINB_PRTMODS0 | WINB_PRTMODS1); 109428221Smsmith 109538061Smsmith /* select CR9 */ 109638061Smsmith outb(efir, 0x9); 109738061Smsmith r |= (inb(efdr) & WINB_PRTMODS2); 109838061Smsmith 109938061Smsmith switch (r) { 110038061Smsmith case WINB_W83757: 110138061Smsmith if (bootverbose) 1102184176Sjhb device_printf(ppc->ppc_dev, 1103184176Sjhb "W83757 compatible mode\n"); 110438061Smsmith return (-1); /* generic or SMC-like */ 110538061Smsmith 110638061Smsmith case WINB_EXTFDC: 110738061Smsmith case WINB_EXTADP: 110838061Smsmith case WINB_EXT2FDD: 110938061Smsmith case WINB_JOYSTICK: 111038061Smsmith if (bootverbose) 1111184176Sjhb device_printf(ppc->ppc_dev, 1112184130Sjhb "not in parallel port mode\n"); 111338061Smsmith return (-1); 111438061Smsmith 111538061Smsmith case (WINB_PARALLEL | WINB_EPP_SPP): 111638061Smsmith ppc->ppc_avm |= PPB_EPP | PPB_SPP; 111738761Snsouch if (bootverbose) 1118184176Sjhb device_printf(ppc->ppc_dev, "EPP SPP\n"); 111938061Smsmith break; 112038061Smsmith 112138061Smsmith case (WINB_PARALLEL | WINB_ECP): 112238061Smsmith ppc->ppc_avm |= PPB_ECP | PPB_SPP; 112338761Snsouch if (bootverbose) 1124184176Sjhb device_printf(ppc->ppc_dev, "ECP SPP\n"); 112538061Smsmith break; 112638061Smsmith 112738061Smsmith case (WINB_PARALLEL | WINB_ECP_EPP): 112838061Smsmith ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP; 112955939Snsouch ppc->ppc_type = PPC_TYPE_SMCLIKE; 113038761Snsouch 113138761Snsouch if (bootverbose) 1132184176Sjhb device_printf(ppc->ppc_dev, "ECP+EPP SPP\n"); 113338061Smsmith break; 113438061Smsmith default: 113587599Sobrien printf("%s: unknown case (0x%x)!\n", __func__, r); 113638061Smsmith } 113738061Smsmith 113838061Smsmith } else { 113938061Smsmith /* mode forced */ 114038061Smsmith 114138061Smsmith /* select CR9 and set PRTMODS2 bit */ 114238061Smsmith outb(efir, 0x9); 114338061Smsmith outb(efdr, inb(efdr) & ~WINB_PRTMODS2); 114438061Smsmith 114538061Smsmith /* select CR0 and reset PRTMODSx bits */ 114638061Smsmith outb(efir, 0x0); 114738061Smsmith outb(efdr, inb(efdr) & ~(WINB_PRTMODS0 | WINB_PRTMODS1)); 114838061Smsmith 114938061Smsmith if (chipset_mode & PPB_ECP) { 115038761Snsouch if (chipset_mode & PPB_EPP) { 115138061Smsmith outb(efdr, inb(efdr) | WINB_ECP_EPP); 115238761Snsouch if (bootverbose) 1153184176Sjhb device_printf(ppc->ppc_dev, 1154184176Sjhb "ECP+EPP\n"); 115538761Snsouch 115655939Snsouch ppc->ppc_type = PPC_TYPE_SMCLIKE; 115738761Snsouch 115838761Snsouch } else { 115938061Smsmith outb(efdr, inb(efdr) | WINB_ECP); 116038761Snsouch if (bootverbose) 1161184176Sjhb device_printf(ppc->ppc_dev, "ECP\n"); 116238761Snsouch } 116338061Smsmith } else { 116438061Smsmith /* select EPP_SPP otherwise */ 116538061Smsmith outb(efdr, inb(efdr) | WINB_EPP_SPP); 116638761Snsouch if (bootverbose) 1167184176Sjhb device_printf(ppc->ppc_dev, "EPP SPP\n"); 116838061Smsmith } 116938061Smsmith ppc->ppc_avm = chipset_mode; 117028221Smsmith } 117138761Snsouch 117238061Smsmith /* exit configuration mode */ 117338061Smsmith outb(efer, 0xaa); 117428221Smsmith 117555939Snsouch switch (ppc->ppc_type) { 117655939Snsouch case PPC_TYPE_SMCLIKE: 117755939Snsouch ppc_smclike_setmode(ppc, chipset_mode); 117855939Snsouch break; 117955939Snsouch default: 118055939Snsouch ppc_generic_setmode(ppc, chipset_mode); 118155939Snsouch break; 118255939Snsouch } 118328221Smsmith 118438061Smsmith return (chipset_mode); 118528221Smsmith} 118655939Snsouch#endif 118728221Smsmith 118828221Smsmith/* 118928221Smsmith * ppc_generic_detect 119028221Smsmith */ 119128221Smsmithstatic int 119238061Smsmithppc_generic_detect(struct ppc_data *ppc, int chipset_mode) 119328221Smsmith{ 119438761Snsouch /* default to generic */ 119555939Snsouch ppc->ppc_type = PPC_TYPE_GENERIC; 119638761Snsouch 119738761Snsouch if (bootverbose) 1198184130Sjhb device_printf(ppc->ppc_dev, "SPP"); 119938761Snsouch 120071622Snsouch /* first, check for ECP */ 120171622Snsouch w_ecr(ppc, PPC_ECR_PS2); 120271622Snsouch if ((r_ecr(ppc) & 0xe0) == PPC_ECR_PS2) { 120371622Snsouch ppc->ppc_dtm |= PPB_ECP | PPB_SPP; 120471622Snsouch if (bootverbose) 1205184130Sjhb printf(" ECP "); 120628221Smsmith 120771622Snsouch /* search for SMC style ECP+EPP mode */ 120871622Snsouch w_ecr(ppc, PPC_ECR_EPP); 120971622Snsouch } 121028221Smsmith 121171622Snsouch /* try to reset EPP timeout bit */ 121271622Snsouch if (ppc_check_epp_timeout(ppc)) { 121371622Snsouch ppc->ppc_dtm |= PPB_EPP; 121428221Smsmith 121571622Snsouch if (ppc->ppc_dtm & PPB_ECP) { 121671622Snsouch /* SMC like chipset found */ 121771622Snsouch ppc->ppc_model = SMC_LIKE; 121871622Snsouch ppc->ppc_type = PPC_TYPE_SMCLIKE; 121938761Snsouch 122071622Snsouch if (bootverbose) 122171622Snsouch printf(" ECP+EPP"); 122238761Snsouch } else { 122371622Snsouch if (bootverbose) 122471622Snsouch printf(" EPP"); 122538061Smsmith } 122671622Snsouch } else { 122771622Snsouch /* restore to standard mode */ 122871622Snsouch w_ecr(ppc, PPC_ECR_STD); 122971622Snsouch } 123028221Smsmith 123171622Snsouch /* XXX try to detect NIBBLE and PS2 modes */ 123271622Snsouch ppc->ppc_dtm |= PPB_NIBBLE; 123328221Smsmith 123471622Snsouch if (chipset_mode) 123538061Smsmith ppc->ppc_avm = chipset_mode; 123671622Snsouch else 123771622Snsouch ppc->ppc_avm = ppc->ppc_dtm; 123838061Smsmith 123938761Snsouch if (bootverbose) 124038761Snsouch printf("\n"); 124138061Smsmith 124255939Snsouch switch (ppc->ppc_type) { 124355939Snsouch case PPC_TYPE_SMCLIKE: 124455939Snsouch ppc_smclike_setmode(ppc, chipset_mode); 124555939Snsouch break; 124655939Snsouch default: 124755939Snsouch ppc_generic_setmode(ppc, chipset_mode); 124855939Snsouch break; 124955939Snsouch } 125038761Snsouch 125138061Smsmith return (chipset_mode); 125228221Smsmith} 125328221Smsmith 125428221Smsmith/* 125528221Smsmith * ppc_detect() 125628221Smsmith * 125728221Smsmith * mode is the mode suggested at boot 125828221Smsmith */ 125928221Smsmithstatic int 126038061Smsmithppc_detect(struct ppc_data *ppc, int chipset_mode) { 126128221Smsmith 126255939Snsouch#ifdef PPC_PROBE_CHIPSET 126338061Smsmith int i, mode; 126428221Smsmith 126538061Smsmith /* list of supported chipsets */ 126638061Smsmith int (*chipset_detect[])(struct ppc_data *, int) = { 126738061Smsmith ppc_pc873xx_detect, 126838061Smsmith ppc_smc37c66xgt_detect, 126938061Smsmith ppc_w83877f_detect, 127063403Sdfr ppc_smc37c935_detect, 127138061Smsmith ppc_generic_detect, 127238061Smsmith NULL 127338061Smsmith }; 127455939Snsouch#endif 127528221Smsmith 127638061Smsmith /* if can't find the port and mode not forced return error */ 127738061Smsmith if (!ppc_detect_port(ppc) && chipset_mode == 0) 127838061Smsmith return (EIO); /* failed, port not present */ 127928221Smsmith 128038061Smsmith /* assume centronics compatible mode is supported */ 128138061Smsmith ppc->ppc_avm = PPB_COMPATIBLE; 128228221Smsmith 128355939Snsouch#ifdef PPC_PROBE_CHIPSET 128438061Smsmith /* we have to differenciate available chipset modes, 128538061Smsmith * chipset running modes and IEEE-1284 operating modes 128638061Smsmith * 128738061Smsmith * after detection, the port must support running in compatible mode 128838061Smsmith */ 128940784Snsouch if (ppc->ppc_flags & 0x40) { 129040784Snsouch if (bootverbose) 129140784Snsouch printf("ppc: chipset forced to generic\n"); 129255939Snsouch#endif 129340784Snsouch 129440784Snsouch ppc->ppc_mode = ppc_generic_detect(ppc, chipset_mode); 129540784Snsouch 129655939Snsouch#ifdef PPC_PROBE_CHIPSET 129740784Snsouch } else { 129840784Snsouch for (i=0; chipset_detect[i] != NULL; i++) { 129940784Snsouch if ((mode = chipset_detect[i](ppc, chipset_mode)) != -1) { 130040784Snsouch ppc->ppc_mode = mode; 130140784Snsouch break; 130240784Snsouch } 130338061Smsmith } 130438061Smsmith } 130555939Snsouch#endif 130628221Smsmith 130742475Snsouch /* configure/detect ECP FIFO */ 130842475Snsouch if ((ppc->ppc_avm & PPB_ECP) && !(ppc->ppc_flags & 0x80)) 130942475Snsouch ppc_detect_fifo(ppc); 131042475Snsouch 131128221Smsmith return (0); 131228221Smsmith} 131328221Smsmith 131428221Smsmith/* 131538061Smsmith * ppc_exec_microseq() 131638061Smsmith * 131738061Smsmith * Execute a microsequence. 131838061Smsmith * Microsequence mechanism is supposed to handle fast I/O operations. 131938061Smsmith */ 1320118292Sambriskoint 132155939Snsouchppc_exec_microseq(device_t dev, struct ppb_microseq **p_msq) 132238061Smsmith{ 132355939Snsouch struct ppc_data *ppc = DEVTOSOFTC(dev); 132439521Snsouch struct ppb_microseq *mi; 132538061Smsmith char cc, *p; 132639135Snsouch int i, iter, len; 132738061Smsmith int error; 132838061Smsmith 132939135Snsouch register int reg; 133039135Snsouch register char mask; 133139135Snsouch register int accum = 0; 133239135Snsouch register char *ptr = 0; 133338061Smsmith 133439521Snsouch struct ppb_microseq *stack = 0; 133538061Smsmith 133638061Smsmith/* microsequence registers are equivalent to PC-like port registers */ 133738061Smsmith 1338182016Sjhb#define r_reg(reg,ppc) (bus_read_1((ppc)->res_ioport, reg)) 1339182016Sjhb#define w_reg(reg, ppc, byte) (bus_write_1((ppc)->res_ioport, reg, byte)) 134078646Snsouch 134139521Snsouch#define INCR_PC (mi ++) /* increment program counter */ 134238061Smsmith 1343187576Sjhb PPC_ASSERT_LOCKED(ppc); 134439521Snsouch mi = *p_msq; 134538061Smsmith for (;;) { 1346185003Sjhb switch (mi->opcode) { 134738061Smsmith case MS_OP_RSET: 134838061Smsmith cc = r_reg(mi->arg[0].i, ppc); 134939135Snsouch cc &= (char)mi->arg[2].i; /* clear mask */ 135039135Snsouch cc |= (char)mi->arg[1].i; /* assert mask */ 1351185003Sjhb w_reg(mi->arg[0].i, ppc, cc); 135238061Smsmith INCR_PC; 1353185003Sjhb break; 135438061Smsmith 135538061Smsmith case MS_OP_RASSERT_P: 135639135Snsouch reg = mi->arg[1].i; 135739135Snsouch ptr = ppc->ppc_ptr; 135839135Snsouch 135939135Snsouch if ((len = mi->arg[0].i) == MS_ACCUM) { 136039135Snsouch accum = ppc->ppc_accum; 136139135Snsouch for (; accum; accum--) 136239135Snsouch w_reg(reg, ppc, *ptr++); 136339135Snsouch ppc->ppc_accum = accum; 136439135Snsouch } else 136539135Snsouch for (i=0; i<len; i++) 136639135Snsouch w_reg(reg, ppc, *ptr++); 136739135Snsouch ppc->ppc_ptr = ptr; 136839135Snsouch 136938061Smsmith INCR_PC; 137038061Smsmith break; 137138061Smsmith 1372185003Sjhb case MS_OP_RFETCH_P: 137339135Snsouch reg = mi->arg[1].i; 137439135Snsouch mask = (char)mi->arg[2].i; 137539135Snsouch ptr = ppc->ppc_ptr; 137639135Snsouch 137739135Snsouch if ((len = mi->arg[0].i) == MS_ACCUM) { 137839135Snsouch accum = ppc->ppc_accum; 137939135Snsouch for (; accum; accum--) 138039135Snsouch *ptr++ = r_reg(reg, ppc) & mask; 138139135Snsouch ppc->ppc_accum = accum; 138239135Snsouch } else 138339135Snsouch for (i=0; i<len; i++) 138439135Snsouch *ptr++ = r_reg(reg, ppc) & mask; 138539135Snsouch ppc->ppc_ptr = ptr; 138639135Snsouch 138738061Smsmith INCR_PC; 1388185003Sjhb break; 138938061Smsmith 1390185003Sjhb case MS_OP_RFETCH: 139138061Smsmith *((char *) mi->arg[2].p) = r_reg(mi->arg[0].i, ppc) & 139239135Snsouch (char)mi->arg[1].i; 139338061Smsmith INCR_PC; 1394185003Sjhb break; 139538061Smsmith 139638061Smsmith case MS_OP_RASSERT: 1397185003Sjhb case MS_OP_DELAY: 1398185003Sjhb 139938061Smsmith /* let's suppose the next instr. is the same */ 140038061Smsmith prefetch: 140138061Smsmith for (;mi->opcode == MS_OP_RASSERT; INCR_PC) 140239135Snsouch w_reg(mi->arg[0].i, ppc, (char)mi->arg[1].i); 140338061Smsmith 140438061Smsmith if (mi->opcode == MS_OP_DELAY) { 140538061Smsmith DELAY(mi->arg[0].i); 140638061Smsmith INCR_PC; 140738061Smsmith goto prefetch; 140838061Smsmith } 140938061Smsmith break; 141038061Smsmith 141139135Snsouch case MS_OP_ADELAY: 1412187576Sjhb if (mi->arg[0].i) { 1413187576Sjhb PPC_UNLOCK(ppc); 1414166909Sjhb pause("ppbdelay", mi->arg[0].i * (hz/1000)); 1415187576Sjhb PPC_LOCK(ppc); 1416187576Sjhb } 141738061Smsmith INCR_PC; 141839135Snsouch break; 141938061Smsmith 142038061Smsmith case MS_OP_TRIG: 142138061Smsmith reg = mi->arg[0].i; 142238061Smsmith iter = mi->arg[1].i; 142338061Smsmith p = (char *)mi->arg[2].p; 142438061Smsmith 142539135Snsouch /* XXX delay limited to 255 us */ 142638061Smsmith for (i=0; i<iter; i++) { 142738061Smsmith w_reg(reg, ppc, *p++); 142838061Smsmith DELAY((unsigned char)*p++); 142938061Smsmith } 143038061Smsmith INCR_PC; 143138061Smsmith break; 143238061Smsmith 1433185003Sjhb case MS_OP_SET: 1434185003Sjhb ppc->ppc_accum = mi->arg[0].i; 143538061Smsmith INCR_PC; 1436185003Sjhb break; 143738061Smsmith 1438185003Sjhb case MS_OP_DBRA: 1439185003Sjhb if (--ppc->ppc_accum > 0) 1440185003Sjhb mi += mi->arg[0].i; 144143433Snsouch INCR_PC; 1442185003Sjhb break; 144338061Smsmith 1444185003Sjhb case MS_OP_BRSET: 1445185003Sjhb cc = r_str(ppc); 1446185003Sjhb if ((cc & (char)mi->arg[0].i) == (char)mi->arg[0].i) 1447185003Sjhb mi += mi->arg[1].i; 144843433Snsouch INCR_PC; 1449185003Sjhb break; 145038061Smsmith 1451185003Sjhb case MS_OP_BRCLEAR: 1452185003Sjhb cc = r_str(ppc); 1453185003Sjhb if ((cc & (char)mi->arg[0].i) == 0) 1454185003Sjhb mi += mi->arg[1].i; 145543433Snsouch INCR_PC; 1456185003Sjhb break; 145738061Smsmith 145839135Snsouch case MS_OP_BRSTAT: 145939135Snsouch cc = r_str(ppc); 146039135Snsouch if ((cc & ((char)mi->arg[0].i | (char)mi->arg[1].i)) == 146139135Snsouch (char)mi->arg[0].i) 146239521Snsouch mi += mi->arg[2].i; 146343433Snsouch INCR_PC; 146439135Snsouch break; 146539135Snsouch 146638061Smsmith case MS_OP_C_CALL: 146738061Smsmith /* 146838061Smsmith * If the C call returns !0 then end the microseq. 146938061Smsmith * The current state of ptr is passed to the C function 147038061Smsmith */ 147139135Snsouch if ((error = mi->arg[0].f(mi->arg[1].p, ppc->ppc_ptr))) 147238061Smsmith return (error); 147338061Smsmith 147438061Smsmith INCR_PC; 147538061Smsmith break; 147638061Smsmith 147738061Smsmith case MS_OP_PTR: 147839135Snsouch ppc->ppc_ptr = (char *)mi->arg[0].p; 147938061Smsmith INCR_PC; 148038061Smsmith break; 148138061Smsmith 148238061Smsmith case MS_OP_CALL: 148339521Snsouch if (stack) 148487599Sobrien panic("%s: too much calls", __func__); 148538061Smsmith 148638061Smsmith if (mi->arg[0].p) { 148738061Smsmith /* store the state of the actual 148838061Smsmith * microsequence 148938061Smsmith */ 149039521Snsouch stack = mi; 149138061Smsmith 149238061Smsmith /* jump to the new microsequence */ 149339521Snsouch mi = (struct ppb_microseq *)mi->arg[0].p; 149438061Smsmith } else 149538061Smsmith INCR_PC; 149638061Smsmith 149738061Smsmith break; 149838061Smsmith 149938061Smsmith case MS_OP_SUBRET: 150038061Smsmith /* retrieve microseq and pc state before the call */ 150139521Snsouch mi = stack; 150238061Smsmith 150338061Smsmith /* reset the stack */ 150439521Snsouch stack = 0; 150538061Smsmith 150638061Smsmith /* XXX return code */ 150738061Smsmith 150838061Smsmith INCR_PC; 150938061Smsmith break; 151038061Smsmith 1511185003Sjhb case MS_OP_PUT: 1512185003Sjhb case MS_OP_GET: 1513185003Sjhb case MS_OP_RET: 151438061Smsmith /* can't return to ppb level during the execution 151538061Smsmith * of a submicrosequence */ 151639521Snsouch if (stack) 151738061Smsmith panic("%s: can't return to ppb level", 151887599Sobrien __func__); 151938061Smsmith 152038061Smsmith /* update pc for ppb level of execution */ 152139521Snsouch *p_msq = mi; 152238061Smsmith 152338061Smsmith /* return to ppb level of execution */ 152438061Smsmith return (0); 152538061Smsmith 1526185003Sjhb default: 1527185003Sjhb panic("%s: unknown microsequence opcode 0x%x", 1528185003Sjhb __func__, mi->opcode); 1529185003Sjhb } 153038061Smsmith } 153138061Smsmith 153238061Smsmith /* unreached */ 153338061Smsmith} 153438061Smsmith 153542475Snsouchstatic void 153655939Snsouchppcintr(void *arg) 153742475Snsouch{ 1538183053Sjhb struct ppc_data *ppc = arg; 153943990Snsouch u_char ctr, ecr, str; 154042475Snsouch 1541183053Sjhb /* 1542183053Sjhb * If we have any child interrupt handlers registered, let 1543183053Sjhb * them handle this interrupt. 1544183053Sjhb * 1545183053Sjhb * XXX: If DMA is in progress should we just complete that w/o 1546183053Sjhb * doing this? 1547183053Sjhb */ 1548187576Sjhb PPC_LOCK(ppc); 1549187576Sjhb if (ppc->ppc_intr_hook != NULL && 1550187576Sjhb ppc->ppc_intr_hook(ppc->ppc_intr_arg) == 0) { 1551187576Sjhb PPC_UNLOCK(ppc); 1552183053Sjhb return; 1553183053Sjhb } 1554183053Sjhb 155543990Snsouch str = r_str(ppc); 155642475Snsouch ctr = r_ctr(ppc); 155742475Snsouch ecr = r_ecr(ppc); 155842475Snsouch 1559153072Sru#if defined(PPC_DEBUG) && PPC_DEBUG > 1 156043990Snsouch printf("![%x/%x/%x]", ctr, ecr, str); 156142475Snsouch#endif 156242475Snsouch 156342475Snsouch /* don't use ecp mode with IRQENABLE set */ 156442475Snsouch if (ctr & IRQENABLE) { 1565187576Sjhb PPC_UNLOCK(ppc); 156642475Snsouch return; 156742475Snsouch } 156842475Snsouch 156943990Snsouch /* interrupts are generated by nFault signal 157043990Snsouch * only in ECP mode */ 157143990Snsouch if ((str & nFAULT) && (ppc->ppc_mode & PPB_ECP)) { 157243990Snsouch /* check if ppc driver has programmed the 157343990Snsouch * nFault interrupt */ 157442475Snsouch if (ppc->ppc_irqstat & PPC_IRQ_nFAULT) { 157542475Snsouch 157642475Snsouch w_ecr(ppc, ecr | PPC_nFAULT_INTR); 157742475Snsouch ppc->ppc_irqstat &= ~PPC_IRQ_nFAULT; 157842475Snsouch } else { 157955939Snsouch /* shall be handled by underlying layers XXX */ 1580187576Sjhb PPC_UNLOCK(ppc); 158142475Snsouch return; 158242475Snsouch } 158342475Snsouch } 158442475Snsouch 158542475Snsouch if (ppc->ppc_irqstat & PPC_IRQ_DMA) { 158642475Snsouch /* disable interrupts (should be done by hardware though) */ 158742475Snsouch w_ecr(ppc, ecr | PPC_SERVICE_INTR); 158842475Snsouch ppc->ppc_irqstat &= ~PPC_IRQ_DMA; 158942475Snsouch ecr = r_ecr(ppc); 159042475Snsouch 159142475Snsouch /* check if DMA completed */ 159242475Snsouch if ((ppc->ppc_avm & PPB_ECP) && (ecr & PPC_ENABLE_DMA)) { 159342475Snsouch#ifdef PPC_DEBUG 159442475Snsouch printf("a"); 159542475Snsouch#endif 159642475Snsouch /* stop DMA */ 159742475Snsouch w_ecr(ppc, ecr & ~PPC_ENABLE_DMA); 159842475Snsouch ecr = r_ecr(ppc); 159942475Snsouch 160042475Snsouch if (ppc->ppc_dmastat == PPC_DMA_STARTED) { 160142475Snsouch#ifdef PPC_DEBUG 160242475Snsouch printf("d"); 160342475Snsouch#endif 1604158005Smarcel ppc->ppc_dmadone(ppc); 160542475Snsouch ppc->ppc_dmastat = PPC_DMA_COMPLETE; 160642475Snsouch 160742475Snsouch /* wakeup the waiting process */ 1608111748Sdes wakeup(ppc); 160942475Snsouch } 161042475Snsouch } 161142475Snsouch } else if (ppc->ppc_irqstat & PPC_IRQ_FIFO) { 161242475Snsouch 161342475Snsouch /* classic interrupt I/O */ 161442475Snsouch ppc->ppc_irqstat &= ~PPC_IRQ_FIFO; 161542475Snsouch } 1616187576Sjhb PPC_UNLOCK(ppc); 161742475Snsouch 161842475Snsouch return; 161942475Snsouch} 162042475Snsouch 1621118292Sambriskoint 162255939Snsouchppc_read(device_t dev, char *buf, int len, int mode) 162342475Snsouch{ 162442475Snsouch return (EINVAL); 162542475Snsouch} 162642475Snsouch 1627118292Sambriskoint 162855939Snsouchppc_write(device_t dev, char *buf, int len, int how) 162942475Snsouch{ 1630158005Smarcel return (EINVAL); 163142475Snsouch} 163242475Snsouch 1633188173Simpint 163455939Snsouchppc_reset_epp(device_t dev) 163538061Smsmith{ 163655939Snsouch struct ppc_data *ppc = DEVTOSOFTC(dev); 1637185003Sjhb 1638187576Sjhb PPC_ASSERT_LOCKED(ppc); 163955939Snsouch ppc_reset_epp_timeout(ppc); 164038061Smsmith 1641188173Simp return 0; 164255939Snsouch} 164338061Smsmith 1644118292Sambriskoint 164555939Snsouchppc_setmode(device_t dev, int mode) 164655939Snsouch{ 164755939Snsouch struct ppc_data *ppc = DEVTOSOFTC(dev); 164838061Smsmith 1649187576Sjhb PPC_ASSERT_LOCKED(ppc); 165055939Snsouch switch (ppc->ppc_type) { 165155939Snsouch case PPC_TYPE_SMCLIKE: 165255939Snsouch return (ppc_smclike_setmode(ppc, mode)); 165355939Snsouch break; 165442475Snsouch 165555939Snsouch case PPC_TYPE_GENERIC: 165655939Snsouch default: 165755939Snsouch return (ppc_generic_setmode(ppc, mode)); 165855939Snsouch break; 165938761Snsouch } 166038761Snsouch 166155939Snsouch /* not reached */ 166255939Snsouch return (ENXIO); 166338061Smsmith} 166438061Smsmith 1665118292Sambriskoint 1666158005Smarcelppc_probe(device_t dev, int rid) 1667118292Sambrisko{ 1668118292Sambrisko#ifdef __i386__ 1669118292Sambrisko static short next_bios_ppc = 0; 1670158005Smarcel#ifdef PC98 1671158005Smarcel unsigned int pc98_ieee_mode = 0x00; 1672158005Smarcel unsigned int tmp; 1673118292Sambrisko#endif 1674158005Smarcel#endif 1675118292Sambrisko struct ppc_data *ppc; 1676118292Sambrisko int error; 1677118292Sambrisko u_long port; 1678118292Sambrisko 167955939Snsouch /* 168055939Snsouch * Allocate the ppc_data structure. 168155939Snsouch */ 168255939Snsouch ppc = DEVTOSOFTC(dev); 168355939Snsouch bzero(ppc, sizeof(struct ppc_data)); 168438761Snsouch 1685158005Smarcel ppc->rid_ioport = rid; 168638761Snsouch 168755939Snsouch /* retrieve ISA parameters */ 1688158005Smarcel error = bus_get_resource(dev, SYS_RES_IOPORT, rid, &port, NULL); 168938761Snsouch 169056617Sdfr#ifdef __i386__ 169128221Smsmith /* 169228221Smsmith * If port not specified, use bios list. 169328221Smsmith */ 169456617Sdfr if (error) { 1695158005Smarcel#ifdef PC98 1696158005Smarcel if (next_bios_ppc == 0) { 1697158005Smarcel /* Use default IEEE-1284 port of NEC PC-98x1 */ 1698158005Smarcel port = PC98_IEEE_1284_PORT; 1699158005Smarcel next_bios_ppc += 1; 1700158005Smarcel if (bootverbose) 1701158005Smarcel device_printf(dev, 1702185003Sjhb "parallel port found at 0x%lx\n", port); 1703158005Smarcel } 1704158005Smarcel#else 1705185003Sjhb if ((next_bios_ppc < BIOS_MAX_PPC) && 1706185003Sjhb (*(BIOS_PORTS + next_bios_ppc) != 0)) { 1707185003Sjhb port = *(BIOS_PORTS + next_bios_ppc++); 170842475Snsouch if (bootverbose) 1709185003Sjhb device_printf(dev, 1710185003Sjhb "parallel port found at 0x%lx\n", port); 171155939Snsouch } else { 171255939Snsouch device_printf(dev, "parallel port not found.\n"); 1713185003Sjhb return (ENXIO); 171455939Snsouch } 1715158005Smarcel#endif /* PC98 */ 1716158005Smarcel bus_set_resource(dev, SYS_RES_IOPORT, rid, port, 171763403Sdfr IO_LPTSIZE_EXTENDED); 171828221Smsmith } 171956617Sdfr#endif 172028221Smsmith 172155939Snsouch /* IO port is mandatory */ 172263403Sdfr 172363403Sdfr /* Try "extended" IO port range...*/ 172455939Snsouch ppc->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT, 172556617Sdfr &ppc->rid_ioport, 0, ~0, 172663403Sdfr IO_LPTSIZE_EXTENDED, RF_ACTIVE); 172728221Smsmith 172863403Sdfr if (ppc->res_ioport != 0) { 172962061Sdfr if (bootverbose) 173063403Sdfr device_printf(dev, "using extended I/O port range\n"); 173163403Sdfr } else { 173263403Sdfr /* Failed? If so, then try the "normal" IO port range... */ 173363403Sdfr ppc->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT, 173463403Sdfr &ppc->rid_ioport, 0, ~0, 173563403Sdfr IO_LPTSIZE_NORMAL, 173663403Sdfr RF_ACTIVE); 173763403Sdfr if (ppc->res_ioport != 0) { 173863403Sdfr if (bootverbose) 173963403Sdfr device_printf(dev, "using normal I/O port range\n"); 174063403Sdfr } else { 174163403Sdfr device_printf(dev, "cannot reserve I/O port range\n"); 174263403Sdfr goto error; 174363403Sdfr } 174462061Sdfr } 174560544Sdfr 174660544Sdfr ppc->ppc_base = rman_get_start(ppc->res_ioport); 174760544Sdfr 174855939Snsouch ppc->ppc_flags = device_get_flags(dev); 174928221Smsmith 175055939Snsouch if (!(ppc->ppc_flags & 0x20)) { 1751127135Snjl ppc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 1752127135Snjl &ppc->rid_irq, 1753127135Snjl RF_SHAREABLE); 1754127135Snjl ppc->res_drq = bus_alloc_resource_any(dev, SYS_RES_DRQ, 1755127135Snjl &ppc->rid_drq, 1756127135Snjl RF_ACTIVE); 175755939Snsouch } 175840784Snsouch 175955939Snsouch if (ppc->res_irq) 176056617Sdfr ppc->ppc_irq = rman_get_start(ppc->res_irq); 176155939Snsouch if (ppc->res_drq) 176256617Sdfr ppc->ppc_dmachan = rman_get_start(ppc->res_drq); 176328221Smsmith 1764184130Sjhb ppc->ppc_dev = dev; 176555939Snsouch ppc->ppc_model = GENERIC; 176628221Smsmith 176755939Snsouch ppc->ppc_mode = PPB_COMPATIBLE; 176855939Snsouch ppc->ppc_epp = (ppc->ppc_flags & 0x10) >> 4; 176942475Snsouch 177055939Snsouch ppc->ppc_type = PPC_TYPE_GENERIC; 177128221Smsmith 1772158005Smarcel#if defined(__i386__) && defined(PC98) 177328221Smsmith /* 1774158005Smarcel * IEEE STD 1284 Function Check and Enable 1775158005Smarcel * for default IEEE-1284 port of NEC PC-98x1 1776158005Smarcel */ 1777158005Smarcel if (ppc->ppc_base == PC98_IEEE_1284_PORT && 1778158005Smarcel !(ppc->ppc_flags & PC98_IEEE_1284_DISABLE)) { 1779158005Smarcel tmp = inb(ppc->ppc_base + PPC_1284_ENABLE); 1780158005Smarcel pc98_ieee_mode = tmp; 1781158005Smarcel if ((tmp & 0x10) == 0x10) { 1782158005Smarcel outb(ppc->ppc_base + PPC_1284_ENABLE, tmp & ~0x10); 1783158005Smarcel tmp = inb(ppc->ppc_base + PPC_1284_ENABLE); 1784158005Smarcel if ((tmp & 0x10) == 0x10) 1785158005Smarcel goto error; 1786158005Smarcel } else { 1787158005Smarcel outb(ppc->ppc_base + PPC_1284_ENABLE, tmp | 0x10); 1788158005Smarcel tmp = inb(ppc->ppc_base + PPC_1284_ENABLE); 1789158005Smarcel if ((tmp & 0x10) != 0x10) 1790158005Smarcel goto error; 1791158005Smarcel } 1792158005Smarcel outb(ppc->ppc_base + PPC_1284_ENABLE, pc98_ieee_mode | 0x10); 1793158005Smarcel } 1794158005Smarcel#endif 1795158005Smarcel 1796158005Smarcel /* 179735256Sdes * Try to detect the chipset and its mode. 179828221Smsmith */ 179955939Snsouch if (ppc_detect(ppc, ppc->ppc_flags & 0xf)) 180028221Smsmith goto error; 180128221Smsmith 180255939Snsouch return (0); 180328221Smsmith 180428221Smsmitherror: 1805158005Smarcel#if defined(__i386__) && defined(PC98) 1806158005Smarcel if (ppc->ppc_base == PC98_IEEE_1284_PORT && 1807158005Smarcel !(ppc->ppc_flags & PC98_IEEE_1284_DISABLE)) { 1808158005Smarcel outb(ppc->ppc_base + PPC_1284_ENABLE, pc98_ieee_mode); 1809158005Smarcel } 1810158005Smarcel#endif 181155939Snsouch if (ppc->res_irq != 0) { 181255939Snsouch bus_release_resource(dev, SYS_RES_IRQ, ppc->rid_irq, 181355939Snsouch ppc->res_irq); 181455939Snsouch } 181555939Snsouch if (ppc->res_ioport != 0) { 181655939Snsouch bus_release_resource(dev, SYS_RES_IOPORT, ppc->rid_ioport, 181755939Snsouch ppc->res_ioport); 181855939Snsouch } 181955939Snsouch if (ppc->res_drq != 0) { 182055939Snsouch bus_release_resource(dev, SYS_RES_DRQ, ppc->rid_drq, 182155939Snsouch ppc->res_drq); 182255939Snsouch } 182355939Snsouch return (ENXIO); 182428221Smsmith} 182528221Smsmith 1826118292Sambriskoint 182755939Snsouchppc_attach(device_t dev) 182828221Smsmith{ 182955939Snsouch struct ppc_data *ppc = DEVTOSOFTC(dev); 1830183053Sjhb int error; 183128221Smsmith 1832187576Sjhb mtx_init(&ppc->ppc_lock, device_get_nameunit(dev), "ppc", MTX_DEF); 1833187576Sjhb 183455939Snsouch device_printf(dev, "%s chipset (%s) in %s mode%s\n", 183555939Snsouch ppc_models[ppc->ppc_model], ppc_avms[ppc->ppc_avm], 183655939Snsouch ppc_modes[ppc->ppc_mode], (PPB_IS_EPP(ppc->ppc_mode)) ? 183755939Snsouch ppc_epp_protocol[ppc->ppc_epp] : ""); 1838185003Sjhb 183942475Snsouch if (ppc->ppc_fifo) 184055939Snsouch device_printf(dev, "FIFO with %d/%d/%d bytes threshold\n", 184155939Snsouch ppc->ppc_fifo, ppc->ppc_wthr, ppc->ppc_rthr); 184242475Snsouch 1843183053Sjhb if (ppc->res_irq) { 1844183053Sjhb /* default to the tty mask for registration */ /* XXX */ 1845187576Sjhb error = bus_setup_intr(dev, ppc->res_irq, INTR_TYPE_TTY | 1846187576Sjhb INTR_MPSAFE, NULL, ppcintr, ppc, &ppc->intr_cookie); 1847183053Sjhb if (error) { 1848183053Sjhb device_printf(dev, 1849183053Sjhb "failed to register interrupt handler: %d\n", 1850183053Sjhb error); 1851187576Sjhb mtx_destroy(&ppc->ppc_lock); 1852183053Sjhb return (error); 1853183053Sjhb } 1854183053Sjhb } 1855183053Sjhb 185655939Snsouch /* add ppbus as a child of this isa to parallel bridge */ 1857187576Sjhb ppc->ppbus = device_add_child(dev, "ppbus", -1); 185855939Snsouch 185928221Smsmith /* 186055939Snsouch * Probe the ppbus and attach devices found. 186128221Smsmith */ 1862187576Sjhb device_probe_and_attach(ppc->ppbus); 186328221Smsmith 186455939Snsouch return (0); 186555939Snsouch} 186642475Snsouch 1867157774Siwasakiint 1868157774Siwasakippc_detach(device_t dev) 1869157774Siwasaki{ 1870157774Siwasaki struct ppc_data *ppc = DEVTOSOFTC(dev); 1871157774Siwasaki 1872157774Siwasaki if (ppc->res_irq == 0) { 1873157774Siwasaki return (ENXIO); 1874157774Siwasaki } 1875157774Siwasaki 1876157774Siwasaki /* detach & delete all children */ 1877227849Shselasky device_delete_children(dev); 1878157774Siwasaki 1879157774Siwasaki if (ppc->res_irq != 0) { 1880157774Siwasaki bus_teardown_intr(dev, ppc->res_irq, ppc->intr_cookie); 1881157774Siwasaki bus_release_resource(dev, SYS_RES_IRQ, ppc->rid_irq, 1882157774Siwasaki ppc->res_irq); 1883157774Siwasaki } 1884157774Siwasaki if (ppc->res_ioport != 0) { 1885157774Siwasaki bus_release_resource(dev, SYS_RES_IOPORT, ppc->rid_ioport, 1886157774Siwasaki ppc->res_ioport); 1887157774Siwasaki } 1888157774Siwasaki if (ppc->res_drq != 0) { 1889157774Siwasaki bus_release_resource(dev, SYS_RES_DRQ, ppc->rid_drq, 1890157774Siwasaki ppc->res_drq); 1891157774Siwasaki } 1892157774Siwasaki 1893187576Sjhb mtx_destroy(&ppc->ppc_lock); 1894187576Sjhb 1895157774Siwasaki return (0); 1896157774Siwasaki} 1897157774Siwasaki 1898118292Sambriskou_char 189955939Snsouchppc_io(device_t ppcdev, int iop, u_char *addr, int cnt, u_char byte) 190055939Snsouch{ 190155939Snsouch struct ppc_data *ppc = DEVTOSOFTC(ppcdev); 1902185003Sjhb 1903187576Sjhb PPC_ASSERT_LOCKED(ppc); 190455939Snsouch switch (iop) { 190555939Snsouch case PPB_OUTSB_EPP: 1906182016Sjhb bus_write_multi_1(ppc->res_ioport, PPC_EPP_DATA, addr, cnt); 190755939Snsouch break; 190855939Snsouch case PPB_OUTSW_EPP: 1909182016Sjhb bus_write_multi_2(ppc->res_ioport, PPC_EPP_DATA, (u_int16_t *)addr, cnt); 191055939Snsouch break; 191155939Snsouch case PPB_OUTSL_EPP: 1912182016Sjhb bus_write_multi_4(ppc->res_ioport, PPC_EPP_DATA, (u_int32_t *)addr, cnt); 191355939Snsouch break; 191455939Snsouch case PPB_INSB_EPP: 1915182016Sjhb bus_read_multi_1(ppc->res_ioport, PPC_EPP_DATA, addr, cnt); 191655939Snsouch break; 191755939Snsouch case PPB_INSW_EPP: 1918182016Sjhb bus_read_multi_2(ppc->res_ioport, PPC_EPP_DATA, (u_int16_t *)addr, cnt); 191955939Snsouch break; 192055939Snsouch case PPB_INSL_EPP: 1921182016Sjhb bus_read_multi_4(ppc->res_ioport, PPC_EPP_DATA, (u_int32_t *)addr, cnt); 192255939Snsouch break; 192355939Snsouch case PPB_RDTR: 192455939Snsouch return (r_dtr(ppc)); 192555939Snsouch case PPB_RSTR: 192655939Snsouch return (r_str(ppc)); 192755939Snsouch case PPB_RCTR: 192855939Snsouch return (r_ctr(ppc)); 192955939Snsouch case PPB_REPP_A: 193055939Snsouch return (r_epp_A(ppc)); 193155939Snsouch case PPB_REPP_D: 193255939Snsouch return (r_epp_D(ppc)); 193355939Snsouch case PPB_RECR: 193455939Snsouch return (r_ecr(ppc)); 193555939Snsouch case PPB_RFIFO: 193655939Snsouch return (r_fifo(ppc)); 193755939Snsouch case PPB_WDTR: 193855939Snsouch w_dtr(ppc, byte); 193955939Snsouch break; 194055939Snsouch case PPB_WSTR: 194155939Snsouch w_str(ppc, byte); 194255939Snsouch break; 194355939Snsouch case PPB_WCTR: 194455939Snsouch w_ctr(ppc, byte); 194555939Snsouch break; 194655939Snsouch case PPB_WEPP_A: 194755939Snsouch w_epp_A(ppc, byte); 194855939Snsouch break; 194955939Snsouch case PPB_WEPP_D: 195055939Snsouch w_epp_D(ppc, byte); 195155939Snsouch break; 195255939Snsouch case PPB_WECR: 195355939Snsouch w_ecr(ppc, byte); 195455939Snsouch break; 195555939Snsouch case PPB_WFIFO: 195655939Snsouch w_fifo(ppc, byte); 195755939Snsouch break; 195855939Snsouch default: 195987599Sobrien panic("%s: unknown I/O operation", __func__); 196055939Snsouch break; 196142475Snsouch } 196242475Snsouch 196355939Snsouch return (0); /* not significative */ 196455939Snsouch} 196528221Smsmith 1966118292Sambriskoint 196755939Snsouchppc_read_ivar(device_t bus, device_t dev, int index, uintptr_t *val) 196855939Snsouch{ 196955939Snsouch struct ppc_data *ppc = (struct ppc_data *)device_get_softc(bus); 197055939Snsouch 197155939Snsouch switch (index) { 197255939Snsouch case PPC_IVAR_EPP_PROTO: 1973187576Sjhb PPC_ASSERT_LOCKED(ppc); 197455939Snsouch *val = (u_long)ppc->ppc_epp; 197555939Snsouch break; 1976187576Sjhb case PPC_IVAR_LOCK: 1977187576Sjhb *val = (uintptr_t)&ppc->ppc_lock; 1978187576Sjhb break; 197955939Snsouch default: 198055939Snsouch return (ENOENT); 198155939Snsouch } 198255939Snsouch 198355939Snsouch return (0); 198428221Smsmith} 198555939Snsouch 1986187576Sjhbint 1987187576Sjhbppc_write_ivar(device_t bus, device_t dev, int index, uintptr_t val) 1988187576Sjhb{ 1989187576Sjhb struct ppc_data *ppc = (struct ppc_data *)device_get_softc(bus); 1990187576Sjhb 1991187576Sjhb switch (index) { 1992187576Sjhb case PPC_IVAR_INTR_HANDLER: 1993187576Sjhb PPC_ASSERT_LOCKED(ppc); 1994187576Sjhb if (dev != ppc->ppbus) 1995187576Sjhb return (EINVAL); 1996187576Sjhb if (val == 0) { 1997187576Sjhb ppc->ppc_intr_hook = NULL; 1998187576Sjhb break; 1999187576Sjhb } 2000187576Sjhb if (ppc->ppc_intr_hook != NULL) 2001187576Sjhb return (EBUSY); 2002187576Sjhb ppc->ppc_intr_hook = (void *)val; 2003187576Sjhb ppc->ppc_intr_arg = device_get_softc(dev); 2004187576Sjhb break; 2005187576Sjhb default: 2006187576Sjhb return (ENOENT); 2007187576Sjhb } 2008187576Sjhb 2009187576Sjhb return (0); 2010187576Sjhb} 2011187576Sjhb 201255939Snsouch/* 2013183053Sjhb * We allow child devices to allocate an IRQ resource at rid 0 for their 2014183053Sjhb * interrupt handlers. 201555939Snsouch */ 2016183053Sjhbstruct resource * 2017183053Sjhbppc_alloc_resource(device_t bus, device_t child, int type, int *rid, 2018183053Sjhb u_long start, u_long end, u_long count, u_int flags) 201955939Snsouch{ 202055939Snsouch struct ppc_data *ppc = DEVTOSOFTC(bus); 202155939Snsouch 2022183053Sjhb switch (type) { 2023183053Sjhb case SYS_RES_IRQ: 2024183053Sjhb if (*rid == 0) 2025183053Sjhb return (ppc->res_irq); 2026183053Sjhb break; 2027183053Sjhb } 2028183053Sjhb return (NULL); 2029183053Sjhb} 203055939Snsouch 2031183053Sjhbint 2032183053Sjhbppc_release_resource(device_t bus, device_t child, int type, int rid, 2033183053Sjhb struct resource *r) 2034183053Sjhb{ 2035183053Sjhb#ifdef INVARIANTS 2036183053Sjhb struct ppc_data *ppc = DEVTOSOFTC(bus); 2037183053Sjhb#endif 203855939Snsouch 2039183053Sjhb switch (type) { 2040183053Sjhb case SYS_RES_IRQ: 2041183053Sjhb if (rid == 0) { 2042183053Sjhb KASSERT(r == ppc->res_irq, 2043183053Sjhb ("ppc child IRQ resource mismatch")); 2044183053Sjhb return (0); 2045183053Sjhb } 2046183053Sjhb break; 204755939Snsouch } 2048183053Sjhb return (EINVAL); 204955939Snsouch} 205055939Snsouch 2051153610SruMODULE_DEPEND(ppc, ppbus, 1, 1, 1); 2052