octeon_machdep.c revision 201881
1194140Simp/*- 2194140Simp * Copyright (c) 2006 Wojciech A. Koszek <wkoszek@FreeBSD.org> 3194140Simp * All rights reserved. 4194140Simp * 5194140Simp * Redistribution and use in source and binary forms, with or without 6194140Simp * modification, are permitted provided that the following conditions 7194140Simp * are met: 8194140Simp * 1. Redistributions of source code must retain the above copyright 9194140Simp * notice, this list of conditions and the following disclaimer. 10194140Simp * 2. Redistributions in binary form must reproduce the above copyright 11194140Simp * notice, this list of conditions and the following disclaimer in the 12194140Simp * documentation and/or other materials provided with the distribution. 13194140Simp * 14194140Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15194140Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16194140Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17194140Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18194140Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19194140Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20194140Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21194140Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22194140Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23194140Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24194140Simp * SUCH DAMAGE. 25194140Simp * 26194140Simp * $FreeBSD: projects/mips/sys/mips/octeon1/octeon_machdep.c 201881 2010-01-09 03:08:22Z imp $ 27194140Simp */ 28194140Simp#include <sys/cdefs.h> 29194140Simp__FBSDID("$FreeBSD: projects/mips/sys/mips/octeon1/octeon_machdep.c 201881 2010-01-09 03:08:22Z imp $"); 30194140Simp 31194140Simp#include <sys/param.h> 32196262Simp#include <sys/conf.h> 33196262Simp#include <sys/kernel.h> 34194140Simp#include <sys/systm.h> 35196262Simp#include <sys/imgact.h> 36196262Simp#include <sys/bio.h> 37196262Simp#include <sys/buf.h> 38196262Simp#include <sys/bus.h> 39196262Simp#include <sys/cpu.h> 40196262Simp#include <sys/cons.h> 41196262Simp#include <sys/exec.h> 42196262Simp#include <sys/ucontext.h> 43196262Simp#include <sys/proc.h> 44196262Simp#include <sys/kdb.h> 45196262Simp#include <sys/ptrace.h> 46196262Simp#include <sys/reboot.h> 47196262Simp#include <sys/signalvar.h> 48196262Simp#include <sys/sysent.h> 49196262Simp#include <sys/sysproto.h> 50196262Simp#include <sys/user.h> 51196262Simp 52196262Simp#include <vm/vm.h> 53196262Simp#include <vm/vm_object.h> 54196262Simp#include <vm/vm_page.h> 55196262Simp#include <vm/vm_pager.h> 56196262Simp 57196262Simp#include <machine/atomic.h> 58196262Simp#include <machine/cache.h> 59196262Simp#include <machine/clock.h> 60196262Simp#include <machine/cpu.h> 61194140Simp#include <machine/cpuregs.h> 62194140Simp#include <machine/cpufunc.h> 63194174Simp#include <mips/octeon1/octeon_pcmap_regs.h> 64194155Simp#include <mips/octeon1/octeonreg.h> 65196262Simp#include <machine/hwfunc.h> 66196262Simp#include <machine/intr_machdep.h> 67196262Simp#include <machine/locore.h> 68196262Simp#include <machine/md_var.h> 69194140Simp#include <machine/pcpu.h> 70196262Simp#include <machine/pte.h> 71196262Simp#include <machine/trap.h> 72196262Simp#include <machine/vmparam.h> 73194140Simp 74194140Simp#if defined(__mips_n64) 75196262Simp#define MAX_APP_DESC_ADDR 0xffffffffafffffff 76194140Simp#else 77196262Simp#define MAX_APP_DESC_ADDR 0xafffffff 78194140Simp#endif 79194140Simp 80196262Simpextern int *edata; 81196262Simpextern int *end; 82194140Simp 83201530Simpuint64_t ciu_get_en_reg_addr_new(int corenum, int intx, int enx, int ciu_ip); 84201530Simpvoid ciu_dump_interrutps_enabled(int core_num, int intx, int enx, int ciu_ip); 85201530Simp 86200344Simpstatic void octeon_boot_params_init(register_t ptr); 87201530Simpstatic uint64_t ciu_get_intr_sum_reg_addr(int core_num, int intx, int enx); 88201530Simpstatic uint64_t ciu_get_intr_en_reg_addr(int core_num, int intx, int enx); 89200344Simp 90198669Srrsvoid 91198669Srrsplatform_cpu_init() 92198669Srrs{ 93198669Srrs /* Nothing special yet */ 94198669Srrs} 95196262Simp 96194140Simp/* 97194140Simp * Perform a board-level soft-reset. 98194140Simp */ 99196314Simpvoid 100196314Simpplatform_reset(void) 101194140Simp{ 102196314Simp ((void(*)(void))0x1fc00000)(); /* Jump to this hex address */ 103194140Simp} 104194140Simp 105194140Simp 106201530Simpstatic inline uint32_t 107201530Simpocteon_disable_interrupts(void) 108194140Simp{ 109201530Simp uint32_t status_bits; 110194140Simp 111201530Simp status_bits = mips_rd_status(); 112201530Simp mips_wr_status(status_bits & ~MIPS_SR_INT_IE); 113201530Simp return (status_bits); 114194140Simp} 115194140Simp 116194140Simp 117201530Simpstatic inline void 118201530Simpocteon_set_interrupts(uint32_t status_bits) 119194140Simp{ 120201530Simp mips_wr_status(status_bits); 121194140Simp} 122194140Simp 123194140Simp 124201530Simpvoid 125201530Simpocteon_led_write_char(int char_position, char val) 126194140Simp{ 127201530Simp uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8); 128194140Simp 129201530Simp if (!octeon_board_real()) 130201530Simp return; 131194140Simp 132201530Simp char_position &= 0x7; /* only 8 chars */ 133201530Simp ptr += char_position; 134201530Simp oct_write8_x8(ptr, val); 135194140Simp} 136194140Simp 137201530Simpvoid 138201530Simpocteon_led_write_char0(char val) 139194140Simp{ 140201530Simp uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8); 141194140Simp 142201530Simp if (!octeon_board_real()) 143201530Simp return; 144201530Simp oct_write8_x8(ptr, val); 145194140Simp} 146194140Simp 147201530Simpvoid 148201530Simpocteon_led_write_hexchar(int char_position, char hexval) 149194140Simp{ 150201530Simp uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8); 151201530Simp char char1, char2; 152194140Simp 153201530Simp if (!octeon_board_real()) 154201530Simp return; 155194140Simp 156201530Simp char1 = (hexval >> 4) & 0x0f; char1 = (char1 < 10)?char1+'0':char1+'7'; 157201530Simp char2 = (hexval & 0x0f); char2 = (char2 < 10)?char2+'0':char2+'7'; 158201530Simp char_position &= 0x7; /* only 8 chars */ 159201530Simp if (char_position > 6) 160201530Simp char_position = 6; 161201530Simp ptr += char_position; 162201530Simp oct_write8_x8(ptr, char1); 163201530Simp ptr++; 164201530Simp oct_write8_x8(ptr, char2); 165194140Simp} 166194140Simp 167201530Simpvoid 168201530Simpocteon_led_write_string(const char *str) 169194140Simp{ 170201530Simp uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8); 171201530Simp int i; 172194140Simp 173201530Simp if (!octeon_board_real()) 174201530Simp return; 175194140Simp 176201530Simp for (i=0; i<8; i++, ptr++) { 177201530Simp if (str && *str) 178201530Simp oct_write8_x8(ptr, *str++); 179201530Simp else 180201530Simp oct_write8_x8(ptr, ' '); 181201530Simp oct_read64(OCTEON_MIO_BOOT_BIST_STAT); 182201530Simp } 183194140Simp} 184194140Simp 185194140Simpstatic char progress[8] = { '-', '/', '|', '\\', '-', '/', '|', '\\'}; 186194140Simp 187201530Simpvoid 188201530Simpocteon_led_run_wheel(int *prog_count, int led_position) 189194140Simp{ 190201530Simp if (!octeon_board_real()) 191201530Simp return; 192201530Simp octeon_led_write_char(led_position, progress[*prog_count]); 193201530Simp *prog_count += 1; 194201530Simp *prog_count &= 0x7; 195194140Simp} 196194140Simp 197194140Simp#define LSR_DATAREADY 0x01 /* Data ready */ 198194140Simp#define LSR_THRE 0x20 /* Transmit holding register empty */ 199194140Simp#define LSR_TEMT 0x40 /* Transmitter Empty. THR, TSR & FIFO */ 200194140Simp#define USR_TXFIFO_NOTFULL 0x02 /* Uart TX FIFO Not full */ 201194140Simp 202194140Simp/* 203194140Simp * octeon_uart_write_byte 204194140Simp * 205194140Simp * Put out a single byte off of uart port. 206194140Simp */ 207194140Simp 208201530Simpvoid 209201530Simpocteon_uart_write_byte(int uart_index, uint8_t ch) 210194140Simp{ 211201530Simp uint64_t val, val2; 212201530Simp if (uart_index < 0 || uart_index > 1) 213201530Simp return; 214194140Simp 215201530Simp while (1) { 216201530Simp val = oct_read64(OCTEON_MIO_UART0_LSR + (uart_index * 0x400)); 217201530Simp val2 = oct_read64(OCTEON_MIO_UART0_USR + (uart_index * 0x400)); 218201530Simp if ((((uint8_t) val) & LSR_THRE) || 219201530Simp (((uint8_t) val2) & USR_TXFIFO_NOTFULL)) { 220201530Simp break; 221201530Simp } 222201530Simp } 223194140Simp 224201530Simp /* Write the byte */ 225201530Simp oct_write8(OCTEON_MIO_UART0_THR + (uart_index * 0x400), (uint64_t) ch); 226194140Simp 227201530Simp /* Force Flush the IOBus */ 228201530Simp oct_read64(OCTEON_MIO_BOOT_BIST_STAT); 229194140Simp} 230194140Simp 231194140Simp 232201530Simpvoid 233201530Simpocteon_uart_write_byte0(uint8_t ch) 234194140Simp{ 235201530Simp uint64_t val, val2; 236194140Simp 237201530Simp while (1) { 238201530Simp val = oct_read64(OCTEON_MIO_UART0_LSR); 239201530Simp val2 = oct_read64(OCTEON_MIO_UART0_USR); 240201530Simp if ((((uint8_t) val) & LSR_THRE) || 241201530Simp (((uint8_t) val2) & USR_TXFIFO_NOTFULL)) { 242201530Simp break; 243201530Simp } 244201530Simp } 245194140Simp 246201530Simp /* Write the byte */ 247201530Simp oct_write8(OCTEON_MIO_UART0_THR, (uint64_t) ch); 248194140Simp 249201530Simp /* Force Flush the IOBus */ 250201530Simp oct_read64(OCTEON_MIO_BOOT_BIST_STAT); 251194140Simp} 252194140Simp 253194140Simp/* 254194140Simp * octeon_uart_write_string 255194140Simp * 256194140Simp */ 257201530Simpvoid 258201530Simpocteon_uart_write_string(int uart_index, const char *str) 259194140Simp{ 260201530Simp /* Just loop writing one byte at a time */ 261194140Simp 262201530Simp while (*str) { 263201530Simp octeon_uart_write_byte(uart_index, *str); 264201530Simp if (*str == '\n') { 265201530Simp octeon_uart_write_byte(uart_index, '\r'); 266201530Simp } 267201530Simp str++; 268201530Simp } 269201530Simp} 270194140Simp 271194140Simpstatic char wstr[30]; 272194140Simp 273201530Simpvoid 274201530Simpocteon_led_write_hex(uint32_t wl) 275194140Simp{ 276201530Simp char nbuf[80]; 277194140Simp 278201530Simp sprintf(nbuf, "%X", wl); 279201530Simp octeon_led_write_string(nbuf); 280194140Simp} 281194140Simp 282194140Simp 283201530Simpvoid octeon_uart_write_hex2(uint32_t wl, uint32_t wh) 284194140Simp{ 285201530Simp sprintf(wstr, "0x%X-0x%X ", wh, wl); 286201530Simp octeon_uart_write_string(0, wstr); 287194140Simp} 288194140Simp 289201530Simpvoid 290201530Simpocteon_uart_write_hex(uint32_t wl) 291194140Simp{ 292201530Simp sprintf(wstr, " 0x%X ", wl); 293201530Simp octeon_uart_write_string(0, wstr); 294194140Simp} 295194140Simp 296194140Simp/* 297194140Simp * octeon_wait_uart_flush 298194140Simp */ 299201530Simpvoid 300201530Simpocteon_wait_uart_flush(int uart_index, uint8_t ch) 301194140Simp{ 302201530Simp uint64_t val; 303201530Simp int64_t val3; 304201530Simp uint32_t cpu_status_bits; 305194140Simp 306201530Simp if (uart_index < 0 || uart_index > 1) 307201530Simp return; 308194140Simp 309201530Simp cpu_status_bits = octeon_disable_interrupts(); 310201530Simp /* Force Flush the IOBus */ 311201530Simp oct_read64(OCTEON_MIO_BOOT_BIST_STAT); 312201530Simp for (val3 = 0xfffffffff; val3 > 0; val3--) { 313201530Simp val = oct_read64(OCTEON_MIO_UART0_LSR + (uart_index * 0x400)); 314201530Simp if (((uint8_t) val) & LSR_TEMT) 315201530Simp break; 316201530Simp } 317201530Simp octeon_set_interrupts(cpu_status_bits); 318194140Simp} 319194140Simp 320194140Simp 321194140Simp/* 322194140Simp * octeon_debug_symbol 323194140Simp * 324194140Simp * Does nothing. 325194140Simp * Used to mark the point for simulator to begin tracing 326194140Simp */ 327201530Simpvoid 328201530Simpocteon_debug_symbol(void) 329194140Simp{ 330194140Simp} 331194140Simp 332201530Simpvoid 333201530Simpocteon_ciu_stop_gtimer(int timer) 334194140Simp{ 335201530Simp oct_write64(OCTEON_CIU_GENTIMER_ADDR(timer), 0ll); 336194140Simp} 337194140Simp 338201530Simpvoid 339201530Simpocteon_ciu_start_gtimer(int timer, u_int one_shot, uint64_t time_cycles) 340194140Simp{ 341194140Simp octeon_ciu_gentimer gentimer; 342194140Simp 343194140Simp gentimer.word64 = 0; 344194140Simp gentimer.bits.one_shot = one_shot; 345194140Simp gentimer.bits.len = time_cycles - 1; 346194140Simp oct_write64(OCTEON_CIU_GENTIMER_ADDR(timer), gentimer.word64); 347194140Simp} 348194140Simp 349194140Simp/* 350194140Simp * octeon_ciu_reset 351194140Simp * 352194140Simp * Shutdown all CIU to IP2, IP3 mappings 353194140Simp */ 354201530Simpvoid 355201530Simpocteon_ciu_reset(void) 356194140Simp{ 357194140Simp 358201530Simp octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_0); 359201530Simp octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_1); 360201530Simp octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_2); 361201530Simp octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_3); 362194140Simp 363201530Simp ciu_disable_intr(CIU_THIS_CORE, CIU_INT_0, CIU_EN_0); 364201530Simp ciu_disable_intr(CIU_THIS_CORE, CIU_INT_0, CIU_EN_1); 365201530Simp ciu_disable_intr(CIU_THIS_CORE, CIU_INT_1, CIU_EN_0); 366201530Simp ciu_disable_intr(CIU_THIS_CORE, CIU_INT_1, CIU_EN_1); 367194140Simp 368201530Simp ciu_clear_int_summary(CIU_THIS_CORE, CIU_INT_0, CIU_EN_0, 0ll); 369201530Simp ciu_clear_int_summary(CIU_THIS_CORE, CIU_INT_1, CIU_EN_0, 0ll); 370201530Simp ciu_clear_int_summary(CIU_THIS_CORE, CIU_INT_1, CIU_EN_1, 0ll); 371194140Simp} 372194140Simp 373194140Simp/* 374194140Simp * mips_disable_interrupt_controllers 375194140Simp * 376194140Simp * Disable interrupts in the CPU controller 377194140Simp */ 378201530Simpvoid 379201530Simpmips_disable_interrupt_controls(void) 380194140Simp{ 381201530Simp /* 382201530Simp * Disable interrupts in CIU. 383201530Simp */ 384201530Simp octeon_ciu_reset(); 385194140Simp} 386194140Simp 387194140Simp/* 388194140Simp * ciu_get_intr_sum_reg_addr 389194140Simp */ 390201530Simpstatic uint64_t 391201530Simpciu_get_intr_sum_reg_addr(int core_num, int intx, int enx) 392194140Simp{ 393201530Simp uint64_t ciu_intr_sum_reg_addr; 394194140Simp 395201530Simp if (enx == CIU_EN_0) 396201530Simp ciu_intr_sum_reg_addr = OCTEON_CIU_SUMMARY_BASE_ADDR + 397201530Simp (core_num * 0x10) + (intx * 0x8); 398201530Simp else 399194140Simp ciu_intr_sum_reg_addr = OCTEON_CIU_SUMMARY_INT1_ADDR; 400194140Simp 401194140Simp return (ciu_intr_sum_reg_addr); 402194140Simp} 403194140Simp 404194140Simp 405194140Simp/* 406194140Simp * ciu_get_intr_en_reg_addr 407194140Simp */ 408201530Simpstatic uint64_t 409201530Simpciu_get_intr_en_reg_addr(int core_num, int intx, int enx) 410194140Simp{ 411201530Simp uint64_t ciu_intr_reg_addr; 412194140Simp 413201530Simp ciu_intr_reg_addr = OCTEON_CIU_ENABLE_BASE_ADDR + 414201530Simp ((enx == 0) ? 0x0 : 0x8) + (intx * 0x10) + (core_num * 0x20); 415194140Simp return (ciu_intr_reg_addr); 416194140Simp} 417194140Simp 418194140Simp 419194140Simp 420194140Simp 421194140Simp/* 422194140Simp * ciu_get_intr_reg_addr 423194140Simp * 424194140Simp * 200 ---int0,en0 ip2 425194140Simp * 208 ---int0,en1 ip2 ----> this is wrong... this is watchdog 426194140Simp * 427194140Simp * 210 ---int0,en0 ip3 -- 428194140Simp * 218 ---int0,en1 ip3 ----> same here.. .this is watchdog... right? 429194140Simp * 430194140Simp * 220 ---int1,en0 ip2 431194140Simp * 228 ---int1,en1 ip2 432194140Simp * 230 ---int1,en0 ip3 -- 433194140Simp * 238 ---int1,en1 ip3 434194140Simp * 435194140Simp */ 436201530Simpuint64_t 437201530Simpciu_get_en_reg_addr_new(int corenum, int intx, int enx, int ciu_ip) 438194140Simp{ 439201530Simp uint64_t ciu_intr_reg_addr = OCTEON_CIU_ENABLE_BASE_ADDR; 440194140Simp 441201530Simp /* XXX kasserts? */ 442201530Simp if (enx < CIU_EN_0 || enx > CIU_EN_1) { 443201530Simp printf("%s: invalid enx value %d, should be %d or %d\n", 444201530Simp __FUNCTION__, enx, CIU_EN_0, CIU_EN_1); 445201530Simp return 0; 446201530Simp } 447201530Simp if (intx < CIU_INT_0 || intx > CIU_INT_1) { 448201530Simp printf("%s: invalid intx value %d, should be %d or %d\n", 449201530Simp __FUNCTION__, enx, CIU_INT_0, CIU_INT_1); 450201530Simp return 0; 451201530Simp } 452201530Simp if (ciu_ip < CIU_MIPS_IP2 || ciu_ip > CIU_MIPS_IP3) { 453201530Simp printf("%s: invalid ciu_ip value %d, should be %d or %d\n", 454201530Simp __FUNCTION__, ciu_ip, CIU_MIPS_IP2, CIU_MIPS_IP3); 455201530Simp return 0; 456201530Simp } 457194140Simp 458201530Simp ciu_intr_reg_addr += (enx * 0x8); 459201530Simp ciu_intr_reg_addr += (ciu_ip * 0x10); 460201530Simp ciu_intr_reg_addr += (intx * 0x20); 461201530Simp return (ciu_intr_reg_addr); 462194140Simp} 463194140Simp 464194140Simp/* 465194140Simp * ciu_get_int_summary 466194140Simp */ 467201530Simpuint64_t 468201530Simpciu_get_int_summary(int core_num, int intx, int enx) 469194140Simp{ 470201530Simp uint64_t ciu_intr_sum_reg_addr; 471194140Simp 472201530Simp if (core_num == CIU_THIS_CORE) 473194140Simp core_num = octeon_get_core_num(); 474201530Simp ciu_intr_sum_reg_addr = ciu_get_intr_sum_reg_addr(core_num, intx, enx); 475201530Simp return (oct_read64(ciu_intr_sum_reg_addr)); 476194140Simp} 477194140Simp 478194140Simp//#define DEBUG_CIU 1 479194140Simp 480194140Simp#ifdef DEBUG_CIU 481194140Simp#define DEBUG_CIU_SUM 1 482194140Simp#define DEBUG_CIU_EN 1 483194140Simp#endif 484194140Simp 485194140Simp 486194140Simp/* 487194140Simp * ciu_clear_int_summary 488194140Simp */ 489201530Simpvoid 490201530Simpciu_clear_int_summary(int core_num, int intx, int enx, uint64_t write_bits) 491194140Simp{ 492201530Simp uint32_t cpu_status_bits; 493201530Simp uint64_t ciu_intr_sum_reg_addr; 494194140Simp 495194140Simp//#define DEBUG_CIU_SUM 1 496194140Simp 497194140Simp#ifdef DEBUG_CIU_SUM 498201530Simp uint64_t ciu_intr_sum_bits; 499194140Simp#endif 500194140Simp 501194140Simp 502201530Simp if (core_num == CIU_THIS_CORE) { 503194140Simp core_num = octeon_get_core_num(); 504201530Simp } 505194140Simp 506194140Simp#ifdef DEBUG_CIU_SUM 507194140Simp printf(" CIU: core %u clear sum IntX %u Enx %u Bits: 0x%llX\n", 508201530Simp core_num, intx, enx, write_bits); 509194140Simp#endif 510194140Simp 511201530Simp cpu_status_bits = octeon_disable_interrupts(); 512194140Simp 513201530Simp ciu_intr_sum_reg_addr = ciu_get_intr_sum_reg_addr(core_num, intx, enx); 514194140Simp 515194140Simp#ifdef DEBUG_CIU_SUM 516194140Simp ciu_intr_sum_bits = oct_read64(ciu_intr_sum_reg_addr); /* unneeded dummy read */ 517194140Simp printf(" CIU: status: 0x%X reg_addr: 0x%llX Val: 0x%llX -> 0x%llX", 518201530Simp cpu_status_bits, ciu_intr_sum_reg_addr, ciu_intr_sum_bits, 519201530Simp ciu_intr_sum_bits | write_bits); 520194140Simp#endif 521194140Simp 522201530Simp oct_write64(ciu_intr_sum_reg_addr, write_bits); 523201530Simp oct_read64(OCTEON_MIO_BOOT_BIST_STAT); /* Bus Barrier */ 524194140Simp 525194140Simp#ifdef DEBUG_CIU_SUM 526194140Simp printf(" Readback: 0x%llX\n\n ", (uint64_t) oct_read64(ciu_intr_sum_reg_addr)); 527194140Simp#endif 528194140Simp 529201530Simp octeon_set_interrupts(cpu_status_bits); 530194140Simp} 531194140Simp 532194140Simp/* 533194140Simp * ciu_disable_intr 534194140Simp */ 535201530Simpvoid 536201530Simpciu_disable_intr(int core_num, int intx, int enx) 537194140Simp{ 538201530Simp uint32_t cpu_status_bits; 539201530Simp uint64_t ciu_intr_reg_addr; 540194140Simp 541201530Simp if (core_num == CIU_THIS_CORE) 542194140Simp core_num = octeon_get_core_num(); 543194140Simp 544201530Simp cpu_status_bits = octeon_disable_interrupts(); 545194140Simp 546201530Simp ciu_intr_reg_addr = ciu_get_intr_en_reg_addr(core_num, intx, enx); 547194140Simp 548201530Simp oct_read64(ciu_intr_reg_addr); /* Dummy read */ 549194140Simp 550201530Simp oct_write64(ciu_intr_reg_addr, 0LL); 551201530Simp oct_read64(OCTEON_MIO_BOOT_BIST_STAT); /* Bus Barrier */ 552194140Simp 553201530Simp octeon_set_interrupts(cpu_status_bits); 554194140Simp} 555194140Simp 556201530Simpvoid 557201530Simpciu_dump_interrutps_enabled(int core_num, int intx, int enx, int ciu_ip) 558194140Simp{ 559194140Simp 560194140Simp uint64_t ciu_intr_reg_addr; 561194140Simp uint64_t ciu_intr_bits; 562194140Simp 563194140Simp if (core_num == CIU_THIS_CORE) { 564194140Simp core_num = octeon_get_core_num(); 565194140Simp } 566194140Simp 567194140Simp#ifndef OCTEON_SMP_1 568194140Simp ciu_intr_reg_addr = ciu_get_intr_en_reg_addr(core_num, intx, enx); 569194140Simp#else 570194140Simp ciu_intr_reg_addr = ciu_get_en_reg_addr_new(core_num, intx, enx, ciu_ip); 571194140Simp#endif 572194140Simp 573194140Simp if (!ciu_intr_reg_addr) { 574194140Simp printf("Bad call to %s\n", __FUNCTION__); 575194140Simp while(1); 576194140Simp return; 577194140Simp } 578194140Simp 579194140Simp ciu_intr_bits = oct_read64(ciu_intr_reg_addr); 580199593Simp printf(" CIU core %d int: %d en: %d ip: %d Add: %#llx enabled: %#llx SR: %x\n", 581199593Simp core_num, intx, enx, ciu_ip, (unsigned long long)ciu_intr_reg_addr, 582195414Simp (unsigned long long)ciu_intr_bits, mips_rd_status()); 583194140Simp} 584194140Simp 585194140Simp 586194140Simp/* 587194140Simp * ciu_enable_interrupts 588194140Simp */ 589201530Simpvoid ciu_enable_interrupts(int core_num, int intx, int enx, 590201530Simp uint64_t set_these_interrupt_bits, int ciu_ip) 591194140Simp{ 592194140Simp uint32_t cpu_status_bits; 593194140Simp uint64_t ciu_intr_reg_addr; 594194140Simp uint64_t ciu_intr_bits; 595194140Simp 596201530Simp if (core_num == CIU_THIS_CORE) 597194140Simp core_num = octeon_get_core_num(); 598194140Simp 599194140Simp//#define DEBUG_CIU_EN 1 600194140Simp 601194140Simp#ifdef DEBUG_CIU_EN 602194140Simp printf(" CIU: core %u enabling Intx %u Enx %u IP %d Bits: 0x%llX\n", 603201530Simp core_num, intx, enx, ciu_ip, set_these_interrupt_bits); 604194140Simp#endif 605194140Simp 606194140Simp cpu_status_bits = octeon_disable_interrupts(); 607194140Simp 608194140Simp#ifndef OCTEON_SMP_1 609194140Simp ciu_intr_reg_addr = ciu_get_intr_en_reg_addr(core_num, intx, enx); 610194140Simp#else 611194140Simp ciu_intr_reg_addr = ciu_get_en_reg_addr_new(core_num, intx, enx, ciu_ip); 612194140Simp#endif 613194140Simp 614194140Simp if (!ciu_intr_reg_addr) { 615201530Simp printf("Bad call to %s\n", __FUNCTION__); 616201530Simp while(1); 617201530Simp return; /* XXX */ 618194140Simp } 619194140Simp 620194140Simp ciu_intr_bits = oct_read64(ciu_intr_reg_addr); 621194140Simp 622194140Simp#ifdef DEBUG_CIU_EN 623194140Simp printf(" CIU: status: 0x%X reg_addr: 0x%llX Val: 0x%llX -> 0x%llX", 624201530Simp cpu_status_bits, ciu_intr_reg_addr, ciu_intr_bits, ciu_intr_bits | set_these_interrupt_bits); 625194140Simp#endif 626194140Simp ciu_intr_bits |= set_these_interrupt_bits; 627194140Simp oct_write64(ciu_intr_reg_addr, ciu_intr_bits); 628194140Simp#ifdef OCTEON_SMP 629194140Simp mips_wbflush(); 630194140Simp#endif 631194140Simp oct_read64(OCTEON_MIO_BOOT_BIST_STAT); /* Bus Barrier */ 632194140Simp 633194140Simp#ifdef DEBUG_CIU_EN 634201530Simp printf(" Readback: 0x%llX\n\n ", 635201530Simp (uint64_t)oct_read64(ciu_intr_reg_addr)); 636194140Simp#endif 637194140Simp 638194140Simp octeon_set_interrupts(cpu_status_bits); 639194140Simp} 640194140Simp 641196262Simpvoid 642201530Simpplatform_start(__register_t a0, __register_t a1, __register_t a2 __unused, 643201530Simp __register_t a3) 644196262Simp{ 645196262Simp uint64_t platform_counter_freq; 646196262Simp vm_offset_t kernend; 647196262Simp int argc = a0; 648196262Simp char **argv = (char **)a1; 649196262Simp int i, mem; 650194140Simp 651196262Simp /* clear the BSS and SBSS segments */ 652196262Simp kernend = round_page((vm_offset_t)&end); 653196262Simp memset(&edata, 0, kernend - (vm_offset_t)(&edata)); 654194140Simp 655201845Simp /* Initialize pcpu stuff */ 656201881Simp mips_pcpu0_init(); 657201845Simp 658200344Simp octeon_boot_params_init(a3); 659200344Simp /* XXX octeon boot decriptor has args in it... */ 660194140Simp octeon_ciu_reset(); 661199740Simp octeon_uart_write_string(0, "Platform Starting\n"); 662194140Simp 663196262Simp /* 664196262Simp * Looking for mem=XXM argument 665196262Simp */ 666196262Simp mem = 0; /* Just something to start with */ 667196262Simp for (i=0; i < argc; i++) { 668196262Simp if (strncmp(argv[i], "mem=", 4) == 0) { 669196262Simp mem = strtol(argv[i] + 4, NULL, 0); 670196262Simp break; 671196262Simp } 672196262Simp } 673194140Simp 674196262Simp bootverbose = 1; 675196262Simp if (mem > 0) 676196262Simp realmem = btoc(mem << 20); 677196262Simp else 678196262Simp realmem = btoc(32 << 20); 679194140Simp 680200344Simp for (i = 0; i < 10; i++) 681196262Simp phys_avail[i] = 0; 682196262Simp 683196262Simp /* phys_avail regions are in bytes */ 684196262Simp phys_avail[0] = MIPS_KSEG0_TO_PHYS((vm_offset_t)&end); 685196262Simp phys_avail[1] = ctob(realmem); 686196262Simp 687196262Simp physmem = realmem; 688196262Simp 689200344Simp pmap_bootstrap(); 690200344Simp mips_proc0_init(); 691200344Simp 692196262Simp init_param1(); 693196262Simp /* TODO: parse argc,argv */ 694196262Simp platform_counter_freq = 330000000UL; /* XXX: from idt */ 695196262Simp mips_timer_init_params(platform_counter_freq, 1); 696196262Simp cninit(); 697196262Simp printf("cmd line: "); 698196262Simp for (i=0; i < argc; i++) 699196262Simp printf("%s ", argv[i]); 700196262Simp printf("\n"); 701196262Simp init_param2(physmem); 702196262Simp mips_cpu_init(); 703196262Simp mutex_init(); 704196262Simp#ifdef DDB 705196262Simp kdb_init(); 706196262Simp#endif 707196262Simp} 708196262Simp 709194140Simp/* 710194140Simp **************************************************************************************** 711194140Simp * 712194140Simp * APP/BOOT DESCRIPTOR STUFF 713194140Simp * 714194140Simp **************************************************************************************** 715194140Simp */ 716194140Simp 717194140Simp/* Define the struct that is initialized by the bootloader used by the 718194140Simp * startup code. 719194140Simp * 720194140Simp * Copyright (c) 2004, 2005, 2006 Cavium Networks. 721194140Simp * 722194140Simp * The authors hereby grant permission to use, copy, modify, distribute, 723194140Simp * and license this software and its documentation for any purpose, provided 724194140Simp * that existing copyright notices are retained in all copies and that this 725194140Simp * notice is included verbatim in any distributions. No written agreement, 726194140Simp * license, or royalty fee is required for any of the authorized uses. 727194140Simp * Modifications to this software may be copyrighted by their authors 728194140Simp * and need not follow the licensing terms described here, provided that 729194140Simp * the new terms are clearly indicated on the first page of each file where 730194140Simp * they apply. 731194140Simp */ 732194140Simp 733194140Simp#define OCTEON_CURRENT_DESC_VERSION 6 734194140Simp#define OCTEON_ARGV_MAX_ARGS (64) 735194140Simp#define OCTOEN_SERIAL_LEN 20 736194140Simp 737194140Simp 738194140Simptypedef struct { 739200344Simp /* Start of block referenced by assembly code - do not change! */ 740200344Simp uint32_t desc_version; 741200344Simp uint32_t desc_size; 742194140Simp 743200344Simp uint64_t stack_top; 744200344Simp uint64_t heap_base; 745200344Simp uint64_t heap_end; 746200344Simp uint64_t entry_point; /* Only used by bootloader */ 747200344Simp uint64_t desc_vaddr; 748200344Simp /* End of This block referenced by assembly code - do not change! */ 749194140Simp 750200344Simp uint32_t exception_base_addr; 751200344Simp uint32_t stack_size; 752200344Simp uint32_t heap_size; 753200344Simp uint32_t argc; /* Argc count for application */ 754200344Simp uint32_t argv[OCTEON_ARGV_MAX_ARGS]; 755200344Simp uint32_t flags; 756200344Simp uint32_t core_mask; 757200344Simp uint32_t dram_size; /**< DRAM size in megabyes */ 758200344Simp uint32_t phy_mem_desc_addr; /**< physical address of free memory descriptor block*/ 759200344Simp uint32_t debugger_flags_base_addr; /**< used to pass flags from app to debugger */ 760200344Simp uint32_t eclock_hz; /**< CPU clock speed, in hz */ 761200344Simp uint32_t dclock_hz; /**< DRAM clock speed, in hz */ 762200344Simp uint32_t spi_clock_hz; /**< SPI4 clock in hz */ 763200344Simp uint16_t board_type; 764200344Simp uint8_t board_rev_major; 765200344Simp uint8_t board_rev_minor; 766200344Simp uint16_t chip_type; 767200344Simp uint8_t chip_rev_major; 768200344Simp uint8_t chip_rev_minor; 769200344Simp char board_serial_number[OCTOEN_SERIAL_LEN]; 770200344Simp uint8_t mac_addr_base[6]; 771200344Simp uint8_t mac_addr_count; 772200344Simp uint64_t cvmx_desc_vaddr; 773194140Simp} octeon_boot_descriptor_t; 774194140Simp 775194140Simp 776194140Simptypedef struct { 777200344Simp uint32_t major_version; 778200344Simp uint32_t minor_version; 779194140Simp 780200344Simp uint64_t stack_top; 781200344Simp uint64_t heap_base; 782200344Simp uint64_t heap_end; 783200344Simp uint64_t desc_vaddr; 784194140Simp 785200344Simp uint32_t exception_base_addr; 786200344Simp uint32_t stack_size; 787200344Simp uint32_t flags; 788200344Simp uint32_t core_mask; 789200344Simp uint32_t dram_size; /**< DRAM size in megabyes */ 790200344Simp uint32_t phy_mem_desc_addr; /**< physical address of free memory descriptor block*/ 791200344Simp uint32_t debugger_flags_base_addr; /**< used to pass flags from app to debugger */ 792200344Simp uint32_t eclock_hz; /**< CPU clock speed, in hz */ 793200344Simp uint32_t dclock_hz; /**< DRAM clock speed, in hz */ 794200344Simp uint32_t spi_clock_hz; /**< SPI4 clock in hz */ 795200344Simp uint16_t board_type; 796200344Simp uint8_t board_rev_major; 797200344Simp uint8_t board_rev_minor; 798200344Simp uint16_t chip_type; 799200344Simp uint8_t chip_rev_major; 800200344Simp uint8_t chip_rev_minor; 801200344Simp char board_serial_number[OCTOEN_SERIAL_LEN]; 802200344Simp uint8_t mac_addr_base[6]; 803200344Simp uint8_t mac_addr_count; 804194140Simp} cvmx_bootinfo_t; 805194140Simp 806194140Simpuint32_t octeon_cpu_clock; 807194140Simpuint64_t octeon_dram; 808194140Simpuint32_t octeon_bd_ver = 0, octeon_cvmx_bd_ver = 0, octeon_board_rev_major, octeon_board_rev_minor, octeon_board_type; 809194140Simpuint8_t octeon_mac_addr[6] = { 0 }; 810194140Simpint octeon_core_mask, octeon_mac_addr_count; 811194140Simpint octeon_chip_rev_major = 0, octeon_chip_rev_minor = 0, octeon_chip_type = 0; 812194140Simp 813200344Simpextern int32_t app_descriptor_addr; 814194140Simpstatic octeon_boot_descriptor_t *app_desc_ptr; 815194140Simpstatic cvmx_bootinfo_t *cvmx_desc_ptr; 816194140Simp 817194140Simp#define OCTEON_BOARD_TYPE_NONE 0 818194140Simp#define OCTEON_BOARD_TYPE_SIM 1 819194140Simp 820194140Simp#define OCTEON_CLOCK_MIN (100 * 1000 * 1000) 821194140Simp#define OCTEON_CLOCK_MAX (800 * 1000 * 1000) 822194140Simp#define OCTEON_DRAM_DEFAULT (256 * 1024 * 1024) 823194140Simp#define OCTEON_DRAM_MIN 30 824194140Simp#define OCTEON_DRAM_MAX 3000 825194140Simp 826194140Simp 827200344Simpint 828200344Simpocteon_board_real(void) 829194140Simp{ 830200344Simp if ((octeon_board_type == OCTEON_BOARD_TYPE_NONE) || 831200344Simp (octeon_board_type == OCTEON_BOARD_TYPE_SIM) || 832200344Simp !octeon_board_rev_major) 833200344Simp return 0; 834200344Simp return 1; 835194140Simp} 836194140Simp 837200344Simpstatic void 838200344Simpocteon_process_app_desc_ver_unknown(void) 839194140Simp{ 840194140Simp printf(" Unknown Boot-Descriptor: Using Defaults\n"); 841194140Simp 842194140Simp octeon_cpu_clock = OCTEON_CLOCK_DEFAULT; 843194140Simp octeon_dram = OCTEON_DRAM_DEFAULT; 844194140Simp octeon_board_rev_major = octeon_board_rev_minor = octeon_board_type = 0; 845194140Simp octeon_core_mask = 1; 846194140Simp octeon_cpu_clock = OCTEON_CLOCK_DEFAULT; 847194140Simp octeon_chip_type = octeon_chip_rev_major = octeon_chip_rev_minor = 0; 848194140Simp octeon_mac_addr[0] = 0x00; octeon_mac_addr[1] = 0x0f; 849194140Simp octeon_mac_addr[2] = 0xb7; octeon_mac_addr[3] = 0x10; 850194140Simp octeon_mac_addr[4] = 0x09; octeon_mac_addr[5] = 0x06; 851194140Simp octeon_mac_addr_count = 1; 852194140Simp} 853194140Simp 854200344Simpstatic int 855200344Simpocteon_process_app_desc_ver_6(void) 856194140Simp{ 857200344Simp /* XXX Why is 0x00000000ffffffffULL a bad value? */ 858200344Simp if (app_desc_ptr->cvmx_desc_vaddr == 0 || 859200344Simp app_desc_ptr->cvmx_desc_vaddr == 0xfffffffful) { 860194174Simp printf ("Bad cvmx_desc_ptr %p\n", cvmx_desc_ptr); 861194140Simp return 1; 862200344Simp } 863200344Simp cvmx_desc_ptr = 864200344Simp (cvmx_bootinfo_t *)(intptr_t)app_desc_ptr->cvmx_desc_vaddr; 865200344Simp cvmx_desc_ptr = 866200344Simp (cvmx_bootinfo_t *) ((intptr_t)cvmx_desc_ptr | MIPS_KSEG0_START); 867194140Simp octeon_cvmx_bd_ver = (cvmx_desc_ptr->major_version * 100) + 868200344Simp cvmx_desc_ptr->minor_version; 869200344Simp /* Too early for panic? */ 870194140Simp if (cvmx_desc_ptr->major_version != 1) { 871194174Simp printf("Incompatible CVMX descriptor from bootloader: %d.%d %p\n", 872194140Simp (int) cvmx_desc_ptr->major_version, 873194140Simp (int) cvmx_desc_ptr->minor_version, cvmx_desc_ptr); 874194140Simp while (1); /* Never return */ 875194140Simp return 1; /* Satisfy the compiler */ 876194140Simp } 877194140Simp 878194140Simp octeon_core_mask = cvmx_desc_ptr->core_mask; 879194140Simp octeon_cpu_clock = cvmx_desc_ptr->eclock_hz; 880194140Simp octeon_board_type = cvmx_desc_ptr->board_type; 881194140Simp octeon_board_rev_major = cvmx_desc_ptr->board_rev_major; 882194140Simp octeon_board_rev_minor = cvmx_desc_ptr->board_rev_minor; 883194140Simp octeon_chip_type = cvmx_desc_ptr->chip_type; 884194140Simp octeon_chip_rev_major = cvmx_desc_ptr->chip_rev_major; 885194140Simp octeon_chip_rev_minor = cvmx_desc_ptr->chip_rev_minor; 886194140Simp octeon_mac_addr[0] = cvmx_desc_ptr->mac_addr_base[0]; 887194140Simp octeon_mac_addr[1] = cvmx_desc_ptr->mac_addr_base[1]; 888194140Simp octeon_mac_addr[2] = cvmx_desc_ptr->mac_addr_base[2]; 889194140Simp octeon_mac_addr[3] = cvmx_desc_ptr->mac_addr_base[3]; 890194140Simp octeon_mac_addr[4] = cvmx_desc_ptr->mac_addr_base[4]; 891194140Simp octeon_mac_addr[5] = cvmx_desc_ptr->mac_addr_base[5]; 892194140Simp octeon_mac_addr_count = cvmx_desc_ptr->mac_addr_count; 893194140Simp 894200344Simp if (app_desc_ptr->dram_size > 16*1024*1024) 895194140Simp octeon_dram = (uint64_t)app_desc_ptr->dram_size; 896200344Simp else 897200344Simp octeon_dram = (uint64_t)app_desc_ptr->dram_size << 20; 898194140Simp return 0; 899194140Simp} 900194140Simp 901200344Simpstatic int 902200344Simpocteon_process_app_desc_ver_3_4_5(void) 903194140Simp{ 904194140Simp 905194140Simp octeon_cvmx_bd_ver = octeon_bd_ver; 906194140Simp octeon_core_mask = app_desc_ptr->core_mask; 907194140Simp 908200344Simp if (app_desc_ptr->desc_version > 3) 909194140Simp octeon_cpu_clock = app_desc_ptr->eclock_hz; 910200344Simp else 911194140Simp octeon_cpu_clock = OCTEON_CLOCK_DEFAULT; 912200344Simp if (app_desc_ptr->dram_size > 16*1024*1024) 913194140Simp octeon_dram = (uint64_t)app_desc_ptr->dram_size; 914200344Simp else 915200344Simp octeon_dram = (uint64_t)app_desc_ptr->dram_size << 20; 916194140Simp 917194140Simp if (app_desc_ptr->desc_version > 4) { 918194140Simp octeon_board_type = app_desc_ptr->board_type; 919194140Simp octeon_board_rev_major = app_desc_ptr->board_rev_major; 920194140Simp octeon_board_rev_minor = app_desc_ptr->board_rev_minor; 921194140Simp octeon_chip_type = app_desc_ptr->chip_type; 922194140Simp octeon_chip_rev_major = app_desc_ptr->chip_rev_major; 923194140Simp octeon_chip_rev_minor = app_desc_ptr->chip_rev_minor; 924194140Simp 925194140Simp octeon_mac_addr[0] = app_desc_ptr->mac_addr_base[0]; 926194140Simp octeon_mac_addr[1] = app_desc_ptr->mac_addr_base[1]; 927194140Simp octeon_mac_addr[2] = app_desc_ptr->mac_addr_base[2]; 928194140Simp octeon_mac_addr[3] = app_desc_ptr->mac_addr_base[3]; 929194140Simp octeon_mac_addr[4] = app_desc_ptr->mac_addr_base[4]; 930194140Simp octeon_mac_addr[5] = app_desc_ptr->mac_addr_base[5]; 931194140Simp octeon_mac_addr_count = app_desc_ptr->mac_addr_count; 932194140Simp } 933194140Simp return 0; 934194140Simp} 935194140Simp 936194140Simp 937200344Simpstatic void 938200344Simpocteon_boot_params_init(register_t ptr) 939194140Simp{ 940200344Simp int bad_desc = 1; 941194140Simp 942200344Simp if (ptr != 0 && ptr < MAX_APP_DESC_ADDR) { 943200344Simp app_desc_ptr = (octeon_boot_descriptor_t *)(intptr_t)ptr; 944194140Simp octeon_bd_ver = app_desc_ptr->desc_version; 945200344Simp if ((octeon_bd_ver >= 3) && (octeon_bd_ver <= 5)) 946200344Simp bad_desc = octeon_process_app_desc_ver_3_4_5(); 947200344Simp else if (app_desc_ptr->desc_version == 6) 948200344Simp bad_desc = octeon_process_app_desc_ver_6(); 949194140Simp } 950200344Simp if (bad_desc) 951194140Simp octeon_process_app_desc_ver_unknown(); 952194140Simp 953194140Simp printf("Boot Descriptor Ver: %u -> %u/%u", 954194140Simp octeon_bd_ver, octeon_cvmx_bd_ver/100, octeon_cvmx_bd_ver%100); 955194140Simp printf(" CPU clock: %uMHz\n", octeon_cpu_clock/1000000); 956194140Simp printf(" Dram: %u MB", (uint32_t)(octeon_dram >> 20)); 957194140Simp printf(" Board Type: %u Revision: %u/%u\n", 958194140Simp octeon_board_type, octeon_board_rev_major, octeon_board_rev_minor); 959194140Simp printf(" Octeon Chip: %u Rev %u/%u", 960194140Simp octeon_chip_type, octeon_chip_rev_major, octeon_chip_rev_minor); 961194140Simp 962194140Simp printf(" Mac Address %02X.%02X.%02X.%02X.%02X.%02X\n", 963194140Simp octeon_mac_addr[0], octeon_mac_addr[1], octeon_mac_addr[2], 964194140Simp octeon_mac_addr[3], octeon_mac_addr[4], octeon_mac_addr[5]); 965194140Simp} 966