iodi.c revision 212102
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 212102 2010-09-01 17:35:31Z 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	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
217	if (xlr_board_info.usb)
218		device_add_child(dev, "ehci", 0);
219
220	if (xlr_board_info.cfi)
221		device_add_child(dev, "cfi", 0);
222
223	if (xlr_board_info.ata)
224		device_add_child(dev, "ata", 0);
225
226	if (xlr_board_info.gmac_block[0].enabled) {
227		tmpd = device_add_child(dev, "rge", 0);
228		device_set_ivars(tmpd, &xlr_board_info.gmac_block[0]);
229
230		tmpd = device_add_child(dev, "rge", 1);
231		device_set_ivars(tmpd, &xlr_board_info.gmac_block[0]);
232
233		tmpd = device_add_child(dev, "rge", 2);
234		device_set_ivars(tmpd, &xlr_board_info.gmac_block[0]);
235
236		tmpd = device_add_child(dev, "rge", 3);
237		device_set_ivars(tmpd, &xlr_board_info.gmac_block[0]);
238	}
239	if (xlr_board_info.gmac_block[1].enabled) {
240		if (xlr_board_info.gmac_block[1].type == XLR_GMAC) {
241			tmpd = device_add_child(dev, "rge", 4);
242			device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]);
243
244			tmpd = device_add_child(dev, "rge", 5);
245			device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]);
246
247			if (xlr_board_info.gmac_block[1].enabled & 0x4) {
248				tmpd = device_add_child(dev, "rge", 6);
249				device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]);
250			}
251
252			if (xlr_board_info.gmac_block[1].enabled & 0x8) {
253				tmpd = device_add_child(dev, "rge", 7);
254				device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]);
255			}
256		} else if (xlr_board_info.gmac_block[1].type == XLR_XGMAC) {
257#if 0				/* XGMAC not yet */
258			tmpd = device_add_child(dev, "rge", 4);
259			device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]);
260
261			tmpd = device_add_child(dev, "rge", 5);
262			device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]);
263#endif
264		} else
265			device_printf(dev, "Unknown type of gmac 1\n");
266	}
267
268	/* This is to add the new GMAC driver. The above adds the old driver,
269	   which has been retained for now as the new driver is stabilized.
270	   The new driver is enabled with "option nlge". Make sure that only
271	   one of rge or nlge is enabled in the conf file. */
272	for (i = 0; i < 3; i++) {
273		if (xlr_board_info.gmac_block[i].enabled == 0)
274			continue;
275		tmpd = device_add_child(dev, "nlna", i);
276		device_set_ivars(tmpd, &xlr_board_info.gmac_block[i]);
277	}
278	bus_generic_probe(dev);
279	bus_generic_attach(dev);
280	return 0;
281}
282
283int
284iodi_detach(device_t dev)
285{
286	device_t nlna_dev;
287	int error, i, ret;
288
289	error = 0;
290	ret = 0;
291	for (i = 0; i < 3; i++) {
292		nlna_dev = device_find_child(dev, "nlna", i);
293		if (nlna_dev != NULL)
294			error = bus_generic_detach(nlna_dev);
295		if (error)
296			ret = error;
297	}
298	return ret;
299}
300
301static device_method_t iodi_methods[] = {
302	DEVMETHOD(device_probe, iodi_probe),
303	DEVMETHOD(device_attach, iodi_attach),
304	DEVMETHOD(device_detach, iodi_detach),
305	DEVMETHOD(device_identify, iodi_identify),
306	DEVMETHOD(bus_alloc_resource, iodi_alloc_resource),
307	DEVMETHOD(bus_activate_resource, iodi_activate_resource),
308	DEVMETHOD(bus_setup_intr, iodi_setup_intr),
309	{0, 0},
310};
311
312static driver_t iodi_driver = {
313	"iodi",
314	iodi_methods,
315	1			/* no softc */
316};
317static devclass_t iodi_devclass;
318
319DRIVER_MODULE(iodi, nexus, iodi_driver, iodi_devclass, 0, 0);
320