freebsd-skq/sys/mips/cavium/octeon_machdep.c
Juli Mallett b6777295a6 o) Add SMP support for Octeon using U-Boot to launch all the processors at the
same time.
o) Remove some unused trivial uart functions from octeon_machdep now that the
   uart part is fully working and they are unused.
o) Use __func__ instead of __FUNCTION__.
o) Use intr_*() instead of other routines that do the same thing.
o) Remove some duplicate printfs from the Octeon port, as well as duplicate
   setting of Maxmem.
o) Use the right frequency divider on Octeon.
o) Use PCPU_GET(cpuid) consistently to get the cpuid of the running core.
o) Remove some unused macros in the Octeon port.
o) Use mips_sync() around use of the global dpcpu, whose value may not be
   visible to APs at first.
o) When loading the first thread's stack, use macros to make the code correct
   for n64 as well.
o) Remove stub, do-nothing FAU init/enable/disable functions from the RGMX
   driver.
2010-04-17 03:08:13 +00:00

858 lines
24 KiB
C

/*-
* Copyright (c) 2006 Wojciech A. Koszek <wkoszek@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/conf.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/imgact.h>
#include <sys/bio.h>
#include <sys/buf.h>
#include <sys/bus.h>
#include <sys/cpu.h>
#include <sys/cons.h>
#include <sys/exec.h>
#include <sys/ucontext.h>
#include <sys/proc.h>
#include <sys/kdb.h>
#include <sys/ptrace.h>
#include <sys/reboot.h>
#include <sys/signalvar.h>
#include <sys/sysent.h>
#include <sys/sysproto.h>
#include <sys/user.h>
#include <vm/vm.h>
#include <vm/vm_object.h>
#include <vm/vm_page.h>
#include <vm/vm_pager.h>
#include <machine/atomic.h>
#include <machine/cache.h>
#include <machine/clock.h>
#include <machine/cpu.h>
#include <machine/cpuregs.h>
#include <machine/cpufunc.h>
#include <mips/cavium/octeon_pcmap_regs.h>
#include <machine/hwfunc.h>
#include <machine/intr_machdep.h>
#include <machine/locore.h>
#include <machine/md_var.h>
#include <machine/pcpu.h>
#include <machine/pte.h>
#include <machine/trap.h>
#include <machine/vmparam.h>
#if defined(__mips_n64)
#define MAX_APP_DESC_ADDR 0xffffffffafffffff
#else
#define MAX_APP_DESC_ADDR 0xafffffff
#endif
extern int *edata;
extern int *end;
uint64_t ciu_get_en_reg_addr_new(int corenum, int intx, int enx, int ciu_ip);
void ciu_dump_interrutps_enabled(int core_num, int intx, int enx, int ciu_ip);
static void octeon_boot_params_init(register_t ptr);
static uint64_t ciu_get_intr_sum_reg_addr(int core_num, int intx, int enx);
static uint64_t ciu_get_intr_en_reg_addr(int core_num, int intx, int enx);
static __inline void
mips_wr_ebase(u_int32_t a0)
{
__asm __volatile("mtc0 %[a0], $15, 1 ;"
:
: [a0] "r"(a0));
mips_barrier();
}
void
platform_cpu_init()
{
/* Nothing special yet */
}
/*
* Perform a board-level soft-reset.
*/
void
platform_reset(void)
{
oct_write64(OCTEON_CIU_SOFT_RST, 1);
}
void
octeon_led_write_char(int char_position, char val)
{
uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8);
if (!octeon_board_real())
return;
char_position &= 0x7; /* only 8 chars */
ptr += char_position;
oct_write8_x8(ptr, val);
}
void
octeon_led_write_char0(char val)
{
uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8);
if (!octeon_board_real())
return;
oct_write8_x8(ptr, val);
}
void
octeon_led_write_hexchar(int char_position, char hexval)
{
uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8);
char char1, char2;
if (!octeon_board_real())
return;
char1 = (hexval >> 4) & 0x0f; char1 = (char1 < 10)?char1+'0':char1+'7';
char2 = (hexval & 0x0f); char2 = (char2 < 10)?char2+'0':char2+'7';
char_position &= 0x7; /* only 8 chars */
if (char_position > 6)
char_position = 6;
ptr += char_position;
oct_write8_x8(ptr, char1);
ptr++;
oct_write8_x8(ptr, char2);
}
void
octeon_led_write_string(const char *str)
{
uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8);
int i;
if (!octeon_board_real())
return;
for (i=0; i<8; i++, ptr++) {
if (str && *str)
oct_write8_x8(ptr, *str++);
else
oct_write8_x8(ptr, ' ');
oct_read64(OCTEON_MIO_BOOT_BIST_STAT);
}
}
static char progress[8] = { '-', '/', '|', '\\', '-', '/', '|', '\\'};
void
octeon_led_run_wheel(int *prog_count, int led_position)
{
if (!octeon_board_real())
return;
octeon_led_write_char(led_position, progress[*prog_count]);
*prog_count += 1;
*prog_count &= 0x7;
}
void
octeon_led_write_hex(uint32_t wl)
{
char nbuf[80];
sprintf(nbuf, "%X", wl);
octeon_led_write_string(nbuf);
}
/*
* octeon_debug_symbol
*
* Does nothing.
* Used to mark the point for simulator to begin tracing
*/
void
octeon_debug_symbol(void)
{
}
void
octeon_ciu_stop_gtimer(int timer)
{
oct_write64(OCTEON_CIU_GENTIMER_ADDR(timer), 0ll);
}
void
octeon_ciu_start_gtimer(int timer, u_int one_shot, uint64_t time_cycles)
{
octeon_ciu_gentimer gentimer;
gentimer.word64 = 0;
gentimer.bits.one_shot = one_shot;
gentimer.bits.len = time_cycles - 1;
oct_write64(OCTEON_CIU_GENTIMER_ADDR(timer), gentimer.word64);
}
/*
* octeon_ciu_reset
*
* Shutdown all CIU to IP2, IP3 mappings
*/
void
octeon_ciu_reset(void)
{
octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_0);
octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_1);
octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_2);
octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_3);
ciu_disable_intr(CIU_THIS_CORE, CIU_INT_0, CIU_EN_0);
ciu_disable_intr(CIU_THIS_CORE, CIU_INT_0, CIU_EN_1);
ciu_disable_intr(CIU_THIS_CORE, CIU_INT_1, CIU_EN_0);
ciu_disable_intr(CIU_THIS_CORE, CIU_INT_1, CIU_EN_1);
ciu_clear_int_summary(CIU_THIS_CORE, CIU_INT_0, CIU_EN_0, 0ll);
ciu_clear_int_summary(CIU_THIS_CORE, CIU_INT_1, CIU_EN_0, 0ll);
ciu_clear_int_summary(CIU_THIS_CORE, CIU_INT_1, CIU_EN_1, 0ll);
}
/*
* mips_disable_interrupt_controllers
*
* Disable interrupts in the CPU controller
*/
void
mips_disable_interrupt_controls(void)
{
/*
* Disable interrupts in CIU.
*/
octeon_ciu_reset();
}
/*
* ciu_get_intr_sum_reg_addr
*/
static uint64_t
ciu_get_intr_sum_reg_addr(int core_num, int intx, int enx)
{
uint64_t ciu_intr_sum_reg_addr;
if (enx == CIU_EN_0)
ciu_intr_sum_reg_addr = OCTEON_CIU_SUMMARY_BASE_ADDR +
(core_num * 0x10) + (intx * 0x8);
else
ciu_intr_sum_reg_addr = OCTEON_CIU_SUMMARY_INT1_ADDR;
return (ciu_intr_sum_reg_addr);
}
/*
* ciu_get_intr_en_reg_addr
*/
static uint64_t
ciu_get_intr_en_reg_addr(int core_num, int intx, int enx)
{
uint64_t ciu_intr_reg_addr;
ciu_intr_reg_addr = OCTEON_CIU_ENABLE_BASE_ADDR +
((enx == 0) ? 0x0 : 0x8) + (intx * 0x10) + (core_num * 0x20);
return (ciu_intr_reg_addr);
}
/*
* ciu_get_intr_reg_addr
*
* 200 ---int0,en0 ip2
* 208 ---int0,en1 ip2 ----> this is wrong... this is watchdog
*
* 210 ---int0,en0 ip3 --
* 218 ---int0,en1 ip3 ----> same here.. .this is watchdog... right?
*
* 220 ---int1,en0 ip2
* 228 ---int1,en1 ip2
* 230 ---int1,en0 ip3 --
* 238 ---int1,en1 ip3
*
*/
uint64_t
ciu_get_en_reg_addr_new(int corenum, int intx, int enx, int ciu_ip)
{
uint64_t ciu_intr_reg_addr = OCTEON_CIU_ENABLE_BASE_ADDR;
/* XXX kasserts? */
if (enx < CIU_EN_0 || enx > CIU_EN_1) {
printf("%s: invalid enx value %d, should be %d or %d\n",
__func__, enx, CIU_EN_0, CIU_EN_1);
return 0;
}
if (intx < CIU_INT_0 || intx > CIU_INT_1) {
printf("%s: invalid intx value %d, should be %d or %d\n",
__func__, enx, CIU_INT_0, CIU_INT_1);
return 0;
}
if (ciu_ip < CIU_MIPS_IP2 || ciu_ip > CIU_MIPS_IP3) {
printf("%s: invalid ciu_ip value %d, should be %d or %d\n",
__func__, ciu_ip, CIU_MIPS_IP2, CIU_MIPS_IP3);
return 0;
}
ciu_intr_reg_addr += (enx * 0x8);
ciu_intr_reg_addr += (ciu_ip * 0x10);
ciu_intr_reg_addr += (intx * 0x20);
return (ciu_intr_reg_addr);
}
/*
* ciu_get_int_summary
*/
uint64_t
ciu_get_int_summary(int core_num, int intx, int enx)
{
uint64_t ciu_intr_sum_reg_addr;
if (core_num == CIU_THIS_CORE)
core_num = octeon_get_core_num();
ciu_intr_sum_reg_addr = ciu_get_intr_sum_reg_addr(core_num, intx, enx);
return (oct_read64(ciu_intr_sum_reg_addr));
}
//#define DEBUG_CIU 1
#ifdef DEBUG_CIU
#define DEBUG_CIU_SUM 1
#define DEBUG_CIU_EN 1
#endif
/*
* ciu_clear_int_summary
*/
void
ciu_clear_int_summary(int core_num, int intx, int enx, uint64_t write_bits)
{
uint32_t cpu_status_bits;
uint64_t ciu_intr_sum_reg_addr;
//#define DEBUG_CIU_SUM 1
#ifdef DEBUG_CIU_SUM
uint64_t ciu_intr_sum_bits;
#endif
if (core_num == CIU_THIS_CORE) {
core_num = octeon_get_core_num();
}
#ifdef DEBUG_CIU_SUM
printf(" CIU: core %u clear sum IntX %u Enx %u Bits: 0x%llX\n",
core_num, intx, enx, write_bits);
#endif
cpu_status_bits = intr_disable();
ciu_intr_sum_reg_addr = ciu_get_intr_sum_reg_addr(core_num, intx, enx);
#ifdef DEBUG_CIU_SUM
ciu_intr_sum_bits = oct_read64(ciu_intr_sum_reg_addr); /* unneeded dummy read */
printf(" CIU: status: 0x%X reg_addr: 0x%llX Val: 0x%llX -> 0x%llX",
cpu_status_bits, ciu_intr_sum_reg_addr, ciu_intr_sum_bits,
ciu_intr_sum_bits | write_bits);
#endif
oct_write64(ciu_intr_sum_reg_addr, write_bits);
oct_read64(OCTEON_MIO_BOOT_BIST_STAT); /* Bus Barrier */
#ifdef DEBUG_CIU_SUM
printf(" Readback: 0x%llX\n\n ", (uint64_t) oct_read64(ciu_intr_sum_reg_addr));
#endif
intr_restore(cpu_status_bits);
}
/*
* ciu_disable_intr
*/
void
ciu_disable_intr(int core_num, int intx, int enx)
{
uint32_t cpu_status_bits;
uint64_t ciu_intr_reg_addr;
if (core_num == CIU_THIS_CORE)
core_num = octeon_get_core_num();
cpu_status_bits = intr_disable();
ciu_intr_reg_addr = ciu_get_intr_en_reg_addr(core_num, intx, enx);
oct_read64(ciu_intr_reg_addr); /* Dummy read */
oct_write64(ciu_intr_reg_addr, 0LL);
oct_read64(OCTEON_MIO_BOOT_BIST_STAT); /* Bus Barrier */
intr_restore(cpu_status_bits);
}
void
ciu_dump_interrutps_enabled(int core_num, int intx, int enx, int ciu_ip)
{
uint64_t ciu_intr_reg_addr;
uint64_t ciu_intr_bits;
if (core_num == CIU_THIS_CORE) {
core_num = octeon_get_core_num();
}
#ifndef OCTEON_SMP_1
ciu_intr_reg_addr = ciu_get_intr_en_reg_addr(core_num, intx, enx);
#else
ciu_intr_reg_addr = ciu_get_en_reg_addr_new(core_num, intx, enx, ciu_ip);
#endif
if (!ciu_intr_reg_addr) {
printf("Bad call to %s\n", __func__);
while(1);
return;
}
ciu_intr_bits = oct_read64(ciu_intr_reg_addr);
printf(" CIU core %d int: %d en: %d ip: %d Add: %#llx enabled: %#llx SR: %x\n",
core_num, intx, enx, ciu_ip, (unsigned long long)ciu_intr_reg_addr,
(unsigned long long)ciu_intr_bits, mips_rd_status());
}
/*
* ciu_enable_interrupts
*/
void ciu_enable_interrupts(int core_num, int intx, int enx,
uint64_t set_these_interrupt_bits, int ciu_ip)
{
uint32_t cpu_status_bits;
uint64_t ciu_intr_reg_addr;
uint64_t ciu_intr_bits;
if (core_num == CIU_THIS_CORE)
core_num = octeon_get_core_num();
//#define DEBUG_CIU_EN 1
#ifdef DEBUG_CIU_EN
printf(" CIU: core %u enabling Intx %u Enx %u IP %d Bits: 0x%llX\n",
core_num, intx, enx, ciu_ip, set_these_interrupt_bits);
#endif
cpu_status_bits = intr_disable();
#ifndef OCTEON_SMP_1
ciu_intr_reg_addr = ciu_get_intr_en_reg_addr(core_num, intx, enx);
#else
ciu_intr_reg_addr = ciu_get_en_reg_addr_new(core_num, intx, enx, ciu_ip);
#endif
if (!ciu_intr_reg_addr) {
printf("Bad call to %s\n", __func__);
while(1);
return; /* XXX */
}
ciu_intr_bits = oct_read64(ciu_intr_reg_addr);
#ifdef DEBUG_CIU_EN
printf(" CIU: status: 0x%X reg_addr: 0x%llX Val: 0x%llX -> 0x%llX",
cpu_status_bits, ciu_intr_reg_addr, ciu_intr_bits, ciu_intr_bits | set_these_interrupt_bits);
#endif
ciu_intr_bits |= set_these_interrupt_bits;
oct_write64(ciu_intr_reg_addr, ciu_intr_bits);
#ifdef SMP
mips_wbflush();
#endif
oct_read64(OCTEON_MIO_BOOT_BIST_STAT); /* Bus Barrier */
#ifdef DEBUG_CIU_EN
printf(" Readback: 0x%llX\n\n ",
(uint64_t)oct_read64(ciu_intr_reg_addr));
#endif
intr_restore(cpu_status_bits);
}
unsigned long
octeon_get_clock_rate(void)
{
return octeon_cpu_clock;
}
static void
octeon_memory_init(void)
{
uint32_t realmem_bytes;
if (octeon_board_real()) {
realmem_bytes = (octeon_dram - PAGE_SIZE);
realmem_bytes &= ~(PAGE_SIZE - 1);
} else {
/* Simulator we limit to 96 meg */
realmem_bytes = (96 << 20);
}
/* phys_avail regions are in bytes */
phys_avail[0] = (MIPS_KSEG0_TO_PHYS((vm_offset_t)&end) + PAGE_SIZE) & ~(PAGE_SIZE - 1);
if (octeon_board_real()) {
if (realmem_bytes > OCTEON_DRAM_FIRST_256_END)
phys_avail[1] = OCTEON_DRAM_FIRST_256_END;
else
phys_avail[1] = realmem_bytes;
realmem_bytes -= OCTEON_DRAM_FIRST_256_END;
realmem_bytes &= ~(PAGE_SIZE - 1);
} else {
/* Simulator gets 96Meg period. */
phys_avail[1] = (96 << 20);
}
/*-
* Octeon Memory looks as follows:
* PA
* 0000 0000 to 0x0 0000 0000 0000
* 0FFF FFFF First 256 MB memory Maps to 0x0 0000 0FFF FFFF
*
* 1000 0000 to 0x1 0000 1000 0000
* 1FFF FFFF Uncached Bu I/O space.converted to 0x1 0000 1FFF FFFF
*
* 2FFF FFFF to Cached 0x0 0000 2000 0000
* FFFF FFFF all dram mem above the first 512M 0x3 FFFF FFFF FFFF
*
*/
physmem = btoc(phys_avail[1] - phys_avail[0]);
if ((octeon_board_real()) &&
(realmem_bytes > OCTEON_DRAM_FIRST_256_END)) {
/* take out the upper non-cached 1/2 */
realmem_bytes -= OCTEON_DRAM_FIRST_256_END;
realmem_bytes &= ~(PAGE_SIZE - 1);
/* Now map the rest of the memory */
phys_avail[2] = 0x20000000;
phys_avail[3] = ((uint32_t) 0x20000000 + realmem_bytes);
physmem += btoc(phys_avail[3] - phys_avail[2]);
}
realmem = physmem;
printf("Total DRAM Size %#X\n", (uint32_t) octeon_dram);
printf("Bank 0 = %#08lX -> %#08lX\n", (long)phys_avail[0], (long)phys_avail[1]);
printf("Bank 1 = %#08lX -> %#08lX\n", (long)phys_avail[2], (long)phys_avail[3]);
}
void
platform_start(__register_t a0, __register_t a1, __register_t a2 __unused,
__register_t a3)
{
uint64_t platform_counter_freq;
/* Initialize pcpu stuff */
mips_pcpu0_init();
mips_timer_early_init(OCTEON_CLOCK_DEFAULT);
cninit();
octeon_ciu_reset();
octeon_boot_params_init(a3);
bootverbose = 1;
/*
* For some reason on the cn38xx simulator ebase register is set to
* 0x80001000 at bootup time. Move it back to the default, but
* when we move to having support for multiple executives, we need
* to rethink this.
*/
mips_wr_ebase(0x80000000);
octeon_memory_init();
init_param1();
init_param2(physmem);
mips_cpu_init();
pmap_bootstrap();
mips_proc0_init();
mutex_init();
kdb_init();
#ifdef KDB
if (boothowto & RB_KDB)
kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger");
#endif
platform_counter_freq = octeon_get_clock_rate();
mips_timer_init_params(platform_counter_freq, 0);
#ifdef SMP
/*
* Clear any pending IPIs and enable the IPI interrupt.
*/
oct_write64(OCTEON_CIU_MBOX_CLRX(0), 0xffffffff);
ciu_enable_interrupts(0, CIU_INT_1, CIU_EN_0, OCTEON_CIU_ENABLE_MBOX_INTR, CIU_MIPS_IP3);
#endif
}
/* impSTART: This stuff should move back into the Cavium SDK */
/*
****************************************************************************************
*
* APP/BOOT DESCRIPTOR STUFF
*
****************************************************************************************
*/
/* Define the struct that is initialized by the bootloader used by the
* startup code.
*
* Copyright (c) 2004, 2005, 2006 Cavium Networks.
*
* The authors hereby grant permission to use, copy, modify, distribute,
* and license this software and its documentation for any purpose, provided
* that existing copyright notices are retained in all copies and that this
* notice is included verbatim in any distributions. No written agreement,
* license, or royalty fee is required for any of the authorized uses.
* Modifications to this software may be copyrighted by their authors
* and need not follow the licensing terms described here, provided that
* the new terms are clearly indicated on the first page of each file where
* they apply.
*/
#define OCTEON_CURRENT_DESC_VERSION 6
#define OCTEON_ARGV_MAX_ARGS (64)
#define OCTOEN_SERIAL_LEN 20
typedef struct {
/* Start of block referenced by assembly code - do not change! */
uint32_t desc_version;
uint32_t desc_size;
uint64_t stack_top;
uint64_t heap_base;
uint64_t heap_end;
uint64_t entry_point; /* Only used by bootloader */
uint64_t desc_vaddr;
/* End of This block referenced by assembly code - do not change! */
uint32_t exception_base_addr;
uint32_t stack_size;
uint32_t heap_size;
uint32_t argc; /* Argc count for application */
uint32_t argv[OCTEON_ARGV_MAX_ARGS];
uint32_t flags;
uint32_t core_mask;
uint32_t dram_size; /**< DRAM size in megabyes */
uint32_t phy_mem_desc_addr; /**< physical address of free memory descriptor block*/
uint32_t debugger_flags_base_addr; /**< used to pass flags from app to debugger */
uint32_t eclock_hz; /**< CPU clock speed, in hz */
uint32_t dclock_hz; /**< DRAM clock speed, in hz */
uint32_t spi_clock_hz; /**< SPI4 clock in hz */
uint16_t board_type;
uint8_t board_rev_major;
uint8_t board_rev_minor;
uint16_t chip_type;
uint8_t chip_rev_major;
uint8_t chip_rev_minor;
char board_serial_number[OCTOEN_SERIAL_LEN];
uint8_t mac_addr_base[6];
uint8_t mac_addr_count;
uint64_t cvmx_desc_vaddr;
} octeon_boot_descriptor_t;
typedef struct {
uint32_t major_version;
uint32_t minor_version;
uint64_t stack_top;
uint64_t heap_base;
uint64_t heap_end;
uint64_t desc_vaddr;
uint32_t exception_base_addr;
uint32_t stack_size;
uint32_t flags;
uint32_t core_mask;
uint32_t dram_size; /**< DRAM size in megabyes */
uint32_t phy_mem_desc_addr; /**< physical address of free memory descriptor block*/
uint32_t debugger_flags_base_addr; /**< used to pass flags from app to debugger */
uint32_t eclock_hz; /**< CPU clock speed, in hz */
uint32_t dclock_hz; /**< DRAM clock speed, in hz */
uint32_t spi_clock_hz; /**< SPI4 clock in hz */
uint16_t board_type;
uint8_t board_rev_major;
uint8_t board_rev_minor;
uint16_t chip_type;
uint8_t chip_rev_major;
uint8_t chip_rev_minor;
char board_serial_number[OCTOEN_SERIAL_LEN];
uint8_t mac_addr_base[6];
uint8_t mac_addr_count;
} cvmx_bootinfo_t;
uint32_t octeon_cpu_clock;
uint64_t octeon_dram;
uint32_t octeon_bd_ver = 0, octeon_cvmx_bd_ver = 0, octeon_board_rev_major, octeon_board_rev_minor, octeon_board_type;
uint8_t octeon_mac_addr[6] = { 0 };
int octeon_core_mask, octeon_mac_addr_count;
int octeon_chip_rev_major = 0, octeon_chip_rev_minor = 0, octeon_chip_type = 0;
static octeon_boot_descriptor_t *app_desc_ptr;
static cvmx_bootinfo_t *cvmx_desc_ptr;
#define OCTEON_BOARD_TYPE_NONE 0
#define OCTEON_BOARD_TYPE_SIM 1
#define OCTEON_BOARD_TYPE_CN3010_EVB_HS5 11
#define OCTEON_CLOCK_MIN (100 * 1000 * 1000)
#define OCTEON_CLOCK_MAX (800 * 1000 * 1000)
#define OCTEON_DRAM_DEFAULT (256 * 1024 * 1024)
#define OCTEON_DRAM_MIN 30
#define OCTEON_DRAM_MAX 3000
int
octeon_board_real(void)
{
switch (octeon_board_type) {
case OCTEON_BOARD_TYPE_NONE:
case OCTEON_BOARD_TYPE_SIM:
return 0;
case OCTEON_BOARD_TYPE_CN3010_EVB_HS5:
/*
* XXX
* The CAM-0100 identifies itself as type 11, revision 0.0,
* despite its being rather real. Disable the revision check
* for type 11.
*/
return 1;
default:
if (octeon_board_rev_major == 0)
return 0;
return 1;
}
}
static void
octeon_process_app_desc_ver_unknown(void)
{
printf(" Unknown Boot-Descriptor: Using Defaults\n");
octeon_cpu_clock = OCTEON_CLOCK_DEFAULT;
octeon_dram = OCTEON_DRAM_DEFAULT;
octeon_board_rev_major = octeon_board_rev_minor = octeon_board_type = 0;
octeon_core_mask = 1;
octeon_chip_type = octeon_chip_rev_major = octeon_chip_rev_minor = 0;
octeon_mac_addr[0] = 0x00; octeon_mac_addr[1] = 0x0f;
octeon_mac_addr[2] = 0xb7; octeon_mac_addr[3] = 0x10;
octeon_mac_addr[4] = 0x09; octeon_mac_addr[5] = 0x06;
octeon_mac_addr_count = 1;
}
static int
octeon_process_app_desc_ver_6(void)
{
/* XXX Why is 0x00000000ffffffffULL a bad value? */
if (app_desc_ptr->cvmx_desc_vaddr == 0 ||
app_desc_ptr->cvmx_desc_vaddr == 0xfffffffful) {
printf ("Bad cvmx_desc_ptr %p\n", cvmx_desc_ptr);
return 1;
}
cvmx_desc_ptr =
(cvmx_bootinfo_t *)(intptr_t)app_desc_ptr->cvmx_desc_vaddr;
cvmx_desc_ptr =
(cvmx_bootinfo_t *) ((intptr_t)cvmx_desc_ptr | MIPS_KSEG0_START);
octeon_cvmx_bd_ver = (cvmx_desc_ptr->major_version * 100) +
cvmx_desc_ptr->minor_version;
if (cvmx_desc_ptr->major_version != 1) {
panic("Incompatible CVMX descriptor from bootloader: %d.%d %p\n",
(int) cvmx_desc_ptr->major_version,
(int) cvmx_desc_ptr->minor_version, cvmx_desc_ptr);
}
octeon_core_mask = cvmx_desc_ptr->core_mask;
octeon_cpu_clock = cvmx_desc_ptr->eclock_hz;
octeon_board_type = cvmx_desc_ptr->board_type;
octeon_board_rev_major = cvmx_desc_ptr->board_rev_major;
octeon_board_rev_minor = cvmx_desc_ptr->board_rev_minor;
octeon_chip_type = cvmx_desc_ptr->chip_type;
octeon_chip_rev_major = cvmx_desc_ptr->chip_rev_major;
octeon_chip_rev_minor = cvmx_desc_ptr->chip_rev_minor;
octeon_mac_addr[0] = cvmx_desc_ptr->mac_addr_base[0];
octeon_mac_addr[1] = cvmx_desc_ptr->mac_addr_base[1];
octeon_mac_addr[2] = cvmx_desc_ptr->mac_addr_base[2];
octeon_mac_addr[3] = cvmx_desc_ptr->mac_addr_base[3];
octeon_mac_addr[4] = cvmx_desc_ptr->mac_addr_base[4];
octeon_mac_addr[5] = cvmx_desc_ptr->mac_addr_base[5];
octeon_mac_addr_count = cvmx_desc_ptr->mac_addr_count;
if (app_desc_ptr->dram_size > 16*1024*1024)
octeon_dram = (uint64_t)app_desc_ptr->dram_size;
else
octeon_dram = (uint64_t)app_desc_ptr->dram_size << 20;
return 0;
}
static void
octeon_boot_params_init(register_t ptr)
{
int bad_desc = 1;
if (ptr != 0 && ptr < MAX_APP_DESC_ADDR) {
app_desc_ptr = (octeon_boot_descriptor_t *)(intptr_t)ptr;
octeon_bd_ver = app_desc_ptr->desc_version;
if (app_desc_ptr->desc_version < 6)
panic("Your boot code is too old to be supported.\n");
if (app_desc_ptr->desc_version >= 6)
bad_desc = octeon_process_app_desc_ver_6();
}
if (bad_desc)
octeon_process_app_desc_ver_unknown();
printf("Boot Descriptor Ver: %u -> %u/%u",
octeon_bd_ver, octeon_cvmx_bd_ver/100, octeon_cvmx_bd_ver%100);
printf(" CPU clock: %uMHz Core Mask: %#x\n", octeon_cpu_clock/1000000, octeon_core_mask);
printf(" Dram: %u MB", (uint32_t)(octeon_dram >> 20));
printf(" Board Type: %u Revision: %u/%u\n",
octeon_board_type, octeon_board_rev_major, octeon_board_rev_minor);
printf(" Octeon Chip: %u Rev %u/%u",
octeon_chip_type, octeon_chip_rev_major, octeon_chip_rev_minor);
printf(" Mac Address %02X.%02X.%02X.%02X.%02X.%02X (%d)\n",
octeon_mac_addr[0], octeon_mac_addr[1], octeon_mac_addr[2],
octeon_mac_addr[3], octeon_mac_addr[4], octeon_mac_addr[5],
octeon_mac_addr_count);
}
/* impEND: This stuff should move back into the Cavium SDK */