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