iodi.c revision 211946
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 211946 2010-08-28 19:02:51Z 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/types.h>
44#include <sys/malloc.h>
45#include <sys/bus.h>
46#include <sys/interrupt.h>
47#include <sys/module.h>
48
49#include <machine/cpu.h>
50#include <machine/bus.h>
51#include <machine/bus.h>
52#include <machine/intr_machdep.h>
53#include <mips/rmi/iomap.h>
54#include <mips/rmi/pic.h>
55#include <mips/rmi/shared_structs.h>
56#include <mips/rmi/board.h>
57#include <sys/rman.h>
58
59
60#include <machine/param.h>
61#include <machine/intr_machdep.h>
62#include <machine/clock.h>	/* for DELAY */
63#include <machine/bus.h>
64#include <machine/resource.h>
65#include <mips/rmi/interrupt.h>
66#include <mips/rmi/msgring.h>
67#include <mips/rmi/iomap.h>
68#include <mips/rmi/debug.h>
69#include <mips/rmi/pic.h>
70#include <mips/rmi/xlrconfig.h>
71#include <mips/rmi/shared_structs.h>
72#include <mips/rmi/board.h>
73
74#include <mips/rmi/dev/xlr/atx_cpld.h>
75#include <mips/rmi/dev/xlr/xgmac_mdio.h>
76
77extern bus_space_tag_t uart_bus_space_mem;
78
79static struct resource *
80iodi_alloc_resource(device_t, device_t, int, int *,
81    u_long, u_long, u_long, u_int);
82
83static int
84iodi_activate_resource(device_t, device_t, int, int,
85    struct resource *);
86static int
87iodi_setup_intr(device_t, device_t, struct resource *, int,
88    driver_filter_t *, driver_intr_t *, void *, void **);
89
90struct iodi_softc *iodi_softc;	/* There can be only one. */
91
92/*
93 * We will manage the Flash/PCMCIA devices in IODI for now.
94 * The NOR flash, Compact flash etc. which can be connected on
95 * various chip selects on the peripheral IO, should have a
96 * separate bus later.
97 */
98static void
99bridge_pcmcia_ack(int irq)
100{
101	xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_FLASH_OFFSET);
102
103	xlr_write_reg(mmio, 0x60, 0xffffffff);
104}
105
106static int
107iodi_setup_intr(device_t dev, device_t child,
108    struct resource *ires, int flags, driver_filter_t * filt,
109    driver_intr_t *intr, void *arg, void **cookiep)
110{
111	const char *name = device_get_name(child);
112
113	if (strcmp(name, "uart") == 0) {
114		/* FIXME uart 1? */
115		cpu_establish_hardintr("uart", filt, intr, arg,
116		    PIC_UART_0_IRQ, flags, cookiep);
117		pic_setup_intr(PIC_IRT_UART_0_INDEX, PIC_UART_0_IRQ, 0x1, 0);
118	} else if (strcmp(name, "rge") == 0 || strcmp(name, "nlge") == 0) {
119		int irq;
120
121		/* This is a hack to pass in the irq */
122		irq = (intptr_t)ires->__r_i;
123		cpu_establish_hardintr("rge", filt, intr, arg, irq, flags,
124		    cookiep);
125		pic_setup_intr(irq - PIC_IRQ_BASE, irq, 0x1, 0);
126	} else if (strcmp(name, "ehci") == 0) {
127		cpu_establish_hardintr("ehci", filt, intr, arg, PIC_USB_IRQ, flags,
128		    cookiep);
129		pic_setup_intr(PIC_USB_IRQ - PIC_IRQ_BASE, PIC_USB_IRQ, 0x1, 0);
130	} else if (strcmp(name, "ata") == 0) {
131		xlr_establish_intr("ata", filt, intr, arg, PIC_PCMCIA_IRQ, flags,
132		    cookiep, bridge_pcmcia_ack);
133		pic_setup_intr(PIC_PCMCIA_IRQ - PIC_IRQ_BASE, PIC_PCMCIA_IRQ, 0x1, 0);
134	}
135	return (0);
136}
137
138static struct resource *
139iodi_alloc_resource(device_t bus, device_t child, int type, int *rid,
140    u_long start, u_long end, u_long count, u_int flags)
141{
142	struct resource *res = malloc(sizeof(*res), M_DEVBUF, M_WAITOK);
143	int unit;
144
145#ifdef DEBUG
146	switch (type) {
147	case SYS_RES_IRQ:
148		device_printf(bus, "IRQ resource - for %s %lx-%lx\n",
149		    device_get_nameunit(child), start, end);
150		break;
151
152	case SYS_RES_IOPORT:
153		device_printf(bus, "IOPORT resource - for %s %lx-%lx\n",
154		    device_get_nameunit(child), start, end);
155		break;
156
157	case SYS_RES_MEMORY:
158		device_printf(bus, "MEMORY resource - for %s %lx-%lx\n",
159		    device_get_nameunit(child), start, end);
160		break;
161	}
162#endif
163
164	if (strcmp(device_get_name(child), "uart") == 0) {
165		if ((unit = device_get_unit(child)) == 0) {	/* uart 0 */
166			res->r_bushandle = (xlr_io_base + XLR_IO_UART_0_OFFSET);
167		} else if (unit == 1) {
168			res->r_bushandle = (xlr_io_base + XLR_IO_UART_1_OFFSET);
169		} else
170			printf("%s: Unknown uart unit\n", __FUNCTION__);
171
172		res->r_bustag = uart_bus_space_mem;
173	} else if (strcmp(device_get_name(child), "ehci") == 0) {
174		res->r_bushandle = MIPS_PHYS_TO_KSEG1(0x1ef24000);
175		res->r_bustag = rmi_pci_bus_space;
176	} else if (strcmp(device_get_name(child), "cfi") == 0) {
177		res->r_bushandle = MIPS_PHYS_TO_KSEG1(0x1c000000);
178		res->r_bustag = 0;
179	} else if (strcmp(device_get_name(child), "ata") == 0) {
180		res->r_bushandle = MIPS_PHYS_TO_KSEG1(0x1d000000);
181		res->r_bustag = rmi_pci_bus_space;  /* byte swapping (not really PCI) */
182	}
183	/* res->r_start = *rid; */
184	return (res);
185}
186
187static int
188iodi_activate_resource(device_t bus, device_t child, int type, int rid,
189    struct resource *r)
190{
191	return (0);
192}
193
194/* prototypes */
195static int iodi_probe(device_t);
196static int iodi_attach(device_t);
197static int iodi_detach(device_t);
198static void iodi_identify(driver_t *, device_t);
199
200int
201iodi_probe(device_t dev)
202{
203	return 0;
204}
205
206void
207iodi_identify(driver_t * driver, device_t parent)
208{
209
210	BUS_ADD_CHILD(parent, 0, "iodi", 0);
211}
212
213int
214iodi_attach(device_t dev)
215{
216	device_t tmpd;
217	int i;
218
219	/*
220	 * Attach each devices
221	 */
222	device_add_child(dev, "uart", 0);
223	device_add_child(dev, "xlr_i2c", 0);
224	device_add_child(dev, "pcib", 0);
225
226	if (xlr_board_info.usb)
227		device_add_child(dev, "ehci", 0);
228
229	if (xlr_board_info.cfi)
230		device_add_child(dev, "cfi", 0);
231
232	if (xlr_board_info.ata)
233		device_add_child(dev, "ata", 0);
234
235	if (xlr_board_info.gmac_block[0].enabled) {
236		tmpd = device_add_child(dev, "rge", 0);
237		device_set_ivars(tmpd, &xlr_board_info.gmac_block[0]);
238
239		tmpd = device_add_child(dev, "rge", 1);
240		device_set_ivars(tmpd, &xlr_board_info.gmac_block[0]);
241
242		tmpd = device_add_child(dev, "rge", 2);
243		device_set_ivars(tmpd, &xlr_board_info.gmac_block[0]);
244
245		tmpd = device_add_child(dev, "rge", 3);
246		device_set_ivars(tmpd, &xlr_board_info.gmac_block[0]);
247	}
248	if (xlr_board_info.gmac_block[1].enabled) {
249		if (xlr_board_info.gmac_block[1].type == XLR_GMAC) {
250			tmpd = device_add_child(dev, "rge", 4);
251			device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]);
252
253			tmpd = device_add_child(dev, "rge", 5);
254			device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]);
255
256			if (xlr_board_info.gmac_block[1].enabled & 0x4) {
257				tmpd = device_add_child(dev, "rge", 6);
258				device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]);
259			}
260
261			if (xlr_board_info.gmac_block[1].enabled & 0x8) {
262				tmpd = device_add_child(dev, "rge", 7);
263				device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]);
264			}
265		} else if (xlr_board_info.gmac_block[1].type == XLR_XGMAC) {
266#if 0				/* XGMAC not yet */
267			tmpd = device_add_child(dev, "rge", 4);
268			device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]);
269
270			tmpd = device_add_child(dev, "rge", 5);
271			device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]);
272#endif
273		} else
274			device_printf(dev, "Unknown type of gmac 1\n");
275	}
276
277	/* This is to add the new GMAC driver. The above adds the old driver,
278	   which has been retained for now as the new driver is stabilized.
279	   The new driver is enabled with "option nlge". Make sure that only
280	   one of rge or nlge is enabled in the conf file. */
281	for (i = 0; i < 3; i++) {
282		if (xlr_board_info.gmac_block[i].enabled == 0)
283			continue;
284		tmpd = device_add_child(dev, "nlna", i);
285		device_set_ivars(tmpd, &xlr_board_info.gmac_block[i]);
286	}
287	bus_generic_probe(dev);
288	bus_generic_attach(dev);
289	return 0;
290}
291
292int
293iodi_detach(device_t dev)
294{
295	device_t nlna_dev;
296	int error, i, ret;
297
298	error = 0;
299	ret = 0;
300	for (i = 0; i < 3; i++) {
301		nlna_dev = device_find_child(dev, "nlna", i);
302		if (nlna_dev != NULL)
303			error = bus_generic_detach(nlna_dev);
304		if (error)
305			ret = error;
306	}
307	return ret;
308}
309
310static device_method_t iodi_methods[] = {
311	DEVMETHOD(device_probe, iodi_probe),
312	DEVMETHOD(device_attach, iodi_attach),
313	DEVMETHOD(device_detach, iodi_detach),
314	DEVMETHOD(device_identify, iodi_identify),
315	DEVMETHOD(bus_alloc_resource, iodi_alloc_resource),
316	DEVMETHOD(bus_activate_resource, iodi_activate_resource),
317	DEVMETHOD(bus_setup_intr, iodi_setup_intr),
318	{0, 0},
319};
320
321static driver_t iodi_driver = {
322	"iodi",
323	iodi_methods,
324	1			/* no softc */
325};
326static devclass_t iodi_devclass;
327
328DRIVER_MODULE(iodi, nexus, iodi_driver, iodi_devclass, 0, 0);
329