iodi.c revision 211994
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 211994 2010-08-30 13:05:21Z 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, 0);
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, 0);
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, 0);
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, 0);
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	int unit;
134
135#ifdef DEBUG
136	switch (type) {
137	case SYS_RES_IRQ:
138		device_printf(bus, "IRQ resource - for %s %lx-%lx\n",
139		    device_get_nameunit(child), start, end);
140		break;
141
142	case SYS_RES_IOPORT:
143		device_printf(bus, "IOPORT resource - for %s %lx-%lx\n",
144		    device_get_nameunit(child), start, end);
145		break;
146
147	case SYS_RES_MEMORY:
148		device_printf(bus, "MEMORY resource - for %s %lx-%lx\n",
149		    device_get_nameunit(child), start, end);
150		break;
151	}
152#endif
153
154	if (strcmp(device_get_name(child), "uart") == 0) {
155		if ((unit = device_get_unit(child)) == 0) {	/* uart 0 */
156			res->r_bushandle = (xlr_io_base + XLR_IO_UART_0_OFFSET);
157		} else if (unit == 1) {
158			res->r_bushandle = (xlr_io_base + XLR_IO_UART_1_OFFSET);
159		} else
160			printf("%s: Unknown uart unit\n", __FUNCTION__);
161
162		res->r_bustag = uart_bus_space_mem;
163	} else if (strcmp(device_get_name(child), "ehci") == 0) {
164		res->r_bushandle = MIPS_PHYS_TO_KSEG1(0x1ef24000);
165		res->r_bustag = rmi_pci_bus_space;
166	} else if (strcmp(device_get_name(child), "cfi") == 0) {
167		res->r_bushandle = MIPS_PHYS_TO_KSEG1(0x1c000000);
168		res->r_bustag = 0;
169	} else if (strcmp(device_get_name(child), "ata") == 0) {
170		res->r_bushandle = MIPS_PHYS_TO_KSEG1(0x1d000000);
171		res->r_bustag = rmi_pci_bus_space;  /* byte swapping (not really PCI) */
172	}
173	/* res->r_start = *rid; */
174	return (res);
175}
176
177static int
178iodi_activate_resource(device_t bus, device_t child, int type, int rid,
179    struct resource *r)
180{
181	return (0);
182}
183
184/* prototypes */
185static int iodi_probe(device_t);
186static int iodi_attach(device_t);
187static int iodi_detach(device_t);
188static void iodi_identify(driver_t *, device_t);
189
190int
191iodi_probe(device_t dev)
192{
193	return 0;
194}
195
196void
197iodi_identify(driver_t * driver, device_t parent)
198{
199
200	BUS_ADD_CHILD(parent, 0, "iodi", 0);
201}
202
203int
204iodi_attach(device_t dev)
205{
206	device_t tmpd;
207	int i;
208
209	/*
210	 * Attach each devices
211	 */
212	device_add_child(dev, "uart", 0);
213	device_add_child(dev, "xlr_i2c", 0);
214	device_add_child(dev, "pcib", 0);
215
216	if (xlr_board_info.usb)
217		device_add_child(dev, "ehci", 0);
218
219	if (xlr_board_info.cfi)
220		device_add_child(dev, "cfi", 0);
221
222	if (xlr_board_info.ata)
223		device_add_child(dev, "ata", 0);
224
225	if (xlr_board_info.gmac_block[0].enabled) {
226		tmpd = device_add_child(dev, "rge", 0);
227		device_set_ivars(tmpd, &xlr_board_info.gmac_block[0]);
228
229		tmpd = device_add_child(dev, "rge", 1);
230		device_set_ivars(tmpd, &xlr_board_info.gmac_block[0]);
231
232		tmpd = device_add_child(dev, "rge", 2);
233		device_set_ivars(tmpd, &xlr_board_info.gmac_block[0]);
234
235		tmpd = device_add_child(dev, "rge", 3);
236		device_set_ivars(tmpd, &xlr_board_info.gmac_block[0]);
237	}
238	if (xlr_board_info.gmac_block[1].enabled) {
239		if (xlr_board_info.gmac_block[1].type == XLR_GMAC) {
240			tmpd = device_add_child(dev, "rge", 4);
241			device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]);
242
243			tmpd = device_add_child(dev, "rge", 5);
244			device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]);
245
246			if (xlr_board_info.gmac_block[1].enabled & 0x4) {
247				tmpd = device_add_child(dev, "rge", 6);
248				device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]);
249			}
250
251			if (xlr_board_info.gmac_block[1].enabled & 0x8) {
252				tmpd = device_add_child(dev, "rge", 7);
253				device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]);
254			}
255		} else if (xlr_board_info.gmac_block[1].type == XLR_XGMAC) {
256#if 0				/* XGMAC not yet */
257			tmpd = device_add_child(dev, "rge", 4);
258			device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]);
259
260			tmpd = device_add_child(dev, "rge", 5);
261			device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]);
262#endif
263		} else
264			device_printf(dev, "Unknown type of gmac 1\n");
265	}
266
267	/* This is to add the new GMAC driver. The above adds the old driver,
268	   which has been retained for now as the new driver is stabilized.
269	   The new driver is enabled with "option nlge". Make sure that only
270	   one of rge or nlge is enabled in the conf file. */
271	for (i = 0; i < 3; i++) {
272		if (xlr_board_info.gmac_block[i].enabled == 0)
273			continue;
274		tmpd = device_add_child(dev, "nlna", i);
275		device_set_ivars(tmpd, &xlr_board_info.gmac_block[i]);
276	}
277	bus_generic_probe(dev);
278	bus_generic_attach(dev);
279	return 0;
280}
281
282int
283iodi_detach(device_t dev)
284{
285	device_t nlna_dev;
286	int error, i, ret;
287
288	error = 0;
289	ret = 0;
290	for (i = 0; i < 3; i++) {
291		nlna_dev = device_find_child(dev, "nlna", i);
292		if (nlna_dev != NULL)
293			error = bus_generic_detach(nlna_dev);
294		if (error)
295			ret = error;
296	}
297	return ret;
298}
299
300static device_method_t iodi_methods[] = {
301	DEVMETHOD(device_probe, iodi_probe),
302	DEVMETHOD(device_attach, iodi_attach),
303	DEVMETHOD(device_detach, iodi_detach),
304	DEVMETHOD(device_identify, iodi_identify),
305	DEVMETHOD(bus_alloc_resource, iodi_alloc_resource),
306	DEVMETHOD(bus_activate_resource, iodi_activate_resource),
307	DEVMETHOD(bus_setup_intr, iodi_setup_intr),
308	{0, 0},
309};
310
311static driver_t iodi_driver = {
312	"iodi",
313	iodi_methods,
314	1			/* no softc */
315};
316static devclass_t iodi_devclass;
317
318DRIVER_MODULE(iodi, nexus, iodi_driver, iodi_devclass, 0, 0);
319