1/* $NetBSD: s3c2410.c,v 1.4 2003/08/27 03:46:05 bsh Exp $ */ 2 3/* 4 * Copyright (c) 2003 Genetec corporation. All rights reserved. 5 * Written by Hiroyuki Bessho for Genetec corporation. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of Genetec corporation may not be used to endorse 16 * or promote products derived from this software without specific prior 17 * written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY GENETEC CORP. ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GENETEC CORP. 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include <sys/cdefs.h> 33__FBSDID("$FreeBSD$"); 34 35#include <sys/param.h> 36#include <sys/systm.h> 37#include <sys/kernel.h> 38#include <sys/reboot.h> 39#include <sys/malloc.h> 40#include <sys/module.h> 41#include <sys/bus.h> 42 43#include <vm/vm.h> 44#include <vm/pmap.h> 45 46#include <machine/cpu.h> 47#include <machine/bus.h> 48 49#include <machine/cpufunc.h> 50#include <machine/intr.h> 51#include <arm/s3c2xx0/s3c2410reg.h> 52#include <arm/s3c2xx0/s3c2440reg.h> 53#include <arm/s3c2xx0/s3c24x0var.h> 54#include <sys/rman.h> 55 56#define S3C2XX0_XTAL_CLK 12000000 57 58#define IPL_LEVELS 13 59u_int irqmasks[IPL_LEVELS]; 60 61static struct { 62 uint32_t idcode; 63 const char *name; 64 s3c2xx0_cpu cpu; 65} s3c2x0_cpu_id[] = { 66 { CHIPID_S3C2410A, "S3C2410A", CPU_S3C2410 }, 67 { CHIPID_S3C2440A, "S3C2440A", CPU_S3C2440 }, 68 { CHIPID_S3C2442B, "S3C2442B", CPU_S3C2440 }, 69 70 { 0, NULL } 71}; 72 73static struct { 74 const char *name; 75 int prio; 76 int unit; 77 struct { 78 int type; 79 u_long start; 80 u_long count; 81 } res[2]; 82} s3c24x0_children[] = { 83 { "rtc", 0, -1, { 84 { SYS_RES_IOPORT, S3C24X0_RTC_PA_BASE, S3C24X0_RTC_SIZE }, 85 { 0 }, 86 } }, 87 { "timer", 0, -1, { { 0 }, } }, 88 { "uart", 1, 0, { 89 { SYS_RES_IRQ, S3C24X0_INT_UART0, 1 }, 90 { SYS_RES_IOPORT, S3C24X0_UART_PA_BASE(0), 91 S3C24X0_UART_BASE(1) - S3C24X0_UART_BASE(0) }, 92 } }, 93 { "uart", 1, 1, { 94 { SYS_RES_IRQ, S3C24X0_INT_UART1, 1 }, 95 { SYS_RES_IOPORT, S3C24X0_UART_PA_BASE(1), 96 S3C24X0_UART_BASE(2) - S3C24X0_UART_BASE(1) }, 97 } }, 98 { "uart", 1, 2, { 99 { SYS_RES_IRQ, S3C24X0_INT_UART2, 1 }, 100 { SYS_RES_IOPORT, S3C24X0_UART_PA_BASE(2), 101 S3C24X0_UART_BASE(3) - S3C24X0_UART_BASE(2) }, 102 } }, 103 { "ohci", 0, -1, { 104 { SYS_RES_IRQ, S3C24X0_INT_USBH, 0 }, 105 { SYS_RES_IOPORT, S3C24X0_USBHC_PA_BASE, S3C24X0_USBHC_SIZE }, 106 } }, 107 { NULL }, 108}; 109 110 111/* prototypes */ 112static device_t s3c24x0_add_child(device_t, int, const char *, int); 113 114static int s3c24x0_probe(device_t); 115static int s3c24x0_attach(device_t); 116static void s3c24x0_identify(driver_t *, device_t); 117static int s3c24x0_setup_intr(device_t, device_t, struct resource *, int, 118 driver_filter_t *, driver_intr_t *, void *, void **); 119static int s3c24x0_teardown_intr(device_t, device_t, struct resource *, 120 void *); 121static int s3c24x0_config_intr(device_t, int, enum intr_trigger, 122 enum intr_polarity); 123static struct resource *s3c24x0_alloc_resource(device_t, device_t, int, int *, 124 u_long, u_long, u_long, u_int); 125static int s3c24x0_activate_resource(device_t, device_t, int, int, 126 struct resource *); 127static int s3c24x0_release_resource(device_t, device_t, int, int, 128 struct resource *); 129static struct resource_list *s3c24x0_get_resource_list(device_t, device_t); 130 131static void s3c24x0_identify_cpu(device_t); 132 133static device_method_t s3c24x0_methods[] = { 134 DEVMETHOD(device_probe, s3c24x0_probe), 135 DEVMETHOD(device_attach, s3c24x0_attach), 136 DEVMETHOD(device_identify, s3c24x0_identify), 137 DEVMETHOD(bus_setup_intr, s3c24x0_setup_intr), 138 DEVMETHOD(bus_teardown_intr, s3c24x0_teardown_intr), 139 DEVMETHOD(bus_config_intr, s3c24x0_config_intr), 140 DEVMETHOD(bus_alloc_resource, s3c24x0_alloc_resource), 141 DEVMETHOD(bus_activate_resource, s3c24x0_activate_resource), 142 DEVMETHOD(bus_release_resource, s3c24x0_release_resource), 143 DEVMETHOD(bus_get_resource_list,s3c24x0_get_resource_list), 144 DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), 145 DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 146 {0, 0}, 147}; 148 149static driver_t s3c24x0_driver = { 150 "s3c24x0", 151 s3c24x0_methods, 152 sizeof(struct s3c24x0_softc), 153}; 154static devclass_t s3c24x0_devclass; 155 156DRIVER_MODULE(s3c24x0, nexus, s3c24x0_driver, s3c24x0_devclass, 0, 0); 157 158struct s3c2xx0_softc *s3c2xx0_softc = NULL; 159 160static device_t 161s3c24x0_add_child(device_t bus, int prio, const char *name, int unit) 162{ 163 device_t child; 164 struct s3c2xx0_ivar *ivar; 165 166 child = device_add_child_ordered(bus, prio, name, unit); 167 if (child == NULL) 168 return (NULL); 169 170 ivar = malloc(sizeof(*ivar), M_DEVBUF, M_NOWAIT | M_ZERO); 171 if (ivar == NULL) { 172 device_delete_child(bus, child); 173 printf("Can't add alloc ivar\n"); 174 return (NULL); 175 } 176 device_set_ivars(child, ivar); 177 resource_list_init(&ivar->resources); 178 179 return (child); 180} 181 182static void 183s3c24x0_enable_ext_intr(unsigned int irq) 184{ 185 uint32_t reg, value; 186 int offset; 187 188 if (irq <= 7) { 189 reg = GPIO_PFCON; 190 offset = irq * 2; 191 } else if (irq <= 23) { 192 reg = GPIO_PGCON; 193 offset = (irq - 8) * 2; 194 } else 195 return; 196 197 /* Make the pin an interrupt source */ 198 value = bus_space_read_4(s3c2xx0_softc->sc_iot, 199 s3c2xx0_softc->sc_gpio_ioh, reg); 200 value &= ~(3 << offset); 201 value |= 2 << offset; 202 bus_space_write_4(s3c2xx0_softc->sc_iot, s3c2xx0_softc->sc_gpio_ioh, 203 reg, value); 204} 205 206static int 207s3c24x0_setup_intr(device_t dev, device_t child, 208 struct resource *ires, int flags, driver_filter_t *filt, 209 driver_intr_t *intr, void *arg, void **cookiep) 210{ 211 int error, irq; 212 213 error = BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags, filt, 214 intr, arg, cookiep); 215 if (error != 0) 216 return (error); 217 218 for (irq = rman_get_start(ires); irq <= rman_get_end(ires); irq++) { 219 if (irq >= S3C24X0_EXTIRQ_MIN && irq <= S3C24X0_EXTIRQ_MAX) { 220 /* Enable the external interrupt pin */ 221 s3c24x0_enable_ext_intr(irq - S3C24X0_EXTIRQ_MIN); 222 } 223 arm_unmask_irq(irq); 224 } 225 return (0); 226} 227 228static int 229s3c24x0_teardown_intr(device_t dev, device_t child, struct resource *res, 230 void *cookie) 231{ 232 return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, res, cookie)); 233} 234 235static int 236s3c24x0_config_intr(device_t dev, int irq, enum intr_trigger trig, 237 enum intr_polarity pol) 238{ 239 uint32_t mask, reg, value; 240 int offset; 241 242 /* Only external interrupts can be configured */ 243 if (irq < S3C24X0_EXTIRQ_MIN || irq > S3C24X0_EXTIRQ_MAX) 244 return (EINVAL); 245 246 /* There is no standard trigger or polarity for the bus */ 247 if (trig == INTR_TRIGGER_CONFORM || pol == INTR_POLARITY_CONFORM) 248 return (EINVAL); 249 250 irq -= S3C24X0_EXTIRQ_MIN; 251 252 /* Get the bits to set */ 253 mask = 0; 254 if (pol == INTR_POLARITY_LOW) { 255 mask = 2; 256 } else if (pol == INTR_POLARITY_HIGH) { 257 mask = 4; 258 } 259 if (trig == INTR_TRIGGER_LEVEL) { 260 mask >>= 2; 261 } 262 263 /* Get the register to set */ 264 if (irq <= 7) { 265 reg = GPIO_EXTINT(0); 266 offset = irq * 4; 267 } else if (irq <= 15) { 268 reg = GPIO_EXTINT(1); 269 offset = (irq - 8) * 4; 270 } else if (irq <= 23) { 271 reg = GPIO_EXTINT(2); 272 offset = (irq - 16) * 4; 273 } else { 274 return (EINVAL); 275 } 276 277 /* Set the new signaling method */ 278 value = bus_space_read_4(s3c2xx0_softc->sc_iot, 279 s3c2xx0_softc->sc_gpio_ioh, reg); 280 value &= ~(7 << offset); 281 value |= mask << offset; 282 bus_space_write_4(s3c2xx0_softc->sc_iot, 283 s3c2xx0_softc->sc_gpio_ioh, reg, value); 284 285 return (0); 286} 287 288static struct resource * 289s3c24x0_alloc_resource(device_t bus, device_t child, int type, int *rid, 290 u_long start, u_long end, u_long count, u_int flags) 291{ 292 struct resource_list_entry *rle; 293 struct s3c2xx0_ivar *ivar = device_get_ivars(child); 294 struct resource_list *rl = &ivar->resources; 295 struct resource *res = NULL; 296 297 if (device_get_parent(child) != bus) 298 return (BUS_ALLOC_RESOURCE(device_get_parent(bus), child, 299 type, rid, start, end, count, flags)); 300 301 rle = resource_list_find(rl, type, *rid); 302 if (rle != NULL) { 303 /* There is a resource list. Use it */ 304 if (rle->res) 305 panic("Resource rid %d type %d already in use", *rid, 306 type); 307 if (start == 0UL && end == ~0UL) { 308 start = rle->start; 309 count = ulmax(count, rle->count); 310 end = ulmax(rle->end, start + count - 1); 311 } 312 /* 313 * When allocating an irq with children irq's really 314 * allocate the children as it is those we are interested 315 * in receiving, not the parent. 316 */ 317 if (type == SYS_RES_IRQ && start == end) { 318 switch (start) { 319 case S3C24X0_INT_ADCTC: 320 start = S3C24X0_INT_TC; 321 end = S3C24X0_INT_ADC; 322 break; 323#ifdef S3C2440_INT_CAM 324 case S3C2440_INT_CAM: 325 start = S3C2440_INT_CAM_C; 326 end = S3C2440_INT_CAM_P; 327 break; 328#endif 329 default: 330 break; 331 } 332 count = end - start + 1; 333 } 334 } 335 336 switch (type) { 337 case SYS_RES_IRQ: 338 res = rman_reserve_resource( 339 &s3c2xx0_softc->s3c2xx0_irq_rman, start, end, 340 count, flags, child); 341 break; 342 343 case SYS_RES_IOPORT: 344 case SYS_RES_MEMORY: 345 res = rman_reserve_resource( 346 &s3c2xx0_softc->s3c2xx0_mem_rman, 347 start, end, count, flags, child); 348 if (res == NULL) 349 panic("Unable to map address space %#lX-%#lX", start, 350 end); 351 352 rman_set_bustag(res, &s3c2xx0_bs_tag); 353 rman_set_bushandle(res, start); 354 if (flags & RF_ACTIVE) { 355 if (bus_activate_resource(child, type, *rid, res)) { 356 rman_release_resource(res); 357 return (NULL); 358 } 359 } 360 break; 361 } 362 363 if (res != NULL) { 364 rman_set_rid(res, *rid); 365 if (rle != NULL) { 366 rle->res = res; 367 rle->start = rman_get_start(res); 368 rle->end = rman_get_end(res); 369 rle->count = count; 370 } 371 } 372 373 return (res); 374} 375 376static int 377s3c24x0_activate_resource(device_t bus, device_t child, int type, int rid, 378 struct resource *r) 379{ 380 bus_space_handle_t p; 381 int error; 382 383 if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) { 384 error = bus_space_map(rman_get_bustag(r), 385 rman_get_bushandle(r), rman_get_size(r), 0, &p); 386 if (error) 387 return (error); 388 rman_set_bushandle(r, p); 389 } 390 return (rman_activate_resource(r)); 391} 392 393static int 394s3c24x0_release_resource(device_t bus, device_t child, int type, int rid, 395 struct resource *r) 396{ 397 struct s3c2xx0_ivar *ivar = device_get_ivars(child); 398 struct resource_list *rl = &ivar->resources; 399 struct resource_list_entry *rle; 400 401 if (rl == NULL) 402 return (EINVAL); 403 404 rle = resource_list_find(rl, type, rid); 405 if (rle == NULL) 406 return (EINVAL); 407 408 rman_release_resource(r); 409 rle->res = NULL; 410 411 return 0; 412} 413 414static struct resource_list * 415s3c24x0_get_resource_list(device_t dev, device_t child) 416{ 417 struct s3c2xx0_ivar *ivar; 418 419 ivar = device_get_ivars(child); 420 return (&(ivar->resources)); 421} 422 423void 424s3c24x0_identify(driver_t *driver, device_t parent) 425{ 426 427 BUS_ADD_CHILD(parent, 0, "s3c24x0", 0); 428} 429 430int 431s3c24x0_probe(device_t dev) 432{ 433 return 0; 434} 435 436int 437s3c24x0_attach(device_t dev) 438{ 439 struct s3c24x0_softc *sc = device_get_softc(dev); 440 bus_space_tag_t iot; 441 device_t child; 442 unsigned int i, j; 443 u_long irqmax; 444 445 s3c2xx0_softc = &(sc->sc_sx); 446 sc->sc_sx.sc_iot = iot = &s3c2xx0_bs_tag; 447 s3c2xx0_softc->s3c2xx0_irq_rman.rm_type = RMAN_ARRAY; 448 s3c2xx0_softc->s3c2xx0_irq_rman.rm_descr = "S3C24X0 IRQs"; 449 s3c2xx0_softc->s3c2xx0_mem_rman.rm_type = RMAN_ARRAY; 450 s3c2xx0_softc->s3c2xx0_mem_rman.rm_descr = "S3C24X0 Device Registers"; 451 /* Manage the registor memory space */ 452 if ((rman_init(&s3c2xx0_softc->s3c2xx0_mem_rman) != 0) || 453 (rman_manage_region(&s3c2xx0_softc->s3c2xx0_mem_rman, 454 S3C24X0_DEV_VA_OFFSET, 455 S3C24X0_DEV_VA_OFFSET + S3C24X0_DEV_VA_SIZE) != 0) || 456 (rman_manage_region(&s3c2xx0_softc->s3c2xx0_mem_rman, 457 S3C24X0_DEV_START, S3C24X0_DEV_STOP) != 0)) 458 panic("s3c24x0_attach: failed to set up register rman"); 459 460 /* These are needed for things without a proper device to attach to */ 461 sc->sc_sx.sc_intctl_ioh = S3C24X0_INTCTL_BASE; 462 sc->sc_sx.sc_gpio_ioh = S3C24X0_GPIO_BASE; 463 sc->sc_sx.sc_clkman_ioh = S3C24X0_CLKMAN_BASE; 464 sc->sc_sx.sc_wdt_ioh = S3C24X0_WDT_BASE; 465 sc->sc_timer_ioh = S3C24X0_TIMER_BASE; 466 467 /* 468 * Identify the CPU 469 */ 470 s3c24x0_identify_cpu(dev); 471 472 /* 473 * Manage the interrupt space. 474 * We need to put this after s3c24x0_identify_cpu as the avaliable 475 * interrupts change depending on which CPU we have. 476 */ 477 if (sc->sc_sx.sc_cpu == CPU_S3C2410) 478 irqmax = S3C2410_SUBIRQ_MAX; 479 else 480 irqmax = S3C2440_SUBIRQ_MAX; 481 if (rman_init(&s3c2xx0_softc->s3c2xx0_irq_rman) != 0 || 482 rman_manage_region(&s3c2xx0_softc->s3c2xx0_irq_rman, 0, 483 irqmax) != 0 || 484 rman_manage_region(&s3c2xx0_softc->s3c2xx0_irq_rman, 485 S3C24X0_EXTIRQ_MIN, S3C24X0_EXTIRQ_MAX)) 486 panic("s3c24x0_attach: failed to set up IRQ rman"); 487 488 /* calculate current clock frequency */ 489 s3c24x0_clock_freq(&sc->sc_sx); 490 device_printf(dev, "fclk %d MHz hclk %d MHz pclk %d MHz\n", 491 sc->sc_sx.sc_fclk / 1000000, sc->sc_sx.sc_hclk / 1000000, 492 sc->sc_sx.sc_pclk / 1000000); 493 494 /* 495 * Attach children devices 496 */ 497 498 for (i = 0; s3c24x0_children[i].name != NULL; i++) { 499 child = s3c24x0_add_child(dev, s3c24x0_children[i].prio, 500 s3c24x0_children[i].name, s3c24x0_children[i].unit); 501 for (j = 0; j < sizeof(s3c24x0_children[i].res) / 502 sizeof(s3c24x0_children[i].res[0]) && 503 s3c24x0_children[i].res[j].type != 0; j++) { 504 bus_set_resource(child, 505 s3c24x0_children[i].res[j].type, 0, 506 s3c24x0_children[i].res[j].start, 507 s3c24x0_children[i].res[j].count); 508 } 509 } 510 511 bus_generic_probe(dev); 512 bus_generic_attach(dev); 513 514 return (0); 515} 516 517static void 518s3c24x0_identify_cpu(device_t dev) 519{ 520 struct s3c24x0_softc *sc = device_get_softc(dev); 521 uint32_t idcode; 522 int i; 523 524 idcode = bus_space_read_4(sc->sc_sx.sc_iot, sc->sc_sx.sc_gpio_ioh, 525 GPIO_GSTATUS1); 526 527 for (i = 0; s3c2x0_cpu_id[i].name != NULL; i++) { 528 if (s3c2x0_cpu_id[i].idcode == idcode) 529 break; 530 } 531 if (s3c2x0_cpu_id[i].name == NULL) 532 panic("Unknown CPU detected ((Chip ID: %#X)", idcode); 533 device_printf(dev, "Found %s CPU (Chip ID: %#X)\n", 534 s3c2x0_cpu_id[i].name, idcode); 535 sc->sc_sx.sc_cpu = s3c2x0_cpu_id[i].cpu; 536} 537 538/* 539 * fill sc_pclk, sc_hclk, sc_fclk from values of clock controller register. 540 * 541 * s3c24{1,4}0_clock_freq2() is meant to be called from kernel startup routines. 542 * s3c24x0_clock_freq() is for after kernel initialization is done. 543 * 544 * Because they can be called before bus_space is available we need to use 545 * volatile pointers rather than bus_space_read. 546 */ 547void 548s3c2410_clock_freq2(vm_offset_t clkman_base, int *fclk, int *hclk, int *pclk) 549{ 550 uint32_t pllcon, divn; 551 unsigned int mdiv, pdiv, sdiv; 552 unsigned int f, h, p; 553 554 pllcon = *(volatile uint32_t *)(clkman_base + CLKMAN_MPLLCON); 555 divn = *(volatile uint32_t *)(clkman_base + CLKMAN_CLKDIVN); 556 557 mdiv = (pllcon & PLLCON_MDIV_MASK) >> PLLCON_MDIV_SHIFT; 558 pdiv = (pllcon & PLLCON_PDIV_MASK) >> PLLCON_PDIV_SHIFT; 559 sdiv = (pllcon & PLLCON_SDIV_MASK) >> PLLCON_SDIV_SHIFT; 560 561 f = ((mdiv + 8) * S3C2XX0_XTAL_CLK) / ((pdiv + 2) * (1 << sdiv)); 562 h = f; 563 if (divn & S3C2410_CLKDIVN_HDIVN) 564 h /= 2; 565 p = h; 566 if (divn & CLKDIVN_PDIVN) 567 p /= 2; 568 569 if (fclk) *fclk = f; 570 if (hclk) *hclk = h; 571 if (pclk) *pclk = p; 572} 573 574void 575s3c2440_clock_freq2(vm_offset_t clkman_base, int *fclk, int *hclk, int *pclk) 576{ 577 uint32_t pllcon, divn, camdivn; 578 unsigned int mdiv, pdiv, sdiv; 579 unsigned int f, h, p; 580 581 pllcon = *(volatile uint32_t *)(clkman_base + CLKMAN_MPLLCON); 582 divn = *(volatile uint32_t *)(clkman_base + CLKMAN_CLKDIVN); 583 camdivn = *(volatile uint32_t *)(clkman_base + S3C2440_CLKMAN_CAMDIVN); 584 585 mdiv = (pllcon & PLLCON_MDIV_MASK) >> PLLCON_MDIV_SHIFT; 586 pdiv = (pllcon & PLLCON_PDIV_MASK) >> PLLCON_PDIV_SHIFT; 587 sdiv = (pllcon & PLLCON_SDIV_MASK) >> PLLCON_SDIV_SHIFT; 588 589 f = (2 * (mdiv + 8) * S3C2XX0_XTAL_CLK) / ((pdiv + 2) * (1 << sdiv)); 590 h = f; 591 switch((divn >> 1) & 3) { 592 case 0: 593 break; 594 case 1: 595 h /= 2; 596 break; 597 case 2: 598 if ((camdivn & S3C2440_CAMDIVN_HCLK4_HALF) == 599 S3C2440_CAMDIVN_HCLK4_HALF) 600 h /= 8; 601 else 602 h /= 4; 603 break; 604 case 3: 605 if ((camdivn & S3C2440_CAMDIVN_HCLK3_HALF) == 606 S3C2440_CAMDIVN_HCLK3_HALF) 607 h /= 6; 608 else 609 h /= 3; 610 break; 611 } 612 p = h; 613 if (divn & CLKDIVN_PDIVN) 614 p /= 2; 615 616 if (fclk) *fclk = f; 617 if (hclk) *hclk = h; 618 if (pclk) *pclk = p; 619} 620 621void 622s3c24x0_clock_freq(struct s3c2xx0_softc *sc) 623{ 624 vm_offset_t va; 625 626 va = sc->sc_clkman_ioh; 627 switch(sc->sc_cpu) { 628 case CPU_S3C2410: 629 s3c2410_clock_freq2(va, &sc->sc_fclk, &sc->sc_hclk, 630 &sc->sc_pclk); 631 break; 632 case CPU_S3C2440: 633 s3c2440_clock_freq2(va, &sc->sc_fclk, &sc->sc_hclk, 634 &sc->sc_pclk); 635 break; 636 } 637} 638 639void 640cpu_reset(void) 641{ 642 (void) disable_interrupts(I32_bit|F32_bit); 643 644 bus_space_write_4(&s3c2xx0_bs_tag, s3c2xx0_softc->sc_wdt_ioh, WDT_WTCON, 645 WTCON_ENABLE | WTCON_CLKSEL_16 | WTCON_ENRST); 646 for(;;); 647} 648 649void 650s3c24x0_sleep(int mode __unused) 651{ 652 int reg; 653 654 reg = bus_space_read_4(&s3c2xx0_bs_tag, s3c2xx0_softc->sc_clkman_ioh, 655 CLKMAN_CLKCON); 656 bus_space_write_4(&s3c2xx0_bs_tag, s3c2xx0_softc->sc_clkman_ioh, 657 CLKMAN_CLKCON, reg | CLKCON_IDLE); 658} 659 660 661int 662arm_get_next_irq(int last __unused) 663{ 664 uint32_t intpnd; 665 int irq, subirq; 666 667 if ((irq = bus_space_read_4(&s3c2xx0_bs_tag, 668 s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTOFFSET)) != 0) { 669 670 /* Clear the pending bit */ 671 intpnd = bus_space_read_4(&s3c2xx0_bs_tag, 672 s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTPND); 673 bus_space_write_4(&s3c2xx0_bs_tag, s3c2xx0_softc->sc_intctl_ioh, 674 INTCTL_SRCPND, intpnd); 675 bus_space_write_4(&s3c2xx0_bs_tag, s3c2xx0_softc->sc_intctl_ioh, 676 INTCTL_INTPND, intpnd); 677 678 switch (irq) { 679 case S3C24X0_INT_ADCTC: 680 case S3C24X0_INT_UART0: 681 case S3C24X0_INT_UART1: 682 case S3C24X0_INT_UART2: 683 /* Find the sub IRQ */ 684 subirq = 0x7ff; 685 subirq &= bus_space_read_4(&s3c2xx0_bs_tag, 686 s3c2xx0_softc->sc_intctl_ioh, INTCTL_SUBSRCPND); 687 subirq &= ~(bus_space_read_4(&s3c2xx0_bs_tag, 688 s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTSUBMSK)); 689 if (subirq == 0) 690 return (irq); 691 692 subirq = ffs(subirq) - 1; 693 694 /* Clear the sub irq pending bit */ 695 bus_space_write_4(&s3c2xx0_bs_tag, 696 s3c2xx0_softc->sc_intctl_ioh, INTCTL_SUBSRCPND, 697 (1 << subirq)); 698 699 /* 700 * Return the parent IRQ for UART 701 * as it is all we ever need 702 */ 703 if (subirq <= 8) 704 return (irq); 705 706 return (S3C24X0_SUBIRQ_MIN + subirq); 707 708 case S3C24X0_INT_0: 709 case S3C24X0_INT_1: 710 case S3C24X0_INT_2: 711 case S3C24X0_INT_3: 712 /* There is a 1:1 mapping to the IRQ we are handling */ 713 return S3C24X0_INT_EXT(irq); 714 715 case S3C24X0_INT_4_7: 716 case S3C24X0_INT_8_23: 717 /* Find the external interrupt being called */ 718 subirq = 0x7fffff; 719 subirq &= bus_space_read_4(&s3c2xx0_bs_tag, 720 s3c2xx0_softc->sc_gpio_ioh, GPIO_EINTPEND); 721 subirq &= ~bus_space_read_4(&s3c2xx0_bs_tag, 722 s3c2xx0_softc->sc_gpio_ioh, GPIO_EINTMASK); 723 if (subirq == 0) 724 return (irq); 725 726 subirq = ffs(subirq) - 1; 727 728 /* Clear the external irq pending bit */ 729 bus_space_write_4(&s3c2xx0_bs_tag, 730 s3c2xx0_softc->sc_gpio_ioh, GPIO_EINTPEND, 731 (1 << subirq)); 732 733 return S3C24X0_INT_EXT(subirq); 734 } 735 736 return (irq); 737 } 738 return (-1); 739} 740 741void 742arm_mask_irq(uintptr_t irq) 743{ 744 u_int32_t mask; 745 746 if (irq >= S3C24X0_INT_EXT(0) && irq <= S3C24X0_INT_EXT(3)) { 747 /* External interrupt 0..3 are directly mapped to irq 0..3 */ 748 irq -= S3C24X0_EXTIRQ_MIN; 749 } 750 if (irq < S3C24X0_SUBIRQ_MIN) { 751 mask = bus_space_read_4(&s3c2xx0_bs_tag, 752 s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTMSK); 753 mask |= (1 << irq); 754 bus_space_write_4(&s3c2xx0_bs_tag, 755 s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTMSK, mask); 756 } else if (irq < S3C24X0_EXTIRQ_MIN) { 757 mask = bus_space_read_4(&s3c2xx0_bs_tag, 758 s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTSUBMSK); 759 mask |= (1 << (irq - S3C24X0_SUBIRQ_MIN)); 760 bus_space_write_4(&s3c2xx0_bs_tag, 761 s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTSUBMSK, mask); 762 } else { 763 mask = bus_space_read_4(&s3c2xx0_bs_tag, 764 s3c2xx0_softc->sc_gpio_ioh, GPIO_EINTMASK); 765 mask |= (1 << (irq - S3C24X0_EXTIRQ_MIN)); 766 bus_space_write_4(&s3c2xx0_bs_tag, 767 s3c2xx0_softc->sc_intctl_ioh, GPIO_EINTMASK, mask); 768 } 769} 770 771void 772arm_unmask_irq(uintptr_t irq) 773{ 774 u_int32_t mask; 775 776 if (irq >= S3C24X0_INT_EXT(0) && irq <= S3C24X0_INT_EXT(3)) { 777 /* External interrupt 0..3 are directly mapped to irq 0..3 */ 778 irq -= S3C24X0_EXTIRQ_MIN; 779 } 780 if (irq < S3C24X0_SUBIRQ_MIN) { 781 mask = bus_space_read_4(&s3c2xx0_bs_tag, 782 s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTMSK); 783 mask &= ~(1 << irq); 784 bus_space_write_4(&s3c2xx0_bs_tag, 785 s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTMSK, mask); 786 } else if (irq < S3C24X0_EXTIRQ_MIN) { 787 mask = bus_space_read_4(&s3c2xx0_bs_tag, 788 s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTSUBMSK); 789 mask &= ~(1 << (irq - S3C24X0_SUBIRQ_MIN)); 790 bus_space_write_4(&s3c2xx0_bs_tag, 791 s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTSUBMSK, mask); 792 } else { 793 mask = bus_space_read_4(&s3c2xx0_bs_tag, 794 s3c2xx0_softc->sc_gpio_ioh, GPIO_EINTMASK); 795 mask &= ~(1 << (irq - S3C24X0_EXTIRQ_MIN)); 796 bus_space_write_4(&s3c2xx0_bs_tag, 797 s3c2xx0_softc->sc_intctl_ioh, GPIO_EINTMASK, mask); 798 } 799} 800