1119418Sobrien/*- 261541Stanimura * Copyright (c) Comtrol Corporation <support@comtrol.com> 361541Stanimura * All rights reserved. 461541Stanimura * 561541Stanimura * PCI-specific part separated from: 661541Stanimura * sys/i386/isa/rp.c,v 1.33 1999/09/28 11:45:27 phk Exp 761541Stanimura * 861541Stanimura * Redistribution and use in source and binary forms, with or without 961541Stanimura * modification, are permitted prodived that the follwoing conditions 1061541Stanimura * are met. 1161541Stanimura * 1. Redistributions of source code must retain the above copyright 1261541Stanimura * notive, this list of conditions and the following disclainer. 1361541Stanimura * 2. Redistributions in binary form must reproduce the above copyright 1461541Stanimura * notice, this list of conditions and the following disclaimer in the 1561541Stanimura * documentation and/or other materials prodided with the distribution. 1661541Stanimura * 3. All advertising materials mentioning features or use of this software 1761541Stanimura * must display the following acknowledgement: 1861541Stanimura * This product includes software developed by Comtrol Corporation. 1961541Stanimura * 4. The name of Comtrol Corporation may not be used to endorse or 2061541Stanimura * promote products derived from this software without specific 2161541Stanimura * prior written permission. 2261541Stanimura * 2361541Stanimura * THIS SOFTWARE IS PROVIDED BY COMTROL CORPORATION ``AS IS'' AND ANY 2461541Stanimura * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2561541Stanimura * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2661541Stanimura * ARE DISCLAIMED. IN NO EVENT SHALL COMTROL CORPORATION BE LIABLE FOR 2761541Stanimura * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2861541Stanimura * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2961541Stanimura * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) 3061541Stanimura * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3161541Stanimura * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3261541Stanimura * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3361541Stanimura * SUCH DAMAGE. 3461541Stanimura */ 3561541Stanimura 36119418Sobrien#include <sys/cdefs.h> 37119418Sobrien__FBSDID("$FreeBSD$"); 38119418Sobrien 3961541Stanimura#include <sys/param.h> 4061541Stanimura#include <sys/systm.h> 4161541Stanimura#include <sys/fcntl.h> 4261541Stanimura#include <sys/malloc.h> 4361541Stanimura#include <sys/tty.h> 4461541Stanimura#include <sys/conf.h> 4561541Stanimura#include <sys/kernel.h> 46129879Sphk#include <sys/module.h> 4761541Stanimura#include <machine/resource.h> 4861541Stanimura#include <machine/bus.h> 4961541Stanimura#include <sys/bus.h> 5061541Stanimura#include <sys/rman.h> 5161541Stanimura 5261541Stanimura#define ROCKET_C 5361541Stanimura#include <dev/rp/rpreg.h> 5461541Stanimura#include <dev/rp/rpvar.h> 5561541Stanimura 56119285Simp#include <dev/pci/pcireg.h> 57119285Simp#include <dev/pci/pcivar.h> 5861541Stanimura 5961541Stanimura/* PCI IDs */ 6061541Stanimura#define RP_VENDOR_ID 0x11FE 6161541Stanimura#define RP_DEVICE_ID_32I 0x0001 6261541Stanimura#define RP_DEVICE_ID_8I 0x0002 6361541Stanimura#define RP_DEVICE_ID_16I 0x0003 6461541Stanimura#define RP_DEVICE_ID_4Q 0x0004 6561541Stanimura#define RP_DEVICE_ID_8O 0x0005 6661541Stanimura#define RP_DEVICE_ID_8J 0x0006 6761541Stanimura#define RP_DEVICE_ID_4J 0x0007 6861541Stanimura#define RP_DEVICE_ID_6M 0x000C 6961541Stanimura#define RP_DEVICE_ID_4M 0x000D 70154817Sjhb#define RP_DEVICE_ID_UPCI_32 0x0801 71191563Sambrisko#define RP_DEVICE_ID_UPCI_16 0x0803 72144090Sjhb#define RP_DEVICE_ID_UPCI_8O 0x0805 7361541Stanimura 7461541Stanimura/************************************************************************** 7561541Stanimura MUDBAC remapped for PCI 7661541Stanimura**************************************************************************/ 7761541Stanimura 7861541Stanimura#define _CFG_INT_PCI 0x40 7961541Stanimura#define _PCI_INT_FUNC 0x3A 8061541Stanimura 8161541Stanimura#define PCI_STROB 0x2000 8261541Stanimura#define INTR_EN_PCI 0x0010 8361541Stanimura 8461541Stanimura/*************************************************************************** 8561541StanimuraFunction: sPCIControllerEOI 8661541StanimuraPurpose: Strobe the MUDBAC's End Of Interrupt bit. 8761541StanimuraCall: sPCIControllerEOI(CtlP) 8861541Stanimura CONTROLLER_T *CtlP; Ptr to controller structure 8961541Stanimura*/ 9061541Stanimura#define sPCIControllerEOI(CtlP) rp_writeio2(CtlP, 0, _PCI_INT_FUNC, PCI_STROB) 9161541Stanimura 9261541Stanimura/*************************************************************************** 9361541StanimuraFunction: sPCIGetControllerIntStatus 9461541StanimuraPurpose: Get the controller interrupt status 9561541StanimuraCall: sPCIGetControllerIntStatus(CtlP) 9661541Stanimura CONTROLLER_T *CtlP; Ptr to controller structure 9761541StanimuraReturn: Byte_t: The controller interrupt status in the lower 4 9861541Stanimura bits. Bits 0 through 3 represent AIOP's 0 9961541Stanimura through 3 respectively. If a bit is set that 10061541Stanimura AIOP is interrupting. Bits 4 through 7 will 10161541Stanimura always be cleared. 10261541Stanimura*/ 10361541Stanimura#define sPCIGetControllerIntStatus(CTLP) ((rp_readio2(CTLP, 0, _PCI_INT_FUNC) >> 8) & 0x1f) 10461541Stanimura 10561541Stanimurastatic devclass_t rp_devclass; 10661541Stanimura 10761541Stanimurastatic int rp_pciprobe(device_t dev); 10861541Stanimurastatic int rp_pciattach(device_t dev); 109153084Sru#ifdef notdef 11061541Stanimurastatic int rp_pcidetach(device_t dev); 11161541Stanimurastatic int rp_pcishutdown(device_t dev); 11261541Stanimura#endif /* notdef */ 11361541Stanimurastatic void rp_pcireleaseresource(CONTROLLER_t *ctlp); 11461541Stanimurastatic int sPCIInitController( CONTROLLER_t *CtlP, 11561541Stanimura int AiopNum, 11661541Stanimura int IRQNum, 11761541Stanimura Byte_t Frequency, 11861541Stanimura int PeriodicOnly, 11961541Stanimura int VendorDevice); 12061541Stanimurastatic rp_aiop2rid_t rp_pci_aiop2rid; 12161541Stanimurastatic rp_aiop2off_t rp_pci_aiop2off; 12261541Stanimurastatic rp_ctlmask_t rp_pci_ctlmask; 12361541Stanimura 12461541Stanimura/* 12561541Stanimura * The following functions are the pci-specific part 12661541Stanimura * of rp driver. 12761541Stanimura */ 12861541Stanimura 12961541Stanimurastatic int 13061541Stanimurarp_pciprobe(device_t dev) 13161541Stanimura{ 13261541Stanimura char *s; 13361541Stanimura 13461541Stanimura s = NULL; 135144090Sjhb if (pci_get_vendor(dev) == RP_VENDOR_ID) 13661541Stanimura s = "RocketPort PCI"; 13761541Stanimura 13861541Stanimura if (s != NULL) { 13961541Stanimura device_set_desc(dev, s); 140142890Simp return (BUS_PROBE_DEFAULT); 14161541Stanimura } 14261541Stanimura 14361541Stanimura return (ENXIO); 14461541Stanimura} 14561541Stanimura 14661541Stanimurastatic int 14761541Stanimurarp_pciattach(device_t dev) 14861541Stanimura{ 14961541Stanimura int num_ports, num_aiops; 15061541Stanimura int aiop; 15161541Stanimura CONTROLLER_t *ctlp; 15261541Stanimura int unit; 15361541Stanimura int retval; 15461541Stanimura 15561541Stanimura ctlp = device_get_softc(dev); 15661541Stanimura bzero(ctlp, sizeof(*ctlp)); 15761541Stanimura ctlp->dev = dev; 15861541Stanimura unit = device_get_unit(dev); 15961541Stanimura ctlp->aiop2rid = rp_pci_aiop2rid; 16061541Stanimura ctlp->aiop2off = rp_pci_aiop2off; 16161541Stanimura ctlp->ctlmask = rp_pci_ctlmask; 16261541Stanimura 16361541Stanimura /* The IO ports of AIOPs for a PCI controller are continuous. */ 16461541Stanimura ctlp->io_num = 1; 16569781Sdwmalone ctlp->io_rid = malloc(sizeof(*(ctlp->io_rid)) * ctlp->io_num, M_DEVBUF, M_NOWAIT | M_ZERO); 16669781Sdwmalone ctlp->io = malloc(sizeof(*(ctlp->io)) * ctlp->io_num, M_DEVBUF, M_NOWAIT | M_ZERO); 16761541Stanimura if (ctlp->io_rid == NULL || ctlp->io == NULL) { 16861541Stanimura device_printf(dev, "rp_pciattach: Out of memory.\n"); 16961541Stanimura retval = ENOMEM; 17061541Stanimura goto nogo; 17161541Stanimura } 17261541Stanimura 17361541Stanimura ctlp->bus_ctlp = NULL; 17461541Stanimura 175144090Sjhb switch (pci_get_device(dev)) { 176191563Sambrisko case RP_DEVICE_ID_UPCI_16: 177154817Sjhb case RP_DEVICE_ID_UPCI_32: 178144090Sjhb case RP_DEVICE_ID_UPCI_8O: 179144090Sjhb ctlp->io_rid[0] = PCIR_BAR(2); 180144090Sjhb break; 181144090Sjhb default: 182144090Sjhb ctlp->io_rid[0] = PCIR_BAR(0); 183144090Sjhb break; 184144090Sjhb } 185127135Snjl ctlp->io[0] = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 186127135Snjl &ctlp->io_rid[0], RF_ACTIVE); 18761541Stanimura if(ctlp->io[0] == NULL) { 18861541Stanimura device_printf(dev, "ioaddr mapping failed for RocketPort(PCI).\n"); 18961541Stanimura retval = ENXIO; 19061541Stanimura goto nogo; 19161541Stanimura } 19261541Stanimura 19361541Stanimura num_aiops = sPCIInitController(ctlp, 19461541Stanimura MAX_AIOPS_PER_BOARD, 0, 195144090Sjhb FREQ_DIS, 0, pci_get_device(dev)); 19661541Stanimura 19761541Stanimura num_ports = 0; 19861541Stanimura for(aiop=0; aiop < num_aiops; aiop++) { 19961541Stanimura sResetAiopByNum(ctlp, aiop); 20061541Stanimura num_ports += sGetAiopNumChan(ctlp, aiop); 20161541Stanimura } 20261541Stanimura 20361541Stanimura retval = rp_attachcommon(ctlp, num_aiops, num_ports); 20461541Stanimura if (retval != 0) 20561541Stanimura goto nogo; 20661541Stanimura 20761541Stanimura return (0); 20861541Stanimura 20961541Stanimuranogo: 21061541Stanimura rp_pcireleaseresource(ctlp); 21161541Stanimura 21261541Stanimura return (retval); 21361541Stanimura} 21461541Stanimura 21561541Stanimurastatic int 21661541Stanimurarp_pcidetach(device_t dev) 21761541Stanimura{ 21861541Stanimura CONTROLLER_t *ctlp; 21961541Stanimura 22061541Stanimura ctlp = device_get_softc(dev); 22161541Stanimura rp_pcireleaseresource(ctlp); 22261541Stanimura 22361541Stanimura return (0); 22461541Stanimura} 22561541Stanimura 22661541Stanimurastatic int 22761541Stanimurarp_pcishutdown(device_t dev) 22861541Stanimura{ 22961541Stanimura CONTROLLER_t *ctlp; 23061541Stanimura 23161541Stanimura ctlp = device_get_softc(dev); 23261541Stanimura rp_pcireleaseresource(ctlp); 23361541Stanimura 23461541Stanimura return (0); 23561541Stanimura} 23661541Stanimura 23761541Stanimurastatic void 23861541Stanimurarp_pcireleaseresource(CONTROLLER_t *ctlp) 23961541Stanimura{ 240130841Sgallatin rp_untimeout(); 24161541Stanimura if (ctlp->io != NULL) { 24261541Stanimura if (ctlp->io[0] != NULL) 24361541Stanimura bus_release_resource(ctlp->dev, SYS_RES_IOPORT, ctlp->io_rid[0], ctlp->io[0]); 24461541Stanimura free(ctlp->io, M_DEVBUF); 245130841Sgallatin ctlp->io = NULL; 24661541Stanimura } 247130841Sgallatin if (ctlp->io_rid != NULL) { 24861541Stanimura free(ctlp->io_rid, M_DEVBUF); 249130841Sgallatin ctlp->io = NULL; 250130841Sgallatin } 251130841Sgallatin rp_releaseresource(ctlp); 25261541Stanimura} 25361541Stanimura 25461541Stanimurastatic int 25561541StanimurasPCIInitController( CONTROLLER_t *CtlP, 25661541Stanimura int AiopNum, 25761541Stanimura int IRQNum, 25861541Stanimura Byte_t Frequency, 25961541Stanimura int PeriodicOnly, 26061541Stanimura int VendorDevice) 26161541Stanimura{ 26261541Stanimura int i; 26361541Stanimura 26461541Stanimura CtlP->CtlID = CTLID_0001; /* controller release 1 */ 26561541Stanimura 26661541Stanimura sPCIControllerEOI(CtlP); 26761541Stanimura 26861541Stanimura /* Init AIOPs */ 26961541Stanimura CtlP->NumAiop = 0; 27061541Stanimura for(i=0; i < AiopNum; i++) 27161541Stanimura { 27261541Stanimura /*device_printf(CtlP->dev, "aiop %d.\n", i);*/ 27361541Stanimura CtlP->AiopID[i] = sReadAiopID(CtlP, i); /* read AIOP ID */ 27461541Stanimura /*device_printf(CtlP->dev, "ID = %d.\n", CtlP->AiopID[i]);*/ 27561541Stanimura if(CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */ 27661541Stanimura { 27761541Stanimura break; /* done looking for AIOPs */ 27861541Stanimura } 27961541Stanimura 28061541Stanimura switch( VendorDevice ) { 28161541Stanimura case RP_DEVICE_ID_4Q: 28261541Stanimura case RP_DEVICE_ID_4J: 28361541Stanimura case RP_DEVICE_ID_4M: 28461541Stanimura CtlP->AiopNumChan[i] = 4; 28561541Stanimura break; 28661541Stanimura case RP_DEVICE_ID_6M: 28761541Stanimura CtlP->AiopNumChan[i] = 6; 28861541Stanimura break; 28961541Stanimura case RP_DEVICE_ID_8O: 29061541Stanimura case RP_DEVICE_ID_8J: 29161541Stanimura case RP_DEVICE_ID_8I: 29261541Stanimura case RP_DEVICE_ID_16I: 29361541Stanimura case RP_DEVICE_ID_32I: 29461541Stanimura CtlP->AiopNumChan[i] = 8; 29561541Stanimura break; 29661541Stanimura default: 297153084Sru#ifdef notdef 29861541Stanimura CtlP->AiopNumChan[i] = 8; 29961541Stanimura#else 30061541Stanimura CtlP->AiopNumChan[i] = sReadAiopNumChan(CtlP, i); 30161541Stanimura#endif /* notdef */ 30261541Stanimura break; 30361541Stanimura } 30461541Stanimura /*device_printf(CtlP->dev, "%d channels.\n", CtlP->AiopNumChan[i]);*/ 30561541Stanimura rp_writeaiop2(CtlP, i, _INDX_ADDR,_CLK_PRE); /* clock prescaler */ 30661541Stanimura /*device_printf(CtlP->dev, "configuring clock prescaler.\n");*/ 30761541Stanimura rp_writeaiop1(CtlP, i, _INDX_DATA,CLOCK_PRESC); 30861541Stanimura /*device_printf(CtlP->dev, "configured clock prescaler.\n");*/ 30961541Stanimura CtlP->NumAiop++; /* bump count of AIOPs */ 31061541Stanimura } 31161541Stanimura 31261541Stanimura if(CtlP->NumAiop == 0) 31361541Stanimura return(-1); 31461541Stanimura else 31561541Stanimura return(CtlP->NumAiop); 31661541Stanimura} 31761541Stanimura 31861541Stanimura/* 31961541Stanimura * ARGSUSED 32061541Stanimura * Maps (aiop, offset) to rid. 32161541Stanimura */ 32261541Stanimurastatic int 32361541Stanimurarp_pci_aiop2rid(int aiop, int offset) 32461541Stanimura{ 32561541Stanimura /* Always return zero for a PCI controller. */ 32661541Stanimura return 0; 32761541Stanimura} 32861541Stanimura 32961541Stanimura/* 33061541Stanimura * ARGSUSED 33161541Stanimura * Maps (aiop, offset) to the offset of resource. 33261541Stanimura */ 33361541Stanimurastatic int 33461541Stanimurarp_pci_aiop2off(int aiop, int offset) 33561541Stanimura{ 33661541Stanimura /* Each AIOP reserves 0x40 bytes. */ 33761541Stanimura return aiop * 0x40 + offset; 33861541Stanimura} 33961541Stanimura 34061541Stanimura/* Read the int status for a PCI controller. */ 341105215Sphkstatic unsigned char 34261541Stanimurarp_pci_ctlmask(CONTROLLER_t *ctlp) 34361541Stanimura{ 34461541Stanimura return sPCIGetControllerIntStatus(ctlp); 34561541Stanimura} 34661541Stanimura 34761541Stanimurastatic device_method_t rp_pcimethods[] = { 34861541Stanimura /* Device interface */ 34961541Stanimura DEVMETHOD(device_probe, rp_pciprobe), 35061541Stanimura DEVMETHOD(device_attach, rp_pciattach), 35161541Stanimura DEVMETHOD(device_detach, rp_pcidetach), 35261541Stanimura DEVMETHOD(device_shutdown, rp_pcishutdown), 35361541Stanimura 35461541Stanimura { 0, 0 } 35561541Stanimura}; 35661541Stanimura 35761541Stanimurastatic driver_t rp_pcidriver = { 35861541Stanimura "rp", 35961541Stanimura rp_pcimethods, 36061541Stanimura sizeof(CONTROLLER_t), 36161541Stanimura}; 36261541Stanimura 36361541Stanimura/* 36461541Stanimura * rp can be attached to a pci bus. 36561541Stanimura */ 36661541StanimuraDRIVER_MODULE(rp, pci, rp_pcidriver, rp_devclass, 0, 0); 367