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