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$"); 38164426Ssam 39189633Ssam#include "opt_ddb.h" 40189633Ssam 41164426Ssam#define _ARM32_BUS_DMA_PRIVATE 42164426Ssam#include <sys/param.h> 43164426Ssam#include <sys/systm.h> 44164426Ssam#include <sys/bus.h> 45164426Ssam#include <sys/kernel.h> 46164426Ssam#include <sys/module.h> 47164426Ssam#include <sys/malloc.h> 48164426Ssam#include <sys/rman.h> 49164426Ssam#include <machine/bus.h> 50164426Ssam#include <machine/intr.h> 51164426Ssam 52164426Ssam#include <vm/vm.h> 53164426Ssam#include <vm/pmap.h> 54164426Ssam#include <arm/xscale/ixp425/ixp425reg.h> 55164426Ssam#include <arm/xscale/ixp425/ixp425var.h> 56164426Ssam#include <arm/xscale/ixp425/ixp425_intr.h> 57164426Ssam 58164426Ssam#include <dev/pci/pcireg.h> 59164426Ssam 60164426Ssamvolatile uint32_t intr_enabled; 61164426Ssamuint32_t intr_steer = 0; 62164426Ssam 63186352Ssam/* ixp43x et. al have +32 IRQ's */ 64186352Ssamvolatile uint32_t intr_enabled2; 65186352Ssamuint32_t intr_steer2 = 0; 66186352Ssam 67164426Ssamstruct ixp425_softc *ixp425_softc = NULL; 68164426Ssam 69215319Sthompsastruct mtx ixp425_gpio_mtx; 70215319Sthompsa 71164426Ssamstatic int ixp425_probe(device_t); 72164426Ssamstatic void ixp425_identify(driver_t *, device_t); 73164426Ssamstatic int ixp425_attach(device_t); 74164426Ssam 75186418Ssam/* 76186418Ssam * Return a mask of the "fuse" bits that identify 77186418Ssam * which h/w features are present. 78186418Ssam * NB: assumes the expansion bus is mapped. 79186418Ssam */ 80186418Ssamuint32_t 81186418Ssamixp4xx_read_feature_bits(void) 82186418Ssam{ 83186418Ssam uint32_t bits = ~IXPREG(IXP425_EXP_VBASE + EXP_FCTRL_OFFSET); 84186418Ssam bits &= ~EXP_FCTRL_RESVD; 85186418Ssam if (!cpu_is_ixp46x()) 86186418Ssam bits &= ~EXP_FCTRL_IXP46X_ONLY; 87186418Ssam return bits; 88186418Ssam} 89186418Ssam 90194319Ssamvoid 91194319Ssamixp4xx_write_feature_bits(uint32_t v) 92194319Ssam{ 93194319Ssam IXPREG(IXP425_EXP_VBASE + EXP_FCTRL_OFFSET) = ~v; 94194319Ssam} 95194319Ssam 96164426Ssamstruct arm32_dma_range * 97164426Ssambus_dma_get_range(void) 98164426Ssam{ 99164426Ssam return (NULL); 100164426Ssam} 101164426Ssam 102164426Ssamint 103164426Ssambus_dma_get_range_nb(void) 104164426Ssam{ 105164426Ssam return (0); 106164426Ssam} 107164426Ssam 108189633Ssamstatic const uint8_t int2gpio[32] __attribute__ ((aligned(32))) = { 109189633Ssam 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* INT#0 -> INT#5 */ 110189633Ssam 0x00, 0x01, /* GPIO#0 -> GPIO#1 */ 111189633Ssam 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* INT#8 -> INT#13 */ 112189633Ssam 0xff, 0xff, 0xff, 0xff, 0xff, /* INT#14 -> INT#18 */ 113189633Ssam 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* GPIO#2 -> GPIO#7 */ 114189633Ssam 0x08, 0x09, 0x0a, 0x0b, 0x0c, /* GPIO#8 -> GPIO#12 */ 115189633Ssam 0xff, 0xff /* INT#30 -> INT#31 */ 116189633Ssam}; 117189633Ssam 118194648Ssamstatic __inline uint32_t 119164426Ssamixp425_irq2gpio_bit(int irq) 120164426Ssam{ 121189633Ssam return (1U << int2gpio[irq]); 122189633Ssam} 123164426Ssam 124189633Ssam#ifdef DDB 125189633Ssam#include <ddb/ddb.h> 126189633Ssam 127189633SsamDB_SHOW_COMMAND(gpio, db_show_gpio) 128189633Ssam{ 129189633Ssam static const char *itype[8] = { 130189633Ssam [GPIO_TYPE_ACT_HIGH] = "act-high", 131189633Ssam [GPIO_TYPE_ACT_LOW] = "act-low", 132189633Ssam [GPIO_TYPE_EDG_RISING] = "edge-rising", 133189633Ssam [GPIO_TYPE_EDG_FALLING] = "edge-falling", 134189633Ssam [GPIO_TYPE_TRANSITIONAL]= "transitional", 135189633Ssam [5] = "type-5", [6] = "type-6", [7] = "type-7" 136164426Ssam }; 137189633Ssam uint32_t gpoutr = GPIO_CONF_READ_4(ixp425_softc, IXP425_GPIO_GPOUTR); 138189633Ssam uint32_t gpoer = GPIO_CONF_READ_4(ixp425_softc, IXP425_GPIO_GPOER); 139189633Ssam uint32_t gpinr = GPIO_CONF_READ_4(ixp425_softc, IXP425_GPIO_GPINR); 140189633Ssam uint32_t gpit1r = GPIO_CONF_READ_4(ixp425_softc, IXP425_GPIO_GPIT1R); 141189633Ssam uint32_t gpit2r = GPIO_CONF_READ_4(ixp425_softc, IXP425_GPIO_GPIT2R); 142189633Ssam int i, j; 143164426Ssam 144194649Ssam db_printf("GPOUTR %08x GPINR %08x GPOER %08x GPISR %08x\n", 145194649Ssam gpoutr, gpinr, gpoer, 146189633Ssam GPIO_CONF_READ_4(ixp425_softc, IXP425_GPIO_GPISR)); 147189633Ssam db_printf("GPIT1R %08x GPIT2R %08x GPCLKR %08x\n", 148189633Ssam gpit1r, gpit2r, GPIO_CONF_READ_4(ixp425_softc, IXP425_GPIO_GPCLKR)); 149189633Ssam for (i = 0; i < 16; i++) { 150189633Ssam db_printf("[%2d] out %u in %u %-3s", i, 151189633Ssam (gpoutr>>i)&1, (gpinr>>i)&1, (gpoer>>i)&1 ? "in" : "out"); 152189633Ssam for (j = 0; j < 32; j++) 153189633Ssam if (int2gpio[j] == i) { 154189633Ssam db_printf(" irq %2u %s", j, itype[ 155189633Ssam (((i & 8) ? gpit2r : gpit1r) >> (3*(i&7))) 156189633Ssam & 7]); 157189633Ssam break; 158189633Ssam } 159189633Ssam db_printf("\n"); 160189633Ssam } 161164426Ssam} 162189633Ssam#endif 163164426Ssam 164194653Ssamvoid 165194653Ssamixp425_set_gpio(struct ixp425_softc *sc, int pin, int type) 166194653Ssam{ 167194653Ssam uint32_t gpiotr = GPIO_CONF_READ_4(sc, GPIO_TYPE_REG(pin)); 168194653Ssam 169215319Sthompsa IXP4XX_GPIO_LOCK(); 170194653Ssam /* clear interrupt type */ 171194653Ssam GPIO_CONF_WRITE_4(sc, GPIO_TYPE_REG(pin), 172194653Ssam gpiotr &~ GPIO_TYPE(pin, GPIO_TYPE_MASK)); 173194653Ssam /* clear any pending interrupt */ 174194653Ssam GPIO_CONF_WRITE_4(sc, IXP425_GPIO_GPISR, (1<<pin)); 175194653Ssam /* set new interrupt type */ 176194653Ssam GPIO_CONF_WRITE_4(sc, GPIO_TYPE_REG(pin), 177194653Ssam gpiotr | GPIO_TYPE(pin, type)); 178194653Ssam 179194653Ssam /* configure gpio line as an input */ 180236987Simp GPIO_CONF_WRITE_4(sc, IXP425_GPIO_GPOER, 181194653Ssam GPIO_CONF_READ_4(sc, IXP425_GPIO_GPOER) | (1<<pin)); 182215319Sthompsa IXP4XX_GPIO_UNLOCK(); 183194653Ssam} 184194653Ssam 185194650Ssamstatic __inline void 186194650Ssamixp425_gpio_ack(int irq) 187194650Ssam{ 188194650Ssam if (irq < 32 && ((1 << irq) & IXP425_INT_GPIOMASK)) 189194650Ssam IXPREG(IXP425_GPIO_VBASE + IXP425_GPIO_GPISR) = 190194650Ssam ixp425_irq2gpio_bit(irq); 191194650Ssam} 192194650Ssam 193194656Ssamstatic void 194194656Ssamixp425_post_filter(void *arg) 195194656Ssam{ 196194656Ssam uintptr_t irq = (uintptr_t) arg; 197194656Ssam ixp425_gpio_ack(irq); 198194656Ssam} 199194656Ssam 200164426Ssamvoid 201164426Ssamarm_mask_irq(uintptr_t nb) 202164426Ssam{ 203182946Scognet int i; 204194651Ssam 205182946Scognet i = disable_interrupts(I32_bit); 206186352Ssam if (nb < 32) { 207186352Ssam intr_enabled &= ~(1 << nb); 208186352Ssam ixp425_set_intrmask(); 209186352Ssam } else { 210186352Ssam intr_enabled2 &= ~(1 << (nb - 32)); 211186352Ssam ixp435_set_intrmask(); 212186352Ssam } 213182946Scognet restore_interrupts(i); 214164426Ssam /*XXX; If it's a GPIO interrupt, ACK it know. Can it be a problem ?*/ 215194650Ssam ixp425_gpio_ack(nb); 216164426Ssam} 217164426Ssam 218164426Ssamvoid 219164426Ssamarm_unmask_irq(uintptr_t nb) 220164426Ssam{ 221182946Scognet int i; 222194651Ssam 223182946Scognet i = disable_interrupts(I32_bit); 224186352Ssam if (nb < 32) { 225186352Ssam intr_enabled |= (1 << nb); 226186352Ssam ixp425_set_intrmask(); 227186352Ssam } else { 228186352Ssam intr_enabled2 |= (1 << (nb - 32)); 229186352Ssam ixp435_set_intrmask(); 230186352Ssam } 231182946Scognet restore_interrupts(i); 232164426Ssam} 233164426Ssam 234164426Ssamstatic __inline uint32_t 235164426Ssamixp425_irq_read(void) 236164426Ssam{ 237164426Ssam return IXPREG(IXP425_INT_STATUS) & intr_enabled; 238164426Ssam} 239164426Ssam 240186352Ssamstatic __inline uint32_t 241186352Ssamixp435_irq_read(void) 242186352Ssam{ 243186352Ssam return IXPREG(IXP435_INT_STATUS2) & intr_enabled2; 244186352Ssam} 245186352Ssam 246164426Ssamint 247194652Ssamarm_get_next_irq(int last) 248164426Ssam{ 249194652Ssam uint32_t mask; 250164426Ssam 251194652Ssam last += 1; /* always advance fwd, NB: handles -1 */ 252194652Ssam if (last < 32) { 253194652Ssam mask = ixp425_irq_read() >> last; 254194752Ssam for (; mask != 0; mask >>= 1, last++) { 255194652Ssam if (mask & 1) 256194652Ssam return last; 257194652Ssam } 258194652Ssam last = 32; 259194652Ssam } 260194652Ssam if (cpu_is_ixp43x()) { 261194652Ssam mask = ixp435_irq_read() >> (32-last); 262194652Ssam for (; mask != 0; mask >>= 1, last++) { 263194652Ssam if (mask & 1) 264194652Ssam return last; 265194652Ssam } 266194652Ssam } 267194652Ssam return -1; 268164426Ssam} 269164426Ssam 270164426Ssamvoid 271164426Ssamcpu_reset(void) 272164426Ssam{ 273164426Ssam 274164426Ssam bus_space_write_4(&ixp425_bs_tag, IXP425_TIMER_VBASE, 275164426Ssam IXP425_OST_WDOG_KEY, OST_WDOG_KEY_MAJICK); 276164426Ssam bus_space_write_4(&ixp425_bs_tag, IXP425_TIMER_VBASE, 277164426Ssam IXP425_OST_WDOG, 0); 278164426Ssam bus_space_write_4(&ixp425_bs_tag, IXP425_TIMER_VBASE, 279164426Ssam IXP425_OST_WDOG_ENAB, OST_WDOG_ENAB_RST_ENA | 280164426Ssam OST_WDOG_ENAB_CNT_ENA); 281164426Ssam printf("Reset failed!\n"); 282164426Ssam for(;;); 283164426Ssam} 284164426Ssam 285164426Ssamstatic void 286164426Ssamixp425_identify(driver_t *driver, device_t parent) 287164426Ssam{ 288164426Ssam BUS_ADD_CHILD(parent, 0, "ixp", 0); 289164426Ssam} 290164426Ssam 291164426Ssamstatic int 292164426Ssamixp425_probe(device_t dev) 293164426Ssam{ 294186352Ssam device_set_desc(dev, "Intel IXP4XX"); 295164426Ssam return (0); 296164426Ssam} 297164426Ssam 298164426Ssamstatic int 299164426Ssamixp425_attach(device_t dev) 300164426Ssam{ 301164426Ssam struct ixp425_softc *sc; 302164426Ssam 303186418Ssam device_printf(dev, "%b\n", ixp4xx_read_feature_bits(), EXP_FCTRL_BITS); 304186418Ssam 305164426Ssam sc = device_get_softc(dev); 306164426Ssam sc->sc_iot = &ixp425_bs_tag; 307186352Ssam KASSERT(ixp425_softc == NULL, ("%s called twice?", __func__)); 308164426Ssam ixp425_softc = sc; 309164426Ssam 310164426Ssam intr_enabled = 0; 311164426Ssam ixp425_set_intrmask(); 312164426Ssam ixp425_set_intrsteer(); 313186352Ssam if (cpu_is_ixp43x()) { 314186352Ssam intr_enabled2 = 0; 315186352Ssam ixp435_set_intrmask(); 316186352Ssam ixp435_set_intrsteer(); 317186352Ssam } 318194656Ssam arm_post_filter = ixp425_post_filter; 319164426Ssam 320215319Sthompsa mtx_init(&ixp425_gpio_mtx, "gpio", NULL, MTX_DEF); 321194670Ssam if (bus_space_map(sc->sc_iot, IXP425_GPIO_HWBASE, IXP425_GPIO_SIZE, 322194670Ssam 0, &sc->sc_gpio_ioh)) 323194670Ssam panic("%s: unable to map GPIO registers", __func__); 324194670Ssam if (bus_space_map(sc->sc_iot, IXP425_EXP_HWBASE, IXP425_EXP_SIZE, 325194670Ssam 0, &sc->sc_exp_ioh)) 326194670Ssam panic("%s: unable to map Expansion Bus registers", __func__); 327194670Ssam 328194670Ssam /* XXX belongs in platform init */ 329194670Ssam if (cpu_is_ixp43x()) 330194670Ssam cambria_exp_bus_init(sc); 331194670Ssam 332166064Scognet if (bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT, 333236987Simp BUS_SPACE_MAXADDR, NULL, NULL, 0xffffffff, 0xff, 0xffffffff, 0, 334166064Scognet NULL, NULL, &sc->sc_dmat)) 335186352Ssam panic("%s: failed to create dma tag", __func__); 336166064Scognet 337164426Ssam sc->sc_irq_rman.rm_type = RMAN_ARRAY; 338186352Ssam sc->sc_irq_rman.rm_descr = "IXP4XX IRQs"; 339164426Ssam if (rman_init(&sc->sc_irq_rman) != 0 || 340186352Ssam rman_manage_region(&sc->sc_irq_rman, 0, cpu_is_ixp43x() ? 63 : 31) != 0) 341186352Ssam panic("%s: failed to set up IRQ rman", __func__); 342164426Ssam 343164426Ssam sc->sc_mem_rman.rm_type = RMAN_ARRAY; 344186352Ssam sc->sc_mem_rman.rm_descr = "IXP4XX Memory"; 345164426Ssam if (rman_init(&sc->sc_mem_rman) != 0 || 346164426Ssam rman_manage_region(&sc->sc_mem_rman, 0, ~0) != 0) 347186352Ssam panic("%s: failed to set up memory rman", __func__); 348164426Ssam 349169952Ssam BUS_ADD_CHILD(dev, 0, "pcib", 0); 350169952Ssam BUS_ADD_CHILD(dev, 0, "ixpclk", 0); 351169952Ssam BUS_ADD_CHILD(dev, 0, "ixpiic", 0); 352169952Ssam /* XXX move to hints? */ 353169952Ssam BUS_ADD_CHILD(dev, 0, "ixpwdog", 0); 354164426Ssam 355169952Ssam /* attach wired devices via hints */ 356169952Ssam bus_enumerate_hinted_children(dev); 357169952Ssam 358164426Ssam bus_generic_probe(dev); 359164426Ssam bus_generic_attach(dev); 360164426Ssam 361164426Ssam return (0); 362164426Ssam} 363164426Ssam 364169952Ssamstatic void 365169952Ssamixp425_hinted_child(device_t bus, const char *dname, int dunit) 366169952Ssam{ 367169952Ssam device_t child; 368169952Ssam struct ixp425_ivar *ivar; 369169952Ssam 370169952Ssam child = BUS_ADD_CHILD(bus, 0, dname, dunit); 371169952Ssam ivar = IXP425_IVAR(child); 372169952Ssam resource_int_value(dname, dunit, "addr", &ivar->addr); 373169952Ssam resource_int_value(dname, dunit, "irq", &ivar->irq); 374169952Ssam} 375169952Ssam 376169952Ssamstatic device_t 377212413Savgixp425_add_child(device_t dev, u_int order, const char *name, int unit) 378169952Ssam{ 379169952Ssam device_t child; 380169952Ssam struct ixp425_ivar *ivar; 381169952Ssam 382169952Ssam child = device_add_child_ordered(dev, order, name, unit); 383169952Ssam if (child == NULL) 384169952Ssam return NULL; 385169952Ssam ivar = malloc(sizeof(struct ixp425_ivar), M_DEVBUF, M_NOWAIT); 386169952Ssam if (ivar == NULL) { 387169952Ssam device_delete_child(dev, child); 388169952Ssam return NULL; 389169952Ssam } 390169952Ssam ivar->addr = 0; 391169952Ssam ivar->irq = -1; 392169952Ssam device_set_ivars(child, ivar); 393169952Ssam return child; 394169952Ssam} 395169952Ssam 396169952Ssamstatic int 397194015Savgixp425_read_ivar(device_t bus, device_t child, int which, uintptr_t *result) 398169952Ssam{ 399169952Ssam struct ixp425_ivar *ivar = IXP425_IVAR(child); 400169952Ssam 401169952Ssam switch (which) { 402169952Ssam case IXP425_IVAR_ADDR: 403169952Ssam if (ivar->addr != 0) { 404169952Ssam *(uint32_t *)result = ivar->addr; 405169952Ssam return 0; 406169952Ssam } 407169952Ssam break; 408169952Ssam case IXP425_IVAR_IRQ: 409169952Ssam if (ivar->irq != -1) { 410169952Ssam *(int *)result = ivar->irq; 411169952Ssam return 0; 412169952Ssam } 413169952Ssam break; 414169952Ssam } 415169952Ssam return EINVAL; 416169952Ssam} 417169952Ssam 418186352Ssam/* 419189632Ssam * NB: This table handles P->V translations for regions setup with 420189632Ssam * static mappings in initarm. This is used solely for calls to 421189632Ssam * bus_alloc_resource_any; anything done with bus_space_map is 422189632Ssam * handled elsewhere and does not require an entry here. 423186352Ssam * 424189632Ssam * XXX this table is also used by uart_cpu_getdev via getvbase 425189632Ssam * (hence the public api) 426186352Ssam */ 427189632Ssamstruct hwvtrans { 428186352Ssam uint32_t hwbase; 429186352Ssam uint32_t size; 430186352Ssam uint32_t vbase; 431189632Ssam int isa4x; /* XXX needs special bus space tag */ 432194670Ssam int isslow; /* XXX needs special bus space tag */ 433186352Ssam}; 434186352Ssam 435189632Ssamstatic const struct hwvtrans * 436189632Ssamgethwvtrans(uint32_t hwbase, uint32_t size) 437186352Ssam{ 438189632Ssam static const struct hwvtrans hwvtrans[] = { 439189632Ssam /* NB: needed only for uart_cpu_getdev */ 440189632Ssam { .hwbase = IXP425_UART0_HWBASE, 441189632Ssam .size = IXP425_REG_SIZE, 442189632Ssam .vbase = IXP425_UART0_VBASE, 443189632Ssam .isa4x = 1 }, 444189632Ssam { .hwbase = IXP425_UART1_HWBASE, 445189632Ssam .size = IXP425_REG_SIZE, 446189632Ssam .vbase = IXP425_UART1_VBASE, 447189632Ssam .isa4x = 1 }, 448189632Ssam { .hwbase = IXP425_PCI_HWBASE, 449189632Ssam .size = IXP425_PCI_SIZE, 450189632Ssam .vbase = IXP425_PCI_VBASE }, 451189632Ssam { .hwbase = IXP425_PCI_MEM_HWBASE, 452189632Ssam .size = IXP425_PCI_MEM_SIZE, 453189632Ssam .vbase = IXP425_PCI_MEM_VBASE }, 454189632Ssam { .hwbase = IXP425_EXP_BUS_CS0_HWBASE, 455189632Ssam .size = IXP425_EXP_BUS_CS0_SIZE, 456189632Ssam .vbase = IXP425_EXP_BUS_CS0_VBASE }, 457189632Ssam /* NB: needed for ixp435 ehci controllers */ 458189632Ssam { .hwbase = IXP435_USB1_HWBASE, 459189632Ssam .size = IXP435_USB1_SIZE, 460189632Ssam .vbase = IXP435_USB1_VBASE }, 461189632Ssam { .hwbase = IXP435_USB2_HWBASE, 462189632Ssam .size = IXP435_USB2_SIZE, 463189632Ssam .vbase = IXP435_USB2_VBASE }, 464189632Ssam { .hwbase = CAMBRIA_GPS_HWBASE, 465189632Ssam .size = CAMBRIA_GPS_SIZE, 466194670Ssam .vbase = CAMBRIA_GPS_VBASE, 467194670Ssam .isslow = 1 }, 468189632Ssam { .hwbase = CAMBRIA_RS485_HWBASE, 469189632Ssam .size = CAMBRIA_RS485_SIZE, 470194670Ssam .vbase = CAMBRIA_RS485_VBASE, 471194670Ssam .isslow = 1 }, 472189632Ssam }; 473186352Ssam int i; 474186352Ssam 475186352Ssam for (i = 0; i < sizeof hwvtrans / sizeof *hwvtrans; i++) { 476186352Ssam if (hwbase >= hwvtrans[i].hwbase && 477189632Ssam hwbase + size <= hwvtrans[i].hwbase + hwvtrans[i].size) 478189632Ssam return &hwvtrans[i]; 479186352Ssam } 480189632Ssam return NULL; 481186352Ssam} 482186352Ssam 483189632Ssam/* XXX for uart_cpu_getdev */ 484189632Ssamint 485189632Ssamgetvbase(uint32_t hwbase, uint32_t size, uint32_t *vbase) 486189632Ssam{ 487189632Ssam const struct hwvtrans *hw; 488189632Ssam 489189632Ssam hw = gethwvtrans(hwbase, size); 490189632Ssam if (hw == NULL) 491189632Ssam return (ENOENT); 492189632Ssam *vbase = hwbase - hw->hwbase + hw->vbase; 493189632Ssam return (0); 494189632Ssam} 495189632Ssam 496164426Ssamstatic struct resource * 497164426Ssamixp425_alloc_resource(device_t dev, device_t child, int type, int *rid, 498164426Ssam u_long start, u_long end, u_long count, u_int flags) 499164426Ssam{ 500164426Ssam struct ixp425_softc *sc = device_get_softc(dev); 501189632Ssam const struct hwvtrans *vtrans; 502164426Ssam struct resource *rv; 503189632Ssam uint32_t addr; 504189630Ssam int needactivate = flags & RF_ACTIVE; 505169952Ssam int irq; 506164426Ssam 507189630Ssam flags &= ~RF_ACTIVE; 508164426Ssam switch (type) { 509164426Ssam case SYS_RES_IRQ: 510169952Ssam /* override per hints */ 511169952Ssam if (BUS_READ_IVAR(dev, child, IXP425_IVAR_IRQ, &irq) == 0) 512169952Ssam start = end = irq; 513189641Ssam rv = rman_reserve_resource(&sc->sc_irq_rman, start, end, count, 514189641Ssam flags, child); 515169952Ssam if (rv != NULL) 516169952Ssam rman_set_rid(rv, *rid); 517164426Ssam break; 518164426Ssam 519164426Ssam case SYS_RES_MEMORY: 520169952Ssam /* override per hints */ 521169952Ssam if (BUS_READ_IVAR(dev, child, IXP425_IVAR_ADDR, &addr) == 0) { 522169952Ssam start = addr; 523189632Ssam /* XXX use nominal window to check for mapping */ 524189632Ssam vtrans = gethwvtrans(start, 0x1000); 525189632Ssam if (vtrans != NULL) { 526189632Ssam /* 527189632Ssam * Assign the entire mapped region; this may 528189632Ssam * not be correct but without more info from 529189632Ssam * the caller we cannot tell. 530189632Ssam */ 531189632Ssam end = start + vtrans->size - 532189632Ssam (start - vtrans->hwbase); 533189632Ssam if (bootverbose) 534189632Ssam device_printf(child, 535189632Ssam "%s: assign 0x%lx:0x%lx%s\n", 536189632Ssam __func__, start, end - start, 537236987Simp vtrans->isa4x ? " A4X" : 538194670Ssam vtrans->isslow ? " SLOW" : ""); 539189632Ssam } 540189632Ssam } else 541189632Ssam vtrans = gethwvtrans(start, end - start); 542189632Ssam if (vtrans == NULL) { 543186352Ssam /* likely means above table needs to be updated */ 544189632Ssam device_printf(child, "%s: no mapping for 0x%lx:0x%lx\n", 545189641Ssam __func__, start, end - start); 546169952Ssam return NULL; 547186352Ssam } 548189641Ssam rv = rman_reserve_resource(&sc->sc_mem_rman, start, end, 549189641Ssam end - start, flags, child); 550189641Ssam if (rv == NULL) { 551189641Ssam device_printf(child, "%s: cannot reserve 0x%lx:0x%lx\n", 552189641Ssam __func__, start, end - start); 553189641Ssam return NULL; 554189641Ssam } 555189641Ssam rman_set_rid(rv, *rid); 556164426Ssam break; 557164426Ssam default: 558169952Ssam rv = NULL; 559169952Ssam break; 560164426Ssam } 561189630Ssam if (rv != NULL && needactivate) { 562189630Ssam if (bus_activate_resource(child, type, *rid, rv)) { 563189630Ssam rman_release_resource(rv); 564189630Ssam return (NULL); 565189630Ssam } 566189630Ssam } 567189630Ssam return (rv); 568164426Ssam} 569164426Ssam 570189630Ssamstatic int 571189641Ssamixp425_release_resource(device_t bus, device_t child, int type, int rid, 572189641Ssam struct resource *r) 573189641Ssam{ 574189641Ssam /* NB: no private resources, just release */ 575189641Ssam return rman_release_resource(r); 576189641Ssam} 577189641Ssam 578189641Ssamstatic int 579189630Ssamixp425_activate_resource(device_t dev, device_t child, int type, int rid, 580189630Ssam struct resource *r) 581189630Ssam{ 582189630Ssam struct ixp425_softc *sc = device_get_softc(dev); 583189632Ssam const struct hwvtrans *vtrans; 584189630Ssam 585189630Ssam if (type == SYS_RES_MEMORY) { 586189632Ssam vtrans = gethwvtrans(rman_get_start(r), rman_get_size(r)); 587189641Ssam if (vtrans == NULL) { /* NB: should not happen */ 588189641Ssam device_printf(child, "%s: no mapping for 0x%lx:0x%lx\n", 589189641Ssam __func__, rman_get_start(r), rman_get_size(r)); 590189632Ssam return (ENOENT); 591189641Ssam } 592189632Ssam if (vtrans->isa4x) 593189630Ssam rman_set_bustag(r, &ixp425_a4x_bs_tag); 594194670Ssam else if (vtrans->isslow) 595194670Ssam rman_set_bustag(r, &cambria_exp_bs_tag); 596189630Ssam else 597189630Ssam rman_set_bustag(r, sc->sc_iot); 598189632Ssam rman_set_bushandle(r, vtrans->vbase); 599189630Ssam } 600189630Ssam return (rman_activate_resource(r)); 601189630Ssam} 602189630Ssam 603189641Ssamstatic int 604189641Ssamixp425_deactivate_resource(device_t bus, device_t child, int type, int rid, 605236987Simp struct resource *r) 606189641Ssam{ 607189641Ssam /* NB: no private resources, just deactive */ 608189641Ssam return (rman_deactivate_resource(r)); 609189641Ssam} 610189641Ssam 611186352Ssamstatic __inline void 612186352Ssamget_masks(struct resource *res, uint32_t *mask, uint32_t *mask2) 613186352Ssam{ 614186352Ssam int i; 615186352Ssam 616186352Ssam *mask = 0; 617186352Ssam for (i = rman_get_start(res); i < 32 && i <= rman_get_end(res); i++) 618186352Ssam *mask |= 1 << i; 619186352Ssam *mask2 = 0; 620186352Ssam for (; i <= rman_get_end(res); i++) 621186352Ssam *mask2 |= 1 << (i - 32); 622186352Ssam} 623186352Ssam 624186352Ssamstatic __inline void 625186352Ssamupdate_masks(uint32_t mask, uint32_t mask2) 626186352Ssam{ 627186352Ssam 628186352Ssam intr_enabled = mask; 629186352Ssam ixp425_set_intrmask(); 630186352Ssam if (cpu_is_ixp43x()) { 631186352Ssam intr_enabled2 = mask2; 632186352Ssam ixp435_set_intrmask(); 633186352Ssam } 634186352Ssam} 635186352Ssam 636164426Ssamstatic int 637164426Ssamixp425_setup_intr(device_t dev, device_t child, 638236987Simp struct resource *res, int flags, driver_filter_t *filt, 639236987Simp driver_intr_t *intr, void *arg, void **cookiep) 640164426Ssam{ 641186352Ssam uint32_t mask, mask2; 642226832Skevlo int error; 643164426Ssam 644226832Skevlo error = BUS_SETUP_INTR(device_get_parent(dev), child, res, flags, 645226832Skevlo filt, intr, arg, cookiep); 646226832Skevlo if (error) 647226832Skevlo return (error); 648164426Ssam 649186352Ssam get_masks(res, &mask, &mask2); 650186352Ssam update_masks(intr_enabled | mask, intr_enabled2 | mask2); 651164426Ssam 652164426Ssam return (0); 653164426Ssam} 654164426Ssam 655164426Ssamstatic int 656164426Ssamixp425_teardown_intr(device_t dev, device_t child, struct resource *res, 657164426Ssam void *cookie) 658164426Ssam{ 659186352Ssam uint32_t mask, mask2; 660164426Ssam 661186352Ssam get_masks(res, &mask, &mask2); 662186352Ssam update_masks(intr_enabled &~ mask, intr_enabled2 &~ mask2); 663164426Ssam 664164426Ssam return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, res, cookie)); 665164426Ssam} 666164426Ssam 667164426Ssamstatic device_method_t ixp425_methods[] = { 668164426Ssam /* Device interface */ 669189641Ssam DEVMETHOD(device_probe, ixp425_probe), 670189641Ssam DEVMETHOD(device_attach, ixp425_attach), 671189641Ssam DEVMETHOD(device_identify, ixp425_identify), 672164426Ssam 673164426Ssam /* Bus interface */ 674189641Ssam DEVMETHOD(bus_add_child, ixp425_add_child), 675189641Ssam DEVMETHOD(bus_hinted_child, ixp425_hinted_child), 676189641Ssam DEVMETHOD(bus_read_ivar, ixp425_read_ivar), 677169952Ssam 678189641Ssam DEVMETHOD(bus_alloc_resource, ixp425_alloc_resource), 679189641Ssam DEVMETHOD(bus_release_resource, ixp425_release_resource), 680189641Ssam DEVMETHOD(bus_activate_resource, ixp425_activate_resource), 681189641Ssam DEVMETHOD(bus_deactivate_resource, ixp425_deactivate_resource), 682189641Ssam DEVMETHOD(bus_setup_intr, ixp425_setup_intr), 683189641Ssam DEVMETHOD(bus_teardown_intr, ixp425_teardown_intr), 684164426Ssam 685164426Ssam {0, 0}, 686164426Ssam}; 687164426Ssam 688164426Ssamstatic driver_t ixp425_driver = { 689164426Ssam "ixp", 690164426Ssam ixp425_methods, 691164426Ssam sizeof(struct ixp425_softc), 692164426Ssam}; 693164426Ssamstatic devclass_t ixp425_devclass; 694164426Ssam 695164426SsamDRIVER_MODULE(ixp, nexus, ixp425_driver, ixp425_devclass, 0, 0); 696