octeon_machdep.c revision 202939
14Srgrimes/*- 24Srgrimes * Copyright (c) 2006 Wojciech A. Koszek <wkoszek@FreeBSD.org> 34Srgrimes * All rights reserved. 44Srgrimes * 54Srgrimes * Redistribution and use in source and binary forms, with or without 64Srgrimes * modification, are permitted provided that the following conditions 74Srgrimes * are met: 84Srgrimes * 1. Redistributions of source code must retain the above copyright 94Srgrimes * notice, this list of conditions and the following disclaimer. 104Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 114Srgrimes * notice, this list of conditions and the following disclaimer in the 124Srgrimes * documentation and/or other materials provided with the distribution. 134Srgrimes * 144Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 154Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 164Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 174Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 184Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 194Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 204Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 214Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 224Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 234Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 244Srgrimes * SUCH DAMAGE. 254Srgrimes * 264Srgrimes * $FreeBSD: head/sys/mips/cavium/octeon_machdep.c 202939 2010-01-24 18:05:38Z imp $ 274Srgrimes */ 284Srgrimes#include <sys/cdefs.h> 294Srgrimes__FBSDID("$FreeBSD: head/sys/mips/cavium/octeon_machdep.c 202939 2010-01-24 18:05:38Z imp $"); 304Srgrimes 314Srgrimes#include <sys/param.h> 324Srgrimes#include <sys/conf.h> 334Srgrimes#include <sys/kernel.h> 344Srgrimes#include <sys/systm.h> 354Srgrimes#include <sys/imgact.h> 36620Srgrimes#include <sys/bio.h> 3716075Sjoerg#include <sys/buf.h> 384Srgrimes#include <sys/bus.h> 394Srgrimes#include <sys/cpu.h> 404Srgrimes#include <sys/cons.h> 414Srgrimes#include <sys/exec.h> 424Srgrimes#include <sys/ucontext.h> 438876Srgrimes#include <sys/proc.h> 444Srgrimes#include <sys/kdb.h> 454Srgrimes#include <sys/ptrace.h> 464Srgrimes#include <sys/reboot.h> 474Srgrimes#include <sys/signalvar.h> 482056Swollman#include <sys/sysent.h> 492056Swollman#include <sys/sysproto.h> 502056Swollman#include <sys/user.h> 512056Swollman 522056Swollman#include <vm/vm.h> 532056Swollman#include <vm/vm_object.h> 542056Swollman#include <vm/vm_page.h> 552056Swollman#include <vm/vm_pager.h> 5612604Sbde 5712649Speter#include <machine/atomic.h> 584Srgrimes#include <machine/cache.h> 5910665Sbde#include <machine/clock.h> 6016075Sjoerg#include <machine/cpu.h> 617090Sbde#include <machine/cpuregs.h> 6212791Sgibbs#include <machine/cpufunc.h> 634Srgrimes#include <mips/cavium/octeon_pcmap_regs.h> 6412604Sbde#include <machine/hwfunc.h> 6512604Sbde#include <machine/intr_machdep.h> 6612604Sbde#include <machine/locore.h> 6712604Sbde#include <machine/md_var.h> 6810665Sbde#include <machine/pcpu.h> 6912604Sbde#include <machine/pte.h> 7012604Sbde#include <machine/trap.h> 7112604Sbde#include <machine/vmparam.h> 7212604Sbde 7310665Sbde#if defined(__mips_n64) 7412604Sbde#define MAX_APP_DESC_ADDR 0xffffffffafffffff 7512604Sbde#else 7612604Sbde#define MAX_APP_DESC_ADDR 0xafffffff 7712604Sbde#endif 78798Swollman 7912604Sbdestatic struct pcpu pcpu0; 8012604Sbdeextern int *edata; 8112604Sbdeextern int *end; 8212604Sbde 834Srgrimesuint64_t ciu_get_en_reg_addr_new(int corenum, int intx, int enx, int ciu_ip); 8412604Sbdevoid ciu_dump_interrutps_enabled(int core_num, int intx, int enx, int ciu_ip); 8512604Sbde 8612604Sbdestatic void octeon_boot_params_init(register_t ptr); 8712604Sbdestatic uint64_t ciu_get_intr_sum_reg_addr(int core_num, int intx, int enx); 8812604Sbdestatic uint64_t ciu_get_intr_en_reg_addr(int core_num, int intx, int enx); 8912604Sbde 9012604Sbdestatic __inline void 9112604Sbdemips_wr_ebase(u_int32_t a0) 9212499Speter{ 9312499Speter __asm __volatile("mtc0 %[a0], $15, 1 ;" 9412499Speter : 954370Sphk : [a0] "r"(a0)); 9610358Sjulian 974370Sphk mips_barrier(); 9810358Sjulian} 9910358Sjulian 10010358Sjulianvoid 1014370Sphkplatform_cpu_init() 10212604Sbde{ 1034370Sphk /* Nothing special yet */ 1047731Sphk} 10512604Sbde 1067731Sphk/* 1078055Sphk * Perform a board-level soft-reset. 10812604Sbde */ 1098055Sphkvoid 1104370Sphkplatform_reset(void) 11112848Sbde{ 11212848Sbde oct_write64(OCTEON_CIU_SOFT_RST, 1); 11312848Sbde} 11412848Sbde 11512848Sbde 1168007Sphkstatic inline uint32_t 1177731Sphkocteon_disable_interrupts(void) 1187731Sphk{ 1197731Sphk uint32_t status_bits; 1207731Sphk 1217731Sphk status_bits = mips_rd_status(); 1227731Sphk mips_wr_status(status_bits & ~MIPS_SR_INT_IE); 1237731Sphk return (status_bits); 1247731Sphk} 1257731Sphk 1267731Sphk 1277731Sphkstatic inline void 1287731Sphkocteon_set_interrupts(uint32_t status_bits) 12912604Sbde{ 13012604Sbde mips_wr_status(status_bits); 13112604Sbde} 13210653Sdg 13310653Sdg 1347731Sphkvoid 1357731Sphkocteon_led_write_char(int char_position, char val) 1367731Sphk{ 1377731Sphk uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8); 1387731Sphk 1397731Sphk if (!octeon_board_real()) 1408456Srgrimes return; 1417731Sphk 14210665Sbde char_position &= 0x7; /* only 8 chars */ 1437731Sphk ptr += char_position; 1447731Sphk oct_write8_x8(ptr, val); 1457731Sphk} 1467731Sphk 1478007Sphkvoid 1487731Sphkocteon_led_write_char0(char val) 14912604Sbde{ 1507818Sdufault uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8); 1517818Sdufault 1527818Sdufault if (!octeon_board_real()) 1537818Sdufault return; 1547818Sdufault oct_write8_x8(ptr, val); 1557818Sdufault} 1567818Sdufault 15712604Sbdevoid 1587818Sdufaultocteon_led_write_hexchar(int char_position, char hexval) 1597818Sdufault{ 1607818Sdufault uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8); 1617818Sdufault char char1, char2; 1627818Sdufault 1637818Sdufault if (!octeon_board_real()) 1647818Sdufault return; 1654Srgrimes 1664Srgrimes char1 = (hexval >> 4) & 0x0f; char1 = (char1 < 10)?char1+'0':char1+'7'; 1674Srgrimes char2 = (hexval & 0x0f); char2 = (char2 < 10)?char2+'0':char2+'7'; 16810665Sbde char_position &= 0x7; /* only 8 chars */ 16910665Sbde if (char_position > 6) 17010653Sdg char_position = 6; 1714Srgrimes ptr += char_position; 1724Srgrimes oct_write8_x8(ptr, char1); 1738015Sjulian ptr++; 1748015Sjulian oct_write8_x8(ptr, char2); 17512791Sgibbs} 17612791Sgibbs 17712791Sgibbsvoid 17812791Sgibbsocteon_led_write_string(const char *str) 17911602Sphk{ 18011602Sphk uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8); 18111602Sphk int i; 18211602Sphk 1837818Sdufault if (!octeon_board_real()) 18412091Sgibbs return; 18512091Sgibbs 18612091Sgibbs for (i=0; i<8; i++, ptr++) { 18712091Sgibbs if (str && *str) 1882430Sse oct_write8_x8(ptr, *str++); 1892430Sse else 1902430Sse oct_write8_x8(ptr, ' '); 1912430Sse oct_read64(OCTEON_MIO_BOOT_BIST_STAT); 19212791Sgibbs } 19312791Sgibbs} 19412791Sgibbs 19512791Sgibbsstatic char progress[8] = { '-', '/', '|', '\\', '-', '/', '|', '\\'}; 1967818Sdufault 1977818Sdufaultvoid 19810665Sbdeocteon_led_run_wheel(int *prog_count, int led_position) 19910665Sbde{ 20016075Sjoerg if (!octeon_board_real()) 20116075Sjoerg return; 20216075Sjoerg octeon_led_write_char(led_position, progress[*prog_count]); 2037731Sphk *prog_count += 1; 20416075Sjoerg *prog_count &= 0x7; 20516075Sjoerg} 20616075Sjoerg 2077731Sphk#define LSR_DATAREADY 0x01 /* Data ready */ 20816075Sjoerg#define LSR_THRE 0x20 /* Transmit holding register empty */ 2097731Sphk#define LSR_TEMT 0x40 /* Transmitter Empty. THR, TSR & FIFO */ 2108007Sphk#define USR_TXFIFO_NOTFULL 0x02 /* Uart TX FIFO Not full */ 2114370Sphk 21216075Sjoerg/* 21316075Sjoerg * octeon_uart_write_byte 21416075Sjoerg * 2153795Sphk * Put out a single byte off of uart port. 21616075Sjoerg */ 2174370Sphk 2188007Sphkvoid 21912499Speterocteon_uart_write_byte(int uart_index, uint8_t ch) 22012499Speter{ 22116075Sjoerg uint64_t val, val2; 22216075Sjoerg if (uart_index < 0 || uart_index > 1) 22312499Speter return; 22412499Speter 22512499Speter while (1) { 22612499Speter val = oct_read64(OCTEON_MIO_UART0_LSR + (uart_index * 0x400)); 22712499Speter val2 = oct_read64(OCTEON_MIO_UART0_USR + (uart_index * 0x400)); 22812499Speter if ((((uint8_t) val) & LSR_THRE) || 22912499Speter (((uint8_t) val2) & USR_TXFIFO_NOTFULL)) { 23012499Speter break; 23112499Speter } 23212499Speter } 23312499Speter 23412499Speter /* Write the byte */ 23512499Speter oct_write8(OCTEON_MIO_UART0_THR + (uart_index * 0x400), (uint64_t) ch); 23612499Speter 2374370Sphk /* Force Flush the IOBus */ 2384370Sphk oct_read64(OCTEON_MIO_BOOT_BIST_STAT); 23916075Sjoerg} 24016075Sjoerg 24110358Sjulian 24210358Sjulianvoid 2436547Swpaulocteon_uart_write_byte0(uint8_t ch) 2446547Swpaul{ 2456547Swpaul uint64_t val, val2; 2466547Swpaul 2476547Swpaul while (1) { 2486547Swpaul val = oct_read64(OCTEON_MIO_UART0_LSR); 2496547Swpaul val2 = oct_read64(OCTEON_MIO_UART0_USR); 2506547Swpaul if ((((uint8_t) val) & LSR_THRE) || 2516547Swpaul (((uint8_t) val2) & USR_TXFIFO_NOTFULL)) { 2525321Sjkh break; 2533795Sphk } 2544Srgrimes } 25510358Sjulian 2564370Sphk /* Write the byte */ 25716075Sjoerg oct_write8(OCTEON_MIO_UART0_THR, (uint64_t) ch); 25816075Sjoerg 25910358Sjulian /* Force Flush the IOBus */ 26010358Sjulian oct_read64(OCTEON_MIO_BOOT_BIST_STAT); 26110358Sjulian} 26210358Sjulian 26310358Sjulian/* 26410358Sjulian * octeon_uart_write_string 26510358Sjulian * 26610358Sjulian */ 26710358Sjulianvoid 26810358Sjulianocteon_uart_write_string(int uart_index, const char *str) 26910358Sjulian{ 27010358Sjulian /* Just loop writing one byte at a time */ 27110358Sjulian 27210358Sjulian while (*str) { 27310358Sjulian octeon_uart_write_byte(uart_index, *str); 2744370Sphk if (*str == '\n') { 2754370Sphk octeon_uart_write_byte(uart_index, '\r'); 2764Srgrimes } 2774Srgrimes str++; 2784Srgrimes } 2794Srgrimes} 28016075Sjoerg 28116075Sjoergstatic char wstr[30]; 2828433Swpaul 2834Srgrimesvoid 28416075Sjoergocteon_led_write_hex(uint32_t wl) 28516075Sjoerg{ 2864Srgrimes char nbuf[80]; 2874Srgrimes 28812722Sphk sprintf(nbuf, "%X", wl); 2898833Sdg octeon_led_write_string(nbuf); 2908833Sdg} 2918481Swollman 2928833Sdg 2938833Sdgvoid octeon_uart_write_hex2(uint32_t wl, uint32_t wh) 2948833Sdg{ 2958833Sdg sprintf(wstr, "0x%X-0x%X ", wh, wl); 2968481Swollman octeon_uart_write_string(0, wstr); 2978481Swollman} 2988833Sdg 2998481Swollmanvoid 3008833Sdgocteon_uart_write_hex(uint32_t wl) 3018833Sdg{ 3028833Sdg sprintf(wstr, " 0x%X ", wl); 30312889Speter octeon_uart_write_string(0, wstr); 30412889Speter} 30512813Sjulian 30612889Speter/* 30712813Sjulian * octeon_wait_uart_flush 3088833Sdg */ 30912889Spetervoid 31015538Sphkocteon_wait_uart_flush(int uart_index, uint8_t ch) 3118833Sdg{ 3128833Sdg uint64_t val; 3138833Sdg int64_t val3; 3148833Sdg uint32_t cpu_status_bits; 3158833Sdg 3168876Srgrimes if (uart_index < 0 || uart_index > 1) 3178481Swollman return; 3188833Sdg 3194Srgrimes cpu_status_bits = octeon_disable_interrupts(); 3204Srgrimes /* Force Flush the IOBus */ 3216105Sse oct_read64(OCTEON_MIO_BOOT_BIST_STAT); 3226105Sse for (val3 = 0xfffffffff; val3 > 0; val3--) { 3231289Sache val = oct_read64(OCTEON_MIO_UART0_LSR + (uart_index * 0x400)); 3246105Sse if (((uint8_t) val) & LSR_TEMT) 3256105Sse break; 3266105Sse } 3274Srgrimes octeon_set_interrupts(cpu_status_bits); 3284Srgrimes} 3294Srgrimes 3304Srgrimes 3311290Sache/* 3322400Sache * octeon_debug_symbol 3334Srgrimes * 3344Srgrimes * Does nothing. 3354Srgrimes * Used to mark the point for simulator to begin tracing 3364Srgrimes */ 3374Srgrimesvoid 3384Srgrimesocteon_debug_symbol(void) 339798Swollman{ 3404Srgrimes} 3414Srgrimes 3424Srgrimesvoid 34312417Sphkocteon_ciu_stop_gtimer(int timer) 3444Srgrimes{ 3454Srgrimes oct_write64(OCTEON_CIU_GENTIMER_ADDR(timer), 0ll); 3464Srgrimes} 3474Srgrimes 3484Srgrimesvoid 3494Srgrimesocteon_ciu_start_gtimer(int timer, u_int one_shot, uint64_t time_cycles) 3504Srgrimes{ 3514Srgrimes octeon_ciu_gentimer gentimer; 3524Srgrimes 3534Srgrimes gentimer.word64 = 0; 3541290Sache gentimer.bits.one_shot = one_shot; 3552400Sache gentimer.bits.len = time_cycles - 1; 3561290Sache oct_write64(OCTEON_CIU_GENTIMER_ADDR(timer), gentimer.word64); 3571290Sache} 3581290Sache 3591290Sache/* 3601289Sache * octeon_ciu_reset 3611290Sache * 3624Srgrimes * Shutdown all CIU to IP2, IP3 mappings 3634Srgrimes */ 3644Srgrimesvoid 3654Srgrimesocteon_ciu_reset(void) 3664Srgrimes{ 3674Srgrimes 3684Srgrimes octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_0); 3694Srgrimes octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_1); 3704Srgrimes octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_2); 3714Srgrimes octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_3); 3721290Sache 3731290Sache ciu_disable_intr(CIU_THIS_CORE, CIU_INT_0, CIU_EN_0); 3744Srgrimes ciu_disable_intr(CIU_THIS_CORE, CIU_INT_0, CIU_EN_1); 37512649Speter ciu_disable_intr(CIU_THIS_CORE, CIU_INT_1, CIU_EN_0); 37612649Speter ciu_disable_intr(CIU_THIS_CORE, CIU_INT_1, CIU_EN_1); 37712649Speter 37812649Speter ciu_clear_int_summary(CIU_THIS_CORE, CIU_INT_0, CIU_EN_0, 0ll); 37912649Speter ciu_clear_int_summary(CIU_THIS_CORE, CIU_INT_1, CIU_EN_0, 0ll); 38012649Speter ciu_clear_int_summary(CIU_THIS_CORE, CIU_INT_1, CIU_EN_1, 0ll); 38112649Speter} 38212649Speter 38312649Speter/* 38412649Speter * mips_disable_interrupt_controllers 38512649Speter * 38612649Speter * Disable interrupts in the CPU controller 38712649Speter */ 38812649Spetervoid 38912649Spetermips_disable_interrupt_controls(void) 39012649Speter{ 39112649Speter /* 392 * Disable interrupts in CIU. 393 */ 394 octeon_ciu_reset(); 395} 396 397/* 398 * ciu_get_intr_sum_reg_addr 399 */ 400static uint64_t 401ciu_get_intr_sum_reg_addr(int core_num, int intx, int enx) 402{ 403 uint64_t ciu_intr_sum_reg_addr; 404 405 if (enx == CIU_EN_0) 406 ciu_intr_sum_reg_addr = OCTEON_CIU_SUMMARY_BASE_ADDR + 407 (core_num * 0x10) + (intx * 0x8); 408 else 409 ciu_intr_sum_reg_addr = OCTEON_CIU_SUMMARY_INT1_ADDR; 410 411 return (ciu_intr_sum_reg_addr); 412} 413 414 415/* 416 * ciu_get_intr_en_reg_addr 417 */ 418static uint64_t 419ciu_get_intr_en_reg_addr(int core_num, int intx, int enx) 420{ 421 uint64_t ciu_intr_reg_addr; 422 423 ciu_intr_reg_addr = OCTEON_CIU_ENABLE_BASE_ADDR + 424 ((enx == 0) ? 0x0 : 0x8) + (intx * 0x10) + (core_num * 0x20); 425 return (ciu_intr_reg_addr); 426} 427 428 429 430 431/* 432 * ciu_get_intr_reg_addr 433 * 434 * 200 ---int0,en0 ip2 435 * 208 ---int0,en1 ip2 ----> this is wrong... this is watchdog 436 * 437 * 210 ---int0,en0 ip3 -- 438 * 218 ---int0,en1 ip3 ----> same here.. .this is watchdog... right? 439 * 440 * 220 ---int1,en0 ip2 441 * 228 ---int1,en1 ip2 442 * 230 ---int1,en0 ip3 -- 443 * 238 ---int1,en1 ip3 444 * 445 */ 446uint64_t 447ciu_get_en_reg_addr_new(int corenum, int intx, int enx, int ciu_ip) 448{ 449 uint64_t ciu_intr_reg_addr = OCTEON_CIU_ENABLE_BASE_ADDR; 450 451 /* XXX kasserts? */ 452 if (enx < CIU_EN_0 || enx > CIU_EN_1) { 453 printf("%s: invalid enx value %d, should be %d or %d\n", 454 __FUNCTION__, enx, CIU_EN_0, CIU_EN_1); 455 return 0; 456 } 457 if (intx < CIU_INT_0 || intx > CIU_INT_1) { 458 printf("%s: invalid intx value %d, should be %d or %d\n", 459 __FUNCTION__, enx, CIU_INT_0, CIU_INT_1); 460 return 0; 461 } 462 if (ciu_ip < CIU_MIPS_IP2 || ciu_ip > CIU_MIPS_IP3) { 463 printf("%s: invalid ciu_ip value %d, should be %d or %d\n", 464 __FUNCTION__, ciu_ip, CIU_MIPS_IP2, CIU_MIPS_IP3); 465 return 0; 466 } 467 468 ciu_intr_reg_addr += (enx * 0x8); 469 ciu_intr_reg_addr += (ciu_ip * 0x10); 470 ciu_intr_reg_addr += (intx * 0x20); 471 return (ciu_intr_reg_addr); 472} 473 474/* 475 * ciu_get_int_summary 476 */ 477uint64_t 478ciu_get_int_summary(int core_num, int intx, int enx) 479{ 480 uint64_t ciu_intr_sum_reg_addr; 481 482 if (core_num == CIU_THIS_CORE) 483 core_num = octeon_get_core_num(); 484 ciu_intr_sum_reg_addr = ciu_get_intr_sum_reg_addr(core_num, intx, enx); 485 return (oct_read64(ciu_intr_sum_reg_addr)); 486} 487 488//#define DEBUG_CIU 1 489 490#ifdef DEBUG_CIU 491#define DEBUG_CIU_SUM 1 492#define DEBUG_CIU_EN 1 493#endif 494 495 496/* 497 * ciu_clear_int_summary 498 */ 499void 500ciu_clear_int_summary(int core_num, int intx, int enx, uint64_t write_bits) 501{ 502 uint32_t cpu_status_bits; 503 uint64_t ciu_intr_sum_reg_addr; 504 505//#define DEBUG_CIU_SUM 1 506 507#ifdef DEBUG_CIU_SUM 508 uint64_t ciu_intr_sum_bits; 509#endif 510 511 512 if (core_num == CIU_THIS_CORE) { 513 core_num = octeon_get_core_num(); 514 } 515 516#ifdef DEBUG_CIU_SUM 517 printf(" CIU: core %u clear sum IntX %u Enx %u Bits: 0x%llX\n", 518 core_num, intx, enx, write_bits); 519#endif 520 521 cpu_status_bits = octeon_disable_interrupts(); 522 523 ciu_intr_sum_reg_addr = ciu_get_intr_sum_reg_addr(core_num, intx, enx); 524 525#ifdef DEBUG_CIU_SUM 526 ciu_intr_sum_bits = oct_read64(ciu_intr_sum_reg_addr); /* unneeded dummy read */ 527 printf(" CIU: status: 0x%X reg_addr: 0x%llX Val: 0x%llX -> 0x%llX", 528 cpu_status_bits, ciu_intr_sum_reg_addr, ciu_intr_sum_bits, 529 ciu_intr_sum_bits | write_bits); 530#endif 531 532 oct_write64(ciu_intr_sum_reg_addr, write_bits); 533 oct_read64(OCTEON_MIO_BOOT_BIST_STAT); /* Bus Barrier */ 534 535#ifdef DEBUG_CIU_SUM 536 printf(" Readback: 0x%llX\n\n ", (uint64_t) oct_read64(ciu_intr_sum_reg_addr)); 537#endif 538 539 octeon_set_interrupts(cpu_status_bits); 540} 541 542/* 543 * ciu_disable_intr 544 */ 545void 546ciu_disable_intr(int core_num, int intx, int enx) 547{ 548 uint32_t cpu_status_bits; 549 uint64_t ciu_intr_reg_addr; 550 551 if (core_num == CIU_THIS_CORE) 552 core_num = octeon_get_core_num(); 553 554 cpu_status_bits = octeon_disable_interrupts(); 555 556 ciu_intr_reg_addr = ciu_get_intr_en_reg_addr(core_num, intx, enx); 557 558 oct_read64(ciu_intr_reg_addr); /* Dummy read */ 559 560 oct_write64(ciu_intr_reg_addr, 0LL); 561 oct_read64(OCTEON_MIO_BOOT_BIST_STAT); /* Bus Barrier */ 562 563 octeon_set_interrupts(cpu_status_bits); 564} 565 566void 567ciu_dump_interrutps_enabled(int core_num, int intx, int enx, int ciu_ip) 568{ 569 570 uint64_t ciu_intr_reg_addr; 571 uint64_t ciu_intr_bits; 572 573 if (core_num == CIU_THIS_CORE) { 574 core_num = octeon_get_core_num(); 575 } 576 577#ifndef OCTEON_SMP_1 578 ciu_intr_reg_addr = ciu_get_intr_en_reg_addr(core_num, intx, enx); 579#else 580 ciu_intr_reg_addr = ciu_get_en_reg_addr_new(core_num, intx, enx, ciu_ip); 581#endif 582 583 if (!ciu_intr_reg_addr) { 584 printf("Bad call to %s\n", __FUNCTION__); 585 while(1); 586 return; 587 } 588 589 ciu_intr_bits = oct_read64(ciu_intr_reg_addr); 590 printf(" CIU core %d int: %d en: %d ip: %d Add: %#llx enabled: %#llx SR: %x\n", 591 core_num, intx, enx, ciu_ip, (unsigned long long)ciu_intr_reg_addr, 592 (unsigned long long)ciu_intr_bits, mips_rd_status()); 593} 594 595 596/* 597 * ciu_enable_interrupts 598 */ 599void ciu_enable_interrupts(int core_num, int intx, int enx, 600 uint64_t set_these_interrupt_bits, int ciu_ip) 601{ 602 uint32_t cpu_status_bits; 603 uint64_t ciu_intr_reg_addr; 604 uint64_t ciu_intr_bits; 605 606 if (core_num == CIU_THIS_CORE) 607 core_num = octeon_get_core_num(); 608 609//#define DEBUG_CIU_EN 1 610 611#ifdef DEBUG_CIU_EN 612 printf(" CIU: core %u enabling Intx %u Enx %u IP %d Bits: 0x%llX\n", 613 core_num, intx, enx, ciu_ip, set_these_interrupt_bits); 614#endif 615 616 cpu_status_bits = octeon_disable_interrupts(); 617 618#ifndef OCTEON_SMP_1 619 ciu_intr_reg_addr = ciu_get_intr_en_reg_addr(core_num, intx, enx); 620#else 621 ciu_intr_reg_addr = ciu_get_en_reg_addr_new(core_num, intx, enx, ciu_ip); 622#endif 623 624 if (!ciu_intr_reg_addr) { 625 printf("Bad call to %s\n", __FUNCTION__); 626 while(1); 627 return; /* XXX */ 628 } 629 630 ciu_intr_bits = oct_read64(ciu_intr_reg_addr); 631 632#ifdef DEBUG_CIU_EN 633 printf(" CIU: status: 0x%X reg_addr: 0x%llX Val: 0x%llX -> 0x%llX", 634 cpu_status_bits, ciu_intr_reg_addr, ciu_intr_bits, ciu_intr_bits | set_these_interrupt_bits); 635#endif 636 ciu_intr_bits |= set_these_interrupt_bits; 637 oct_write64(ciu_intr_reg_addr, ciu_intr_bits); 638#ifdef OCTEON_SMP 639 mips_wbflush(); 640#endif 641 oct_read64(OCTEON_MIO_BOOT_BIST_STAT); /* Bus Barrier */ 642 643#ifdef DEBUG_CIU_EN 644 printf(" Readback: 0x%llX\n\n ", 645 (uint64_t)oct_read64(ciu_intr_reg_addr)); 646#endif 647 648 octeon_set_interrupts(cpu_status_bits); 649} 650 651unsigned long 652octeon_get_clock_rate(void) 653{ 654 return octeon_cpu_clock; 655} 656 657static void 658octeon_memory_init(void) 659{ 660 uint32_t realmem_bytes; 661 662 if (octeon_board_real()) { 663 printf("octeon_dram == %llx\n", octeon_dram); 664 printf("reduced to ram: %u MB", (uint32_t) octeon_dram >> 20); 665 666 realmem_bytes = (octeon_dram - PAGE_SIZE); 667 realmem_bytes &= ~(PAGE_SIZE - 1); 668 printf("Real memory bytes is %x\n", realmem_bytes); 669 } else { 670 /* Simulator we limit to 96 meg */ 671 realmem_bytes = (96 << 20); 672 } 673 /* phys_avail regions are in bytes */ 674 phys_avail[0] = (MIPS_KSEG0_TO_PHYS((vm_offset_t)&end) + PAGE_SIZE) & ~(PAGE_SIZE - 1); 675 if (octeon_board_real()) { 676 if (realmem_bytes > OCTEON_DRAM_FIRST_256_END) 677 phys_avail[1] = OCTEON_DRAM_FIRST_256_END; 678 else 679 phys_avail[1] = realmem_bytes; 680 realmem_bytes -= OCTEON_DRAM_FIRST_256_END; 681 realmem_bytes &= ~(PAGE_SIZE - 1); 682 printf("phys_avail[0] = %x phys_avail[1] = %x\n", 683 phys_avail[0], phys_avail[1]); 684 } else { 685 /* Simulator gets 96Meg period. */ 686 phys_avail[1] = (96 << 20); 687 } 688 /*- 689 * Octeon Memory looks as follows: 690 * PA 691 * 0000 0000 to 0x0 0000 0000 0000 692 * 0FFF FFFF First 256 MB memory Maps to 0x0 0000 0FFF FFFF 693 * 694 * 1000 0000 to 0x1 0000 1000 0000 695 * 1FFF FFFF Uncached Bu I/O space.converted to 0x1 0000 1FFF FFFF 696 * 697 * 2FFF FFFF to Cached 0x0 0000 2000 0000 698 * FFFF FFFF all dram mem above the first 512M 0x3 FFFF FFFF FFFF 699 * 700 */ 701 physmem = btoc(phys_avail[1] - phys_avail[0]); 702 if ((octeon_board_real()) && 703 (realmem_bytes > OCTEON_DRAM_FIRST_256_END)) { 704 /* take out the upper non-cached 1/2 */ 705 realmem_bytes -= OCTEON_DRAM_FIRST_256_END; 706 realmem_bytes &= ~(PAGE_SIZE - 1); 707 /* Now map the rest of the memory */ 708 phys_avail[2] = 0x20000000; 709 printf("realmem_bytes is now at %x\n", realmem_bytes); 710 phys_avail[3] = ((uint32_t) 0x20000000 + realmem_bytes); 711 printf("Next block of memory goes from %x to %x\n", 712 phys_avail[2], phys_avail[3]); 713 physmem += btoc(phys_avail[3] - phys_avail[2]); 714 } else { 715 printf("realmem_bytes is %d\n", realmem_bytes); 716 } 717 realmem = physmem; 718 719 printf("\nTotal DRAM Size 0x%X", (uint32_t) octeon_dram); 720 printf("\nBank 0 = 0x%8X -> 0x%8X", phys_avail[0], phys_avail[1]); 721 printf("\nBank 1 = 0x%8X -> 0x%8X\n", phys_avail[2], phys_avail[3]); 722 printf("\nphysmem: 0x%lx", physmem); 723 724 Maxmem = physmem; 725 726} 727 728void 729platform_start(__register_t a0, __register_t a1, __register_t a2 __unused, 730 __register_t a3) 731{ 732 uint64_t platform_counter_freq; 733 734 /* Initialize pcpu stuff */ 735 mips_pcpu0_init(); 736 mips_timer_early_init(OCTEON_CLOCK_DEFAULT); 737 cninit(); 738 739 octeon_ciu_reset(); 740 octeon_boot_params_init(a3); 741 bootverbose = 1; 742 cpuid_to_pcpu[0] = &pcpu0; 743 744 /* 745 * For some reason on the cn38xx simulator ebase register is set to 746 * 0x80001000 at bootup time. Move it back to the default, but 747 * when we move to having support for multiple executives, we need 748 * to rethink this. 749 */ 750 mips_wr_ebase(0x80000000); 751 752 octeon_memory_init(); 753 init_param1(); 754 init_param2(physmem); 755 mips_cpu_init(); 756 pmap_bootstrap(); 757 mips_proc0_init(); 758 mutex_init(); 759 kdb_init(); 760#ifdef KDB 761 if (boothowto & RB_KDB) 762 kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); 763#endif 764 platform_counter_freq = octeon_get_clock_rate(); 765 mips_timer_init_params(platform_counter_freq, 1); 766} 767 768/* impSTART: This stuff should move back into the Cavium SDK */ 769/* 770 **************************************************************************************** 771 * 772 * APP/BOOT DESCRIPTOR STUFF 773 * 774 **************************************************************************************** 775 */ 776 777/* Define the struct that is initialized by the bootloader used by the 778 * startup code. 779 * 780 * Copyright (c) 2004, 2005, 2006 Cavium Networks. 781 * 782 * The authors hereby grant permission to use, copy, modify, distribute, 783 * and license this software and its documentation for any purpose, provided 784 * that existing copyright notices are retained in all copies and that this 785 * notice is included verbatim in any distributions. No written agreement, 786 * license, or royalty fee is required for any of the authorized uses. 787 * Modifications to this software may be copyrighted by their authors 788 * and need not follow the licensing terms described here, provided that 789 * the new terms are clearly indicated on the first page of each file where 790 * they apply. 791 */ 792 793#define OCTEON_CURRENT_DESC_VERSION 6 794#define OCTEON_ARGV_MAX_ARGS (64) 795#define OCTOEN_SERIAL_LEN 20 796 797 798typedef struct { 799 /* Start of block referenced by assembly code - do not change! */ 800 uint32_t desc_version; 801 uint32_t desc_size; 802 803 uint64_t stack_top; 804 uint64_t heap_base; 805 uint64_t heap_end; 806 uint64_t entry_point; /* Only used by bootloader */ 807 uint64_t desc_vaddr; 808 /* End of This block referenced by assembly code - do not change! */ 809 810 uint32_t exception_base_addr; 811 uint32_t stack_size; 812 uint32_t heap_size; 813 uint32_t argc; /* Argc count for application */ 814 uint32_t argv[OCTEON_ARGV_MAX_ARGS]; 815 uint32_t flags; 816 uint32_t core_mask; 817 uint32_t dram_size; /**< DRAM size in megabyes */ 818 uint32_t phy_mem_desc_addr; /**< physical address of free memory descriptor block*/ 819 uint32_t debugger_flags_base_addr; /**< used to pass flags from app to debugger */ 820 uint32_t eclock_hz; /**< CPU clock speed, in hz */ 821 uint32_t dclock_hz; /**< DRAM clock speed, in hz */ 822 uint32_t spi_clock_hz; /**< SPI4 clock in hz */ 823 uint16_t board_type; 824 uint8_t board_rev_major; 825 uint8_t board_rev_minor; 826 uint16_t chip_type; 827 uint8_t chip_rev_major; 828 uint8_t chip_rev_minor; 829 char board_serial_number[OCTOEN_SERIAL_LEN]; 830 uint8_t mac_addr_base[6]; 831 uint8_t mac_addr_count; 832 uint64_t cvmx_desc_vaddr; 833} octeon_boot_descriptor_t; 834 835 836typedef struct { 837 uint32_t major_version; 838 uint32_t minor_version; 839 840 uint64_t stack_top; 841 uint64_t heap_base; 842 uint64_t heap_end; 843 uint64_t desc_vaddr; 844 845 uint32_t exception_base_addr; 846 uint32_t stack_size; 847 uint32_t flags; 848 uint32_t core_mask; 849 uint32_t dram_size; /**< DRAM size in megabyes */ 850 uint32_t phy_mem_desc_addr; /**< physical address of free memory descriptor block*/ 851 uint32_t debugger_flags_base_addr; /**< used to pass flags from app to debugger */ 852 uint32_t eclock_hz; /**< CPU clock speed, in hz */ 853 uint32_t dclock_hz; /**< DRAM clock speed, in hz */ 854 uint32_t spi_clock_hz; /**< SPI4 clock in hz */ 855 uint16_t board_type; 856 uint8_t board_rev_major; 857 uint8_t board_rev_minor; 858 uint16_t chip_type; 859 uint8_t chip_rev_major; 860 uint8_t chip_rev_minor; 861 char board_serial_number[OCTOEN_SERIAL_LEN]; 862 uint8_t mac_addr_base[6]; 863 uint8_t mac_addr_count; 864} cvmx_bootinfo_t; 865 866uint32_t octeon_cpu_clock; 867uint64_t octeon_dram; 868uint32_t octeon_bd_ver = 0, octeon_cvmx_bd_ver = 0, octeon_board_rev_major, octeon_board_rev_minor, octeon_board_type; 869uint8_t octeon_mac_addr[6] = { 0 }; 870int octeon_core_mask, octeon_mac_addr_count; 871int octeon_chip_rev_major = 0, octeon_chip_rev_minor = 0, octeon_chip_type = 0; 872 873static octeon_boot_descriptor_t *app_desc_ptr; 874static cvmx_bootinfo_t *cvmx_desc_ptr; 875 876#define OCTEON_BOARD_TYPE_NONE 0 877#define OCTEON_BOARD_TYPE_SIM 1 878 879#define OCTEON_CLOCK_MIN (100 * 1000 * 1000) 880#define OCTEON_CLOCK_MAX (800 * 1000 * 1000) 881#define OCTEON_DRAM_DEFAULT (256 * 1024 * 1024) 882#define OCTEON_DRAM_MIN 30 883#define OCTEON_DRAM_MAX 3000 884 885 886int 887octeon_board_real(void) 888{ 889 if ((octeon_board_type == OCTEON_BOARD_TYPE_NONE) || 890 (octeon_board_type == OCTEON_BOARD_TYPE_SIM) || 891 !octeon_board_rev_major) 892 return 0; 893 return 1; 894} 895 896static void 897octeon_process_app_desc_ver_unknown(void) 898{ 899 printf(" Unknown Boot-Descriptor: Using Defaults\n"); 900 901 octeon_cpu_clock = OCTEON_CLOCK_DEFAULT; 902 octeon_dram = OCTEON_DRAM_DEFAULT; 903 octeon_board_rev_major = octeon_board_rev_minor = octeon_board_type = 0; 904 octeon_core_mask = 1; 905 octeon_chip_type = octeon_chip_rev_major = octeon_chip_rev_minor = 0; 906 octeon_mac_addr[0] = 0x00; octeon_mac_addr[1] = 0x0f; 907 octeon_mac_addr[2] = 0xb7; octeon_mac_addr[3] = 0x10; 908 octeon_mac_addr[4] = 0x09; octeon_mac_addr[5] = 0x06; 909 octeon_mac_addr_count = 1; 910} 911 912static int 913octeon_process_app_desc_ver_6(void) 914{ 915 /* XXX Why is 0x00000000ffffffffULL a bad value? */ 916 if (app_desc_ptr->cvmx_desc_vaddr == 0 || 917 app_desc_ptr->cvmx_desc_vaddr == 0xfffffffful) { 918 printf ("Bad cvmx_desc_ptr %p\n", cvmx_desc_ptr); 919 return 1; 920 } 921 cvmx_desc_ptr = 922 (cvmx_bootinfo_t *)(intptr_t)app_desc_ptr->cvmx_desc_vaddr; 923 cvmx_desc_ptr = 924 (cvmx_bootinfo_t *) ((intptr_t)cvmx_desc_ptr | MIPS_KSEG0_START); 925 octeon_cvmx_bd_ver = (cvmx_desc_ptr->major_version * 100) + 926 cvmx_desc_ptr->minor_version; 927 if (cvmx_desc_ptr->major_version != 1) { 928 panic("Incompatible CVMX descriptor from bootloader: %d.%d %p\n", 929 (int) cvmx_desc_ptr->major_version, 930 (int) cvmx_desc_ptr->minor_version, cvmx_desc_ptr); 931 } 932 933 octeon_core_mask = cvmx_desc_ptr->core_mask; 934 octeon_cpu_clock = cvmx_desc_ptr->eclock_hz; 935 octeon_board_type = cvmx_desc_ptr->board_type; 936 octeon_board_rev_major = cvmx_desc_ptr->board_rev_major; 937 octeon_board_rev_minor = cvmx_desc_ptr->board_rev_minor; 938 octeon_chip_type = cvmx_desc_ptr->chip_type; 939 octeon_chip_rev_major = cvmx_desc_ptr->chip_rev_major; 940 octeon_chip_rev_minor = cvmx_desc_ptr->chip_rev_minor; 941 octeon_mac_addr[0] = cvmx_desc_ptr->mac_addr_base[0]; 942 octeon_mac_addr[1] = cvmx_desc_ptr->mac_addr_base[1]; 943 octeon_mac_addr[2] = cvmx_desc_ptr->mac_addr_base[2]; 944 octeon_mac_addr[3] = cvmx_desc_ptr->mac_addr_base[3]; 945 octeon_mac_addr[4] = cvmx_desc_ptr->mac_addr_base[4]; 946 octeon_mac_addr[5] = cvmx_desc_ptr->mac_addr_base[5]; 947 octeon_mac_addr_count = cvmx_desc_ptr->mac_addr_count; 948 949 if (app_desc_ptr->dram_size > 16*1024*1024) 950 octeon_dram = (uint64_t)app_desc_ptr->dram_size; 951 else 952 octeon_dram = (uint64_t)app_desc_ptr->dram_size << 20; 953 return 0; 954} 955 956static void 957octeon_boot_params_init(register_t ptr) 958{ 959 int bad_desc = 1; 960 961 if (ptr != 0 && ptr < MAX_APP_DESC_ADDR) { 962 app_desc_ptr = (octeon_boot_descriptor_t *)(intptr_t)ptr; 963 octeon_bd_ver = app_desc_ptr->desc_version; 964 if (app_desc_ptr->desc_version < 6) 965 panic("Your boot code is too old to be supported.\n"); 966 if (app_desc_ptr->desc_version >= 6) 967 bad_desc = octeon_process_app_desc_ver_6(); 968 } 969 if (bad_desc) 970 octeon_process_app_desc_ver_unknown(); 971 972 printf("Boot Descriptor Ver: %u -> %u/%u", 973 octeon_bd_ver, octeon_cvmx_bd_ver/100, octeon_cvmx_bd_ver%100); 974 printf(" CPU clock: %uMHz\n", octeon_cpu_clock/1000000); 975 printf(" Dram: %u MB", (uint32_t)(octeon_dram >> 20)); 976 printf(" Board Type: %u Revision: %u/%u\n", 977 octeon_board_type, octeon_board_rev_major, octeon_board_rev_minor); 978 printf(" Octeon Chip: %u Rev %u/%u", 979 octeon_chip_type, octeon_chip_rev_major, octeon_chip_rev_minor); 980 981 printf(" Mac Address %02X.%02X.%02X.%02X.%02X.%02X (%d)\n", 982 octeon_mac_addr[0], octeon_mac_addr[1], octeon_mac_addr[2], 983 octeon_mac_addr[3], octeon_mac_addr[4], octeon_mac_addr[5], 984 octeon_mac_addr_count); 985} 986/* impEND: This stuff should move back into the Cavium SDK */ 987