iodi.c revision 212763
1/*-
2 * Copyright (c) 2003-2009 RMI Corporation
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of RMI Corporation, nor the names of its contributors,
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * RMI_BSD
30 */
31
32#include <sys/cdefs.h>
33__FBSDID("$FreeBSD: head/sys/mips/rmi/iodi.c 212763 2010-09-16 20:23:22Z jchandra $");
34
35#define __RMAN_RESOURCE_VISIBLE
36#include <sys/param.h>
37#include <sys/systm.h>
38#include <sys/bus.h>
39#include <sys/kernel.h>
40#include <sys/lock.h>
41#include <sys/mutex.h>
42#include <sys/reboot.h>
43#include <sys/rman.h>
44#include <sys/types.h>
45#include <sys/malloc.h>
46#include <sys/bus.h>
47#include <sys/interrupt.h>
48#include <sys/module.h>
49
50#include <machine/cpu.h>
51#include <machine/bus.h>
52#include <machine/param.h>
53#include <machine/intr_machdep.h>
54#include <machine/clock.h>	/* for DELAY */
55#include <machine/resource.h>
56
57#include <mips/rmi/board.h>
58#include <mips/rmi/pic.h>
59#include <mips/rmi/interrupt.h>
60#include <mips/rmi/msgring.h>
61#include <mips/rmi/iomap.h>
62#include <mips/rmi/rmi_mips_exts.h>
63
64#include <mips/rmi/dev/xlr/atx_cpld.h>
65#include <mips/rmi/dev/xlr/xgmac_mdio.h>
66
67extern bus_space_tag_t uart_bus_space_mem;
68
69static struct resource *
70iodi_alloc_resource(device_t, device_t, int, int *,
71    u_long, u_long, u_long, u_int);
72
73static int
74iodi_activate_resource(device_t, device_t, int, int,
75    struct resource *);
76static int
77iodi_setup_intr(device_t, device_t, struct resource *, int,
78    driver_filter_t *, driver_intr_t *, void *, void **);
79
80struct iodi_softc *iodi_softc;	/* There can be only one. */
81
82/*
83 * We will manage the Flash/PCMCIA devices in IODI for now.
84 * The NOR flash, Compact flash etc. which can be connected on
85 * various chip selects on the peripheral IO, should have a
86 * separate bus later.
87 */
88static void
89bridge_pcmcia_ack(int irq)
90{
91	xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_FLASH_OFFSET);
92
93	xlr_write_reg(mmio, 0x60, 0xffffffff);
94}
95
96static int
97iodi_setup_intr(device_t dev, device_t child,
98    struct resource *ires, int flags, driver_filter_t *filt,
99    driver_intr_t *intr, void *arg, void **cookiep)
100{
101	const char *name = device_get_name(child);
102
103	if (strcmp(name, "uart") == 0) {
104		/* FIXME uart 1? */
105		cpu_establish_hardintr("uart", filt, intr, arg,
106		    PIC_UART_0_IRQ, flags, cookiep);
107		pic_setup_intr(PIC_IRT_UART_0_INDEX, PIC_UART_0_IRQ, 0x1, 1);
108	} else if (strcmp(name, "rge") == 0 || strcmp(name, "nlge") == 0) {
109		int irq;
110
111		/* This is a hack to pass in the irq */
112		irq = (intptr_t)ires->__r_i;
113		cpu_establish_hardintr("rge", filt, intr, arg, irq, flags,
114		    cookiep);
115		pic_setup_intr(irq - PIC_IRQ_BASE, irq, 0x1, 1);
116	} else if (strcmp(name, "ehci") == 0) {
117		cpu_establish_hardintr("ehci", filt, intr, arg, PIC_USB_IRQ, flags,
118		    cookiep);
119		pic_setup_intr(PIC_USB_IRQ - PIC_IRQ_BASE, PIC_USB_IRQ, 0x1, 1);
120	} else if (strcmp(name, "ata") == 0) {
121		xlr_establish_intr("ata", filt, intr, arg, PIC_PCMCIA_IRQ, flags,
122		    cookiep, bridge_pcmcia_ack);
123		pic_setup_intr(PIC_PCMCIA_IRQ - PIC_IRQ_BASE, PIC_PCMCIA_IRQ, 0x1, 1);
124	}
125	return (0);
126}
127
128static struct resource *
129iodi_alloc_resource(device_t bus, device_t child, int type, int *rid,
130    u_long start, u_long end, u_long count, u_int flags)
131{
132	struct resource *res = malloc(sizeof(*res), M_DEVBUF, M_WAITOK);
133	const char *name = device_get_name(child);
134	int unit;
135
136#ifdef DEBUG
137	switch (type) {
138	case SYS_RES_IRQ:
139		device_printf(bus, "IRQ resource - for %s %lx-%lx\n",
140		    device_get_nameunit(child), start, end);
141		break;
142
143	case SYS_RES_IOPORT:
144		device_printf(bus, "IOPORT resource - for %s %lx-%lx\n",
145		    device_get_nameunit(child), start, end);
146		break;
147
148	case SYS_RES_MEMORY:
149		device_printf(bus, "MEMORY resource - for %s %lx-%lx\n",
150		    device_get_nameunit(child), start, end);
151		break;
152	}
153#endif
154
155	if (strcmp(name, "uart") == 0) {
156		if ((unit = device_get_unit(child)) == 0) {	/* uart 0 */
157			res->r_bushandle = (xlr_io_base + XLR_IO_UART_0_OFFSET);
158		} else if (unit == 1) {
159			res->r_bushandle = (xlr_io_base + XLR_IO_UART_1_OFFSET);
160		} else
161			printf("%s: Unknown uart unit\n", __FUNCTION__);
162
163		res->r_bustag = uart_bus_space_mem;
164	} else if (strcmp(name, "ehci") == 0) {
165		res->r_bushandle = MIPS_PHYS_TO_KSEG1(0x1ef24000);
166		res->r_bustag = rmi_pci_bus_space;
167	} else if (strcmp(name, "cfi") == 0) {
168		res->r_bushandle = MIPS_PHYS_TO_KSEG1(0x1c000000);
169		res->r_bustag = 0;
170	} else if (strcmp(name, "ata") == 0) {
171		res->r_bushandle = MIPS_PHYS_TO_KSEG1(0x1d000000);
172		res->r_bustag = rmi_pci_bus_space;  /* byte swapping (not really PCI) */
173	}
174	/* res->r_start = *rid; */
175	return (res);
176}
177
178static int
179iodi_activate_resource(device_t bus, device_t child, int type, int rid,
180    struct resource *r)
181{
182	return (0);
183}
184
185/* prototypes */
186static int iodi_probe(device_t);
187static int iodi_attach(device_t);
188static int iodi_detach(device_t);
189static void iodi_identify(driver_t *, device_t);
190
191int
192iodi_probe(device_t dev)
193{
194	return 0;
195}
196
197void
198iodi_identify(driver_t * driver, device_t parent)
199{
200
201	BUS_ADD_CHILD(parent, 0, "iodi", 0);
202}
203
204int
205iodi_attach(device_t dev)
206{
207	device_t tmpd;
208	int i;
209
210	/*
211	 * Attach each devices
212	 */
213	device_add_child(dev, "uart", 0);
214	device_add_child(dev, "xlr_i2c", 0);
215	device_add_child(dev, "pcib", 0);
216	device_add_child(dev, "rmisec", -1);
217
218	if (xlr_board_info.usb)
219		device_add_child(dev, "ehci", 0);
220
221	if (xlr_board_info.cfi)
222		device_add_child(dev, "cfi", 0);
223
224	if (xlr_board_info.ata)
225		device_add_child(dev, "ata", 0);
226
227	if (xlr_board_info.gmac_block[0].enabled) {
228		tmpd = device_add_child(dev, "rge", 0);
229		device_set_ivars(tmpd, &xlr_board_info.gmac_block[0]);
230
231		tmpd = device_add_child(dev, "rge", 1);
232		device_set_ivars(tmpd, &xlr_board_info.gmac_block[0]);
233
234		tmpd = device_add_child(dev, "rge", 2);
235		device_set_ivars(tmpd, &xlr_board_info.gmac_block[0]);
236
237		tmpd = device_add_child(dev, "rge", 3);
238		device_set_ivars(tmpd, &xlr_board_info.gmac_block[0]);
239	}
240	if (xlr_board_info.gmac_block[1].enabled) {
241		if (xlr_board_info.gmac_block[1].type == XLR_GMAC) {
242			tmpd = device_add_child(dev, "rge", 4);
243			device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]);
244
245			tmpd = device_add_child(dev, "rge", 5);
246			device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]);
247
248			if (xlr_board_info.gmac_block[1].enabled & 0x4) {
249				tmpd = device_add_child(dev, "rge", 6);
250				device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]);
251			}
252
253			if (xlr_board_info.gmac_block[1].enabled & 0x8) {
254				tmpd = device_add_child(dev, "rge", 7);
255				device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]);
256			}
257		} else if (xlr_board_info.gmac_block[1].type == XLR_XGMAC) {
258#if 0				/* XGMAC not yet */
259			tmpd = device_add_child(dev, "rge", 4);
260			device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]);
261
262			tmpd = device_add_child(dev, "rge", 5);
263			device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]);
264#endif
265		} else
266			device_printf(dev, "Unknown type of gmac 1\n");
267	}
268
269	/* This is to add the new GMAC driver. The above adds the old driver,
270	   which has been retained for now as the new driver is stabilized.
271	   The new driver is enabled with "option nlge". Make sure that only
272	   one of rge or nlge is enabled in the conf file. */
273	for (i = 0; i < 3; i++) {
274		if (xlr_board_info.gmac_block[i].enabled == 0)
275			continue;
276		tmpd = device_add_child(dev, "nlna", i);
277		device_set_ivars(tmpd, &xlr_board_info.gmac_block[i]);
278	}
279	bus_generic_probe(dev);
280	bus_generic_attach(dev);
281	return 0;
282}
283
284int
285iodi_detach(device_t dev)
286{
287	device_t nlna_dev;
288	int error, i, ret;
289
290	error = 0;
291	ret = 0;
292	for (i = 0; i < 3; i++) {
293		nlna_dev = device_find_child(dev, "nlna", i);
294		if (nlna_dev != NULL)
295			error = bus_generic_detach(nlna_dev);
296		if (error)
297			ret = error;
298	}
299	return ret;
300}
301
302static device_method_t iodi_methods[] = {
303	DEVMETHOD(device_probe, iodi_probe),
304	DEVMETHOD(device_attach, iodi_attach),
305	DEVMETHOD(device_detach, iodi_detach),
306	DEVMETHOD(device_identify, iodi_identify),
307	DEVMETHOD(bus_alloc_resource, iodi_alloc_resource),
308	DEVMETHOD(bus_activate_resource, iodi_activate_resource),
309	DEVMETHOD(bus_add_child, bus_generic_add_child),
310	DEVMETHOD(bus_setup_intr, iodi_setup_intr),
311	{0, 0},
312};
313
314static driver_t iodi_driver = {
315	"iodi",
316	iodi_methods,
317	1			/* no softc */
318};
319static devclass_t iodi_devclass;
320
321DRIVER_MODULE(iodi, nexus, iodi_driver, iodi_devclass, 0, 0);
322