ixp425.c revision 189632
1164426Ssam/* $NetBSD: ixp425.c,v 1.10 2005/12/11 12:16:51 christos Exp $ */ 2164426Ssam 3164426Ssam/* 4164426Ssam * Copyright (c) 2003 5164426Ssam * Ichiro FUKUHARA <ichiro@ichiro.org>. 6164426Ssam * All rights reserved. 7164426Ssam * 8164426Ssam * Redistribution and use in source and binary forms, with or without 9164426Ssam * modification, are permitted provided that the following conditions 10164426Ssam * are met: 11164426Ssam * 1. Redistributions of source code must retain the above copyright 12164426Ssam * notice, this list of conditions and the following disclaimer. 13164426Ssam * 2. Redistributions in binary form must reproduce the above copyright 14164426Ssam * notice, this list of conditions and the following disclaimer in the 15164426Ssam * documentation and/or other materials provided with the distribution. 16164426Ssam * 3. All advertising materials mentioning features or use of this software 17164426Ssam * must display the following acknowledgement: 18164426Ssam * This product includes software developed by Ichiro FUKUHARA. 19164426Ssam * 4. The name of the company nor the name of the author may be used to 20164426Ssam * endorse or promote products derived from this software without specific 21164426Ssam * prior written permission. 22164426Ssam * 23164426Ssam * THIS SOFTWARE IS PROVIDED BY ICHIRO FUKUHARA ``AS IS'' AND ANY EXPRESS OR 24164426Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25164426Ssam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26164426Ssam * IN NO EVENT SHALL ICHIRO FUKUHARA OR THE VOICES IN HIS HEAD BE LIABLE FOR 27164426Ssam * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28164426Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29164426Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30164426Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31164426Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32164426Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33164426Ssam * SUCH DAMAGE. 34164426Ssam */ 35164426Ssam 36164426Ssam#include <sys/cdefs.h> 37164426Ssam__FBSDID("$FreeBSD: head/sys/arm/xscale/ixp425/ixp425.c 189632 2009-03-10 17:16:16Z sam $"); 38164426Ssam 39164426Ssam#define _ARM32_BUS_DMA_PRIVATE 40164426Ssam#include <sys/param.h> 41164426Ssam#include <sys/systm.h> 42164426Ssam#include <sys/bus.h> 43164426Ssam#include <sys/kernel.h> 44164426Ssam#include <sys/module.h> 45164426Ssam#include <sys/malloc.h> 46164426Ssam#include <sys/rman.h> 47164426Ssam#include <machine/bus.h> 48164426Ssam#include <machine/intr.h> 49164426Ssam 50164426Ssam#include <vm/vm.h> 51164426Ssam#include <vm/pmap.h> 52164426Ssam#include <arm/xscale/ixp425/ixp425reg.h> 53164426Ssam#include <arm/xscale/ixp425/ixp425var.h> 54164426Ssam#include <arm/xscale/ixp425/ixp425_intr.h> 55164426Ssam 56164426Ssam#include <dev/pci/pcireg.h> 57164426Ssam 58164426Ssamvolatile uint32_t intr_enabled; 59164426Ssamuint32_t intr_steer = 0; 60164426Ssam 61186352Ssam/* ixp43x et. al have +32 IRQ's */ 62186352Ssamvolatile uint32_t intr_enabled2; 63186352Ssamuint32_t intr_steer2 = 0; 64186352Ssam 65164426Ssamstruct ixp425_softc *ixp425_softc = NULL; 66164426Ssam 67164426Ssamstatic int ixp425_probe(device_t); 68164426Ssamstatic void ixp425_identify(driver_t *, device_t); 69164426Ssamstatic int ixp425_attach(device_t); 70164426Ssam 71186418Ssam/* 72186418Ssam * Return a mask of the "fuse" bits that identify 73186418Ssam * which h/w features are present. 74186418Ssam * NB: assumes the expansion bus is mapped. 75186418Ssam */ 76186418Ssamuint32_t 77186418Ssamixp4xx_read_feature_bits(void) 78186418Ssam{ 79186418Ssam uint32_t bits = ~IXPREG(IXP425_EXP_VBASE + EXP_FCTRL_OFFSET); 80186418Ssam bits &= ~EXP_FCTRL_RESVD; 81186418Ssam if (!cpu_is_ixp46x()) 82186418Ssam bits &= ~EXP_FCTRL_IXP46X_ONLY; 83186418Ssam return bits; 84186418Ssam} 85186418Ssam 86164426Ssamstruct arm32_dma_range * 87164426Ssambus_dma_get_range(void) 88164426Ssam{ 89164426Ssam return (NULL); 90164426Ssam} 91164426Ssam 92164426Ssamint 93164426Ssambus_dma_get_range_nb(void) 94164426Ssam{ 95164426Ssam return (0); 96164426Ssam} 97164426Ssam 98164426Ssamstatic __inline u_int32_t 99164426Ssamixp425_irq2gpio_bit(int irq) 100164426Ssam{ 101164426Ssam 102164426Ssam static const uint8_t int2gpio[32] __attribute__ ((aligned(32))) = { 103164426Ssam 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* INT#0 -> INT#5 */ 104164426Ssam 0x00, 0x01, /* GPIO#0 -> GPIO#1 */ 105164426Ssam 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* INT#8 -> INT#13 */ 106164426Ssam 0xff, 0xff, 0xff, 0xff, 0xff, /* INT#14 -> INT#18 */ 107164426Ssam 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* GPIO#2 -> GPIO#7 */ 108164426Ssam 0x08, 0x09, 0x0a, 0x0b, 0x0c, /* GPIO#8 -> GPIO#12 */ 109164426Ssam 0xff, 0xff /* INT#30 -> INT#31 */ 110164426Ssam }; 111164426Ssam 112164426Ssam return (1U << int2gpio[irq]); 113164426Ssam} 114164426Ssam 115164426Ssamvoid 116164426Ssamarm_mask_irq(uintptr_t nb) 117164426Ssam{ 118182946Scognet int i; 119182946Scognet 120182946Scognet i = disable_interrupts(I32_bit); 121186352Ssam if (nb < 32) { 122186352Ssam intr_enabled &= ~(1 << nb); 123186352Ssam ixp425_set_intrmask(); 124186352Ssam } else { 125186352Ssam intr_enabled2 &= ~(1 << (nb - 32)); 126186352Ssam ixp435_set_intrmask(); 127186352Ssam } 128182946Scognet restore_interrupts(i); 129164426Ssam /*XXX; If it's a GPIO interrupt, ACK it know. Can it be a problem ?*/ 130186352Ssam if (nb < 32 && ((1 << nb) & IXP425_INT_GPIOMASK)) 131164426Ssam IXPREG(IXP425_GPIO_VBASE + IXP425_GPIO_GPISR) = 132164426Ssam ixp425_irq2gpio_bit(nb); 133164426Ssam} 134164426Ssam 135164426Ssamvoid 136164426Ssamarm_unmask_irq(uintptr_t nb) 137164426Ssam{ 138182946Scognet int i; 139182946Scognet 140182946Scognet i = disable_interrupts(I32_bit); 141186352Ssam if (nb < 32) { 142186352Ssam intr_enabled |= (1 << nb); 143186352Ssam ixp425_set_intrmask(); 144186352Ssam } else { 145186352Ssam intr_enabled2 |= (1 << (nb - 32)); 146186352Ssam ixp435_set_intrmask(); 147186352Ssam } 148182946Scognet restore_interrupts(i); 149164426Ssam} 150164426Ssam 151164426Ssamstatic __inline uint32_t 152164426Ssamixp425_irq_read(void) 153164426Ssam{ 154164426Ssam return IXPREG(IXP425_INT_STATUS) & intr_enabled; 155164426Ssam} 156164426Ssam 157186352Ssamstatic __inline uint32_t 158186352Ssamixp435_irq_read(void) 159186352Ssam{ 160186352Ssam return IXPREG(IXP435_INT_STATUS2) & intr_enabled2; 161186352Ssam} 162186352Ssam 163164426Ssamint 164164426Ssamarm_get_next_irq(void) 165164426Ssam{ 166186352Ssam uint32_t irq; 167164426Ssam 168164426Ssam if ((irq = ixp425_irq_read())) 169164426Ssam return (ffs(irq) - 1); 170186352Ssam if (cpu_is_ixp43x() && (irq = ixp435_irq_read())) 171186352Ssam return (32 + ffs(irq) - 1); 172164426Ssam return (-1); 173164426Ssam} 174164426Ssam 175164426Ssamvoid 176164426Ssamcpu_reset(void) 177164426Ssam{ 178164426Ssam 179164426Ssam bus_space_write_4(&ixp425_bs_tag, IXP425_TIMER_VBASE, 180164426Ssam IXP425_OST_WDOG_KEY, OST_WDOG_KEY_MAJICK); 181164426Ssam bus_space_write_4(&ixp425_bs_tag, IXP425_TIMER_VBASE, 182164426Ssam IXP425_OST_WDOG, 0); 183164426Ssam bus_space_write_4(&ixp425_bs_tag, IXP425_TIMER_VBASE, 184164426Ssam IXP425_OST_WDOG_ENAB, OST_WDOG_ENAB_RST_ENA | 185164426Ssam OST_WDOG_ENAB_CNT_ENA); 186164426Ssam printf("Reset failed!\n"); 187164426Ssam for(;;); 188164426Ssam} 189164426Ssam 190164426Ssamstatic void 191164426Ssamixp425_identify(driver_t *driver, device_t parent) 192164426Ssam{ 193164426Ssam BUS_ADD_CHILD(parent, 0, "ixp", 0); 194164426Ssam} 195164426Ssam 196164426Ssamstatic int 197164426Ssamixp425_probe(device_t dev) 198164426Ssam{ 199186352Ssam device_set_desc(dev, "Intel IXP4XX"); 200164426Ssam return (0); 201164426Ssam} 202164426Ssam 203164426Ssamstatic int 204164426Ssamixp425_attach(device_t dev) 205164426Ssam{ 206164426Ssam struct ixp425_softc *sc; 207164426Ssam 208186418Ssam device_printf(dev, "%b\n", ixp4xx_read_feature_bits(), EXP_FCTRL_BITS); 209186418Ssam 210164426Ssam sc = device_get_softc(dev); 211164426Ssam sc->sc_iot = &ixp425_bs_tag; 212186352Ssam KASSERT(ixp425_softc == NULL, ("%s called twice?", __func__)); 213164426Ssam ixp425_softc = sc; 214164426Ssam 215164426Ssam intr_enabled = 0; 216164426Ssam ixp425_set_intrmask(); 217164426Ssam ixp425_set_intrsteer(); 218186352Ssam if (cpu_is_ixp43x()) { 219186352Ssam intr_enabled2 = 0; 220186352Ssam ixp435_set_intrmask(); 221186352Ssam ixp435_set_intrsteer(); 222186352Ssam } 223164426Ssam 224166064Scognet if (bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT, 225166064Scognet BUS_SPACE_MAXADDR, NULL, NULL, 0xffffffff, 0xff, 0xffffffff, 0, 226166064Scognet NULL, NULL, &sc->sc_dmat)) 227186352Ssam panic("%s: failed to create dma tag", __func__); 228166064Scognet 229164426Ssam sc->sc_irq_rman.rm_type = RMAN_ARRAY; 230186352Ssam sc->sc_irq_rman.rm_descr = "IXP4XX IRQs"; 231164426Ssam if (rman_init(&sc->sc_irq_rman) != 0 || 232186352Ssam rman_manage_region(&sc->sc_irq_rman, 0, cpu_is_ixp43x() ? 63 : 31) != 0) 233186352Ssam panic("%s: failed to set up IRQ rman", __func__); 234164426Ssam 235164426Ssam sc->sc_mem_rman.rm_type = RMAN_ARRAY; 236186352Ssam sc->sc_mem_rman.rm_descr = "IXP4XX Memory"; 237164426Ssam if (rman_init(&sc->sc_mem_rman) != 0 || 238164426Ssam rman_manage_region(&sc->sc_mem_rman, 0, ~0) != 0) 239186352Ssam panic("%s: failed to set up memory rman", __func__); 240164426Ssam 241169952Ssam BUS_ADD_CHILD(dev, 0, "pcib", 0); 242169952Ssam BUS_ADD_CHILD(dev, 0, "ixpclk", 0); 243169952Ssam BUS_ADD_CHILD(dev, 0, "ixpiic", 0); 244169952Ssam /* XXX move to hints? */ 245169952Ssam BUS_ADD_CHILD(dev, 0, "ixpwdog", 0); 246164426Ssam 247169952Ssam /* attach wired devices via hints */ 248169952Ssam bus_enumerate_hinted_children(dev); 249169952Ssam 250164426Ssam if (bus_space_map(sc->sc_iot, IXP425_GPIO_HWBASE, IXP425_GPIO_SIZE, 251164426Ssam 0, &sc->sc_gpio_ioh)) 252186352Ssam panic("%s: unable to map GPIO registers", __func__); 253164426Ssam if (bus_space_map(sc->sc_iot, IXP425_EXP_HWBASE, IXP425_EXP_SIZE, 254164426Ssam 0, &sc->sc_exp_ioh)) 255186352Ssam panic("%s: unable to map Expansion Bus registers", __func__); 256164426Ssam 257164426Ssam bus_generic_probe(dev); 258164426Ssam bus_generic_attach(dev); 259164426Ssam 260164426Ssam return (0); 261164426Ssam} 262164426Ssam 263169952Ssamstatic void 264169952Ssamixp425_hinted_child(device_t bus, const char *dname, int dunit) 265169952Ssam{ 266169952Ssam device_t child; 267169952Ssam struct ixp425_ivar *ivar; 268169952Ssam 269169952Ssam child = BUS_ADD_CHILD(bus, 0, dname, dunit); 270169952Ssam ivar = IXP425_IVAR(child); 271169952Ssam resource_int_value(dname, dunit, "addr", &ivar->addr); 272169952Ssam resource_int_value(dname, dunit, "irq", &ivar->irq); 273169952Ssam} 274169952Ssam 275169952Ssamstatic device_t 276169952Ssamixp425_add_child(device_t dev, int order, const char *name, int unit) 277169952Ssam{ 278169952Ssam device_t child; 279169952Ssam struct ixp425_ivar *ivar; 280169952Ssam 281169952Ssam child = device_add_child_ordered(dev, order, name, unit); 282169952Ssam if (child == NULL) 283169952Ssam return NULL; 284169952Ssam ivar = malloc(sizeof(struct ixp425_ivar), M_DEVBUF, M_NOWAIT); 285169952Ssam if (ivar == NULL) { 286169952Ssam device_delete_child(dev, child); 287169952Ssam return NULL; 288169952Ssam } 289169952Ssam ivar->addr = 0; 290169952Ssam ivar->irq = -1; 291169952Ssam device_set_ivars(child, ivar); 292169952Ssam return child; 293169952Ssam} 294169952Ssam 295169952Ssamstatic int 296169952Ssamixp425_read_ivar(device_t bus, device_t child, int which, u_char *result) 297169952Ssam{ 298169952Ssam struct ixp425_ivar *ivar = IXP425_IVAR(child); 299169952Ssam 300169952Ssam switch (which) { 301169952Ssam case IXP425_IVAR_ADDR: 302169952Ssam if (ivar->addr != 0) { 303169952Ssam *(uint32_t *)result = ivar->addr; 304169952Ssam return 0; 305169952Ssam } 306169952Ssam break; 307169952Ssam case IXP425_IVAR_IRQ: 308169952Ssam if (ivar->irq != -1) { 309169952Ssam *(int *)result = ivar->irq; 310169952Ssam return 0; 311169952Ssam } 312169952Ssam break; 313169952Ssam } 314169952Ssam return EINVAL; 315169952Ssam} 316169952Ssam 317186352Ssam/* 318189632Ssam * NB: This table handles P->V translations for regions setup with 319189632Ssam * static mappings in initarm. This is used solely for calls to 320189632Ssam * bus_alloc_resource_any; anything done with bus_space_map is 321189632Ssam * handled elsewhere and does not require an entry here. 322186352Ssam * 323189632Ssam * XXX this table is also used by uart_cpu_getdev via getvbase 324189632Ssam * (hence the public api) 325186352Ssam */ 326189632Ssamstruct hwvtrans { 327186352Ssam uint32_t hwbase; 328186352Ssam uint32_t size; 329186352Ssam uint32_t vbase; 330189632Ssam int isa4x; /* XXX needs special bus space tag */ 331186352Ssam}; 332186352Ssam 333189632Ssamstatic const struct hwvtrans * 334189632Ssamgethwvtrans(uint32_t hwbase, uint32_t size) 335186352Ssam{ 336189632Ssam static const struct hwvtrans hwvtrans[] = { 337189632Ssam /* NB: needed only for uart_cpu_getdev */ 338189632Ssam { .hwbase = IXP425_UART0_HWBASE, 339189632Ssam .size = IXP425_REG_SIZE, 340189632Ssam .vbase = IXP425_UART0_VBASE, 341189632Ssam .isa4x = 1 }, 342189632Ssam { .hwbase = IXP425_UART1_HWBASE, 343189632Ssam .size = IXP425_REG_SIZE, 344189632Ssam .vbase = IXP425_UART1_VBASE, 345189632Ssam .isa4x = 1 }, 346189632Ssam { .hwbase = IXP425_PCI_HWBASE, 347189632Ssam .size = IXP425_PCI_SIZE, 348189632Ssam .vbase = IXP425_PCI_VBASE }, 349189632Ssam { .hwbase = IXP425_PCI_MEM_HWBASE, 350189632Ssam .size = IXP425_PCI_MEM_SIZE, 351189632Ssam .vbase = IXP425_PCI_MEM_VBASE }, 352189632Ssam { .hwbase = IXP425_EXP_BUS_CS0_HWBASE, 353189632Ssam .size = IXP425_EXP_BUS_CS0_SIZE, 354189632Ssam .vbase = IXP425_EXP_BUS_CS0_VBASE }, 355189632Ssam /* NB: needed for ixp435 ehci controllers */ 356189632Ssam { .hwbase = IXP435_USB1_HWBASE, 357189632Ssam .size = IXP435_USB1_SIZE, 358189632Ssam .vbase = IXP435_USB1_VBASE }, 359189632Ssam { .hwbase = IXP435_USB2_HWBASE, 360189632Ssam .size = IXP435_USB2_SIZE, 361189632Ssam .vbase = IXP435_USB2_VBASE }, 362189632Ssam#ifdef CAMBRIA_GPS_VBASE 363189632Ssam { .hwbase = CAMBRIA_GPS_HWBASE, 364189632Ssam .size = CAMBRIA_GPS_SIZE, 365189632Ssam .vbase = CAMBRIA_GPS_VBASE }, 366189632Ssam#endif 367189632Ssam#ifdef CAMBRIA_RS485_VBASE 368189632Ssam { .hwbase = CAMBRIA_RS485_HWBASE, 369189632Ssam .size = CAMBRIA_RS485_SIZE, 370189632Ssam .vbase = CAMBRIA_RS485_VBASE }, 371189632Ssam#endif 372189632Ssam }; 373186352Ssam int i; 374186352Ssam 375186352Ssam for (i = 0; i < sizeof hwvtrans / sizeof *hwvtrans; i++) { 376186352Ssam if (hwbase >= hwvtrans[i].hwbase && 377189632Ssam hwbase + size <= hwvtrans[i].hwbase + hwvtrans[i].size) 378189632Ssam return &hwvtrans[i]; 379186352Ssam } 380189632Ssam return NULL; 381186352Ssam} 382186352Ssam 383189632Ssam/* XXX for uart_cpu_getdev */ 384189632Ssamint 385189632Ssamgetvbase(uint32_t hwbase, uint32_t size, uint32_t *vbase) 386189632Ssam{ 387189632Ssam const struct hwvtrans *hw; 388189632Ssam 389189632Ssam hw = gethwvtrans(hwbase, size); 390189632Ssam if (hw == NULL) 391189632Ssam return (ENOENT); 392189632Ssam *vbase = hwbase - hw->hwbase + hw->vbase; 393189632Ssam return (0); 394189632Ssam} 395189632Ssam 396164426Ssamstatic struct resource * 397164426Ssamixp425_alloc_resource(device_t dev, device_t child, int type, int *rid, 398164426Ssam u_long start, u_long end, u_long count, u_int flags) 399164426Ssam{ 400164426Ssam struct ixp425_softc *sc = device_get_softc(dev); 401189632Ssam const struct hwvtrans *vtrans; 402164426Ssam struct rman *rmanp; 403164426Ssam struct resource *rv; 404189632Ssam uint32_t addr; 405189630Ssam int needactivate = flags & RF_ACTIVE; 406169952Ssam int irq; 407164426Ssam 408189630Ssam flags &= ~RF_ACTIVE; 409164426Ssam switch (type) { 410164426Ssam case SYS_RES_IRQ: 411164426Ssam rmanp = &sc->sc_irq_rman; 412169952Ssam /* override per hints */ 413169952Ssam if (BUS_READ_IVAR(dev, child, IXP425_IVAR_IRQ, &irq) == 0) 414169952Ssam start = end = irq; 415169952Ssam rv = rman_reserve_resource(rmanp, start, end, count, 416169952Ssam flags, child); 417169952Ssam if (rv != NULL) 418169952Ssam rman_set_rid(rv, *rid); 419164426Ssam break; 420164426Ssam 421164426Ssam case SYS_RES_MEMORY: 422164426Ssam rmanp = &sc->sc_mem_rman; 423169952Ssam /* override per hints */ 424169952Ssam if (BUS_READ_IVAR(dev, child, IXP425_IVAR_ADDR, &addr) == 0) { 425169952Ssam start = addr; 426189632Ssam /* XXX use nominal window to check for mapping */ 427189632Ssam vtrans = gethwvtrans(start, 0x1000); 428189632Ssam if (vtrans != NULL) { 429189632Ssam /* 430189632Ssam * Assign the entire mapped region; this may 431189632Ssam * not be correct but without more info from 432189632Ssam * the caller we cannot tell. 433189632Ssam */ 434189632Ssam end = start + vtrans->size - 435189632Ssam (start - vtrans->hwbase); 436189632Ssam if (bootverbose) 437189632Ssam device_printf(child, 438189632Ssam "%s: assign 0x%lx:0x%lx%s\n", 439189632Ssam __func__, start, end - start, 440189632Ssam vtrans->isa4x ? " A4X" : ""); 441189632Ssam } 442189632Ssam } else 443189632Ssam vtrans = gethwvtrans(start, end - start); 444189632Ssam if (vtrans == NULL) { 445186352Ssam /* likely means above table needs to be updated */ 446189632Ssam device_printf(child, "%s: no mapping for 0x%lx:0x%lx\n", 447186352Ssam __func__, start, end-start); 448169952Ssam return NULL; 449186352Ssam } 450189632Ssam rv = rman_reserve_resource(rmanp, start, end, end - start, 451169952Ssam flags, child); 452189630Ssam if (rv != NULL) 453169952Ssam rman_set_rid(rv, *rid); 454164426Ssam break; 455164426Ssam default: 456169952Ssam rv = NULL; 457169952Ssam break; 458164426Ssam } 459189630Ssam if (rv != NULL && needactivate) { 460189630Ssam if (bus_activate_resource(child, type, *rid, rv)) { 461189630Ssam rman_release_resource(rv); 462189630Ssam return (NULL); 463189630Ssam } 464189630Ssam } 465189630Ssam return (rv); 466164426Ssam} 467164426Ssam 468189630Ssamstatic int 469189630Ssamixp425_activate_resource(device_t dev, device_t child, int type, int rid, 470189630Ssam struct resource *r) 471189630Ssam{ 472189630Ssam struct ixp425_softc *sc = device_get_softc(dev); 473189632Ssam const struct hwvtrans *vtrans; 474189630Ssam 475189630Ssam if (type == SYS_RES_MEMORY) { 476189632Ssam vtrans = gethwvtrans(rman_get_start(r), rman_get_size(r)); 477189632Ssam if (vtrans == NULL) /* NB: should not happen */ 478189632Ssam return (ENOENT); 479189632Ssam if (vtrans->isa4x) 480189630Ssam rman_set_bustag(r, &ixp425_a4x_bs_tag); 481189630Ssam else 482189630Ssam rman_set_bustag(r, sc->sc_iot); 483189632Ssam rman_set_bushandle(r, vtrans->vbase); 484189630Ssam } 485189630Ssam return (rman_activate_resource(r)); 486189630Ssam} 487189630Ssam 488186352Ssamstatic __inline void 489186352Ssamget_masks(struct resource *res, uint32_t *mask, uint32_t *mask2) 490186352Ssam{ 491186352Ssam int i; 492186352Ssam 493186352Ssam *mask = 0; 494186352Ssam for (i = rman_get_start(res); i < 32 && i <= rman_get_end(res); i++) 495186352Ssam *mask |= 1 << i; 496186352Ssam *mask2 = 0; 497186352Ssam for (; i <= rman_get_end(res); i++) 498186352Ssam *mask2 |= 1 << (i - 32); 499186352Ssam} 500186352Ssam 501186352Ssamstatic __inline void 502186352Ssamupdate_masks(uint32_t mask, uint32_t mask2) 503186352Ssam{ 504186352Ssam 505186352Ssam intr_enabled = mask; 506186352Ssam ixp425_set_intrmask(); 507186352Ssam if (cpu_is_ixp43x()) { 508186352Ssam intr_enabled2 = mask2; 509186352Ssam ixp435_set_intrmask(); 510186352Ssam } 511186352Ssam} 512186352Ssam 513164426Ssamstatic int 514164426Ssamixp425_setup_intr(device_t dev, device_t child, 515186352Ssam struct resource *res, int flags, driver_filter_t *filt, 516166901Spiso driver_intr_t *intr, void *arg, void **cookiep) 517164426Ssam{ 518186352Ssam uint32_t mask, mask2; 519164426Ssam 520186352Ssam BUS_SETUP_INTR(device_get_parent(dev), child, res, flags, filt, intr, 521166901Spiso arg, cookiep); 522164426Ssam 523186352Ssam get_masks(res, &mask, &mask2); 524186352Ssam update_masks(intr_enabled | mask, intr_enabled2 | mask2); 525164426Ssam 526164426Ssam return (0); 527164426Ssam} 528164426Ssam 529164426Ssamstatic int 530164426Ssamixp425_teardown_intr(device_t dev, device_t child, struct resource *res, 531164426Ssam void *cookie) 532164426Ssam{ 533186352Ssam uint32_t mask, mask2; 534164426Ssam 535186352Ssam get_masks(res, &mask, &mask2); 536186352Ssam update_masks(intr_enabled &~ mask, intr_enabled2 &~ mask2); 537164426Ssam 538164426Ssam return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, res, cookie)); 539164426Ssam} 540164426Ssam 541164426Ssamstatic device_method_t ixp425_methods[] = { 542164426Ssam /* Device interface */ 543164426Ssam DEVMETHOD(device_probe, ixp425_probe), 544164426Ssam DEVMETHOD(device_attach, ixp425_attach), 545164426Ssam DEVMETHOD(device_identify, ixp425_identify), 546164426Ssam 547164426Ssam /* Bus interface */ 548169952Ssam DEVMETHOD(bus_add_child, ixp425_add_child), 549169952Ssam DEVMETHOD(bus_hinted_child, ixp425_hinted_child), 550169952Ssam DEVMETHOD(bus_read_ivar, ixp425_read_ivar), 551169952Ssam 552164426Ssam DEVMETHOD(bus_alloc_resource, ixp425_alloc_resource), 553189630Ssam DEVMETHOD(bus_activate_resource, ixp425_activate_resource), 554164426Ssam DEVMETHOD(bus_setup_intr, ixp425_setup_intr), 555164426Ssam DEVMETHOD(bus_teardown_intr, ixp425_teardown_intr), 556164426Ssam 557164426Ssam {0, 0}, 558164426Ssam}; 559164426Ssam 560164426Ssamstatic driver_t ixp425_driver = { 561164426Ssam "ixp", 562164426Ssam ixp425_methods, 563164426Ssam sizeof(struct ixp425_softc), 564164426Ssam}; 565164426Ssamstatic devclass_t ixp425_devclass; 566164426Ssam 567164426SsamDRIVER_MODULE(ixp, nexus, ixp425_driver, ixp425_devclass, 0, 0); 568