octeon_machdep.c revision 206721
11573Srgrimes/*- 2128004Stjr * Copyright (c) 2006 Wojciech A. Koszek <wkoszek@FreeBSD.org> 31573Srgrimes * All rights reserved. 41573Srgrimes * 51573Srgrimes * Redistribution and use in source and binary forms, with or without 61573Srgrimes * modification, are permitted provided that the following conditions 71573Srgrimes * are met: 81573Srgrimes * 1. Redistributions of source code must retain the above copyright 9227753Stheraven * notice, this list of conditions and the following disclaimer. 10227753Stheraven * 2. Redistributions in binary form must reproduce the above copyright 11227753Stheraven * notice, this list of conditions and the following disclaimer in the 12227753Stheraven * documentation and/or other materials provided with the distribution. 13227753Stheraven * 141573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 151573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 161573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 171573Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 181573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 191573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 201573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 211573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 221573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 231573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 241573Srgrimes * SUCH DAMAGE. 251573Srgrimes * 261573Srgrimes * $FreeBSD: head/sys/mips/cavium/octeon_machdep.c 206721 2010-04-17 03:08:13Z jmallett $ 271573Srgrimes */ 281573Srgrimes#include <sys/cdefs.h> 291573Srgrimes__FBSDID("$FreeBSD: head/sys/mips/cavium/octeon_machdep.c 206721 2010-04-17 03:08:13Z jmallett $"); 301573Srgrimes 311573Srgrimes#include <sys/param.h> 321573Srgrimes#include <sys/conf.h> 331573Srgrimes#include <sys/kernel.h> 341573Srgrimes#include <sys/systm.h> 351573Srgrimes#include <sys/imgact.h> 361573Srgrimes#include <sys/bio.h> 371573Srgrimes#include <sys/buf.h> 381573Srgrimes#include <sys/bus.h> 391573Srgrimes#include <sys/cpu.h> 401573Srgrimes#include <sys/cons.h> 411573Srgrimes#include <sys/exec.h> 4292986Sobrien#include <sys/ucontext.h> 4392986Sobrien#include <sys/proc.h> 441573Srgrimes#include <sys/kdb.h> 45121845Stjr#include <sys/ptrace.h> 46105233Stjr#include <sys/reboot.h> 47121845Stjr#include <sys/signalvar.h> 481573Srgrimes#include <sys/sysent.h> 491573Srgrimes#include <sys/sysproto.h> 501573Srgrimes#include <sys/user.h> 51129179Stjr 52121845Stjr#include <vm/vm.h> 53129153Stjr#include <vm/vm_object.h> 541573Srgrimes#include <vm/vm_page.h> 55142654Sphantom#include <vm/vm_pager.h> 56142654Sphantom 57142654Sphantom#include <machine/atomic.h> 58142654Sphantom#include <machine/cache.h> 59142654Sphantom#include <machine/clock.h> 60142654Sphantom#include <machine/cpu.h> 61142654Sphantom#include <machine/cpuregs.h> 62142654Sphantom#include <machine/cpufunc.h> 63142654Sphantom#include <mips/cavium/octeon_pcmap_regs.h> 64142654Sphantom#include <machine/hwfunc.h> 65121845Stjr#include <machine/intr_machdep.h> 66172619Sache#include <machine/locore.h> 67172619Sache#include <machine/md_var.h> 68172619Sache#include <machine/pcpu.h> 69172619Sache#include <machine/pte.h> 70172619Sache#include <machine/trap.h> 711573Srgrimes#include <machine/vmparam.h> 72227753Stheraven 731573Srgrimes#if defined(__mips_n64) 74121845Stjr#define MAX_APP_DESC_ADDR 0xffffffffafffffff 75227753Stheraven#else 76227753Stheraven#define MAX_APP_DESC_ADDR 0xafffffff 77227753Stheraven#endif 78227753Stheraven 79227753Stheravenextern int *edata; 80227753Stheravenextern int *end; 81227753Stheraven 82227753Stheravenuint64_t ciu_get_en_reg_addr_new(int corenum, int intx, int enx, int ciu_ip); 831573Srgrimesvoid ciu_dump_interrutps_enabled(int core_num, int intx, int enx, int ciu_ip); 841573Srgrimes 851573Srgrimesstatic void octeon_boot_params_init(register_t ptr); 86142654Sphantomstatic uint64_t ciu_get_intr_sum_reg_addr(int core_num, int intx, int enx); 87128004Stjrstatic uint64_t ciu_get_intr_en_reg_addr(int core_num, int intx, int enx); 88128004Stjr 89128004Stjrstatic __inline void 90128004Stjrmips_wr_ebase(u_int32_t a0) 91128004Stjr{ 92128004Stjr __asm __volatile("mtc0 %[a0], $15, 1 ;" 93128004Stjr : 94128004Stjr : [a0] "r"(a0)); 95128004Stjr 96128004Stjr mips_barrier(); 97142654Sphantom} 98121845Stjr 99121845Stjrvoid 1001573Srgrimesplatform_cpu_init() 101121845Stjr{ 102121845Stjr /* Nothing special yet */ 103121845Stjr} 104121845Stjr 105121845Stjr/* 106121845Stjr * Perform a board-level soft-reset. 107121845Stjr */ 108121845Stjrvoid 109121845Stjrplatform_reset(void) 110121845Stjr{ 1111573Srgrimes oct_write64(OCTEON_CIU_SOFT_RST, 1); 1121573Srgrimes} 113142654Sphantom 114121845Stjrvoid 115121845Stjrocteon_led_write_char(int char_position, char val) 1161573Srgrimes{ 117121845Stjr uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8); 118121845Stjr 119121845Stjr if (!octeon_board_real()) 120121845Stjr return; 121121845Stjr 122121845Stjr char_position &= 0x7; /* only 8 chars */ 123121845Stjr ptr += char_position; 124121845Stjr oct_write8_x8(ptr, val); 125121845Stjr} 126121845Stjr 1271573Srgrimesvoid 128129179Stjrocteon_led_write_char0(char val) 129142654Sphantom{ 130132497Stjr uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8); 131132497Stjr 132129179Stjr if (!octeon_board_real()) 133129179Stjr return; 134129179Stjr oct_write8_x8(ptr, val); 135129179Stjr} 136132497Stjr 137132497Stjrvoid 138132497Stjrocteon_led_write_hexchar(int char_position, char hexval) 139132497Stjr{ 140129179Stjr uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8); 141129179Stjr char char1, char2; 142129179Stjr 143132497Stjr if (!octeon_board_real()) 144129179Stjr return; 145129179Stjr 146129179Stjr char1 = (hexval >> 4) & 0x0f; char1 = (char1 < 10)?char1+'0':char1+'7'; 147129179Stjr char2 = (hexval & 0x0f); char2 = (char2 < 10)?char2+'0':char2+'7'; 148129179Stjr char_position &= 0x7; /* only 8 chars */ 149129179Stjr if (char_position > 6) 150129179Stjr char_position = 6; 151129179Stjr ptr += char_position; 152129179Stjr oct_write8_x8(ptr, char1); 153129179Stjr ptr++; 154142654Sphantom oct_write8_x8(ptr, char2); 155132497Stjr} 156132497Stjr 157129179Stjrvoid 158129179Stjrocteon_led_write_string(const char *str) 159129179Stjr{ 160129179Stjr uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8); 161129707Stjr int i; 162132497Stjr 163129707Stjr if (!octeon_board_real()) 164129707Stjr return; 165129707Stjr 166129707Stjr for (i=0; i<8; i++, ptr++) { 167129707Stjr if (str && *str) 168129707Stjr oct_write8_x8(ptr, *str++); 169129707Stjr else 170129179Stjr oct_write8_x8(ptr, ' '); 171129179Stjr oct_read64(OCTEON_MIO_BOOT_BIST_STAT); 172129179Stjr } 173132497Stjr} 174129179Stjr 175129179Stjrstatic char progress[8] = { '-', '/', '|', '\\', '-', '/', '|', '\\'}; 176129179Stjr 177129179Stjrvoid 178129179Stjrocteon_led_run_wheel(int *prog_count, int led_position) 179129179Stjr{ 180129179Stjr if (!octeon_board_real()) 181129179Stjr return; 182129179Stjr octeon_led_write_char(led_position, progress[*prog_count]); 183129179Stjr *prog_count += 1; 184129179Stjr *prog_count &= 0x7; 185129179Stjr} 186129179Stjr 187142654Sphantomvoid 188142654Sphantomocteon_led_write_hex(uint32_t wl) 189142654Sphantom{ 190142654Sphantom char nbuf[80]; 191142654Sphantom 192142654Sphantom sprintf(nbuf, "%X", wl); 193142654Sphantom octeon_led_write_string(nbuf); 194142654Sphantom} 195142654Sphantom 196142654Sphantom 197142654Sphantom/* 198142654Sphantom * octeon_debug_symbol 199142654Sphantom * 200227753Stheraven * Does nothing. 201227753Stheraven * Used to mark the point for simulator to begin tracing 202227753Stheraven */ 203227753Stheravenvoid 204227753Stheravenocteon_debug_symbol(void) 205227753Stheraven{ 206227753Stheraven} 207227753Stheraven 208227753Stheravenvoid 209227753Stheravenocteon_ciu_stop_gtimer(int timer) 210227753Stheraven{ 211227753Stheraven oct_write64(OCTEON_CIU_GENTIMER_ADDR(timer), 0ll); 212227753Stheraven} 213227753Stheraven 214227753Stheravenvoid 215227753Stheravenocteon_ciu_start_gtimer(int timer, u_int one_shot, uint64_t time_cycles) 216227753Stheraven{ 217227753Stheraven octeon_ciu_gentimer gentimer; 218227753Stheraven 219227753Stheraven gentimer.word64 = 0; 220227753Stheraven gentimer.bits.one_shot = one_shot; 221227753Stheraven gentimer.bits.len = time_cycles - 1; 222227753Stheraven oct_write64(OCTEON_CIU_GENTIMER_ADDR(timer), gentimer.word64); 223} 224 225/* 226 * octeon_ciu_reset 227 * 228 * Shutdown all CIU to IP2, IP3 mappings 229 */ 230void 231octeon_ciu_reset(void) 232{ 233 234 octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_0); 235 octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_1); 236 octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_2); 237 octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_3); 238 239 ciu_disable_intr(CIU_THIS_CORE, CIU_INT_0, CIU_EN_0); 240 ciu_disable_intr(CIU_THIS_CORE, CIU_INT_0, CIU_EN_1); 241 ciu_disable_intr(CIU_THIS_CORE, CIU_INT_1, CIU_EN_0); 242 ciu_disable_intr(CIU_THIS_CORE, CIU_INT_1, CIU_EN_1); 243 244 ciu_clear_int_summary(CIU_THIS_CORE, CIU_INT_0, CIU_EN_0, 0ll); 245 ciu_clear_int_summary(CIU_THIS_CORE, CIU_INT_1, CIU_EN_0, 0ll); 246 ciu_clear_int_summary(CIU_THIS_CORE, CIU_INT_1, CIU_EN_1, 0ll); 247} 248 249/* 250 * mips_disable_interrupt_controllers 251 * 252 * Disable interrupts in the CPU controller 253 */ 254void 255mips_disable_interrupt_controls(void) 256{ 257 /* 258 * Disable interrupts in CIU. 259 */ 260 octeon_ciu_reset(); 261} 262 263/* 264 * ciu_get_intr_sum_reg_addr 265 */ 266static uint64_t 267ciu_get_intr_sum_reg_addr(int core_num, int intx, int enx) 268{ 269 uint64_t ciu_intr_sum_reg_addr; 270 271 if (enx == CIU_EN_0) 272 ciu_intr_sum_reg_addr = OCTEON_CIU_SUMMARY_BASE_ADDR + 273 (core_num * 0x10) + (intx * 0x8); 274 else 275 ciu_intr_sum_reg_addr = OCTEON_CIU_SUMMARY_INT1_ADDR; 276 277 return (ciu_intr_sum_reg_addr); 278} 279 280 281/* 282 * ciu_get_intr_en_reg_addr 283 */ 284static uint64_t 285ciu_get_intr_en_reg_addr(int core_num, int intx, int enx) 286{ 287 uint64_t ciu_intr_reg_addr; 288 289 ciu_intr_reg_addr = OCTEON_CIU_ENABLE_BASE_ADDR + 290 ((enx == 0) ? 0x0 : 0x8) + (intx * 0x10) + (core_num * 0x20); 291 return (ciu_intr_reg_addr); 292} 293 294 295 296 297/* 298 * ciu_get_intr_reg_addr 299 * 300 * 200 ---int0,en0 ip2 301 * 208 ---int0,en1 ip2 ----> this is wrong... this is watchdog 302 * 303 * 210 ---int0,en0 ip3 -- 304 * 218 ---int0,en1 ip3 ----> same here.. .this is watchdog... right? 305 * 306 * 220 ---int1,en0 ip2 307 * 228 ---int1,en1 ip2 308 * 230 ---int1,en0 ip3 -- 309 * 238 ---int1,en1 ip3 310 * 311 */ 312uint64_t 313ciu_get_en_reg_addr_new(int corenum, int intx, int enx, int ciu_ip) 314{ 315 uint64_t ciu_intr_reg_addr = OCTEON_CIU_ENABLE_BASE_ADDR; 316 317 /* XXX kasserts? */ 318 if (enx < CIU_EN_0 || enx > CIU_EN_1) { 319 printf("%s: invalid enx value %d, should be %d or %d\n", 320 __func__, enx, CIU_EN_0, CIU_EN_1); 321 return 0; 322 } 323 if (intx < CIU_INT_0 || intx > CIU_INT_1) { 324 printf("%s: invalid intx value %d, should be %d or %d\n", 325 __func__, enx, CIU_INT_0, CIU_INT_1); 326 return 0; 327 } 328 if (ciu_ip < CIU_MIPS_IP2 || ciu_ip > CIU_MIPS_IP3) { 329 printf("%s: invalid ciu_ip value %d, should be %d or %d\n", 330 __func__, ciu_ip, CIU_MIPS_IP2, CIU_MIPS_IP3); 331 return 0; 332 } 333 334 ciu_intr_reg_addr += (enx * 0x8); 335 ciu_intr_reg_addr += (ciu_ip * 0x10); 336 ciu_intr_reg_addr += (intx * 0x20); 337 return (ciu_intr_reg_addr); 338} 339 340/* 341 * ciu_get_int_summary 342 */ 343uint64_t 344ciu_get_int_summary(int core_num, int intx, int enx) 345{ 346 uint64_t ciu_intr_sum_reg_addr; 347 348 if (core_num == CIU_THIS_CORE) 349 core_num = octeon_get_core_num(); 350 ciu_intr_sum_reg_addr = ciu_get_intr_sum_reg_addr(core_num, intx, enx); 351 return (oct_read64(ciu_intr_sum_reg_addr)); 352} 353 354//#define DEBUG_CIU 1 355 356#ifdef DEBUG_CIU 357#define DEBUG_CIU_SUM 1 358#define DEBUG_CIU_EN 1 359#endif 360 361 362/* 363 * ciu_clear_int_summary 364 */ 365void 366ciu_clear_int_summary(int core_num, int intx, int enx, uint64_t write_bits) 367{ 368 uint32_t cpu_status_bits; 369 uint64_t ciu_intr_sum_reg_addr; 370 371//#define DEBUG_CIU_SUM 1 372 373#ifdef DEBUG_CIU_SUM 374 uint64_t ciu_intr_sum_bits; 375#endif 376 377 378 if (core_num == CIU_THIS_CORE) { 379 core_num = octeon_get_core_num(); 380 } 381 382#ifdef DEBUG_CIU_SUM 383 printf(" CIU: core %u clear sum IntX %u Enx %u Bits: 0x%llX\n", 384 core_num, intx, enx, write_bits); 385#endif 386 387 cpu_status_bits = intr_disable(); 388 389 ciu_intr_sum_reg_addr = ciu_get_intr_sum_reg_addr(core_num, intx, enx); 390 391#ifdef DEBUG_CIU_SUM 392 ciu_intr_sum_bits = oct_read64(ciu_intr_sum_reg_addr); /* unneeded dummy read */ 393 printf(" CIU: status: 0x%X reg_addr: 0x%llX Val: 0x%llX -> 0x%llX", 394 cpu_status_bits, ciu_intr_sum_reg_addr, ciu_intr_sum_bits, 395 ciu_intr_sum_bits | write_bits); 396#endif 397 398 oct_write64(ciu_intr_sum_reg_addr, write_bits); 399 oct_read64(OCTEON_MIO_BOOT_BIST_STAT); /* Bus Barrier */ 400 401#ifdef DEBUG_CIU_SUM 402 printf(" Readback: 0x%llX\n\n ", (uint64_t) oct_read64(ciu_intr_sum_reg_addr)); 403#endif 404 405 intr_restore(cpu_status_bits); 406} 407 408/* 409 * ciu_disable_intr 410 */ 411void 412ciu_disable_intr(int core_num, int intx, int enx) 413{ 414 uint32_t cpu_status_bits; 415 uint64_t ciu_intr_reg_addr; 416 417 if (core_num == CIU_THIS_CORE) 418 core_num = octeon_get_core_num(); 419 420 cpu_status_bits = intr_disable(); 421 422 ciu_intr_reg_addr = ciu_get_intr_en_reg_addr(core_num, intx, enx); 423 424 oct_read64(ciu_intr_reg_addr); /* Dummy read */ 425 426 oct_write64(ciu_intr_reg_addr, 0LL); 427 oct_read64(OCTEON_MIO_BOOT_BIST_STAT); /* Bus Barrier */ 428 429 intr_restore(cpu_status_bits); 430} 431 432void 433ciu_dump_interrutps_enabled(int core_num, int intx, int enx, int ciu_ip) 434{ 435 436 uint64_t ciu_intr_reg_addr; 437 uint64_t ciu_intr_bits; 438 439 if (core_num == CIU_THIS_CORE) { 440 core_num = octeon_get_core_num(); 441 } 442 443#ifndef OCTEON_SMP_1 444 ciu_intr_reg_addr = ciu_get_intr_en_reg_addr(core_num, intx, enx); 445#else 446 ciu_intr_reg_addr = ciu_get_en_reg_addr_new(core_num, intx, enx, ciu_ip); 447#endif 448 449 if (!ciu_intr_reg_addr) { 450 printf("Bad call to %s\n", __func__); 451 while(1); 452 return; 453 } 454 455 ciu_intr_bits = oct_read64(ciu_intr_reg_addr); 456 printf(" CIU core %d int: %d en: %d ip: %d Add: %#llx enabled: %#llx SR: %x\n", 457 core_num, intx, enx, ciu_ip, (unsigned long long)ciu_intr_reg_addr, 458 (unsigned long long)ciu_intr_bits, mips_rd_status()); 459} 460 461 462/* 463 * ciu_enable_interrupts 464 */ 465void ciu_enable_interrupts(int core_num, int intx, int enx, 466 uint64_t set_these_interrupt_bits, int ciu_ip) 467{ 468 uint32_t cpu_status_bits; 469 uint64_t ciu_intr_reg_addr; 470 uint64_t ciu_intr_bits; 471 472 if (core_num == CIU_THIS_CORE) 473 core_num = octeon_get_core_num(); 474 475//#define DEBUG_CIU_EN 1 476 477#ifdef DEBUG_CIU_EN 478 printf(" CIU: core %u enabling Intx %u Enx %u IP %d Bits: 0x%llX\n", 479 core_num, intx, enx, ciu_ip, set_these_interrupt_bits); 480#endif 481 482 cpu_status_bits = intr_disable(); 483 484#ifndef OCTEON_SMP_1 485 ciu_intr_reg_addr = ciu_get_intr_en_reg_addr(core_num, intx, enx); 486#else 487 ciu_intr_reg_addr = ciu_get_en_reg_addr_new(core_num, intx, enx, ciu_ip); 488#endif 489 490 if (!ciu_intr_reg_addr) { 491 printf("Bad call to %s\n", __func__); 492 while(1); 493 return; /* XXX */ 494 } 495 496 ciu_intr_bits = oct_read64(ciu_intr_reg_addr); 497 498#ifdef DEBUG_CIU_EN 499 printf(" CIU: status: 0x%X reg_addr: 0x%llX Val: 0x%llX -> 0x%llX", 500 cpu_status_bits, ciu_intr_reg_addr, ciu_intr_bits, ciu_intr_bits | set_these_interrupt_bits); 501#endif 502 ciu_intr_bits |= set_these_interrupt_bits; 503 oct_write64(ciu_intr_reg_addr, ciu_intr_bits); 504#ifdef SMP 505 mips_wbflush(); 506#endif 507 oct_read64(OCTEON_MIO_BOOT_BIST_STAT); /* Bus Barrier */ 508 509#ifdef DEBUG_CIU_EN 510 printf(" Readback: 0x%llX\n\n ", 511 (uint64_t)oct_read64(ciu_intr_reg_addr)); 512#endif 513 514 intr_restore(cpu_status_bits); 515} 516 517unsigned long 518octeon_get_clock_rate(void) 519{ 520 return octeon_cpu_clock; 521} 522 523static void 524octeon_memory_init(void) 525{ 526 uint32_t realmem_bytes; 527 528 if (octeon_board_real()) { 529 realmem_bytes = (octeon_dram - PAGE_SIZE); 530 realmem_bytes &= ~(PAGE_SIZE - 1); 531 } else { 532 /* Simulator we limit to 96 meg */ 533 realmem_bytes = (96 << 20); 534 } 535 /* phys_avail regions are in bytes */ 536 phys_avail[0] = (MIPS_KSEG0_TO_PHYS((vm_offset_t)&end) + PAGE_SIZE) & ~(PAGE_SIZE - 1); 537 if (octeon_board_real()) { 538 if (realmem_bytes > OCTEON_DRAM_FIRST_256_END) 539 phys_avail[1] = OCTEON_DRAM_FIRST_256_END; 540 else 541 phys_avail[1] = realmem_bytes; 542 realmem_bytes -= OCTEON_DRAM_FIRST_256_END; 543 realmem_bytes &= ~(PAGE_SIZE - 1); 544 } else { 545 /* Simulator gets 96Meg period. */ 546 phys_avail[1] = (96 << 20); 547 } 548 /*- 549 * Octeon Memory looks as follows: 550 * PA 551 * 0000 0000 to 0x0 0000 0000 0000 552 * 0FFF FFFF First 256 MB memory Maps to 0x0 0000 0FFF FFFF 553 * 554 * 1000 0000 to 0x1 0000 1000 0000 555 * 1FFF FFFF Uncached Bu I/O space.converted to 0x1 0000 1FFF FFFF 556 * 557 * 2FFF FFFF to Cached 0x0 0000 2000 0000 558 * FFFF FFFF all dram mem above the first 512M 0x3 FFFF FFFF FFFF 559 * 560 */ 561 physmem = btoc(phys_avail[1] - phys_avail[0]); 562 if ((octeon_board_real()) && 563 (realmem_bytes > OCTEON_DRAM_FIRST_256_END)) { 564 /* take out the upper non-cached 1/2 */ 565 realmem_bytes -= OCTEON_DRAM_FIRST_256_END; 566 realmem_bytes &= ~(PAGE_SIZE - 1); 567 /* Now map the rest of the memory */ 568 phys_avail[2] = 0x20000000; 569 phys_avail[3] = ((uint32_t) 0x20000000 + realmem_bytes); 570 physmem += btoc(phys_avail[3] - phys_avail[2]); 571 } 572 realmem = physmem; 573 574 printf("Total DRAM Size %#X\n", (uint32_t) octeon_dram); 575 printf("Bank 0 = %#08lX -> %#08lX\n", (long)phys_avail[0], (long)phys_avail[1]); 576 printf("Bank 1 = %#08lX -> %#08lX\n", (long)phys_avail[2], (long)phys_avail[3]); 577} 578 579void 580platform_start(__register_t a0, __register_t a1, __register_t a2 __unused, 581 __register_t a3) 582{ 583 uint64_t platform_counter_freq; 584 585 /* Initialize pcpu stuff */ 586 mips_pcpu0_init(); 587 mips_timer_early_init(OCTEON_CLOCK_DEFAULT); 588 cninit(); 589 590 octeon_ciu_reset(); 591 octeon_boot_params_init(a3); 592 bootverbose = 1; 593 594 /* 595 * For some reason on the cn38xx simulator ebase register is set to 596 * 0x80001000 at bootup time. Move it back to the default, but 597 * when we move to having support for multiple executives, we need 598 * to rethink this. 599 */ 600 mips_wr_ebase(0x80000000); 601 602 octeon_memory_init(); 603 init_param1(); 604 init_param2(physmem); 605 mips_cpu_init(); 606 pmap_bootstrap(); 607 mips_proc0_init(); 608 mutex_init(); 609 kdb_init(); 610#ifdef KDB 611 if (boothowto & RB_KDB) 612 kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); 613#endif 614 platform_counter_freq = octeon_get_clock_rate(); 615 mips_timer_init_params(platform_counter_freq, 0); 616 617#ifdef SMP 618 /* 619 * Clear any pending IPIs and enable the IPI interrupt. 620 */ 621 oct_write64(OCTEON_CIU_MBOX_CLRX(0), 0xffffffff); 622 ciu_enable_interrupts(0, CIU_INT_1, CIU_EN_0, OCTEON_CIU_ENABLE_MBOX_INTR, CIU_MIPS_IP3); 623#endif 624} 625 626/* impSTART: This stuff should move back into the Cavium SDK */ 627/* 628 **************************************************************************************** 629 * 630 * APP/BOOT DESCRIPTOR STUFF 631 * 632 **************************************************************************************** 633 */ 634 635/* Define the struct that is initialized by the bootloader used by the 636 * startup code. 637 * 638 * Copyright (c) 2004, 2005, 2006 Cavium Networks. 639 * 640 * The authors hereby grant permission to use, copy, modify, distribute, 641 * and license this software and its documentation for any purpose, provided 642 * that existing copyright notices are retained in all copies and that this 643 * notice is included verbatim in any distributions. No written agreement, 644 * license, or royalty fee is required for any of the authorized uses. 645 * Modifications to this software may be copyrighted by their authors 646 * and need not follow the licensing terms described here, provided that 647 * the new terms are clearly indicated on the first page of each file where 648 * they apply. 649 */ 650 651#define OCTEON_CURRENT_DESC_VERSION 6 652#define OCTEON_ARGV_MAX_ARGS (64) 653#define OCTOEN_SERIAL_LEN 20 654 655 656typedef struct { 657 /* Start of block referenced by assembly code - do not change! */ 658 uint32_t desc_version; 659 uint32_t desc_size; 660 661 uint64_t stack_top; 662 uint64_t heap_base; 663 uint64_t heap_end; 664 uint64_t entry_point; /* Only used by bootloader */ 665 uint64_t desc_vaddr; 666 /* End of This block referenced by assembly code - do not change! */ 667 668 uint32_t exception_base_addr; 669 uint32_t stack_size; 670 uint32_t heap_size; 671 uint32_t argc; /* Argc count for application */ 672 uint32_t argv[OCTEON_ARGV_MAX_ARGS]; 673 uint32_t flags; 674 uint32_t core_mask; 675 uint32_t dram_size; /**< DRAM size in megabyes */ 676 uint32_t phy_mem_desc_addr; /**< physical address of free memory descriptor block*/ 677 uint32_t debugger_flags_base_addr; /**< used to pass flags from app to debugger */ 678 uint32_t eclock_hz; /**< CPU clock speed, in hz */ 679 uint32_t dclock_hz; /**< DRAM clock speed, in hz */ 680 uint32_t spi_clock_hz; /**< SPI4 clock in hz */ 681 uint16_t board_type; 682 uint8_t board_rev_major; 683 uint8_t board_rev_minor; 684 uint16_t chip_type; 685 uint8_t chip_rev_major; 686 uint8_t chip_rev_minor; 687 char board_serial_number[OCTOEN_SERIAL_LEN]; 688 uint8_t mac_addr_base[6]; 689 uint8_t mac_addr_count; 690 uint64_t cvmx_desc_vaddr; 691} octeon_boot_descriptor_t; 692 693 694typedef struct { 695 uint32_t major_version; 696 uint32_t minor_version; 697 698 uint64_t stack_top; 699 uint64_t heap_base; 700 uint64_t heap_end; 701 uint64_t desc_vaddr; 702 703 uint32_t exception_base_addr; 704 uint32_t stack_size; 705 uint32_t flags; 706 uint32_t core_mask; 707 uint32_t dram_size; /**< DRAM size in megabyes */ 708 uint32_t phy_mem_desc_addr; /**< physical address of free memory descriptor block*/ 709 uint32_t debugger_flags_base_addr; /**< used to pass flags from app to debugger */ 710 uint32_t eclock_hz; /**< CPU clock speed, in hz */ 711 uint32_t dclock_hz; /**< DRAM clock speed, in hz */ 712 uint32_t spi_clock_hz; /**< SPI4 clock in hz */ 713 uint16_t board_type; 714 uint8_t board_rev_major; 715 uint8_t board_rev_minor; 716 uint16_t chip_type; 717 uint8_t chip_rev_major; 718 uint8_t chip_rev_minor; 719 char board_serial_number[OCTOEN_SERIAL_LEN]; 720 uint8_t mac_addr_base[6]; 721 uint8_t mac_addr_count; 722} cvmx_bootinfo_t; 723 724uint32_t octeon_cpu_clock; 725uint64_t octeon_dram; 726uint32_t octeon_bd_ver = 0, octeon_cvmx_bd_ver = 0, octeon_board_rev_major, octeon_board_rev_minor, octeon_board_type; 727uint8_t octeon_mac_addr[6] = { 0 }; 728int octeon_core_mask, octeon_mac_addr_count; 729int octeon_chip_rev_major = 0, octeon_chip_rev_minor = 0, octeon_chip_type = 0; 730 731static octeon_boot_descriptor_t *app_desc_ptr; 732static cvmx_bootinfo_t *cvmx_desc_ptr; 733 734#define OCTEON_BOARD_TYPE_NONE 0 735#define OCTEON_BOARD_TYPE_SIM 1 736#define OCTEON_BOARD_TYPE_CN3010_EVB_HS5 11 737 738#define OCTEON_CLOCK_MIN (100 * 1000 * 1000) 739#define OCTEON_CLOCK_MAX (800 * 1000 * 1000) 740#define OCTEON_DRAM_DEFAULT (256 * 1024 * 1024) 741#define OCTEON_DRAM_MIN 30 742#define OCTEON_DRAM_MAX 3000 743 744 745int 746octeon_board_real(void) 747{ 748 switch (octeon_board_type) { 749 case OCTEON_BOARD_TYPE_NONE: 750 case OCTEON_BOARD_TYPE_SIM: 751 return 0; 752 case OCTEON_BOARD_TYPE_CN3010_EVB_HS5: 753 /* 754 * XXX 755 * The CAM-0100 identifies itself as type 11, revision 0.0, 756 * despite its being rather real. Disable the revision check 757 * for type 11. 758 */ 759 return 1; 760 default: 761 if (octeon_board_rev_major == 0) 762 return 0; 763 return 1; 764 } 765} 766 767static void 768octeon_process_app_desc_ver_unknown(void) 769{ 770 printf(" Unknown Boot-Descriptor: Using Defaults\n"); 771 772 octeon_cpu_clock = OCTEON_CLOCK_DEFAULT; 773 octeon_dram = OCTEON_DRAM_DEFAULT; 774 octeon_board_rev_major = octeon_board_rev_minor = octeon_board_type = 0; 775 octeon_core_mask = 1; 776 octeon_chip_type = octeon_chip_rev_major = octeon_chip_rev_minor = 0; 777 octeon_mac_addr[0] = 0x00; octeon_mac_addr[1] = 0x0f; 778 octeon_mac_addr[2] = 0xb7; octeon_mac_addr[3] = 0x10; 779 octeon_mac_addr[4] = 0x09; octeon_mac_addr[5] = 0x06; 780 octeon_mac_addr_count = 1; 781} 782 783static int 784octeon_process_app_desc_ver_6(void) 785{ 786 /* XXX Why is 0x00000000ffffffffULL a bad value? */ 787 if (app_desc_ptr->cvmx_desc_vaddr == 0 || 788 app_desc_ptr->cvmx_desc_vaddr == 0xfffffffful) { 789 printf ("Bad cvmx_desc_ptr %p\n", cvmx_desc_ptr); 790 return 1; 791 } 792 cvmx_desc_ptr = 793 (cvmx_bootinfo_t *)(intptr_t)app_desc_ptr->cvmx_desc_vaddr; 794 cvmx_desc_ptr = 795 (cvmx_bootinfo_t *) ((intptr_t)cvmx_desc_ptr | MIPS_KSEG0_START); 796 octeon_cvmx_bd_ver = (cvmx_desc_ptr->major_version * 100) + 797 cvmx_desc_ptr->minor_version; 798 if (cvmx_desc_ptr->major_version != 1) { 799 panic("Incompatible CVMX descriptor from bootloader: %d.%d %p\n", 800 (int) cvmx_desc_ptr->major_version, 801 (int) cvmx_desc_ptr->minor_version, cvmx_desc_ptr); 802 } 803 804 octeon_core_mask = cvmx_desc_ptr->core_mask; 805 octeon_cpu_clock = cvmx_desc_ptr->eclock_hz; 806 octeon_board_type = cvmx_desc_ptr->board_type; 807 octeon_board_rev_major = cvmx_desc_ptr->board_rev_major; 808 octeon_board_rev_minor = cvmx_desc_ptr->board_rev_minor; 809 octeon_chip_type = cvmx_desc_ptr->chip_type; 810 octeon_chip_rev_major = cvmx_desc_ptr->chip_rev_major; 811 octeon_chip_rev_minor = cvmx_desc_ptr->chip_rev_minor; 812 octeon_mac_addr[0] = cvmx_desc_ptr->mac_addr_base[0]; 813 octeon_mac_addr[1] = cvmx_desc_ptr->mac_addr_base[1]; 814 octeon_mac_addr[2] = cvmx_desc_ptr->mac_addr_base[2]; 815 octeon_mac_addr[3] = cvmx_desc_ptr->mac_addr_base[3]; 816 octeon_mac_addr[4] = cvmx_desc_ptr->mac_addr_base[4]; 817 octeon_mac_addr[5] = cvmx_desc_ptr->mac_addr_base[5]; 818 octeon_mac_addr_count = cvmx_desc_ptr->mac_addr_count; 819 820 if (app_desc_ptr->dram_size > 16*1024*1024) 821 octeon_dram = (uint64_t)app_desc_ptr->dram_size; 822 else 823 octeon_dram = (uint64_t)app_desc_ptr->dram_size << 20; 824 return 0; 825} 826 827static void 828octeon_boot_params_init(register_t ptr) 829{ 830 int bad_desc = 1; 831 832 if (ptr != 0 && ptr < MAX_APP_DESC_ADDR) { 833 app_desc_ptr = (octeon_boot_descriptor_t *)(intptr_t)ptr; 834 octeon_bd_ver = app_desc_ptr->desc_version; 835 if (app_desc_ptr->desc_version < 6) 836 panic("Your boot code is too old to be supported.\n"); 837 if (app_desc_ptr->desc_version >= 6) 838 bad_desc = octeon_process_app_desc_ver_6(); 839 } 840 if (bad_desc) 841 octeon_process_app_desc_ver_unknown(); 842 843 printf("Boot Descriptor Ver: %u -> %u/%u", 844 octeon_bd_ver, octeon_cvmx_bd_ver/100, octeon_cvmx_bd_ver%100); 845 printf(" CPU clock: %uMHz Core Mask: %#x\n", octeon_cpu_clock/1000000, octeon_core_mask); 846 printf(" Dram: %u MB", (uint32_t)(octeon_dram >> 20)); 847 printf(" Board Type: %u Revision: %u/%u\n", 848 octeon_board_type, octeon_board_rev_major, octeon_board_rev_minor); 849 printf(" Octeon Chip: %u Rev %u/%u", 850 octeon_chip_type, octeon_chip_rev_major, octeon_chip_rev_minor); 851 852 printf(" Mac Address %02X.%02X.%02X.%02X.%02X.%02X (%d)\n", 853 octeon_mac_addr[0], octeon_mac_addr[1], octeon_mac_addr[2], 854 octeon_mac_addr[3], octeon_mac_addr[4], octeon_mac_addr[5], 855 octeon_mac_addr_count); 856} 857/* impEND: This stuff should move back into the Cavium SDK */ 858