econa.c revision 295832
1/*- 2 * Copyright (c) 2009 Yohanes Nugroho <yohanes@gmail.com> 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: head/sys/arm/cavium/cns11xx/econa.c 295832 2016-02-20 01:32:58Z jhibbits $"); 29 30#include <sys/param.h> 31#include <sys/systm.h> 32#include <sys/bus.h> 33#include <sys/types.h> 34#include <sys/kernel.h> 35#include <sys/malloc.h> 36#include <sys/module.h> 37#include <sys/rman.h> 38#include <vm/vm.h> 39#include <vm/vm_kern.h> 40#include <vm/pmap.h> 41#include <vm/vm_page.h> 42#include <vm/vm_extern.h> 43 44#define _ARM32_BUS_DMA_PRIVATE 45#include <machine/armreg.h> 46#include <machine/bus.h> 47#include <machine/intr.h> 48#include <machine/resource.h> 49 50#include "econa_reg.h" 51#include "econa_var.h" 52 53static struct econa_softc *econa_softc; 54 55unsigned int CPU_clock = 200000000; 56unsigned int AHB_clock; 57unsigned int APB_clock; 58 59bus_space_tag_t obio_tag; 60 61static int 62econa_probe(device_t dev) 63{ 64 65 device_set_desc(dev, "ECONA device bus"); 66 return (BUS_PROBE_NOWILDCARD); 67} 68 69static void 70econa_identify(driver_t *drv, device_t parent) 71{ 72 73 BUS_ADD_CHILD(parent, 0, "econaarm", 0); 74} 75 76struct arm32_dma_range * 77bus_dma_get_range(void) 78{ 79 80 return (NULL); 81} 82 83int 84bus_dma_get_range_nb(void) 85{ 86 87 return (0); 88} 89 90extern void irq_entry(void); 91 92static void 93econa_add_child(device_t dev, int prio, const char *name, int unit, 94 bus_addr_t addr, bus_size_t size, 95 int irq0, int irq1, 96 int irq2, int irq3, int irq4) 97{ 98 device_t kid; 99 struct econa_ivar *ivar; 100 101 kid = device_add_child_ordered(dev, prio, name, unit); 102 if (kid == NULL) { 103 printf("Can't add child %s%d ordered\n", name, unit); 104 return; 105 } 106 ivar = malloc(sizeof(*ivar), M_DEVBUF, M_NOWAIT | M_ZERO); 107 if (ivar == NULL) { 108 device_delete_child(dev, kid); 109 return; 110 } 111 device_set_ivars(kid, ivar); 112 resource_list_init(&ivar->resources); 113 if (irq0 != -1) 114 bus_set_resource(kid, SYS_RES_IRQ, 0, irq0, 1); 115 if (irq1 != 0) 116 bus_set_resource(kid, SYS_RES_IRQ, 1, irq1, 1); 117 if (irq2 != 0) 118 bus_set_resource(kid, SYS_RES_IRQ, 2, irq2, 1); 119 if (irq3 != 0) 120 bus_set_resource(kid, SYS_RES_IRQ, 3, irq3, 1); 121 if (irq4 != 0) 122 bus_set_resource(kid, SYS_RES_IRQ, 4, irq4, 1); 123 124 if (addr != 0) 125 bus_set_resource(kid, SYS_RES_MEMORY, 0, addr, size); 126 127} 128 129struct cpu_devs 130{ 131 const char *name; 132 int unit; 133 bus_addr_t mem_base; 134 bus_size_t mem_len; 135 int irq0; 136 int irq1; 137 int irq2; 138 int irq3; 139 int irq4; 140}; 141 142struct cpu_devs econarm_devs[] = 143{ 144 { 145 "econa_ic", 0, 146 ECONA_IO_BASE + ECONA_PIC_BASE, ECONA_PIC_SIZE, 147 0 148 }, 149 { 150 "system", 0, 151 ECONA_IO_BASE + ECONA_SYSTEM_BASE, ECONA_SYSTEM_SIZE, 152 0 153 }, 154 { 155 "uart", 0, 156 ECONA_IO_BASE + ECONA_UART_BASE, ECONA_UART_SIZE, 157 ECONA_IRQ_UART 158 }, 159 { 160 "timer", 0, 161 ECONA_IO_BASE + ECONA_TIMER_BASE, ECONA_TIMER_SIZE, 162 ECONA_IRQ_TIMER_1, ECONA_IRQ_TIMER_2 163 }, 164 { 165 "ohci", 0, 166 ECONA_OHCI_VBASE, ECONA_OHCI_SIZE, 167 ECONA_IRQ_OHCI 168 }, 169 { 170 "ehci", 0, 171 ECONA_EHCI_VBASE, ECONA_EHCI_SIZE, 172 ECONA_IRQ_EHCI 173 }, 174 { 175 "cfi", 0, 176 ECONA_CFI_VBASE, ECONA_CFI_SIZE, 177 0 178 }, 179 { 180 "ece", 0, 181 ECONA_IO_BASE + ECONA_NET_BASE, ECONA_NET_SIZE, 182 ECONA_IRQ_STATUS, 183 ECONA_IRQ_TSTC, ECONA_IRQ_FSRC, 184 ECONA_IRQ_TSQE, ECONA_IRQ_FSQF, 185 }, 186 { 0, 0, 0, 0, 0, 0, 0, 0, 0 } 187}; 188 189static void 190econa_cpu_add_builtin_children(device_t dev, struct econa_softc *sc) 191{ 192 int i; 193 struct cpu_devs *walker; 194 195 for (i = 0, walker = econarm_devs; walker->name; i++, walker++) { 196 econa_add_child(dev, i, walker->name, walker->unit, 197 walker->mem_base, walker->mem_len, 198 walker->irq0,walker->irq1, walker->irq2, 199 walker->irq3, walker->irq4); 200 } 201 202} 203 204struct intc_trigger_t { 205 int mode; 206 int level; 207}; 208 209static struct intc_trigger_t intc_trigger_table[] = { 210 {INTC_EDGE_TRIGGER, INTC_RISING_EDGE}, 211 {INTC_EDGE_TRIGGER, INTC_RISING_EDGE}, 212 {INTC_EDGE_TRIGGER, INTC_FALLING_EDGE}, 213 {INTC_EDGE_TRIGGER, INTC_RISING_EDGE}, 214 {INTC_TRIGGER_UNKNOWN, INTC_TRIGGER_UNKNOWN}, 215 {INTC_LEVEL_TRIGGER, INTC_ACTIVE_LOW}, 216 {INTC_LEVEL_TRIGGER, INTC_ACTIVE_LOW}, 217 {INTC_LEVEL_TRIGGER, INTC_ACTIVE_HIGH}, 218 {INTC_TRIGGER_UNKNOWN, INTC_TRIGGER_UNKNOWN}, 219 {INTC_LEVEL_TRIGGER, INTC_ACTIVE_HIGH}, 220 {INTC_LEVEL_TRIGGER, INTC_ACTIVE_HIGH}, 221 {INTC_LEVEL_TRIGGER, INTC_ACTIVE_HIGH}, 222 {INTC_LEVEL_TRIGGER, INTC_ACTIVE_HIGH}, 223 {INTC_TRIGGER_UNKNOWN, INTC_TRIGGER_UNKNOWN}, 224 {INTC_LEVEL_TRIGGER, INTC_ACTIVE_HIGH}, 225 {INTC_EDGE_TRIGGER, INTC_FALLING_EDGE}, 226 {INTC_TRIGGER_UNKNOWN, INTC_TRIGGER_UNKNOWN}, 227 {INTC_TRIGGER_UNKNOWN, INTC_TRIGGER_UNKNOWN}, 228 {INTC_LEVEL_TRIGGER, INTC_ACTIVE_HIGH}, 229 {INTC_EDGE_TRIGGER, INTC_RISING_EDGE}, 230 {INTC_EDGE_TRIGGER, INTC_RISING_EDGE}, 231 {INTC_EDGE_TRIGGER, INTC_RISING_EDGE}, 232 {INTC_EDGE_TRIGGER, INTC_RISING_EDGE}, 233 {INTC_LEVEL_TRIGGER, INTC_ACTIVE_LOW}, 234 {INTC_LEVEL_TRIGGER, INTC_ACTIVE_LOW}, 235}; 236 237static inline uint32_t 238read_4(struct econa_softc *sc, bus_size_t off) 239{ 240 241 return bus_space_read_4(sc->ec_st, sc->ec_sys_sh, off); 242} 243 244static inline void 245write_4(struct econa_softc *sc, bus_size_t off, uint32_t val) 246{ 247 248 return bus_space_write_4(sc->ec_st, sc->ec_sys_sh, off, val); 249} 250 251static inline uint32_t 252system_read_4(struct econa_softc *sc, bus_size_t off) 253{ 254 255 return bus_space_read_4(sc->ec_st, sc->ec_system_sh, off); 256} 257 258static inline void 259system_write_4(struct econa_softc *sc, bus_size_t off, uint32_t val) 260{ 261 262 return bus_space_write_4(sc->ec_st, sc->ec_system_sh, off, val); 263} 264 265 266 267static inline void 268econa_set_irq_mode(struct econa_softc * sc, unsigned int irq, 269 unsigned int mode) 270{ 271 unsigned int val; 272 273 if ((mode != INTC_LEVEL_TRIGGER) && (mode != INTC_EDGE_TRIGGER)) 274 return; 275 276 val = read_4(sc, INTC_INTERRUPT_TRIGGER_MODE_REG_OFFSET); 277 278 if (mode == INTC_LEVEL_TRIGGER) { 279 if (val & (1UL << irq)) { 280 val &= ~(1UL << irq); 281 write_4(sc, INTC_INTERRUPT_TRIGGER_MODE_REG_OFFSET, 282 val); 283 } 284 } else { 285 if (!(val & (1UL << irq))) { 286 val |= (1UL << irq); 287 write_4(sc, INTC_INTERRUPT_TRIGGER_MODE_REG_OFFSET, 288 val); 289 } 290 } 291} 292 293/* 294 * Configure interrupt trigger level to be Active High/Low 295 * or Rising/Falling Edge 296 */ 297static inline void 298econa_set_irq_level(struct econa_softc * sc, 299 unsigned int irq, unsigned int level) 300{ 301 unsigned int val; 302 303 if ((level != INTC_ACTIVE_HIGH) && 304 (level != INTC_ACTIVE_LOW) && 305 (level != INTC_RISING_EDGE) && 306 (level != INTC_FALLING_EDGE)) { 307 return; 308 } 309 310 val = read_4(sc, INTC_INTERRUPT_TRIGGER_LEVEL_REG_OFFSET); 311 312 if ((level == INTC_ACTIVE_HIGH) || (level == INTC_RISING_EDGE)) { 313 if (val & (1UL << irq)) { 314 val &= ~(1UL << irq); 315 write_4(sc, INTC_INTERRUPT_TRIGGER_LEVEL_REG_OFFSET, 316 val); 317 } 318 } else { 319 if (!(val & (1UL << irq))) { 320 val |= (1UL << irq); 321 write_4(sc, INTC_INTERRUPT_TRIGGER_LEVEL_REG_OFFSET, 322 val); 323 } 324 } 325} 326 327static void 328get_system_clock(void) 329{ 330 uint32_t sclock = system_read_4(econa_softc, SYSTEM_CLOCK); 331 332 sclock = (sclock >> 6) & 0x03; 333 334 switch (sclock) { 335 case 0: 336 CPU_clock = 175000000; 337 break; 338 case 1: 339 CPU_clock = 200000000; 340 break; 341 case 2: 342 CPU_clock = 225000000; 343 break; 344 case 3: 345 CPU_clock = 250000000; 346 break; 347 } 348 AHB_clock = CPU_clock >> 1; 349 APB_clock = AHB_clock >> 1; 350} 351 352static int 353econa_attach(device_t dev) 354{ 355 struct econa_softc *sc = device_get_softc(dev); 356 int i; 357 358 obio_tag = arm_base_bs_tag; 359 360 econa_softc = sc; 361 sc->ec_st = arm_base_bs_tag; 362 sc->ec_sh = ECONA_IO_BASE; 363 sc->dev = dev; 364 if (bus_space_subregion(sc->ec_st, sc->ec_sh, ECONA_PIC_BASE, 365 ECONA_PIC_SIZE, &sc->ec_sys_sh) != 0) 366 panic("Unable to map IRQ registers"); 367 368 if (bus_space_subregion(sc->ec_st, sc->ec_sh, ECONA_SYSTEM_BASE, 369 ECONA_SYSTEM_SIZE, &sc->ec_system_sh) != 0) 370 panic("Unable to map IRQ registers"); 371 372 sc->ec_irq_rman.rm_type = RMAN_ARRAY; 373 sc->ec_irq_rman.rm_descr = "ECONA IRQs"; 374 sc->ec_mem_rman.rm_type = RMAN_ARRAY; 375 sc->ec_mem_rman.rm_descr = "ECONA Memory"; 376 if (rman_init(&sc->ec_irq_rman) != 0 || 377 rman_manage_region(&sc->ec_irq_rman, 0, 31) != 0) 378 panic("econa_attach: failed to set up IRQ rman"); 379 if (rman_init(&sc->ec_mem_rman) != 0 || 380 rman_manage_region(&sc->ec_mem_rman, 0, 381 ~0) != 0) 382 panic("econa_attach: failed to set up memory rman"); 383 384 write_4(sc, INTC_INTERRUPT_CLEAR_EDGE_TRIGGER_REG_OFFSET, 0xffffffff); 385 386 write_4(sc, INTC_INTERRUPT_MASK_REG_OFFSET, 0xffffffff); 387 388 write_4(sc, INTC_FIQ_MODE_SELECT_REG_OFFSET, 0); 389 390 /*initialize irq*/ 391 for (i = 0; i < 32; i++) { 392 if (intc_trigger_table[i].mode != INTC_TRIGGER_UNKNOWN) { 393 econa_set_irq_mode(sc,i, intc_trigger_table[i].mode); 394 econa_set_irq_level(sc, i, intc_trigger_table[i].level); 395 } 396 } 397 398 get_system_clock(); 399 400 econa_cpu_add_builtin_children(dev, sc); 401 402 bus_generic_probe(dev); 403 bus_generic_attach(dev); 404 enable_interrupts(PSR_I | PSR_F); 405 406 return (0); 407} 408 409static struct resource * 410econa_alloc_resource(device_t dev, device_t child, int type, int *rid, 411 rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 412{ 413 struct econa_softc *sc = device_get_softc(dev); 414 struct resource_list_entry *rle; 415 struct econa_ivar *ivar = device_get_ivars(child); 416 struct resource_list *rl = &ivar->resources; 417 418 if (device_get_parent(child) != dev) 419 return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child, 420 type, rid, start, end, count, flags)); 421 422 rle = resource_list_find(rl, type, *rid); 423 if (rle == NULL) { 424 return (NULL); 425 } 426 if (rle->res) 427 panic("Resource rid %d type %d already in use", *rid, type); 428 if (RMAN_IS_DEFAULT_RANGE(start, end)) { 429 start = rle->start; 430 count = ulmax(count, rle->count); 431 end = ulmax(rle->end, start + count - 1); 432 } 433 switch (type) 434 { 435 case SYS_RES_IRQ: 436 rle->res = rman_reserve_resource(&sc->ec_irq_rman, 437 start, end, count, flags, child); 438 break; 439 case SYS_RES_MEMORY: 440 rle->res = rman_reserve_resource(&sc->ec_mem_rman, 441 start, end, count, flags, child); 442 if (rle->res != NULL) { 443 rman_set_bustag(rle->res, arm_base_bs_tag); 444 rman_set_bushandle(rle->res, start); 445 } 446 break; 447 } 448 if (rle->res) { 449 rle->start = rman_get_start(rle->res); 450 rle->end = rman_get_end(rle->res); 451 rle->count = count; 452 rman_set_rid(rle->res, *rid); 453 } 454 return (rle->res); 455} 456 457static struct resource_list * 458econa_get_resource_list(device_t dev, device_t child) 459{ 460 struct econa_ivar *ivar; 461 ivar = device_get_ivars(child); 462 return (&(ivar->resources)); 463} 464 465static int 466econa_release_resource(device_t dev, device_t child, int type, 467 int rid, struct resource *r) 468{ 469 struct resource_list *rl; 470 struct resource_list_entry *rle; 471 472 rl = econa_get_resource_list(dev, child); 473 if (rl == NULL) 474 return (EINVAL); 475 rle = resource_list_find(rl, type, rid); 476 if (rle == NULL) 477 return (EINVAL); 478 rman_release_resource(r); 479 rle->res = NULL; 480 return (0); 481} 482 483static int 484econa_setup_intr(device_t dev, device_t child, 485 struct resource *ires, int flags, driver_filter_t *filt, 486 driver_intr_t *intr, void *arg, void **cookiep) 487{ 488 int error; 489 490 if (rman_get_start(ires) == ECONA_IRQ_SYSTEM && filt == NULL) 491 panic("All system interrupt ISRs must be FILTER"); 492 493 error = BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags, 494 filt, intr, arg, cookiep); 495 if (error) 496 return (error); 497 498 return (0); 499} 500 501static int 502econa_teardown_intr(device_t dev, device_t child, struct resource *res, 503 void *cookie) 504{ 505 506 return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, res, cookie)); 507} 508 509static int 510econa_activate_resource(device_t bus, device_t child, int type, int rid, 511 struct resource *r) 512{ 513 514 return (rman_activate_resource(r)); 515} 516 517static int 518econa_print_child(device_t dev, device_t child) 519{ 520 struct econa_ivar *ivars; 521 struct resource_list *rl; 522 int retval = 0; 523 524 ivars = device_get_ivars(child); 525 rl = &ivars->resources; 526 527 retval += bus_print_child_header(dev, child); 528 529 retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#lx"); 530 retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx"); 531 retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld"); 532 if (device_get_flags(dev)) 533 retval += printf(" flags %#x", device_get_flags(dev)); 534 535 retval += bus_print_child_footer(dev, child); 536 537 return (retval); 538} 539 540void 541arm_mask_irq(uintptr_t nb) 542{ 543 unsigned int value; 544 545 value = read_4(econa_softc,INTC_INTERRUPT_MASK_REG_OFFSET) | 1<<nb; 546 write_4(econa_softc, INTC_INTERRUPT_MASK_REG_OFFSET, value); 547} 548 549void 550arm_unmask_irq(uintptr_t nb) 551{ 552 unsigned int value; 553 554 value = read_4(econa_softc, 555 INTC_INTERRUPT_CLEAR_EDGE_TRIGGER_REG_OFFSET) | (1 << nb); 556 write_4(econa_softc, 557 INTC_INTERRUPT_CLEAR_EDGE_TRIGGER_REG_OFFSET, value); 558 value = read_4(econa_softc, INTC_INTERRUPT_MASK_REG_OFFSET)& ~(1 << nb); 559 write_4(econa_softc, INTC_INTERRUPT_MASK_REG_OFFSET, value); 560} 561 562int 563arm_get_next_irq(int x) 564{ 565 int irq; 566 567 irq = read_4(econa_softc, INTC_INTERRUPT_STATUS_REG_OFFSET) & 568 ~(read_4(econa_softc, INTC_INTERRUPT_MASK_REG_OFFSET)); 569 570 if (irq!=0) { 571 return (ffs(irq) - 1); 572 } 573 574 return (-1); 575} 576 577void 578cpu_reset(void) 579{ 580 uint32_t control; 581 582 control = system_read_4(econa_softc, RESET_CONTROL); 583 control |= GLOBAL_RESET; 584 system_write_4(econa_softc, RESET_CONTROL, control); 585 control = system_read_4(econa_softc, RESET_CONTROL); 586 control &= (~(GLOBAL_RESET)); 587 system_write_4(econa_softc, RESET_CONTROL, control); 588 while (1); 589} 590 591 592 593void 594power_on_network_interface(void) 595{ 596 uint32_t cfg_reg; 597 int ii; 598 599 cfg_reg = system_read_4(econa_softc, RESET_CONTROL); 600 cfg_reg |= NET_INTERFACE_RESET; 601 /* set reset bit to HIGH active; */ 602 system_write_4(econa_softc, RESET_CONTROL, cfg_reg); 603 604 /*pulse delay */ 605 for (ii = 0; ii < 0xFFF; ii++) 606 DELAY(100); 607 /* set reset bit to LOW active; */ 608 cfg_reg = system_read_4(econa_softc, RESET_CONTROL); 609 cfg_reg &= ~(NET_INTERFACE_RESET); 610 system_write_4(econa_softc, RESET_CONTROL, cfg_reg); 611 612 /*pulse delay */ 613 for (ii = 0; ii < 0xFFF; ii++) 614 DELAY(100); 615 cfg_reg = system_read_4(econa_softc, RESET_CONTROL); 616 cfg_reg |= NET_INTERFACE_RESET; 617 /* set reset bit to HIGH active; */ 618 system_write_4(econa_softc, RESET_CONTROL, cfg_reg); 619} 620 621unsigned int 622get_tclk(void) 623{ 624 625 return CPU_clock; 626} 627 628static device_method_t econa_methods[] = { 629 DEVMETHOD(device_probe, econa_probe), 630 DEVMETHOD(device_attach, econa_attach), 631 DEVMETHOD(device_identify, econa_identify), 632 DEVMETHOD(bus_alloc_resource, econa_alloc_resource), 633 DEVMETHOD(bus_setup_intr, econa_setup_intr), 634 DEVMETHOD(bus_teardown_intr, econa_teardown_intr), 635 DEVMETHOD(bus_activate_resource, econa_activate_resource), 636 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 637 DEVMETHOD(bus_get_resource_list, econa_get_resource_list), 638 DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), 639 DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 640 DEVMETHOD(bus_release_resource, econa_release_resource), 641 DEVMETHOD(bus_print_child, econa_print_child), 642 {0, 0}, 643}; 644 645static driver_t econa_driver = { 646 "econaarm", 647 econa_methods, 648 sizeof(struct econa_softc), 649}; 650static devclass_t econa_devclass; 651 652DRIVER_MODULE(econaarm, nexus, econa_driver, econa_devclass, 0, 0); 653