1198160Srrs/*-
2198160Srrs * Copyright (c) 2003-2009 RMI Corporation
3198160Srrs * All rights reserved.
4198160Srrs *
5198160Srrs * Redistribution and use in source and binary forms, with or without
6198160Srrs * modification, are permitted provided that the following conditions
7198160Srrs * are met:
8198160Srrs * 1. Redistributions of source code must retain the above copyright
9198160Srrs *    notice, this list of conditions and the following disclaimer.
10198160Srrs * 2. Redistributions in binary form must reproduce the above copyright
11198160Srrs *    notice, this list of conditions and the following disclaimer in the
12198160Srrs *    documentation and/or other materials provided with the distribution.
13198160Srrs * 3. Neither the name of RMI Corporation, nor the names of its contributors,
14198160Srrs *    may be used to endorse or promote products derived from this software
15198160Srrs *    without specific prior written permission.
16198160Srrs *
17198160Srrs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18198160Srrs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19198160Srrs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20198160Srrs * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21198160Srrs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22198160Srrs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23198160Srrs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24198160Srrs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25198160Srrs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26198160Srrs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27198160Srrs * SUCH DAMAGE.
28198160Srrs *
29202066Simp * RMI_BSD
30202066Simp */
31198160Srrs
32202066Simp#include <sys/cdefs.h>
33202066Simp__FBSDID("$FreeBSD$");
34202066Simp
35198160Srrs#define __RMAN_RESOURCE_VISIBLE
36198160Srrs#include <sys/param.h>
37198160Srrs#include <sys/systm.h>
38198160Srrs#include <sys/bus.h>
39198160Srrs#include <sys/kernel.h>
40198160Srrs#include <sys/lock.h>
41198160Srrs#include <sys/mutex.h>
42198160Srrs#include <sys/reboot.h>
43211994Sjchandra#include <sys/rman.h>
44198160Srrs#include <sys/types.h>
45198160Srrs#include <sys/malloc.h>
46198160Srrs#include <sys/interrupt.h>
47198160Srrs#include <sys/module.h>
48198160Srrs
49198160Srrs#include <machine/cpu.h>
50198160Srrs#include <machine/bus.h>
51198607Srrs#include <machine/param.h>
52198607Srrs#include <machine/intr_machdep.h>
53198607Srrs#include <machine/clock.h>	/* for DELAY */
54198607Srrs#include <machine/resource.h>
55211994Sjchandra
56211994Sjchandra#include <mips/rmi/board.h>
57211994Sjchandra#include <mips/rmi/pic.h>
58198607Srrs#include <mips/rmi/interrupt.h>
59198607Srrs#include <mips/rmi/msgring.h>
60198607Srrs#include <mips/rmi/iomap.h>
61211994Sjchandra#include <mips/rmi/rmi_mips_exts.h>
62198607Srrs
63202066Simp#include <mips/rmi/dev/xlr/atx_cpld.h>
64202066Simp#include <mips/rmi/dev/xlr/xgmac_mdio.h>
65198607Srrs
66198160Srrsextern bus_space_tag_t uart_bus_space_mem;
67198160Srrs
68198625Srrsstatic struct resource *
69198625Srrsiodi_alloc_resource(device_t, device_t, int, int *,
70198625Srrs    u_long, u_long, u_long, u_int);
71198160Srrs
72199090Srrsstatic int
73198625Srrsiodi_activate_resource(device_t, device_t, int, int,
74198625Srrs    struct resource *);
75199090Srrsstatic int
76198625Srrsiodi_setup_intr(device_t, device_t, struct resource *, int,
77198625Srrs    driver_filter_t *, driver_intr_t *, void *, void **);
78198160Srrs
79198625Srrsstruct iodi_softc *iodi_softc;	/* There can be only one. */
80198160Srrs
81211923Sjchandra/*
82211923Sjchandra * We will manage the Flash/PCMCIA devices in IODI for now.
83211923Sjchandra * The NOR flash, Compact flash etc. which can be connected on
84211923Sjchandra * various chip selects on the peripheral IO, should have a
85211923Sjchandra * separate bus later.
86211923Sjchandra */
87211923Sjchandrastatic void
88211923Sjchandrabridge_pcmcia_ack(int irq)
89211923Sjchandra{
90211923Sjchandra	xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_FLASH_OFFSET);
91211923Sjchandra
92211923Sjchandra	xlr_write_reg(mmio, 0x60, 0xffffffff);
93211923Sjchandra}
94211923Sjchandra
95198160Srrsstatic int
96198160Srrsiodi_setup_intr(device_t dev, device_t child,
97212102Sjchandra    struct resource *ires, int flags, driver_filter_t *filt,
98211811Sjchandra    driver_intr_t *intr, void *arg, void **cookiep)
99198160Srrs{
100211946Sjchandra	const char *name = device_get_name(child);
101198160Srrs
102211946Sjchandra	if (strcmp(name, "uart") == 0) {
103198625Srrs		/* FIXME uart 1? */
104211811Sjchandra		cpu_establish_hardintr("uart", filt, intr, arg,
105211811Sjchandra		    PIC_UART_0_IRQ, flags, cookiep);
106212248Sjchandra		pic_setup_intr(PIC_IRT_UART_0_INDEX, PIC_UART_0_IRQ, 0x1, 1);
107211946Sjchandra	} else if (strcmp(name, "rge") == 0 || strcmp(name, "nlge") == 0) {
108198625Srrs		int irq;
109199090Srrs
110199089Srrs		/* This is a hack to pass in the irq */
111209808Sjchandra		irq = (intptr_t)ires->__r_i;
112211811Sjchandra		cpu_establish_hardintr("rge", filt, intr, arg, irq, flags,
113211811Sjchandra		    cookiep);
114212248Sjchandra		pic_setup_intr(irq - PIC_IRQ_BASE, irq, 0x1, 1);
115211946Sjchandra	} else if (strcmp(name, "ehci") == 0) {
116211811Sjchandra		cpu_establish_hardintr("ehci", filt, intr, arg, PIC_USB_IRQ, flags,
117211811Sjchandra		    cookiep);
118212248Sjchandra		pic_setup_intr(PIC_USB_IRQ - PIC_IRQ_BASE, PIC_USB_IRQ, 0x1, 1);
119211946Sjchandra	} else if (strcmp(name, "ata") == 0) {
120211923Sjchandra		xlr_establish_intr("ata", filt, intr, arg, PIC_PCMCIA_IRQ, flags,
121211923Sjchandra		    cookiep, bridge_pcmcia_ack);
122212248Sjchandra		pic_setup_intr(PIC_PCMCIA_IRQ - PIC_IRQ_BASE, PIC_PCMCIA_IRQ, 0x1, 1);
123198625Srrs	}
124198625Srrs	return (0);
125198160Srrs}
126198160Srrs
127198160Srrsstatic struct resource *
128198160Srrsiodi_alloc_resource(device_t bus, device_t child, int type, int *rid,
129198625Srrs    u_long start, u_long end, u_long count, u_int flags)
130198160Srrs{
131198160Srrs	struct resource *res = malloc(sizeof(*res), M_DEVBUF, M_WAITOK);
132212102Sjchandra	const char *name = device_get_name(child);
133198160Srrs	int unit;
134198160Srrs
135198160Srrs#ifdef DEBUG
136198160Srrs	switch (type) {
137198160Srrs	case SYS_RES_IRQ:
138198160Srrs		device_printf(bus, "IRQ resource - for %s %lx-%lx\n",
139198625Srrs		    device_get_nameunit(child), start, end);
140198625Srrs		break;
141198160Srrs
142198625Srrs	case SYS_RES_IOPORT:
143198160Srrs		device_printf(bus, "IOPORT resource - for %s %lx-%lx\n",
144198625Srrs		    device_get_nameunit(child), start, end);
145198625Srrs		break;
146198160Srrs
147198625Srrs	case SYS_RES_MEMORY:
148198160Srrs		device_printf(bus, "MEMORY resource - for %s %lx-%lx\n",
149198625Srrs		    device_get_nameunit(child), start, end);
150198625Srrs		break;
151198625Srrs	}
152198160Srrs#endif
153198160Srrs
154212102Sjchandra	if (strcmp(name, "uart") == 0) {
155198625Srrs		if ((unit = device_get_unit(child)) == 0) {	/* uart 0 */
156198160Srrs			res->r_bushandle = (xlr_io_base + XLR_IO_UART_0_OFFSET);
157198625Srrs		} else if (unit == 1) {
158198160Srrs			res->r_bushandle = (xlr_io_base + XLR_IO_UART_1_OFFSET);
159198625Srrs		} else
160198160Srrs			printf("%s: Unknown uart unit\n", __FUNCTION__);
161198160Srrs
162198160Srrs		res->r_bustag = uart_bus_space_mem;
163212102Sjchandra	} else if (strcmp(name, "ehci") == 0) {
164209808Sjchandra		res->r_bushandle = MIPS_PHYS_TO_KSEG1(0x1ef24000);
165204577Srrs		res->r_bustag = rmi_pci_bus_space;
166212102Sjchandra	} else if (strcmp(name, "cfi") == 0) {
167209808Sjchandra		res->r_bushandle = MIPS_PHYS_TO_KSEG1(0x1c000000);
168198160Srrs		res->r_bustag = 0;
169212102Sjchandra	} else if (strcmp(name, "ata") == 0) {
170211923Sjchandra		res->r_bushandle = MIPS_PHYS_TO_KSEG1(0x1d000000);
171211923Sjchandra		res->r_bustag = rmi_pci_bus_space;  /* byte swapping (not really PCI) */
172198160Srrs	}
173198625Srrs	/* res->r_start = *rid; */
174198160Srrs	return (res);
175198160Srrs}
176198160Srrs
177198160Srrsstatic int
178198160Srrsiodi_activate_resource(device_t bus, device_t child, int type, int rid,
179198625Srrs    struct resource *r)
180198160Srrs{
181198160Srrs	return (0);
182198160Srrs}
183198625Srrs
184198160Srrs/* prototypes */
185198625Srrsstatic int iodi_probe(device_t);
186198625Srrsstatic int iodi_attach(device_t);
187211946Sjchandrastatic int iodi_detach(device_t);
188198625Srrsstatic void iodi_identify(driver_t *, device_t);
189198160Srrs
190198160Srrsint
191198160Srrsiodi_probe(device_t dev)
192198160Srrs{
193198160Srrs	return 0;
194198160Srrs}
195198160Srrs
196198160Srrsvoid
197198625Srrsiodi_identify(driver_t * driver, device_t parent)
198198160Srrs{
199198625Srrs
200198160Srrs	BUS_ADD_CHILD(parent, 0, "iodi", 0);
201198160Srrs}
202198160Srrs
203198160Srrsint
204198160Srrsiodi_attach(device_t dev)
205198160Srrs{
206198160Srrs	device_t tmpd;
207211946Sjchandra	int i;
208198625Srrs
209198160Srrs	/*
210198625Srrs	 * Attach each devices
211198160Srrs	 */
212198160Srrs	device_add_child(dev, "uart", 0);
213198160Srrs	device_add_child(dev, "xlr_i2c", 0);
214216390Sjchandra	device_add_child(dev, "xlr_i2c", 1);
215208165Srrs	device_add_child(dev, "pcib", 0);
216212763Sjchandra	device_add_child(dev, "rmisec", -1);
217198625Srrs
218198160Srrs	if (xlr_board_info.usb)
219198160Srrs		device_add_child(dev, "ehci", 0);
220198625Srrs
221198160Srrs	if (xlr_board_info.cfi)
222198160Srrs		device_add_child(dev, "cfi", 0);
223198160Srrs
224211923Sjchandra	if (xlr_board_info.ata)
225211923Sjchandra		device_add_child(dev, "ata", 0);
226211923Sjchandra
227198160Srrs	if (xlr_board_info.gmac_block[0].enabled) {
228198160Srrs		tmpd = device_add_child(dev, "rge", 0);
229198160Srrs		device_set_ivars(tmpd, &xlr_board_info.gmac_block[0]);
230198160Srrs
231198160Srrs		tmpd = device_add_child(dev, "rge", 1);
232198160Srrs		device_set_ivars(tmpd, &xlr_board_info.gmac_block[0]);
233198160Srrs
234198160Srrs		tmpd = device_add_child(dev, "rge", 2);
235198160Srrs		device_set_ivars(tmpd, &xlr_board_info.gmac_block[0]);
236198160Srrs
237198160Srrs		tmpd = device_add_child(dev, "rge", 3);
238198160Srrs		device_set_ivars(tmpd, &xlr_board_info.gmac_block[0]);
239198160Srrs	}
240198160Srrs	if (xlr_board_info.gmac_block[1].enabled) {
241198160Srrs		if (xlr_board_info.gmac_block[1].type == XLR_GMAC) {
242198160Srrs			tmpd = device_add_child(dev, "rge", 4);
243198160Srrs			device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]);
244198160Srrs
245198160Srrs			tmpd = device_add_child(dev, "rge", 5);
246198160Srrs			device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]);
247198160Srrs
248204137Srrs			if (xlr_board_info.gmac_block[1].enabled & 0x4) {
249204137Srrs				tmpd = device_add_child(dev, "rge", 6);
250204137Srrs				device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]);
251204137Srrs			}
252198160Srrs
253204137Srrs			if (xlr_board_info.gmac_block[1].enabled & 0x8) {
254204137Srrs				tmpd = device_add_child(dev, "rge", 7);
255204137Srrs				device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]);
256204137Srrs			}
257198160Srrs		} else if (xlr_board_info.gmac_block[1].type == XLR_XGMAC) {
258198625Srrs#if 0				/* XGMAC not yet */
259198160Srrs			tmpd = device_add_child(dev, "rge", 4);
260198160Srrs			device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]);
261198160Srrs
262198160Srrs			tmpd = device_add_child(dev, "rge", 5);
263198160Srrs			device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]);
264198160Srrs#endif
265211946Sjchandra		} else
266211946Sjchandra			device_printf(dev, "Unknown type of gmac 1\n");
267198160Srrs	}
268211946Sjchandra
269211946Sjchandra	/* This is to add the new GMAC driver. The above adds the old driver,
270211946Sjchandra	   which has been retained for now as the new driver is stabilized.
271211946Sjchandra	   The new driver is enabled with "option nlge". Make sure that only
272211946Sjchandra	   one of rge or nlge is enabled in the conf file. */
273211946Sjchandra	for (i = 0; i < 3; i++) {
274211946Sjchandra		if (xlr_board_info.gmac_block[i].enabled == 0)
275211946Sjchandra			continue;
276211946Sjchandra		tmpd = device_add_child(dev, "nlna", i);
277211946Sjchandra		device_set_ivars(tmpd, &xlr_board_info.gmac_block[i]);
278211946Sjchandra	}
279198160Srrs	bus_generic_probe(dev);
280198160Srrs	bus_generic_attach(dev);
281198160Srrs	return 0;
282198160Srrs}
283198160Srrs
284211946Sjchandraint
285211946Sjchandraiodi_detach(device_t dev)
286211946Sjchandra{
287211946Sjchandra	device_t nlna_dev;
288211946Sjchandra	int error, i, ret;
289211946Sjchandra
290211946Sjchandra	error = 0;
291211946Sjchandra	ret = 0;
292211946Sjchandra	for (i = 0; i < 3; i++) {
293211946Sjchandra		nlna_dev = device_find_child(dev, "nlna", i);
294211946Sjchandra		if (nlna_dev != NULL)
295211946Sjchandra			error = bus_generic_detach(nlna_dev);
296211946Sjchandra		if (error)
297211946Sjchandra			ret = error;
298211946Sjchandra	}
299211946Sjchandra	return ret;
300211946Sjchandra}
301211946Sjchandra
302198160Srrsstatic device_method_t iodi_methods[] = {
303198160Srrs	DEVMETHOD(device_probe, iodi_probe),
304198160Srrs	DEVMETHOD(device_attach, iodi_attach),
305211946Sjchandra	DEVMETHOD(device_detach, iodi_detach),
306198160Srrs	DEVMETHOD(device_identify, iodi_identify),
307198160Srrs	DEVMETHOD(bus_alloc_resource, iodi_alloc_resource),
308198160Srrs	DEVMETHOD(bus_activate_resource, iodi_activate_resource),
309212550Sjchandra	DEVMETHOD(bus_add_child, bus_generic_add_child),
310198160Srrs	DEVMETHOD(bus_setup_intr, iodi_setup_intr),
311198160Srrs	{0, 0},
312198160Srrs};
313198160Srrs
314198160Srrsstatic driver_t iodi_driver = {
315198160Srrs	"iodi",
316198160Srrs	iodi_methods,
317198625Srrs	1			/* no softc */
318198160Srrs};
319198160Srrsstatic devclass_t iodi_devclass;
320198160Srrs
321198160SrrsDRIVER_MODULE(iodi, nexus, iodi_driver, iodi_devclass, 0, 0);
322