octeon_machdep.c revision 199740
1/*- 2 * Copyright (c) 2006 Wojciech A. Koszek <wkoszek@FreeBSD.org> 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 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 THE 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 * $FreeBSD: projects/mips/sys/mips/octeon1/octeon_machdep.c 199740 2009-11-24 08:21:23Z imp $ 27 */ 28#include <sys/cdefs.h> 29__FBSDID("$FreeBSD: projects/mips/sys/mips/octeon1/octeon_machdep.c 199740 2009-11-24 08:21:23Z imp $"); 30 31#include <sys/param.h> 32#include <sys/conf.h> 33#include <sys/kernel.h> 34#include <sys/systm.h> 35#include <sys/imgact.h> 36#include <sys/bio.h> 37#include <sys/buf.h> 38#include <sys/bus.h> 39#include <sys/cpu.h> 40#include <sys/cons.h> 41#include <sys/exec.h> 42#include <sys/ucontext.h> 43#include <sys/proc.h> 44#include <sys/kdb.h> 45#include <sys/ptrace.h> 46#include <sys/reboot.h> 47#include <sys/signalvar.h> 48#include <sys/sysent.h> 49#include <sys/sysproto.h> 50#include <sys/user.h> 51 52#include <vm/vm.h> 53#include <vm/vm_object.h> 54#include <vm/vm_page.h> 55#include <vm/vm_pager.h> 56 57#include <machine/atomic.h> 58#include <machine/cache.h> 59#include <machine/clock.h> 60#include <machine/cpu.h> 61#include <machine/cpuregs.h> 62#include <machine/cpufunc.h> 63#include <mips/octeon1/octeon_pcmap_regs.h> 64#include <mips/octeon1/octeonreg.h> 65#include <machine/hwfunc.h> 66#include <machine/intr_machdep.h> 67#include <machine/locore.h> 68#include <machine/md_var.h> 69#include <machine/pcpu.h> 70#include <machine/pte.h> 71#include <machine/trap.h> 72#include <machine/vmparam.h> 73 74#if defined(__mips_n64) 75#define MAX_APP_DESC_ADDR 0xffffffffafffffff 76#else 77#define MAX_APP_DESC_ADDR 0xafffffff 78#endif 79 80extern int *edata; 81extern int *end; 82 83void 84platform_cpu_init() 85{ 86 /* Nothing special yet */ 87} 88 89/* 90 * Perform a board-level soft-reset. 91 * Note that this is not emulated by gxemul. 92 */ 93void 94platform_reset(void) 95{ 96 ((void(*)(void))0x1fc00000)(); /* Jump to this hex address */ 97} 98 99 100static inline uint32_t octeon_disable_interrupts (void) 101{ 102 uint32_t status_bits; 103 104 status_bits = mips_rd_status(); 105 mips_wr_status(status_bits & ~MIPS_SR_INT_IE); 106 return (status_bits); 107} 108 109 110static inline void octeon_set_interrupts (uint32_t status_bits) 111{ 112 mips_wr_status(status_bits); 113} 114 115 116void octeon_led_write_char (int char_position, char val) 117{ 118 uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8); 119 120 if (!octeon_board_real()) return; 121 122 char_position &= 0x7; /* only 8 chars */ 123 ptr += char_position; 124 oct_write8_x8(ptr, val); 125} 126 127void octeon_led_write_char0 (char val) 128{ 129 uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8); 130 131 if (!octeon_board_real()) return; 132 133 oct_write8_x8(ptr, val); 134} 135 136void octeon_led_write_hexchar (int char_position, char hexval) 137{ 138 uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8); 139 char char1, char2; 140 141 if (!octeon_board_real()) return; 142 143 char1 = (hexval >> 4) & 0x0f; char1 = (char1 < 10)?char1+'0':char1+'7'; 144 char2 = (hexval & 0x0f); char2 = (char2 < 10)?char2+'0':char2+'7'; 145 char_position &= 0x7; /* only 8 chars */ 146 if (char_position > 6) char_position = 6; 147 ptr += char_position; 148 oct_write8_x8(ptr, char1); 149 ptr++; 150 oct_write8_x8(ptr, char2); 151} 152 153void octeon_led_write_string (const char *str) 154{ 155 uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8); 156 int i; 157 158 if (!octeon_board_real()) return; 159 160 for (i=0; i<8; i++, ptr++) { 161 if (str && *str) { 162 oct_write8_x8(ptr, *str++); 163 } else { 164 oct_write8_x8(ptr, ' '); 165 } 166 oct_read64(OCTEON_MIO_BOOT_BIST_STAT); 167 } 168} 169 170static char progress[8] = { '-', '/', '|', '\\', '-', '/', '|', '\\'}; 171 172void octeon_led_run_wheel (/*int count, */int *prog_count, int led_position) 173{ 174 if (!octeon_board_real()) return; 175 176 octeon_led_write_char(led_position, progress[*prog_count]); 177 *prog_count += 1; 178 *prog_count &= 0x7; 179} 180 181#define LSR_DATAREADY 0x01 /* Data ready */ 182#define LSR_THRE 0x20 /* Transmit holding register empty */ 183#define LSR_TEMT 0x40 /* Transmitter Empty. THR, TSR & FIFO */ 184#define USR_TXFIFO_NOTFULL 0x02 /* Uart TX FIFO Not full */ 185 186/* 187 * octeon_uart_write_byte 188 * 189 * Put out a single byte off of uart port. 190 */ 191 192void octeon_uart_write_byte (int uart_index, uint8_t ch) 193{ 194 uint64_t val, val2; 195 if ((uart_index < 0) || (uart_index > 1)) { 196 return; 197 } 198 199 while (1) { 200 val = oct_read64(OCTEON_MIO_UART0_LSR + (uart_index * 0x400)); 201 val2 = oct_read64(OCTEON_MIO_UART0_USR + (uart_index * 0x400)); 202 if ((((uint8_t) val) & LSR_THRE) || 203 (((uint8_t) val2) & USR_TXFIFO_NOTFULL)) { 204 break; 205 } 206 } 207 208 /* Write the byte */ 209 oct_write8(OCTEON_MIO_UART0_THR + (uart_index * 0x400), (uint64_t) ch); 210 211 /* Force Flush the IOBus */ 212 oct_read64(OCTEON_MIO_BOOT_BIST_STAT); 213} 214 215 216void octeon_uart_write_byte0 (uint8_t ch) 217{ 218 uint64_t val, val2; 219 220 while (1) { 221 val = oct_read64(OCTEON_MIO_UART0_LSR); 222 val2 = oct_read64(OCTEON_MIO_UART0_USR); 223 if ((((uint8_t) val) & LSR_THRE) || 224 (((uint8_t) val2) & USR_TXFIFO_NOTFULL)) { 225 break; 226 } 227 } 228 229 /* Write the byte */ 230 oct_write8(OCTEON_MIO_UART0_THR, (uint64_t) ch); 231 232 /* Force Flush the IOBus */ 233 oct_read64(OCTEON_MIO_BOOT_BIST_STAT); 234} 235 236/* 237 * octeon_uart_write_string 238 * 239 */ 240void octeon_uart_write_string (int uart_index, const char *str) 241{ 242 /* Just loop writing one byte at a time */ 243 244 while (*str) 245 { 246 octeon_uart_write_byte(uart_index, *str); 247 if (*str == '\n') { 248 octeon_uart_write_byte(uart_index, '\r'); 249 } 250 str++; 251 } 252 } 253 254static char wstr[30]; 255 256void octeon_led_write_hex (uint32_t wl) 257{ 258 char nbuf[80]; 259 260 sprintf(nbuf, "%X", wl); 261 octeon_led_write_string(nbuf); 262} 263 264 265void octeon_uart_write_hex2 (uint32_t wl, uint32_t wh) 266{ 267 sprintf(wstr, "0x%X-0x%X ", wh, wl); 268 octeon_uart_write_string(0, wstr); 269} 270 271void octeon_uart_write_hex (uint32_t wl) 272{ 273 sprintf(wstr, " 0x%X ", wl); 274 octeon_uart_write_string(0, wstr); 275} 276 277#ifdef __not_used__ 278#define OCT_CONS_BUFLEN 200 279static char console_str_buff0[OCT_CONS_BUFLEN + 1]; 280#include <machine/stdarg.h> 281 282//#define USE_KERN_SUBR_PRINTF 283#ifndef USE_KERN_SUBR_PRINTF 284static int oct_printf (const char *fmt, va_list ap); 285#endif 286 287int kern_cons_printf(const char *fmt, ...) 288{ 289 va_list ap; 290 291 va_start(ap, fmt); 292#ifndef USE_KERN_SUBR_PRINTF 293 oct_printf(fmt, ap); 294#else 295 ker_printf(fmt, ap); 296#endif 297 va_end(ap); 298 return (0); 299} 300 301#ifndef USE_KERN_SUBR_PRINTF 302static int oct_printf(const char *fmt, va_list ap) 303{ 304 snprintf(console_str_buff0, OCT_CONS_BUFLEN, fmt, ap); 305 octeon_uart_write_string(0, console_str_buff0); 306 return (0); 307} 308#endif 309 310int console_printf(const char *fmt, ...) 311{ 312 va_list ap; 313 314 va_start(ap, fmt); 315 sprintf(console_str_buff0, fmt, ap); 316 va_end(ap); 317 octeon_uart_write_string(0, console_str_buff0); 318 return (0); 319} 320#endif 321 322 323/* 324 * octeon_wait_uart_flush 325 */ 326void octeon_wait_uart_flush (int uart_index, uint8_t ch) 327{ 328 uint64_t val; 329 int64_t val3; 330 uint32_t cpu_status_bits; 331 332 if ((uart_index < 0) || (uart_index > 1)) { 333 return; 334 } 335 336 cpu_status_bits = octeon_disable_interrupts(); 337 /* Force Flush the IOBus */ 338 oct_read64(OCTEON_MIO_BOOT_BIST_STAT); 339 for (val3 = 0xfffffffff; val3 > 0; val3--) { 340 val = oct_read64(OCTEON_MIO_UART0_LSR + (uart_index * 0x400)); 341 if (((uint8_t) val) & LSR_TEMT) { 342 break; 343 } 344 } 345 octeon_set_interrupts(cpu_status_bits); 346} 347 348 349/* 350 * octeon_debug_symbol 351 * 352 * Does nothing. 353 * Used to mark the point for simulator to begin tracing 354 */ 355void octeon_debug_symbol (void) 356{ 357} 358 359void octeon_ciu_stop_gtimer (int timer) 360{ 361 oct_write64(OCTEON_CIU_GENTIMER_ADDR(timer), 0ll); 362} 363 364void octeon_ciu_start_gtimer (int timer, u_int one_shot, uint64_t time_cycles) 365{ 366 octeon_ciu_gentimer gentimer; 367 368 gentimer.word64 = 0; 369 gentimer.bits.one_shot = one_shot; 370 gentimer.bits.len = time_cycles - 1; 371 oct_write64(OCTEON_CIU_GENTIMER_ADDR(timer), gentimer.word64); 372} 373 374/* 375 * octeon_ciu_reset 376 * 377 * Shutdown all CIU to IP2, IP3 mappings 378 */ 379void octeon_ciu_reset (void) 380{ 381 382 octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_0); 383 octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_1); 384 octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_2); 385 octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_3); 386 387 ciu_disable_intr(CIU_THIS_CORE, CIU_INT_0, CIU_EN_0); 388 ciu_disable_intr(CIU_THIS_CORE, CIU_INT_0, CIU_EN_1); 389 ciu_disable_intr(CIU_THIS_CORE, CIU_INT_1, CIU_EN_0); 390 ciu_disable_intr(CIU_THIS_CORE, CIU_INT_1, CIU_EN_1); 391 392 ciu_clear_int_summary(CIU_THIS_CORE, CIU_INT_0, CIU_EN_0, 0ll); 393 ciu_clear_int_summary(CIU_THIS_CORE, CIU_INT_1, CIU_EN_0, 0ll); 394 ciu_clear_int_summary(CIU_THIS_CORE, CIU_INT_1, CIU_EN_1, 0ll); 395} 396 397/* 398 * mips_disable_interrupt_controllers 399 * 400 * Disable interrupts in the CPU controller 401 */ 402void mips_disable_interrupt_controls (void) 403{ 404 /* 405 * Disable interrupts in CIU. 406 */ 407 octeon_ciu_reset(); 408} 409 410static uint64_t ciu_get_intr_sum_reg_addr(int core_num, int intx, int enx); 411 412/* 413 * ciu_get_intr_sum_reg_addr 414 */ 415static uint64_t ciu_get_intr_sum_reg_addr (int core_num, int intx, int enx) 416{ 417 uint64_t ciu_intr_sum_reg_addr; 418 419 if (enx == CIU_EN_0) { 420 ciu_intr_sum_reg_addr = OCTEON_CIU_SUMMARY_BASE_ADDR + (core_num * 0x10) + 421 (intx * 0x8); 422 } else { 423 ciu_intr_sum_reg_addr = OCTEON_CIU_SUMMARY_INT1_ADDR; 424 } 425 426 return (ciu_intr_sum_reg_addr); 427} 428 429 430static uint64_t ciu_get_intr_en_reg_addr(int core_num, int intx, int enx); 431 432/* 433 * ciu_get_intr_en_reg_addr 434 */ 435static uint64_t ciu_get_intr_en_reg_addr (int core_num, int intx, int enx) 436{ 437 uint64_t ciu_intr_reg_addr; 438 439 440 ciu_intr_reg_addr = OCTEON_CIU_ENABLE_BASE_ADDR + ((enx == 0) ? 0x0 : 0x8) + 441 (intx * 0x10) + (core_num * 0x20); 442 443 return (ciu_intr_reg_addr); 444} 445 446 447 448 449uint64_t ciu_get_en_reg_addr_new (int corenum, int intx, int enx, int ciu_ip); 450 451/* 452 * ciu_get_intr_reg_addr 453 * 454 * 200 ---int0,en0 ip2 455 * 208 ---int0,en1 ip2 ----> this is wrong... this is watchdog 456 * 457 * 210 ---int0,en0 ip3 -- 458 * 218 ---int0,en1 ip3 ----> same here.. .this is watchdog... right? 459 * 460 * 220 ---int1,en0 ip2 461 * 228 ---int1,en1 ip2 462 * 230 ---int1,en0 ip3 -- 463 * 238 ---int1,en1 ip3 464 * 465 */ 466uint64_t ciu_get_en_reg_addr_new (int corenum, int intx, int enx, int ciu_ip) 467{ 468 uint64_t ciu_intr_reg_addr = OCTEON_CIU_ENABLE_BASE_ADDR; 469 470 if (enx < CIU_EN_0 || enx > CIU_EN_1) { 471 printf("%s: invalid enx value %d, should be %d or %d\n", 472 __FUNCTION__, enx, CIU_EN_0, CIU_EN_1); 473 return 0; 474 } 475 if (intx < CIU_INT_0 || intx > CIU_INT_1) { 476 printf("%s: invalid intx value %d, should be %d or %d\n", 477 __FUNCTION__, enx, CIU_INT_0, CIU_INT_1); 478 return 0; 479 } 480 if (ciu_ip < CIU_MIPS_IP2 || ciu_ip > CIU_MIPS_IP3) { 481 printf("%s: invalid ciu_ip value %d, should be %d or %d\n", 482 __FUNCTION__, ciu_ip, CIU_MIPS_IP2, CIU_MIPS_IP3); 483 return 0; 484 } 485 486 ciu_intr_reg_addr += (enx * 0x8); 487 ciu_intr_reg_addr += (ciu_ip * 0x10); 488 ciu_intr_reg_addr += (intx * 0x20); 489 490 return (ciu_intr_reg_addr); 491} 492 493/* 494 * ciu_get_int_summary 495 */ 496uint64_t ciu_get_int_summary (int core_num, int intx, int enx) 497{ 498 uint64_t ciu_intr_sum_reg_addr; 499 500 if (core_num == CIU_THIS_CORE) { 501 core_num = octeon_get_core_num(); 502 } 503 ciu_intr_sum_reg_addr = ciu_get_intr_sum_reg_addr(core_num, intx, enx); 504 return (oct_read64(ciu_intr_sum_reg_addr)); 505} 506 507//#define DEBUG_CIU 1 508 509#ifdef DEBUG_CIU 510#define DEBUG_CIU_SUM 1 511#define DEBUG_CIU_EN 1 512#endif 513 514 515/* 516 * ciu_clear_int_summary 517 */ 518void ciu_clear_int_summary (int core_num, int intx, int enx, uint64_t write_bits) 519{ 520 uint32_t cpu_status_bits; 521 uint64_t ciu_intr_sum_reg_addr; 522 523//#define DEBUG_CIU_SUM 1 524 525#ifdef DEBUG_CIU_SUM 526 uint64_t ciu_intr_sum_bits; 527#endif 528 529 530 if (core_num == CIU_THIS_CORE) { 531 core_num = octeon_get_core_num(); 532 } 533 534#ifdef DEBUG_CIU_SUM 535 printf(" CIU: core %u clear sum IntX %u Enx %u Bits: 0x%llX\n", 536 core_num, intx, enx, write_bits); 537#endif 538 539 cpu_status_bits = octeon_disable_interrupts(); 540 541 ciu_intr_sum_reg_addr = ciu_get_intr_sum_reg_addr(core_num, intx, enx); 542 543#ifdef DEBUG_CIU_SUM 544 ciu_intr_sum_bits = oct_read64(ciu_intr_sum_reg_addr); /* unneeded dummy read */ 545 printf(" CIU: status: 0x%X reg_addr: 0x%llX Val: 0x%llX -> 0x%llX", 546 cpu_status_bits, ciu_intr_sum_reg_addr, ciu_intr_sum_bits, 547 ciu_intr_sum_bits | write_bits); 548#endif 549 550 oct_write64(ciu_intr_sum_reg_addr, write_bits); 551 oct_read64(OCTEON_MIO_BOOT_BIST_STAT); /* Bus Barrier */ 552 553#ifdef DEBUG_CIU_SUM 554 printf(" Readback: 0x%llX\n\n ", (uint64_t) oct_read64(ciu_intr_sum_reg_addr)); 555#endif 556 557 octeon_set_interrupts(cpu_status_bits); 558} 559 560/* 561 * ciu_disable_intr 562 */ 563void ciu_disable_intr (int core_num, int intx, int enx) 564{ 565 uint32_t cpu_status_bits; 566 uint64_t ciu_intr_reg_addr; 567 568 if (core_num == CIU_THIS_CORE) { 569 core_num = octeon_get_core_num(); 570 } 571 572 cpu_status_bits = octeon_disable_interrupts(); 573 574 ciu_intr_reg_addr = ciu_get_intr_en_reg_addr(core_num, intx, enx); 575 576 oct_read64(ciu_intr_reg_addr); /* Dummy read */ 577 578 oct_write64(ciu_intr_reg_addr, 0LL); 579 oct_read64(OCTEON_MIO_BOOT_BIST_STAT); /* Bus Barrier */ 580 581 octeon_set_interrupts(cpu_status_bits); 582} 583 584void ciu_dump_interrutps_enabled (int core_num, int intx, int enx, int ciu_ip); 585void ciu_dump_interrutps_enabled (int core_num, int intx, int enx, int ciu_ip) 586{ 587 588 uint64_t ciu_intr_reg_addr; 589 uint64_t ciu_intr_bits; 590 591 if (core_num == CIU_THIS_CORE) { 592 core_num = octeon_get_core_num(); 593 } 594 595#ifndef OCTEON_SMP_1 596 ciu_intr_reg_addr = ciu_get_intr_en_reg_addr(core_num, intx, enx); 597#else 598 ciu_intr_reg_addr = ciu_get_en_reg_addr_new(core_num, intx, enx, ciu_ip); 599#endif 600 601 if (!ciu_intr_reg_addr) { 602 printf("Bad call to %s\n", __FUNCTION__); 603 while(1); 604 return; 605 } 606 607 ciu_intr_bits = oct_read64(ciu_intr_reg_addr); 608 printf(" CIU core %d int: %d en: %d ip: %d Add: %#llx enabled: %#llx SR: %x\n", 609 core_num, intx, enx, ciu_ip, (unsigned long long)ciu_intr_reg_addr, 610 (unsigned long long)ciu_intr_bits, mips_rd_status()); 611} 612 613 614/* 615 * ciu_enable_interrupts 616 */ 617void ciu_enable_interrupts (int core_num, int intx, int enx, uint64_t set_these_interrupt_bits, 618 int ciu_ip) 619{ 620 621 uint32_t cpu_status_bits; 622 uint64_t ciu_intr_reg_addr; 623 uint64_t ciu_intr_bits; 624 625 if (core_num == CIU_THIS_CORE) { 626 core_num = octeon_get_core_num(); 627 } 628 629//#define DEBUG_CIU_EN 1 630 631#ifdef DEBUG_CIU_EN 632 printf(" CIU: core %u enabling Intx %u Enx %u IP %d Bits: 0x%llX\n", 633 core_num, intx, enx, ciu_ip, set_these_interrupt_bits); 634#endif 635 636 cpu_status_bits = octeon_disable_interrupts(); 637 638#ifndef OCTEON_SMP_1 639 ciu_intr_reg_addr = ciu_get_intr_en_reg_addr(core_num, intx, enx); 640#else 641 ciu_intr_reg_addr = ciu_get_en_reg_addr_new(core_num, intx, enx, ciu_ip); 642#endif 643 644 if (!ciu_intr_reg_addr) { 645 printf("Bad call to %s\n", __FUNCTION__); 646 while(1); 647 return; 648 } 649 650 ciu_intr_bits = oct_read64(ciu_intr_reg_addr); 651 652#ifdef DEBUG_CIU_EN 653 printf(" CIU: status: 0x%X reg_addr: 0x%llX Val: 0x%llX -> 0x%llX", 654 cpu_status_bits, ciu_intr_reg_addr, ciu_intr_bits, ciu_intr_bits | set_these_interrupt_bits); 655#endif 656 ciu_intr_bits |= set_these_interrupt_bits; 657 oct_write64(ciu_intr_reg_addr, ciu_intr_bits); 658#ifdef OCTEON_SMP 659 mips_wbflush(); 660#endif 661 oct_read64(OCTEON_MIO_BOOT_BIST_STAT); /* Bus Barrier */ 662 663#ifdef DEBUG_CIU_EN 664 printf(" Readback: 0x%llX\n\n ", (uint64_t) oct_read64(ciu_intr_reg_addr)); 665#endif 666 667 octeon_set_interrupts(cpu_status_bits); 668} 669 670void 671platform_start(__register_t a0, __register_t a1, 672 __register_t a2 __unused, __register_t a3 __unused) 673{ 674 uint64_t platform_counter_freq; 675 vm_offset_t kernend; 676 int argc = a0; 677 char **argv = (char **)a1; 678 int i, mem; 679 680 /* clear the BSS and SBSS segments */ 681 kernend = round_page((vm_offset_t)&end); 682 memset(&edata, 0, kernend - (vm_offset_t)(&edata)); 683 684 octeon_ciu_reset(); 685 octeon_uart_write_string(0, "Platform Starting\n"); 686 687/* From here on down likely is bogus */ 688 /* 689 * Looking for mem=XXM argument 690 */ 691 mem = 0; /* Just something to start with */ 692 for (i=0; i < argc; i++) { 693 if (strncmp(argv[i], "mem=", 4) == 0) { 694 mem = strtol(argv[i] + 4, NULL, 0); 695 break; 696 } 697 } 698 699 bootverbose = 1; 700 if (mem > 0) 701 realmem = btoc(mem << 20); 702 else 703 realmem = btoc(32 << 20); 704 705 for (i = 0; i < 10; i++) { 706 phys_avail[i] = 0; 707 } 708 709 /* phys_avail regions are in bytes */ 710 phys_avail[0] = MIPS_KSEG0_TO_PHYS((vm_offset_t)&end); 711 phys_avail[1] = ctob(realmem); 712 713 physmem = realmem; 714 715 /* 716 * ns8250 uart code uses DELAY so ticker should be inititalized 717 * before cninit. And tick_init_params refers to hz, so * init_param1 718 * should be called first. 719 */ 720 init_param1(); 721 /* TODO: parse argc,argv */ 722 platform_counter_freq = 330000000UL; /* XXX: from idt */ 723 mips_timer_init_params(platform_counter_freq, 1); 724 cninit(); 725 printf("Now is the time to get happy!\n"); 726 /* Panic here, after cninit */ 727#if 0 728 if (mem == 0) 729 panic("No mem=XX parameter in arguments"); 730#endif 731 732 printf("cmd line: "); 733 for (i=0; i < argc; i++) 734 printf("%s ", argv[i]); 735 printf("\n"); 736 737 init_param2(physmem); 738 mips_cpu_init(); 739 pmap_bootstrap(); 740 mips_proc0_init(); 741 mutex_init(); 742#ifdef DDB 743 kdb_init(); 744#endif 745} 746 747/* 748 **************************************************************************************** 749 * 750 * APP/BOOT DESCRIPTOR STUFF 751 * 752 **************************************************************************************** 753 */ 754 755/* Define the struct that is initialized by the bootloader used by the 756 * startup code. 757 * 758 * Copyright (c) 2004, 2005, 2006 Cavium Networks. 759 * 760 * The authors hereby grant permission to use, copy, modify, distribute, 761 * and license this software and its documentation for any purpose, provided 762 * that existing copyright notices are retained in all copies and that this 763 * notice is included verbatim in any distributions. No written agreement, 764 * license, or royalty fee is required for any of the authorized uses. 765 * Modifications to this software may be copyrighted by their authors 766 * and need not follow the licensing terms described here, provided that 767 * the new terms are clearly indicated on the first page of each file where 768 * they apply. 769 */ 770 771#define OCTEON_CURRENT_DESC_VERSION 6 772#define OCTEON_ARGV_MAX_ARGS (64) 773#define OCTOEN_SERIAL_LEN 20 774 775 776typedef struct { 777 /* Start of block referenced by assembly code - do not change! */ 778 uint32_t desc_version; 779 uint32_t desc_size; 780 781 uint64_t stack_top; 782 uint64_t heap_base; 783 uint64_t heap_end; 784 uint64_t entry_point; /* Only used by bootloader */ 785 uint64_t desc_vaddr; 786 /* End of This block referenced by assembly code - do not change! */ 787 788 uint32_t exception_base_addr; 789 uint32_t stack_size; 790 uint32_t heap_size; 791 uint32_t argc; /* Argc count for application */ 792 uint32_t argv[OCTEON_ARGV_MAX_ARGS]; 793 uint32_t flags; 794 uint32_t core_mask; 795 uint32_t dram_size; /**< DRAM size in megabyes */ 796 uint32_t phy_mem_desc_addr; /**< physical address of free memory descriptor block*/ 797 uint32_t debugger_flags_base_addr; /**< used to pass flags from app to debugger */ 798 uint32_t eclock_hz; /**< CPU clock speed, in hz */ 799 uint32_t dclock_hz; /**< DRAM clock speed, in hz */ 800 uint32_t spi_clock_hz; /**< SPI4 clock in hz */ 801 uint16_t board_type; 802 uint8_t board_rev_major; 803 uint8_t board_rev_minor; 804 uint16_t chip_type; 805 uint8_t chip_rev_major; 806 uint8_t chip_rev_minor; 807 char board_serial_number[OCTOEN_SERIAL_LEN]; 808 uint8_t mac_addr_base[6]; 809 uint8_t mac_addr_count; 810 uint64_t cvmx_desc_vaddr; 811 812} octeon_boot_descriptor_t; 813 814 815typedef struct { 816 uint32_t major_version; 817 uint32_t minor_version; 818 819 uint64_t stack_top; 820 uint64_t heap_base; 821 uint64_t heap_end; 822 uint64_t desc_vaddr; 823 824 uint32_t exception_base_addr; 825 uint32_t stack_size; 826 uint32_t flags; 827 uint32_t core_mask; 828 uint32_t dram_size; /**< DRAM size in megabyes */ 829 uint32_t phy_mem_desc_addr; /**< physical address of free memory descriptor block*/ 830 uint32_t debugger_flags_base_addr; /**< used to pass flags from app to debugger */ 831 uint32_t eclock_hz; /**< CPU clock speed, in hz */ 832 uint32_t dclock_hz; /**< DRAM clock speed, in hz */ 833 uint32_t spi_clock_hz; /**< SPI4 clock in hz */ 834 uint16_t board_type; 835 uint8_t board_rev_major; 836 uint8_t board_rev_minor; 837 uint16_t chip_type; 838 uint8_t chip_rev_major; 839 uint8_t chip_rev_minor; 840 char board_serial_number[OCTOEN_SERIAL_LEN]; 841 uint8_t mac_addr_base[6]; 842 uint8_t mac_addr_count; 843 844} cvmx_bootinfo_t; 845 846uint32_t octeon_cpu_clock; 847uint64_t octeon_dram; 848uint32_t octeon_bd_ver = 0, octeon_cvmx_bd_ver = 0, octeon_board_rev_major, octeon_board_rev_minor, octeon_board_type; 849uint8_t octeon_mac_addr[6] = { 0 }; 850int octeon_core_mask, octeon_mac_addr_count; 851int octeon_chip_rev_major = 0, octeon_chip_rev_minor = 0, octeon_chip_type = 0; 852 853#if defined(__mips_n64) 854extern uint64_t app_descriptor_addr; 855#else 856extern uint32_t app_descriptor_addr; 857#endif 858static octeon_boot_descriptor_t *app_desc_ptr; 859static cvmx_bootinfo_t *cvmx_desc_ptr; 860 861#define OCTEON_BOARD_TYPE_NONE 0 862#define OCTEON_BOARD_TYPE_SIM 1 863 864#define OCTEON_CLOCK_MIN (100 * 1000 * 1000) 865#define OCTEON_CLOCK_MAX (800 * 1000 * 1000) 866#define OCTEON_DRAM_DEFAULT (256 * 1024 * 1024) 867#define OCTEON_DRAM_MIN 30 868#define OCTEON_DRAM_MAX 3000 869 870 871int octeon_board_real (void) 872{ 873 if ((octeon_board_type == OCTEON_BOARD_TYPE_NONE) || 874 (octeon_board_type == OCTEON_BOARD_TYPE_SIM) || 875 !octeon_board_rev_major) { 876 return 0; 877 } 878 return 1; 879} 880 881static void octeon_process_app_desc_ver_unknown (void) 882{ 883 printf(" Unknown Boot-Descriptor: Using Defaults\n"); 884 885 octeon_cpu_clock = OCTEON_CLOCK_DEFAULT; 886 octeon_dram = OCTEON_DRAM_DEFAULT; 887 octeon_board_rev_major = octeon_board_rev_minor = octeon_board_type = 0; 888 889 octeon_core_mask = 1; 890 octeon_cpu_clock = OCTEON_CLOCK_DEFAULT; 891 octeon_chip_type = octeon_chip_rev_major = octeon_chip_rev_minor = 0; 892 893 octeon_mac_addr[0] = 0x00; octeon_mac_addr[1] = 0x0f; 894 octeon_mac_addr[2] = 0xb7; octeon_mac_addr[3] = 0x10; 895 octeon_mac_addr[4] = 0x09; octeon_mac_addr[5] = 0x06; 896 octeon_mac_addr_count = 1; 897} 898 899static int octeon_process_app_desc_ver_6 (void) 900{ 901 cvmx_desc_ptr = (cvmx_bootinfo_t *) ((long) app_desc_ptr->cvmx_desc_vaddr); 902 903 if ((cvmx_desc_ptr == NULL) || (cvmx_desc_ptr == (cvmx_bootinfo_t *)0xffffffff)) { 904 printf ("Bad cvmx_desc_ptr %p\n", cvmx_desc_ptr); 905 return 1; 906 } 907 908 cvmx_desc_ptr = (cvmx_bootinfo_t *) (((long) cvmx_desc_ptr) | MIPS_KSEG0_START); 909 octeon_cvmx_bd_ver = (cvmx_desc_ptr->major_version * 100) + 910 cvmx_desc_ptr->minor_version; 911 912 if (cvmx_desc_ptr->major_version != 1) { 913 printf("Incompatible CVMX descriptor from bootloader: %d.%d %p\n", 914 (int) cvmx_desc_ptr->major_version, 915 (int) cvmx_desc_ptr->minor_version, cvmx_desc_ptr); 916 while (1); /* Never return */ 917 return 1; /* Satisfy the compiler */ 918 } 919 920 octeon_core_mask = cvmx_desc_ptr->core_mask; 921 octeon_cpu_clock = cvmx_desc_ptr->eclock_hz; 922 octeon_board_type = cvmx_desc_ptr->board_type; 923 octeon_board_rev_major = cvmx_desc_ptr->board_rev_major; 924 octeon_board_rev_minor = cvmx_desc_ptr->board_rev_minor; 925 octeon_chip_type = cvmx_desc_ptr->chip_type; 926 octeon_chip_rev_major = cvmx_desc_ptr->chip_rev_major; 927 octeon_chip_rev_minor = cvmx_desc_ptr->chip_rev_minor; 928 octeon_mac_addr[0] = cvmx_desc_ptr->mac_addr_base[0]; 929 octeon_mac_addr[1] = cvmx_desc_ptr->mac_addr_base[1]; 930 octeon_mac_addr[2] = cvmx_desc_ptr->mac_addr_base[2]; 931 octeon_mac_addr[3] = cvmx_desc_ptr->mac_addr_base[3]; 932 octeon_mac_addr[4] = cvmx_desc_ptr->mac_addr_base[4]; 933 octeon_mac_addr[5] = cvmx_desc_ptr->mac_addr_base[5]; 934 octeon_mac_addr_count = cvmx_desc_ptr->mac_addr_count; 935 936 if (app_desc_ptr->dram_size > 16*1024*1024) { 937 octeon_dram = (uint64_t)app_desc_ptr->dram_size; 938 } else { 939 octeon_dram = (uint64_t)app_desc_ptr->dram_size * 1024 * 1024; 940 } 941 return 0; 942} 943 944static int octeon_process_app_desc_ver_3_4_5 (void) 945{ 946 947 octeon_cvmx_bd_ver = octeon_bd_ver; 948 octeon_core_mask = app_desc_ptr->core_mask; 949 950 if (app_desc_ptr->desc_version > 3) { 951 octeon_cpu_clock = app_desc_ptr->eclock_hz; 952 } else { 953 octeon_cpu_clock = OCTEON_CLOCK_DEFAULT; 954 } 955 956 if (app_desc_ptr->dram_size > 16*1024*1024) { 957 octeon_dram = (uint64_t)app_desc_ptr->dram_size; 958 } else { 959 octeon_dram = (uint64_t)app_desc_ptr->dram_size * 1024 * 1024; 960 } 961 962 if (app_desc_ptr->desc_version > 4) { 963 octeon_board_type = app_desc_ptr->board_type; 964 octeon_board_rev_major = app_desc_ptr->board_rev_major; 965 octeon_board_rev_minor = app_desc_ptr->board_rev_minor; 966 octeon_chip_type = app_desc_ptr->chip_type; 967 octeon_chip_rev_major = app_desc_ptr->chip_rev_major; 968 octeon_chip_rev_minor = app_desc_ptr->chip_rev_minor; 969 970 octeon_mac_addr[0] = app_desc_ptr->mac_addr_base[0]; 971 octeon_mac_addr[1] = app_desc_ptr->mac_addr_base[1]; 972 octeon_mac_addr[2] = app_desc_ptr->mac_addr_base[2]; 973 octeon_mac_addr[3] = app_desc_ptr->mac_addr_base[3]; 974 octeon_mac_addr[4] = app_desc_ptr->mac_addr_base[4]; 975 octeon_mac_addr[5] = app_desc_ptr->mac_addr_base[5]; 976 octeon_mac_addr_count = app_desc_ptr->mac_addr_count; 977 } 978 return 0; 979} 980 981 982void mips_boot_params_init(void); 983 984void mips_boot_params_init (void) 985{ 986 int descriptor_not_parsed = 1; 987 988 if ((app_descriptor_addr == 0) || (app_descriptor_addr >= MAX_APP_DESC_ADDR)) { 989 990 } else { 991 992 app_desc_ptr = (octeon_boot_descriptor_t *) app_descriptor_addr; 993 octeon_bd_ver = app_desc_ptr->desc_version; 994 995 if ((octeon_bd_ver >= 3) && (octeon_bd_ver <= 5)) { 996 descriptor_not_parsed = octeon_process_app_desc_ver_3_4_5(); 997 998 } else if (app_desc_ptr->desc_version == 6) { 999 descriptor_not_parsed = octeon_process_app_desc_ver_6(); 1000 } 1001 1002 } 1003 1004 if (descriptor_not_parsed) { 1005 octeon_process_app_desc_ver_unknown(); 1006 } 1007 1008 printf("Boot Descriptor Ver: %u -> %u/%u", 1009 octeon_bd_ver, octeon_cvmx_bd_ver/100, octeon_cvmx_bd_ver%100); 1010 printf(" CPU clock: %uMHz\n", octeon_cpu_clock/1000000); 1011 printf(" Dram: %u MB", (uint32_t)(octeon_dram >> 20)); 1012 printf(" Board Type: %u Revision: %u/%u\n", 1013 octeon_board_type, octeon_board_rev_major, octeon_board_rev_minor); 1014 printf(" Octeon Chip: %u Rev %u/%u", 1015 octeon_chip_type, octeon_chip_rev_major, octeon_chip_rev_minor); 1016 1017 printf(" Mac Address %02X.%02X.%02X.%02X.%02X.%02X\n", 1018 octeon_mac_addr[0], octeon_mac_addr[1], octeon_mac_addr[2], 1019 octeon_mac_addr[3], octeon_mac_addr[4], octeon_mac_addr[5]); 1020} 1021