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