1/*- 2 * Copyright (c) 2006 Olivier Houchard 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 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 16 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 18 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 * POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD$"); 29 30#include <sys/param.h> 31#include <sys/systm.h> 32#include <sys/bus.h> 33#include <sys/kernel.h> 34#include <sys/module.h> 35 36#define _ARM32_BUS_DMA_PRIVATE 37#include <machine/bus.h> 38#include <machine/intr.h> 39 40#include <arm/xscale/i8134x/i81342reg.h> 41#include <arm/xscale/i8134x/i81342var.h> 42 43#define WDTCR_ENABLE1 0x1e1e1e1e 44#define WDTCR_ENABLE2 0xe1e1e1e1 45 46static volatile int intr_enabled0; 47static volatile int intr_enabled1; 48static volatile int intr_enabled2; 49static volatile int intr_enabled3; 50 51struct bus_space i81342_bs_tag; 52 53/* Read the interrupt pending register */ 54 55static __inline 56uint32_t intpnd0_read(void) 57{ 58 uint32_t ret; 59 60 __asm __volatile("mrc p6, 0, %0, c0, c3, 0" 61 : "=r" (ret)); 62 return (ret); 63} 64 65static __inline 66uint32_t intpnd1_read(void) 67{ 68 uint32_t ret; 69 70 __asm __volatile("mrc p6, 0, %0, c1, c3, 0" 71 : "=r" (ret)); 72 return (ret); 73} 74 75static __inline 76uint32_t intpnd2_read(void) 77{ 78 uint32_t ret; 79 80 __asm __volatile("mrc p6, 0, %0, c2, c3, 0" 81 : "=r" (ret)); 82 return (ret); 83} 84 85static __inline 86uint32_t intpnd3_read(void) 87{ 88 uint32_t ret; 89 90 __asm __volatile("mrc p6, 0, %0, c3, c3, 0" 91 : "=r" (ret)); 92 return (ret); 93} 94 95/* Read the interrupt control register */ 96/* 0 masked, 1 unmasked */ 97static __inline 98uint32_t intctl0_read(void) 99{ 100 uint32_t ret; 101 102 __asm __volatile("mrc p6, 0, %0, c0, c4, 0" 103 : "=r" (ret)); 104 return (ret); 105} 106 107static __inline 108uint32_t intctl1_read(void) 109{ 110 uint32_t ret; 111 112 __asm __volatile("mrc p6, 0, %0, c1, c4, 0" 113 : "=r" (ret)); 114 return (ret); 115} 116 117static __inline 118uint32_t intctl2_read(void) 119{ 120 uint32_t ret; 121 122 __asm __volatile("mrc p6, 0, %0, c2, c4, 0" 123 : "=r" (ret)); 124 return (ret); 125} 126 127static __inline 128uint32_t intctl3_read(void) 129{ 130 uint32_t ret; 131 132 __asm __volatile("mrc p6, 0, %0, c3, c4, 0" 133 : "=r" (ret)); 134 return (ret); 135} 136 137/* Write the interrupt control register */ 138 139static __inline 140void intctl0_write(uint32_t val) 141{ 142 143 __asm __volatile("mcr p6, 0, %0, c0, c4, 0" 144 : : "r" (val)); 145} 146 147static __inline 148void intctl1_write(uint32_t val) 149{ 150 151 __asm __volatile("mcr p6, 0, %0, c1, c4, 0" 152 : : "r" (val)); 153} 154 155static __inline 156void intctl2_write(uint32_t val) 157{ 158 159 __asm __volatile("mcr p6, 0, %0, c2, c4, 0" 160 : : "r" (val)); 161} 162 163static __inline 164void intctl3_write(uint32_t val) 165{ 166 167 __asm __volatile("mcr p6, 0, %0, c3, c4, 0" 168 : : "r" (val)); 169} 170 171/* Read the interrupt steering register */ 172/* 0 IRQ 1 FIQ */ 173static __inline 174uint32_t intstr0_read(void) 175{ 176 uint32_t ret; 177 178 __asm __volatile("mrc p6, 0, %0, c0, c5, 0" 179 : "=r" (ret)); 180 return (ret); 181} 182 183static __inline 184uint32_t intstr1_read(void) 185{ 186 uint32_t ret; 187 188 __asm __volatile("mrc p6, 0, %0, c1, c5, 0" 189 : "=r" (ret)); 190 return (ret); 191} 192 193static __inline 194uint32_t intstr2_read(void) 195{ 196 uint32_t ret; 197 198 __asm __volatile("mrc p6, 0, %0, c2, c5, 0" 199 : "=r" (ret)); 200 return (ret); 201} 202 203static __inline 204uint32_t intstr3_read(void) 205{ 206 uint32_t ret; 207 208 __asm __volatile("mrc p6, 0, %0, c3, c5, 0" 209 : "=r" (ret)); 210 return (ret); 211} 212 213/* Write the interrupt steering register */ 214 215static __inline 216void intstr0_write(uint32_t val) 217{ 218 219 __asm __volatile("mcr p6, 0, %0, c0, c5, 0" 220 : : "r" (val)); 221} 222 223static __inline 224void intstr1_write(uint32_t val) 225{ 226 227 __asm __volatile("mcr p6, 0, %0, c1, c5, 0" 228 : : "r" (val)); 229} 230 231static __inline 232void intstr2_write(uint32_t val) 233{ 234 235 __asm __volatile("mcr p6, 0, %0, c2, c5, 0" 236 : : "r" (val)); 237} 238 239static __inline 240void intstr3_write(uint32_t val) 241{ 242 243 __asm __volatile("mcr p6, 0, %0, c3, c5, 0" 244 : : "r" (val)); 245} 246 247void 248cpu_reset(void) 249{ 250 251 disable_interrupts(I32_bit); 252 /* XXX: Use the watchdog to reset for now */ 253 __asm __volatile("mcr p6, 0, %0, c8, c9, 0\n" 254 "mcr p6, 0, %1, c7, c9, 0\n" 255 "mcr p6, 0, %2, c7, c9, 0\n" 256 : : "r" (1), "r" (WDTCR_ENABLE1), "r" (WDTCR_ENABLE2)); 257 while (1); 258} 259 260void 261arm_mask_irq(uintptr_t nb) 262{ 263 264 if (nb < 32) { 265 intr_enabled0 &= ~(1 << nb); 266 intctl0_write(intr_enabled0); 267 } else if (nb < 64) { 268 intr_enabled1 &= ~(1 << (nb - 32)); 269 intctl1_write(intr_enabled1); 270 } else if (nb < 96) { 271 intr_enabled2 &= ~(1 << (nb - 64)); 272 intctl2_write(intr_enabled2); 273 } else { 274 intr_enabled3 &= ~(1 << (nb - 96)); 275 intctl3_write(intr_enabled3); 276 } 277} 278 279void 280arm_unmask_irq(uintptr_t nb) 281{ 282 if (nb < 32) { 283 intr_enabled0 |= (1 << nb); 284 intctl0_write(intr_enabled0); 285 } else if (nb < 64) { 286 intr_enabled1 |= (1 << (nb - 32)); 287 intctl1_write(intr_enabled1); 288 } else if (nb < 96) { 289 intr_enabled2 |= (1 << (nb - 64)); 290 intctl2_write(intr_enabled2); 291 } else { 292 intr_enabled3 |= (1 << (nb - 96)); 293 intctl3_write(intr_enabled3); 294 } 295} 296 297int 298arm_get_next_irq(int last __unused) 299{ 300 uint32_t val; 301 val = intpnd0_read() & intr_enabled0; 302 if (val) 303 return (ffs(val) - 1); 304 val = intpnd1_read() & intr_enabled1; 305 if (val) 306 return (32 + ffs(val) - 1); 307 val = intpnd2_read() & intr_enabled2; 308 if (val) 309 return (64 + ffs(val) - 1); 310 val = intpnd3_read() & intr_enabled3; 311 if (val) 312 return (96 + ffs(val) - 1); 313 return (-1); 314} 315 316int 317bus_dma_get_range_nb(void) 318{ 319 return (0); 320} 321 322struct arm32_dma_range * 323bus_dma_get_range(void) 324{ 325 return (NULL); 326} 327 328static int 329i81342_probe(device_t dev) 330{ 331 unsigned int freq; 332 333 freq = *(volatile unsigned int *)(IOP34X_VADDR + IOP34X_PFR); 334 335 switch (freq & IOP34X_FREQ_MASK) { 336 case IOP34X_FREQ_600: 337 device_set_desc(dev, "Intel 81342 600MHz"); 338 break; 339 case IOP34X_FREQ_667: 340 device_set_desc(dev, "Intel 81342 667MHz"); 341 break; 342 case IOP34X_FREQ_800: 343 device_set_desc(dev, "Intel 81342 800MHz"); 344 break; 345 case IOP34X_FREQ_833: 346 device_set_desc(dev, "Intel 81342 833MHz"); 347 break; 348 case IOP34X_FREQ_1000: 349 device_set_desc(dev, "Intel 81342 1000MHz"); 350 break; 351 case IOP34X_FREQ_1200: 352 device_set_desc(dev, "Intel 81342 1200MHz"); 353 break; 354 default: 355 device_set_desc(dev, "Intel 81342 unknown frequency"); 356 break; 357 } 358 return (0); 359} 360 361static void 362i81342_identify(driver_t *driver, device_t parent) 363{ 364 365 BUS_ADD_CHILD(parent, 0, "iq", 0); 366} 367 368static int 369i81342_attach(device_t dev) 370{ 371 struct i81342_softc *sc = device_get_softc(dev); 372 uint32_t esstrsr; 373 374 i81342_bs_init(&i81342_bs_tag, sc); 375 sc->sc_st = &i81342_bs_tag; 376 sc->sc_sh = IOP34X_VADDR; 377 esstrsr = bus_space_read_4(sc->sc_st, sc->sc_sh, IOP34X_ESSTSR0); 378 sc->sc_atux_sh = IOP34X_ATUX_ADDR(esstrsr) - IOP34X_HWADDR + 379 IOP34X_VADDR; 380 sc->sc_atue_sh = IOP34X_ATUE_ADDR(esstrsr) - IOP34X_HWADDR + 381 IOP34X_VADDR; 382 /* Disable all interrupts. */ 383 intctl0_write(0); 384 intctl1_write(0); 385 intctl2_write(0); 386 intctl3_write(0); 387 /* Defaults to IRQ */ 388 intstr0_write(0); 389 intstr1_write(0); 390 intstr2_write(0); 391 intstr3_write(0); 392 sc->sc_irq_rman.rm_type = RMAN_ARRAY; 393 sc->sc_irq_rman.rm_descr = "i81342 IRQs"; 394 if (rman_init(&sc->sc_irq_rman) != 0 || 395 rman_manage_region(&sc->sc_irq_rman, 0, 127) != 0) 396 panic("i81342_attach: failed to set up IRQ rman"); 397 398 device_add_child(dev, "obio", 0); 399 device_add_child(dev, "itimer", 0); 400 device_add_child(dev, "iopwdog", 0); 401 device_add_child(dev, "pcib", 0); 402 device_add_child(dev, "pcib", 1); 403 device_add_child(dev, "iqseg", 0); 404 bus_generic_probe(dev); 405 bus_generic_attach(dev); 406 return (0); 407} 408 409static struct resource * 410i81342_alloc_resource(device_t dev, device_t child, int type, int *rid, 411 u_long start, u_long end, u_long count, u_int flags) 412{ 413 struct i81342_softc *sc = device_get_softc(dev); 414 struct resource *rv; 415 416 if (type == SYS_RES_IRQ) { 417 rv = rman_reserve_resource(&sc->sc_irq_rman, 418 start, end, count, flags, child); 419 if (rv != NULL) 420 rman_set_rid(rv, *rid); 421 return (rv); 422 } 423 424 return (NULL); 425} 426 427static int 428i81342_setup_intr(device_t dev, device_t child, struct resource *ires, 429 int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg, 430 void **cookiep) 431{ 432 int error; 433 434 error = BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags, 435 filt, intr, arg, cookiep); 436 if (error) 437 return (error); 438 return (0); 439} 440 441static int 442i81342_teardown_intr(device_t dev, device_t child, struct resource *res, 443 void *cookie) 444{ 445 return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, res, cookie)); 446} 447 448static device_method_t i81342_methods[] = { 449 DEVMETHOD(device_probe, i81342_probe), 450 DEVMETHOD(device_attach, i81342_attach), 451 DEVMETHOD(device_identify, i81342_identify), 452 DEVMETHOD(bus_alloc_resource, i81342_alloc_resource), 453 DEVMETHOD(bus_setup_intr, i81342_setup_intr), 454 DEVMETHOD(bus_teardown_intr, i81342_teardown_intr), 455 {0, 0}, 456}; 457 458static driver_t i81342_driver = { 459 "iq", 460 i81342_methods, 461 sizeof(struct i81342_softc), 462}; 463static devclass_t i81342_devclass; 464 465DRIVER_MODULE(iq, nexus, i81342_driver, i81342_devclass, 0, 0); 466