rp_pci.c revision 153084
1/*-
2 * Copyright (c) Comtrol Corporation <support@comtrol.com>
3 * All rights reserved.
4 *
5 * PCI-specific part separated from:
6 * sys/i386/isa/rp.c,v 1.33 1999/09/28 11:45:27 phk Exp
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted prodived that the follwoing conditions
10 * are met.
11 * 1. Redistributions of source code must retain the above copyright
12 *    notive, this list of conditions and the following disclainer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials prodided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *       This product includes software developed by Comtrol Corporation.
19 * 4. The name of Comtrol Corporation may not be used to endorse or
20 *    promote products derived from this software without specific
21 *    prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY COMTROL CORPORATION ``AS IS'' AND ANY
24 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL COMTROL CORPORATION BE LIABLE FOR
27 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include <sys/cdefs.h>
37__FBSDID("$FreeBSD: head/sys/dev/rp/rp_pci.c 153084 2005-12-04 10:06:06Z ru $");
38
39#include <sys/param.h>
40#include <sys/systm.h>
41#include <sys/fcntl.h>
42#include <sys/malloc.h>
43#include <sys/tty.h>
44#include <sys/conf.h>
45#include <sys/kernel.h>
46#include <sys/module.h>
47#include <machine/resource.h>
48#include <machine/bus.h>
49#include <sys/bus.h>
50#include <sys/rman.h>
51
52#define ROCKET_C
53#include <dev/rp/rpreg.h>
54#include <dev/rp/rpvar.h>
55
56#include <dev/pci/pcireg.h>
57#include <dev/pci/pcivar.h>
58
59/* PCI IDs  */
60#define RP_VENDOR_ID		0x11FE
61#define RP_DEVICE_ID_32I	0x0001
62#define RP_DEVICE_ID_8I		0x0002
63#define RP_DEVICE_ID_16I	0x0003
64#define RP_DEVICE_ID_4Q		0x0004
65#define RP_DEVICE_ID_8O		0x0005
66#define RP_DEVICE_ID_8J		0x0006
67#define RP_DEVICE_ID_4J		0x0007
68#define RP_DEVICE_ID_6M		0x000C
69#define RP_DEVICE_ID_4M		0x000D
70#define RP_DEVICE_ID_UPCI_8O	0x0805
71
72/**************************************************************************
73  MUDBAC remapped for PCI
74**************************************************************************/
75
76#define _CFG_INT_PCI	0x40
77#define _PCI_INT_FUNC	0x3A
78
79#define PCI_STROB	0x2000
80#define INTR_EN_PCI	0x0010
81
82/***************************************************************************
83Function: sPCIControllerEOI
84Purpose:  Strobe the MUDBAC's End Of Interrupt bit.
85Call:	  sPCIControllerEOI(CtlP)
86	  CONTROLLER_T *CtlP; Ptr to controller structure
87*/
88#define sPCIControllerEOI(CtlP) rp_writeio2(CtlP, 0, _PCI_INT_FUNC, PCI_STROB)
89
90/***************************************************************************
91Function: sPCIGetControllerIntStatus
92Purpose:  Get the controller interrupt status
93Call:	  sPCIGetControllerIntStatus(CtlP)
94	  CONTROLLER_T *CtlP; Ptr to controller structure
95Return:   Byte_t: The controller interrupt status in the lower 4
96			 bits.	Bits 0 through 3 represent AIOP's 0
97			 through 3 respectively.  If a bit is set that
98			 AIOP is interrupting.	Bits 4 through 7 will
99			 always be cleared.
100*/
101#define sPCIGetControllerIntStatus(CTLP) ((rp_readio2(CTLP, 0, _PCI_INT_FUNC) >> 8) & 0x1f)
102
103static devclass_t rp_devclass;
104
105static int rp_pciprobe(device_t dev);
106static int rp_pciattach(device_t dev);
107#ifdef notdef
108static int rp_pcidetach(device_t dev);
109static int rp_pcishutdown(device_t dev);
110#endif /* notdef */
111static void rp_pcireleaseresource(CONTROLLER_t *ctlp);
112static int sPCIInitController( CONTROLLER_t *CtlP,
113			       int AiopNum,
114			       int IRQNum,
115			       Byte_t Frequency,
116			       int PeriodicOnly,
117			       int VendorDevice);
118static rp_aiop2rid_t rp_pci_aiop2rid;
119static rp_aiop2off_t rp_pci_aiop2off;
120static rp_ctlmask_t rp_pci_ctlmask;
121
122/*
123 * The following functions are the pci-specific part
124 * of rp driver.
125 */
126
127static int
128rp_pciprobe(device_t dev)
129{
130	char *s;
131
132	s = NULL;
133	if (pci_get_vendor(dev) == RP_VENDOR_ID)
134		s = "RocketPort PCI";
135
136	if (s != NULL) {
137		device_set_desc(dev, s);
138		return (BUS_PROBE_DEFAULT);
139	}
140
141	return (ENXIO);
142}
143
144static int
145rp_pciattach(device_t dev)
146{
147	int	num_ports, num_aiops;
148	int	aiop;
149	CONTROLLER_t	*ctlp;
150	int	unit;
151	int	retval;
152	u_int32_t	stcmd;
153
154	ctlp = device_get_softc(dev);
155	bzero(ctlp, sizeof(*ctlp));
156	ctlp->dev = dev;
157	unit = device_get_unit(dev);
158	ctlp->aiop2rid = rp_pci_aiop2rid;
159	ctlp->aiop2off = rp_pci_aiop2off;
160	ctlp->ctlmask = rp_pci_ctlmask;
161
162	/* Wake up the device. */
163	stcmd = pci_read_config(dev, PCIR_COMMAND, 4);
164	if ((stcmd & PCIM_CMD_PORTEN) == 0) {
165		stcmd |= (PCIM_CMD_PORTEN);
166		pci_write_config(dev, PCIR_COMMAND, 4, stcmd);
167	}
168
169	/* The IO ports of AIOPs for a PCI controller are continuous. */
170	ctlp->io_num = 1;
171	ctlp->io_rid = malloc(sizeof(*(ctlp->io_rid)) * ctlp->io_num, M_DEVBUF, M_NOWAIT | M_ZERO);
172	ctlp->io = malloc(sizeof(*(ctlp->io)) * ctlp->io_num, M_DEVBUF, M_NOWAIT | M_ZERO);
173	if (ctlp->io_rid == NULL || ctlp->io == NULL) {
174		device_printf(dev, "rp_pciattach: Out of memory.\n");
175		retval = ENOMEM;
176		goto nogo;
177	}
178
179	ctlp->bus_ctlp = NULL;
180
181	switch (pci_get_device(dev)) {
182	case RP_DEVICE_ID_UPCI_8O:
183		ctlp->io_rid[0] = PCIR_BAR(2);
184		break;
185	default:
186		ctlp->io_rid[0] = PCIR_BAR(0);
187		break;
188	}
189	ctlp->io[0] = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
190		&ctlp->io_rid[0], RF_ACTIVE);
191	if(ctlp->io[0] == NULL) {
192		device_printf(dev, "ioaddr mapping failed for RocketPort(PCI).\n");
193		retval = ENXIO;
194		goto nogo;
195	}
196
197	num_aiops = sPCIInitController(ctlp,
198				       MAX_AIOPS_PER_BOARD, 0,
199				       FREQ_DIS, 0, pci_get_device(dev));
200
201	num_ports = 0;
202	for(aiop=0; aiop < num_aiops; aiop++) {
203		sResetAiopByNum(ctlp, aiop);
204		num_ports += sGetAiopNumChan(ctlp, aiop);
205	}
206
207	retval = rp_attachcommon(ctlp, num_aiops, num_ports);
208	if (retval != 0)
209		goto nogo;
210
211	return (0);
212
213nogo:
214	rp_pcireleaseresource(ctlp);
215
216	return (retval);
217}
218
219static int
220rp_pcidetach(device_t dev)
221{
222	CONTROLLER_t	*ctlp;
223
224	if (device_get_state(dev) == DS_BUSY)
225		return (EBUSY);
226
227	ctlp = device_get_softc(dev);
228
229	rp_pcireleaseresource(ctlp);
230
231	return (0);
232}
233
234static int
235rp_pcishutdown(device_t dev)
236{
237	CONTROLLER_t	*ctlp;
238
239	if (device_get_state(dev) == DS_BUSY)
240		return (EBUSY);
241
242	ctlp = device_get_softc(dev);
243
244	rp_pcireleaseresource(ctlp);
245
246	return (0);
247}
248
249static void
250rp_pcireleaseresource(CONTROLLER_t *ctlp)
251{
252	rp_untimeout();
253	if (ctlp->io != NULL) {
254		if (ctlp->io[0] != NULL)
255			bus_release_resource(ctlp->dev, SYS_RES_IOPORT, ctlp->io_rid[0], ctlp->io[0]);
256		free(ctlp->io, M_DEVBUF);
257		ctlp->io = NULL;
258	}
259	if (ctlp->io_rid != NULL) {
260		free(ctlp->io_rid, M_DEVBUF);
261		ctlp->io = NULL;
262	}
263	rp_releaseresource(ctlp);
264}
265
266static int
267sPCIInitController( CONTROLLER_t *CtlP,
268		    int AiopNum,
269		    int IRQNum,
270		    Byte_t Frequency,
271		    int PeriodicOnly,
272		    int VendorDevice)
273{
274	int		i;
275
276	CtlP->CtlID = CTLID_0001;	/* controller release 1 */
277
278	sPCIControllerEOI(CtlP);
279
280	/* Init AIOPs */
281	CtlP->NumAiop = 0;
282	for(i=0; i < AiopNum; i++)
283	{
284		/*device_printf(CtlP->dev, "aiop %d.\n", i);*/
285		CtlP->AiopID[i] = sReadAiopID(CtlP, i);	/* read AIOP ID */
286		/*device_printf(CtlP->dev, "ID = %d.\n", CtlP->AiopID[i]);*/
287		if(CtlP->AiopID[i] == AIOPID_NULL)	/* if AIOP does not exist */
288		{
289			break;				/* done looking for AIOPs */
290		}
291
292		switch( VendorDevice ) {
293		case RP_DEVICE_ID_4Q:
294		case RP_DEVICE_ID_4J:
295		case RP_DEVICE_ID_4M:
296      			CtlP->AiopNumChan[i] = 4;
297			break;
298		case RP_DEVICE_ID_6M:
299      			CtlP->AiopNumChan[i] = 6;
300			break;
301		case RP_DEVICE_ID_8O:
302		case RP_DEVICE_ID_8J:
303		case RP_DEVICE_ID_8I:
304		case RP_DEVICE_ID_16I:
305		case RP_DEVICE_ID_32I:
306      			CtlP->AiopNumChan[i] = 8;
307			break;
308		default:
309#ifdef notdef
310      			CtlP->AiopNumChan[i] = 8;
311#else
312      			CtlP->AiopNumChan[i] = sReadAiopNumChan(CtlP, i);
313#endif /* notdef */
314			break;
315		}
316		/*device_printf(CtlP->dev, "%d channels.\n", CtlP->AiopNumChan[i]);*/
317		rp_writeaiop2(CtlP, i, _INDX_ADDR,_CLK_PRE);	/* clock prescaler */
318		/*device_printf(CtlP->dev, "configuring clock prescaler.\n");*/
319		rp_writeaiop1(CtlP, i, _INDX_DATA,CLOCK_PRESC);
320		/*device_printf(CtlP->dev, "configured clock prescaler.\n");*/
321		CtlP->NumAiop++;				/* bump count of AIOPs */
322	}
323
324	if(CtlP->NumAiop == 0)
325		return(-1);
326	else
327		return(CtlP->NumAiop);
328}
329
330/*
331 * ARGSUSED
332 * Maps (aiop, offset) to rid.
333 */
334static int
335rp_pci_aiop2rid(int aiop, int offset)
336{
337	/* Always return zero for a PCI controller. */
338	return 0;
339}
340
341/*
342 * ARGSUSED
343 * Maps (aiop, offset) to the offset of resource.
344 */
345static int
346rp_pci_aiop2off(int aiop, int offset)
347{
348	/* Each AIOP reserves 0x40 bytes. */
349	return aiop * 0x40 + offset;
350}
351
352/* Read the int status for a PCI controller. */
353static unsigned char
354rp_pci_ctlmask(CONTROLLER_t *ctlp)
355{
356	return sPCIGetControllerIntStatus(ctlp);
357}
358
359static device_method_t rp_pcimethods[] = {
360	/* Device interface */
361	DEVMETHOD(device_probe,		rp_pciprobe),
362	DEVMETHOD(device_attach,	rp_pciattach),
363	DEVMETHOD(device_detach,	rp_pcidetach),
364	DEVMETHOD(device_shutdown,	rp_pcishutdown),
365
366	{ 0, 0 }
367};
368
369static driver_t rp_pcidriver = {
370	"rp",
371	rp_pcimethods,
372	sizeof(CONTROLLER_t),
373};
374
375/*
376 * rp can be attached to a pci bus.
377 */
378DRIVER_MODULE(rp, pci, rp_pcidriver, rp_devclass, 0, 0);
379