octeon_machdep.c revision 206829
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: head/sys/mips/cavium/octeon_machdep.c 206829 2010-04-19 06:01:58Z jmallett $ 27 */ 28#include <sys/cdefs.h> 29__FBSDID("$FreeBSD: head/sys/mips/cavium/octeon_machdep.c 206829 2010-04-19 06:01:58Z jmallett $"); 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/cavium/octeon_pcmap_regs.h> 64#include <machine/hwfunc.h> 65#include <machine/intr_machdep.h> 66#include <machine/locore.h> 67#include <machine/md_var.h> 68#include <machine/pcpu.h> 69#include <machine/pte.h> 70#include <machine/trap.h> 71#include <machine/vmparam.h> 72 73#if defined(__mips_n64) 74#define MAX_APP_DESC_ADDR 0xffffffffafffffff 75#else 76#define MAX_APP_DESC_ADDR 0xafffffff 77#endif 78 79extern int *edata; 80extern int *end; 81 82uint64_t ciu_get_en_reg_addr_new(int corenum, int intx, int enx, int ciu_ip); 83void ciu_dump_interrutps_enabled(int core_num, int intx, int enx, int ciu_ip); 84 85static void octeon_boot_params_init(register_t ptr); 86static uint64_t ciu_get_intr_sum_reg_addr(int core_num, int intx, int enx); 87static uint64_t ciu_get_intr_en_reg_addr(int core_num, int intx, int enx); 88 89void 90platform_cpu_init() 91{ 92 /* Nothing special yet */ 93} 94 95/* 96 * Perform a board-level soft-reset. 97 */ 98void 99platform_reset(void) 100{ 101 oct_write64(OCTEON_CIU_SOFT_RST, 1); 102} 103 104void 105octeon_led_write_char(int char_position, char val) 106{ 107 uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8); 108 109 if (!octeon_board_real()) 110 return; 111 112 char_position &= 0x7; /* only 8 chars */ 113 ptr += char_position; 114 oct_write8_x8(ptr, val); 115} 116 117void 118octeon_led_write_char0(char val) 119{ 120 uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8); 121 122 if (!octeon_board_real()) 123 return; 124 oct_write8_x8(ptr, val); 125} 126 127void 128octeon_led_write_hexchar(int char_position, char hexval) 129{ 130 uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8); 131 char char1, char2; 132 133 if (!octeon_board_real()) 134 return; 135 136 char1 = (hexval >> 4) & 0x0f; char1 = (char1 < 10)?char1+'0':char1+'7'; 137 char2 = (hexval & 0x0f); char2 = (char2 < 10)?char2+'0':char2+'7'; 138 char_position &= 0x7; /* only 8 chars */ 139 if (char_position > 6) 140 char_position = 6; 141 ptr += char_position; 142 oct_write8_x8(ptr, char1); 143 ptr++; 144 oct_write8_x8(ptr, char2); 145} 146 147void 148octeon_led_write_string(const char *str) 149{ 150 uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8); 151 int i; 152 153 if (!octeon_board_real()) 154 return; 155 156 for (i=0; i<8; i++, ptr++) { 157 if (str && *str) 158 oct_write8_x8(ptr, *str++); 159 else 160 oct_write8_x8(ptr, ' '); 161 oct_read64(OCTEON_MIO_BOOT_BIST_STAT); 162 } 163} 164 165static char progress[8] = { '-', '/', '|', '\\', '-', '/', '|', '\\'}; 166 167void 168octeon_led_run_wheel(int *prog_count, int led_position) 169{ 170 if (!octeon_board_real()) 171 return; 172 octeon_led_write_char(led_position, progress[*prog_count]); 173 *prog_count += 1; 174 *prog_count &= 0x7; 175} 176 177void 178octeon_led_write_hex(uint32_t wl) 179{ 180 char nbuf[80]; 181 182 sprintf(nbuf, "%X", wl); 183 octeon_led_write_string(nbuf); 184} 185 186 187/* 188 * octeon_debug_symbol 189 * 190 * Does nothing. 191 * Used to mark the point for simulator to begin tracing 192 */ 193void 194octeon_debug_symbol(void) 195{ 196} 197 198void 199octeon_ciu_stop_gtimer(int timer) 200{ 201 oct_write64(OCTEON_CIU_GENTIMER_ADDR(timer), 0ll); 202} 203 204void 205octeon_ciu_start_gtimer(int timer, u_int one_shot, uint64_t time_cycles) 206{ 207 octeon_ciu_gentimer gentimer; 208 209 gentimer.word64 = 0; 210 gentimer.bits.one_shot = one_shot; 211 gentimer.bits.len = time_cycles - 1; 212 oct_write64(OCTEON_CIU_GENTIMER_ADDR(timer), gentimer.word64); 213} 214 215/* 216 * octeon_ciu_reset 217 * 218 * Shutdown all CIU to IP2, IP3 mappings 219 */ 220void 221octeon_ciu_reset(void) 222{ 223 224 octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_0); 225 octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_1); 226 octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_2); 227 octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_3); 228 229 ciu_disable_intr(CIU_THIS_CORE, CIU_INT_0, CIU_EN_0); 230 ciu_disable_intr(CIU_THIS_CORE, CIU_INT_0, CIU_EN_1); 231 ciu_disable_intr(CIU_THIS_CORE, CIU_INT_1, CIU_EN_0); 232 ciu_disable_intr(CIU_THIS_CORE, CIU_INT_1, CIU_EN_1); 233 234 ciu_clear_int_summary(CIU_THIS_CORE, CIU_INT_0, CIU_EN_0, 0ll); 235 ciu_clear_int_summary(CIU_THIS_CORE, CIU_INT_1, CIU_EN_0, 0ll); 236 ciu_clear_int_summary(CIU_THIS_CORE, CIU_INT_1, CIU_EN_1, 0ll); 237} 238 239/* 240 * mips_disable_interrupt_controllers 241 * 242 * Disable interrupts in the CPU controller 243 */ 244void 245mips_disable_interrupt_controls(void) 246{ 247 /* 248 * Disable interrupts in CIU. 249 */ 250 octeon_ciu_reset(); 251} 252 253/* 254 * ciu_get_intr_sum_reg_addr 255 */ 256static uint64_t 257ciu_get_intr_sum_reg_addr(int core_num, int intx, int enx) 258{ 259 uint64_t ciu_intr_sum_reg_addr; 260 261 if (enx == CIU_EN_0) 262 ciu_intr_sum_reg_addr = OCTEON_CIU_SUMMARY_BASE_ADDR + 263 (core_num * 0x10) + (intx * 0x8); 264 else 265 ciu_intr_sum_reg_addr = OCTEON_CIU_SUMMARY_INT1_ADDR; 266 267 return (ciu_intr_sum_reg_addr); 268} 269 270 271/* 272 * ciu_get_intr_en_reg_addr 273 */ 274static uint64_t 275ciu_get_intr_en_reg_addr(int core_num, int intx, int enx) 276{ 277 uint64_t ciu_intr_reg_addr; 278 279 ciu_intr_reg_addr = OCTEON_CIU_ENABLE_BASE_ADDR + 280 ((enx == 0) ? 0x0 : 0x8) + (intx * 0x10) + (core_num * 0x20); 281 return (ciu_intr_reg_addr); 282} 283 284 285 286 287/* 288 * ciu_get_intr_reg_addr 289 * 290 * 200 ---int0,en0 ip2 291 * 208 ---int0,en1 ip2 ----> this is wrong... this is watchdog 292 * 293 * 210 ---int0,en0 ip3 -- 294 * 218 ---int0,en1 ip3 ----> same here.. .this is watchdog... right? 295 * 296 * 220 ---int1,en0 ip2 297 * 228 ---int1,en1 ip2 298 * 230 ---int1,en0 ip3 -- 299 * 238 ---int1,en1 ip3 300 * 301 */ 302uint64_t 303ciu_get_en_reg_addr_new(int corenum, int intx, int enx, int ciu_ip) 304{ 305 uint64_t ciu_intr_reg_addr = OCTEON_CIU_ENABLE_BASE_ADDR; 306 307 /* XXX kasserts? */ 308 if (enx < CIU_EN_0 || enx > CIU_EN_1) { 309 printf("%s: invalid enx value %d, should be %d or %d\n", 310 __func__, enx, CIU_EN_0, CIU_EN_1); 311 return 0; 312 } 313 if (intx < CIU_INT_0 || intx > CIU_INT_1) { 314 printf("%s: invalid intx value %d, should be %d or %d\n", 315 __func__, enx, CIU_INT_0, CIU_INT_1); 316 return 0; 317 } 318 if (ciu_ip < CIU_MIPS_IP2 || ciu_ip > CIU_MIPS_IP3) { 319 printf("%s: invalid ciu_ip value %d, should be %d or %d\n", 320 __func__, ciu_ip, CIU_MIPS_IP2, CIU_MIPS_IP3); 321 return 0; 322 } 323 324 ciu_intr_reg_addr += (enx * 0x8); 325 ciu_intr_reg_addr += (ciu_ip * 0x10); 326 ciu_intr_reg_addr += (intx * 0x20); 327 return (ciu_intr_reg_addr); 328} 329 330/* 331 * ciu_get_int_summary 332 */ 333uint64_t 334ciu_get_int_summary(int core_num, int intx, int enx) 335{ 336 uint64_t ciu_intr_sum_reg_addr; 337 338 if (core_num == CIU_THIS_CORE) 339 core_num = octeon_get_core_num(); 340 ciu_intr_sum_reg_addr = ciu_get_intr_sum_reg_addr(core_num, intx, enx); 341 return (oct_read64(ciu_intr_sum_reg_addr)); 342} 343 344//#define DEBUG_CIU 1 345 346#ifdef DEBUG_CIU 347#define DEBUG_CIU_SUM 1 348#define DEBUG_CIU_EN 1 349#endif 350 351 352/* 353 * ciu_clear_int_summary 354 */ 355void 356ciu_clear_int_summary(int core_num, int intx, int enx, uint64_t write_bits) 357{ 358 uint32_t cpu_status_bits; 359 uint64_t ciu_intr_sum_reg_addr; 360 361//#define DEBUG_CIU_SUM 1 362 363#ifdef DEBUG_CIU_SUM 364 uint64_t ciu_intr_sum_bits; 365#endif 366 367 368 if (core_num == CIU_THIS_CORE) { 369 core_num = octeon_get_core_num(); 370 } 371 372#ifdef DEBUG_CIU_SUM 373 printf(" CIU: core %u clear sum IntX %u Enx %u Bits: 0x%llX\n", 374 core_num, intx, enx, write_bits); 375#endif 376 377 cpu_status_bits = intr_disable(); 378 379 ciu_intr_sum_reg_addr = ciu_get_intr_sum_reg_addr(core_num, intx, enx); 380 381#ifdef DEBUG_CIU_SUM 382 ciu_intr_sum_bits = oct_read64(ciu_intr_sum_reg_addr); /* unneeded dummy read */ 383 printf(" CIU: status: 0x%X reg_addr: 0x%llX Val: 0x%llX -> 0x%llX", 384 cpu_status_bits, ciu_intr_sum_reg_addr, ciu_intr_sum_bits, 385 ciu_intr_sum_bits | write_bits); 386#endif 387 388 oct_write64(ciu_intr_sum_reg_addr, write_bits); 389 oct_read64(OCTEON_MIO_BOOT_BIST_STAT); /* Bus Barrier */ 390 391#ifdef DEBUG_CIU_SUM 392 printf(" Readback: 0x%llX\n\n ", (uint64_t) oct_read64(ciu_intr_sum_reg_addr)); 393#endif 394 395 intr_restore(cpu_status_bits); 396} 397 398/* 399 * ciu_disable_intr 400 */ 401void 402ciu_disable_intr(int core_num, int intx, int enx) 403{ 404 uint32_t cpu_status_bits; 405 uint64_t ciu_intr_reg_addr; 406 407 if (core_num == CIU_THIS_CORE) 408 core_num = octeon_get_core_num(); 409 410 cpu_status_bits = intr_disable(); 411 412 ciu_intr_reg_addr = ciu_get_intr_en_reg_addr(core_num, intx, enx); 413 414 oct_read64(ciu_intr_reg_addr); /* Dummy read */ 415 416 oct_write64(ciu_intr_reg_addr, 0LL); 417 oct_read64(OCTEON_MIO_BOOT_BIST_STAT); /* Bus Barrier */ 418 419 intr_restore(cpu_status_bits); 420} 421 422void 423ciu_dump_interrutps_enabled(int core_num, int intx, int enx, int ciu_ip) 424{ 425 426 uint64_t ciu_intr_reg_addr; 427 uint64_t ciu_intr_bits; 428 429 if (core_num == CIU_THIS_CORE) { 430 core_num = octeon_get_core_num(); 431 } 432 433#ifndef OCTEON_SMP_1 434 ciu_intr_reg_addr = ciu_get_intr_en_reg_addr(core_num, intx, enx); 435#else 436 ciu_intr_reg_addr = ciu_get_en_reg_addr_new(core_num, intx, enx, ciu_ip); 437#endif 438 439 if (!ciu_intr_reg_addr) { 440 printf("Bad call to %s\n", __func__); 441 while(1); 442 return; 443 } 444 445 ciu_intr_bits = oct_read64(ciu_intr_reg_addr); 446 printf(" CIU core %d int: %d en: %d ip: %d Add: %#llx enabled: %#llx SR: %x\n", 447 core_num, intx, enx, ciu_ip, (unsigned long long)ciu_intr_reg_addr, 448 (unsigned long long)ciu_intr_bits, mips_rd_status()); 449} 450 451 452/* 453 * ciu_enable_interrupts 454 */ 455void ciu_enable_interrupts(int core_num, int intx, int enx, 456 uint64_t set_these_interrupt_bits, int ciu_ip) 457{ 458 uint32_t cpu_status_bits; 459 uint64_t ciu_intr_reg_addr; 460 uint64_t ciu_intr_bits; 461 462 if (core_num == CIU_THIS_CORE) 463 core_num = octeon_get_core_num(); 464 465//#define DEBUG_CIU_EN 1 466 467#ifdef DEBUG_CIU_EN 468 printf(" CIU: core %u enabling Intx %u Enx %u IP %d Bits: 0x%llX\n", 469 core_num, intx, enx, ciu_ip, set_these_interrupt_bits); 470#endif 471 472 cpu_status_bits = intr_disable(); 473 474#ifndef OCTEON_SMP_1 475 ciu_intr_reg_addr = ciu_get_intr_en_reg_addr(core_num, intx, enx); 476#else 477 ciu_intr_reg_addr = ciu_get_en_reg_addr_new(core_num, intx, enx, ciu_ip); 478#endif 479 480 if (!ciu_intr_reg_addr) { 481 printf("Bad call to %s\n", __func__); 482 while(1); 483 return; /* XXX */ 484 } 485 486 ciu_intr_bits = oct_read64(ciu_intr_reg_addr); 487 488#ifdef DEBUG_CIU_EN 489 printf(" CIU: status: 0x%X reg_addr: 0x%llX Val: 0x%llX -> 0x%llX", 490 cpu_status_bits, ciu_intr_reg_addr, ciu_intr_bits, ciu_intr_bits | set_these_interrupt_bits); 491#endif 492 ciu_intr_bits |= set_these_interrupt_bits; 493 oct_write64(ciu_intr_reg_addr, ciu_intr_bits); 494#ifdef SMP 495 mips_wbflush(); 496#endif 497 oct_read64(OCTEON_MIO_BOOT_BIST_STAT); /* Bus Barrier */ 498 499#ifdef DEBUG_CIU_EN 500 printf(" Readback: 0x%llX\n\n ", 501 (uint64_t)oct_read64(ciu_intr_reg_addr)); 502#endif 503 504 intr_restore(cpu_status_bits); 505} 506 507unsigned long 508octeon_get_clock_rate(void) 509{ 510 return octeon_cpu_clock; 511} 512 513static void 514octeon_memory_init(void) 515{ 516 uint32_t realmem_bytes; 517 518 if (octeon_board_real()) { 519 realmem_bytes = (octeon_dram - PAGE_SIZE); 520 realmem_bytes &= ~(PAGE_SIZE - 1); 521 } else { 522 /* Simulator we limit to 96 meg */ 523 realmem_bytes = (96 << 20); 524 } 525 /* phys_avail regions are in bytes */ 526 phys_avail[0] = (MIPS_KSEG0_TO_PHYS((vm_offset_t)&end) + PAGE_SIZE) & ~(PAGE_SIZE - 1); 527 if (octeon_board_real()) { 528 if (realmem_bytes > OCTEON_DRAM_FIRST_256_END) 529 phys_avail[1] = OCTEON_DRAM_FIRST_256_END; 530 else 531 phys_avail[1] = realmem_bytes; 532 realmem_bytes -= OCTEON_DRAM_FIRST_256_END; 533 realmem_bytes &= ~(PAGE_SIZE - 1); 534 } else { 535 /* Simulator gets 96Meg period. */ 536 phys_avail[1] = (96 << 20); 537 } 538 /*- 539 * Octeon Memory looks as follows: 540 * PA 541 * 0000 0000 to 0x0 0000 0000 0000 542 * 0FFF FFFF First 256 MB memory Maps to 0x0 0000 0FFF FFFF 543 * 544 * 1000 0000 to 0x1 0000 1000 0000 545 * 1FFF FFFF Uncached Bu I/O space.converted to 0x1 0000 1FFF FFFF 546 * 547 * 2FFF FFFF to Cached 0x0 0000 2000 0000 548 * FFFF FFFF all dram mem above the first 512M 0x3 FFFF FFFF FFFF 549 * 550 */ 551 physmem = btoc(phys_avail[1] - phys_avail[0]); 552 if ((octeon_board_real()) && 553 (realmem_bytes > OCTEON_DRAM_FIRST_256_END)) { 554 /* take out the upper non-cached 1/2 */ 555 realmem_bytes -= OCTEON_DRAM_FIRST_256_END; 556 realmem_bytes &= ~(PAGE_SIZE - 1); 557 /* Now map the rest of the memory */ 558 phys_avail[2] = 0x20000000; 559 phys_avail[3] = ((uint32_t) 0x20000000 + realmem_bytes); 560 physmem += btoc(phys_avail[3] - phys_avail[2]); 561 } 562 realmem = physmem; 563 564 printf("Total DRAM Size %#X\n", (uint32_t) octeon_dram); 565 printf("Bank 0 = %#08lX -> %#08lX\n", (long)phys_avail[0], (long)phys_avail[1]); 566 printf("Bank 1 = %#08lX -> %#08lX\n", (long)phys_avail[2], (long)phys_avail[3]); 567} 568 569void 570platform_start(__register_t a0, __register_t a1, __register_t a2 __unused, 571 __register_t a3) 572{ 573 uint64_t platform_counter_freq; 574 575 /* Initialize pcpu stuff */ 576 mips_pcpu0_init(); 577 mips_timer_early_init(OCTEON_CLOCK_DEFAULT); 578 cninit(); 579 580 octeon_ciu_reset(); 581 octeon_boot_params_init(a3); 582 bootverbose = 1; 583 584 /* 585 * For some reason on the cn38xx simulator ebase register is set to 586 * 0x80001000 at bootup time. Move it back to the default, but 587 * when we move to having support for multiple executives, we need 588 * to rethink this. 589 */ 590 mips_wr_ebase(0x80000000); 591 592 octeon_memory_init(); 593 init_param1(); 594 init_param2(physmem); 595 mips_cpu_init(); 596 pmap_bootstrap(); 597 mips_proc0_init(); 598 mutex_init(); 599 kdb_init(); 600#ifdef KDB 601 if (boothowto & RB_KDB) 602 kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); 603#endif 604 platform_counter_freq = octeon_get_clock_rate(); 605 mips_timer_init_params(platform_counter_freq, 0); 606 607#ifdef SMP 608 /* 609 * Clear any pending IPIs and enable the IPI interrupt. 610 */ 611 oct_write64(OCTEON_CIU_MBOX_CLRX(0), 0xffffffff); 612 ciu_enable_interrupts(0, CIU_INT_1, CIU_EN_0, OCTEON_CIU_ENABLE_MBOX_INTR, CIU_MIPS_IP3); 613#endif 614} 615 616/* impSTART: This stuff should move back into the Cavium SDK */ 617/* 618 **************************************************************************************** 619 * 620 * APP/BOOT DESCRIPTOR STUFF 621 * 622 **************************************************************************************** 623 */ 624 625/* Define the struct that is initialized by the bootloader used by the 626 * startup code. 627 * 628 * Copyright (c) 2004, 2005, 2006 Cavium Networks. 629 * 630 * The authors hereby grant permission to use, copy, modify, distribute, 631 * and license this software and its documentation for any purpose, provided 632 * that existing copyright notices are retained in all copies and that this 633 * notice is included verbatim in any distributions. No written agreement, 634 * license, or royalty fee is required for any of the authorized uses. 635 * Modifications to this software may be copyrighted by their authors 636 * and need not follow the licensing terms described here, provided that 637 * the new terms are clearly indicated on the first page of each file where 638 * they apply. 639 */ 640 641#define OCTEON_CURRENT_DESC_VERSION 6 642#define OCTEON_ARGV_MAX_ARGS (64) 643#define OCTOEN_SERIAL_LEN 20 644 645 646typedef struct { 647 /* Start of block referenced by assembly code - do not change! */ 648 uint32_t desc_version; 649 uint32_t desc_size; 650 651 uint64_t stack_top; 652 uint64_t heap_base; 653 uint64_t heap_end; 654 uint64_t entry_point; /* Only used by bootloader */ 655 uint64_t desc_vaddr; 656 /* End of This block referenced by assembly code - do not change! */ 657 658 uint32_t exception_base_addr; 659 uint32_t stack_size; 660 uint32_t heap_size; 661 uint32_t argc; /* Argc count for application */ 662 uint32_t argv[OCTEON_ARGV_MAX_ARGS]; 663 uint32_t flags; 664 uint32_t core_mask; 665 uint32_t dram_size; /**< DRAM size in megabyes */ 666 uint32_t phy_mem_desc_addr; /**< physical address of free memory descriptor block*/ 667 uint32_t debugger_flags_base_addr; /**< used to pass flags from app to debugger */ 668 uint32_t eclock_hz; /**< CPU clock speed, in hz */ 669 uint32_t dclock_hz; /**< DRAM clock speed, in hz */ 670 uint32_t spi_clock_hz; /**< SPI4 clock in hz */ 671 uint16_t board_type; 672 uint8_t board_rev_major; 673 uint8_t board_rev_minor; 674 uint16_t chip_type; 675 uint8_t chip_rev_major; 676 uint8_t chip_rev_minor; 677 char board_serial_number[OCTOEN_SERIAL_LEN]; 678 uint8_t mac_addr_base[6]; 679 uint8_t mac_addr_count; 680 uint64_t cvmx_desc_vaddr; 681} octeon_boot_descriptor_t; 682 683 684typedef struct { 685 uint32_t major_version; 686 uint32_t minor_version; 687 688 uint64_t stack_top; 689 uint64_t heap_base; 690 uint64_t heap_end; 691 uint64_t desc_vaddr; 692 693 uint32_t exception_base_addr; 694 uint32_t stack_size; 695 uint32_t flags; 696 uint32_t core_mask; 697 uint32_t dram_size; /**< DRAM size in megabyes */ 698 uint32_t phy_mem_desc_addr; /**< physical address of free memory descriptor block*/ 699 uint32_t debugger_flags_base_addr; /**< used to pass flags from app to debugger */ 700 uint32_t eclock_hz; /**< CPU clock speed, in hz */ 701 uint32_t dclock_hz; /**< DRAM clock speed, in hz */ 702 uint32_t spi_clock_hz; /**< SPI4 clock in hz */ 703 uint16_t board_type; 704 uint8_t board_rev_major; 705 uint8_t board_rev_minor; 706 uint16_t chip_type; 707 uint8_t chip_rev_major; 708 uint8_t chip_rev_minor; 709 char board_serial_number[OCTOEN_SERIAL_LEN]; 710 uint8_t mac_addr_base[6]; 711 uint8_t mac_addr_count; 712} cvmx_bootinfo_t; 713 714uint32_t octeon_cpu_clock; 715uint64_t octeon_dram; 716uint32_t octeon_bd_ver = 0, octeon_cvmx_bd_ver = 0, octeon_board_rev_major, octeon_board_rev_minor, octeon_board_type; 717uint8_t octeon_mac_addr[6] = { 0 }; 718int octeon_core_mask, octeon_mac_addr_count; 719int octeon_chip_rev_major = 0, octeon_chip_rev_minor = 0, octeon_chip_type = 0; 720 721static octeon_boot_descriptor_t *app_desc_ptr; 722static cvmx_bootinfo_t *cvmx_desc_ptr; 723 724#define OCTEON_BOARD_TYPE_NONE 0 725#define OCTEON_BOARD_TYPE_SIM 1 726#define OCTEON_BOARD_TYPE_CN3010_EVB_HS5 11 727 728#define OCTEON_CLOCK_MIN (100 * 1000 * 1000) 729#define OCTEON_CLOCK_MAX (800 * 1000 * 1000) 730#define OCTEON_DRAM_DEFAULT (256 * 1024 * 1024) 731#define OCTEON_DRAM_MIN 30 732#define OCTEON_DRAM_MAX 3000 733 734 735int 736octeon_board_real(void) 737{ 738 switch (octeon_board_type) { 739 case OCTEON_BOARD_TYPE_NONE: 740 case OCTEON_BOARD_TYPE_SIM: 741 return 0; 742 case OCTEON_BOARD_TYPE_CN3010_EVB_HS5: 743 /* 744 * XXX 745 * The CAM-0100 identifies itself as type 11, revision 0.0, 746 * despite its being rather real. Disable the revision check 747 * for type 11. 748 */ 749 return 1; 750 default: 751 if (octeon_board_rev_major == 0) 752 return 0; 753 return 1; 754 } 755} 756 757static void 758octeon_process_app_desc_ver_unknown(void) 759{ 760 printf(" Unknown Boot-Descriptor: Using Defaults\n"); 761 762 octeon_cpu_clock = OCTEON_CLOCK_DEFAULT; 763 octeon_dram = OCTEON_DRAM_DEFAULT; 764 octeon_board_rev_major = octeon_board_rev_minor = octeon_board_type = 0; 765 octeon_core_mask = 1; 766 octeon_chip_type = octeon_chip_rev_major = octeon_chip_rev_minor = 0; 767 octeon_mac_addr[0] = 0x00; octeon_mac_addr[1] = 0x0f; 768 octeon_mac_addr[2] = 0xb7; octeon_mac_addr[3] = 0x10; 769 octeon_mac_addr[4] = 0x09; octeon_mac_addr[5] = 0x06; 770 octeon_mac_addr_count = 1; 771} 772 773static int 774octeon_process_app_desc_ver_6(void) 775{ 776 /* XXX Why is 0x00000000ffffffffULL a bad value? */ 777 if (app_desc_ptr->cvmx_desc_vaddr == 0 || 778 app_desc_ptr->cvmx_desc_vaddr == 0xfffffffful) { 779 printf ("Bad cvmx_desc_ptr %p\n", cvmx_desc_ptr); 780 return 1; 781 } 782 cvmx_desc_ptr = 783 (cvmx_bootinfo_t *)(intptr_t)app_desc_ptr->cvmx_desc_vaddr; 784 cvmx_desc_ptr = 785 (cvmx_bootinfo_t *) ((intptr_t)cvmx_desc_ptr | MIPS_KSEG0_START); 786 octeon_cvmx_bd_ver = (cvmx_desc_ptr->major_version * 100) + 787 cvmx_desc_ptr->minor_version; 788 if (cvmx_desc_ptr->major_version != 1) { 789 panic("Incompatible CVMX descriptor from bootloader: %d.%d %p\n", 790 (int) cvmx_desc_ptr->major_version, 791 (int) cvmx_desc_ptr->minor_version, cvmx_desc_ptr); 792 } 793 794 octeon_core_mask = cvmx_desc_ptr->core_mask; 795 octeon_cpu_clock = cvmx_desc_ptr->eclock_hz; 796 octeon_board_type = cvmx_desc_ptr->board_type; 797 octeon_board_rev_major = cvmx_desc_ptr->board_rev_major; 798 octeon_board_rev_minor = cvmx_desc_ptr->board_rev_minor; 799 octeon_chip_type = cvmx_desc_ptr->chip_type; 800 octeon_chip_rev_major = cvmx_desc_ptr->chip_rev_major; 801 octeon_chip_rev_minor = cvmx_desc_ptr->chip_rev_minor; 802 octeon_mac_addr[0] = cvmx_desc_ptr->mac_addr_base[0]; 803 octeon_mac_addr[1] = cvmx_desc_ptr->mac_addr_base[1]; 804 octeon_mac_addr[2] = cvmx_desc_ptr->mac_addr_base[2]; 805 octeon_mac_addr[3] = cvmx_desc_ptr->mac_addr_base[3]; 806 octeon_mac_addr[4] = cvmx_desc_ptr->mac_addr_base[4]; 807 octeon_mac_addr[5] = cvmx_desc_ptr->mac_addr_base[5]; 808 octeon_mac_addr_count = cvmx_desc_ptr->mac_addr_count; 809 810 if (app_desc_ptr->dram_size > 16*1024*1024) 811 octeon_dram = (uint64_t)app_desc_ptr->dram_size; 812 else 813 octeon_dram = (uint64_t)app_desc_ptr->dram_size << 20; 814 return 0; 815} 816 817static void 818octeon_boot_params_init(register_t ptr) 819{ 820 int bad_desc = 1; 821 822 if (ptr != 0 && ptr < MAX_APP_DESC_ADDR) { 823 app_desc_ptr = (octeon_boot_descriptor_t *)(intptr_t)ptr; 824 octeon_bd_ver = app_desc_ptr->desc_version; 825 if (app_desc_ptr->desc_version < 6) 826 panic("Your boot code is too old to be supported.\n"); 827 if (app_desc_ptr->desc_version >= 6) 828 bad_desc = octeon_process_app_desc_ver_6(); 829 } 830 if (bad_desc) 831 octeon_process_app_desc_ver_unknown(); 832 833 printf("Boot Descriptor Ver: %u -> %u/%u", 834 octeon_bd_ver, octeon_cvmx_bd_ver/100, octeon_cvmx_bd_ver%100); 835 printf(" CPU clock: %uMHz Core Mask: %#x\n", octeon_cpu_clock/1000000, octeon_core_mask); 836 printf(" Dram: %u MB", (uint32_t)(octeon_dram >> 20)); 837 printf(" Board Type: %u Revision: %u/%u\n", 838 octeon_board_type, octeon_board_rev_major, octeon_board_rev_minor); 839 printf(" Octeon Chip: %u Rev %u/%u", 840 octeon_chip_type, octeon_chip_rev_major, octeon_chip_rev_minor); 841 842 printf(" Mac Address %02X.%02X.%02X.%02X.%02X.%02X (%d)\n", 843 octeon_mac_addr[0], octeon_mac_addr[1], octeon_mac_addr[2], 844 octeon_mac_addr[3], octeon_mac_addr[4], octeon_mac_addr[5], 845 octeon_mac_addr_count); 846} 847/* impEND: This stuff should move back into the Cavium SDK */ 848