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