iodi.c revision 223562
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 223562 2011-06-26 10:07:48Z kevlo $");
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/interrupt.h>
47#include <sys/module.h>
48
49#include <machine/cpu.h>
50#include <machine/bus.h>
51#include <machine/param.h>
52#include <machine/intr_machdep.h>
53#include <machine/clock.h>	/* for DELAY */
54#include <machine/resource.h>
55
56#include <mips/rmi/board.h>
57#include <mips/rmi/pic.h>
58#include <mips/rmi/interrupt.h>
59#include <mips/rmi/msgring.h>
60#include <mips/rmi/iomap.h>
61#include <mips/rmi/rmi_mips_exts.h>
62
63#include <mips/rmi/dev/xlr/atx_cpld.h>
64#include <mips/rmi/dev/xlr/xgmac_mdio.h>
65
66extern bus_space_tag_t uart_bus_space_mem;
67
68static struct resource *
69iodi_alloc_resource(device_t, device_t, int, int *,
70    u_long, u_long, u_long, u_int);
71
72static int
73iodi_activate_resource(device_t, device_t, int, int,
74    struct resource *);
75static int
76iodi_setup_intr(device_t, device_t, struct resource *, int,
77    driver_filter_t *, driver_intr_t *, void *, void **);
78
79struct iodi_softc *iodi_softc;	/* There can be only one. */
80
81/*
82 * We will manage the Flash/PCMCIA devices in IODI for now.
83 * The NOR flash, Compact flash etc. which can be connected on
84 * various chip selects on the peripheral IO, should have a
85 * separate bus later.
86 */
87static void
88bridge_pcmcia_ack(int irq)
89{
90	xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_FLASH_OFFSET);
91
92	xlr_write_reg(mmio, 0x60, 0xffffffff);
93}
94
95static int
96iodi_setup_intr(device_t dev, device_t child,
97    struct resource *ires, int flags, driver_filter_t *filt,
98    driver_intr_t *intr, void *arg, void **cookiep)
99{
100	const char *name = device_get_name(child);
101
102	if (strcmp(name, "uart") == 0) {
103		/* FIXME uart 1? */
104		cpu_establish_hardintr("uart", filt, intr, arg,
105		    PIC_UART_0_IRQ, flags, cookiep);
106		pic_setup_intr(PIC_IRT_UART_0_INDEX, PIC_UART_0_IRQ, 0x1, 1);
107	} else if (strcmp(name, "rge") == 0 || strcmp(name, "nlge") == 0) {
108		int irq;
109
110		/* This is a hack to pass in the irq */
111		irq = (intptr_t)ires->__r_i;
112		cpu_establish_hardintr("rge", filt, intr, arg, irq, flags,
113		    cookiep);
114		pic_setup_intr(irq - PIC_IRQ_BASE, irq, 0x1, 1);
115	} else if (strcmp(name, "ehci") == 0) {
116		cpu_establish_hardintr("ehci", filt, intr, arg, PIC_USB_IRQ, flags,
117		    cookiep);
118		pic_setup_intr(PIC_USB_IRQ - PIC_IRQ_BASE, PIC_USB_IRQ, 0x1, 1);
119	} else if (strcmp(name, "ata") == 0) {
120		xlr_establish_intr("ata", filt, intr, arg, PIC_PCMCIA_IRQ, flags,
121		    cookiep, bridge_pcmcia_ack);
122		pic_setup_intr(PIC_PCMCIA_IRQ - PIC_IRQ_BASE, PIC_PCMCIA_IRQ, 0x1, 1);
123	}
124	return (0);
125}
126
127static struct resource *
128iodi_alloc_resource(device_t bus, device_t child, int type, int *rid,
129    u_long start, u_long end, u_long count, u_int flags)
130{
131	struct resource *res = malloc(sizeof(*res), M_DEVBUF, M_WAITOK);
132	const char *name = device_get_name(child);
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(name, "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(name, "ehci") == 0) {
164		res->r_bushandle = MIPS_PHYS_TO_KSEG1(0x1ef24000);
165		res->r_bustag = rmi_pci_bus_space;
166	} else if (strcmp(name, "cfi") == 0) {
167		res->r_bushandle = MIPS_PHYS_TO_KSEG1(0x1c000000);
168		res->r_bustag = 0;
169	} else if (strcmp(name, "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, "xlr_i2c", 1);
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