2009-06-14 02:46:07 +00:00
|
|
|
/*-
|
|
|
|
* 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/systm.h>
|
|
|
|
#include <machine/cpuregs.h>
|
|
|
|
#include <machine/cpufunc.h>
|
2009-06-14 04:26:56 +00:00
|
|
|
#include <mips/octeon1/octeonreg.h>
|
2009-06-14 02:46:07 +00:00
|
|
|
#include <machine/atomic.h>
|
|
|
|
#include <machine/pcpu.h>
|
|
|
|
|
|
|
|
#if defined(__mips_n64)
|
|
|
|
#define MAX_APP_DESC_ADDR 0xffffffffafffffff
|
|
|
|
#else
|
|
|
|
#define MAX_APP_DESC_ADDR 0xafffffff
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Perform a board-level soft-reset.
|
|
|
|
* Note that this is not emulated by gxemul.
|
|
|
|
*/
|
|
|
|
void octeon_reset (void)
|
|
|
|
{
|
|
|
|
void (*reset_func)(void) = (void (*)(void) )0x1fc00000;
|
|
|
|
reset_func();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static inline uint32_t octeon_disable_interrupts (void)
|
|
|
|
{
|
|
|
|
uint32_t status_bits;
|
|
|
|
|
|
|
|
status_bits = mips_rd_status();
|
|
|
|
mips_wr_status(status_bits & ~MIPS_SR_INT_IE);
|
|
|
|
return (status_bits);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static inline void octeon_set_interrupts (uint32_t status_bits)
|
|
|
|
{
|
|
|
|
mips_wr_status(status_bits);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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 count, */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;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define LSR_DATAREADY 0x01 /* Data ready */
|
|
|
|
#define LSR_THRE 0x20 /* Transmit holding register empty */
|
|
|
|
#define LSR_TEMT 0x40 /* Transmitter Empty. THR, TSR & FIFO */
|
|
|
|
#define USR_TXFIFO_NOTFULL 0x02 /* Uart TX FIFO Not full */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* octeon_uart_write_byte
|
|
|
|
*
|
|
|
|
* Put out a single byte off of uart port.
|
|
|
|
*/
|
|
|
|
|
|
|
|
void octeon_uart_write_byte (int uart_index, uint8_t ch)
|
|
|
|
{
|
|
|
|
uint64_t val, val2;
|
|
|
|
if ((uart_index < 0) || (uart_index > 1)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
val = oct_read64(OCTEON_MIO_UART0_LSR + (uart_index * 0x400));
|
|
|
|
val2 = oct_read64(OCTEON_MIO_UART0_USR + (uart_index * 0x400));
|
|
|
|
if ((((uint8_t) val) & LSR_THRE) ||
|
|
|
|
(((uint8_t) val2) & USR_TXFIFO_NOTFULL)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Write the byte */
|
|
|
|
oct_write8(OCTEON_MIO_UART0_THR + (uart_index * 0x400), (uint64_t) ch);
|
|
|
|
|
|
|
|
/* Force Flush the IOBus */
|
|
|
|
oct_read64(OCTEON_MIO_BOOT_BIST_STAT);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void octeon_uart_write_byte0 (uint8_t ch)
|
|
|
|
{
|
|
|
|
uint64_t val, val2;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
val = oct_read64(OCTEON_MIO_UART0_LSR);
|
|
|
|
val2 = oct_read64(OCTEON_MIO_UART0_USR);
|
|
|
|
if ((((uint8_t) val) & LSR_THRE) ||
|
|
|
|
(((uint8_t) val2) & USR_TXFIFO_NOTFULL)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Write the byte */
|
|
|
|
oct_write8(OCTEON_MIO_UART0_THR, (uint64_t) ch);
|
|
|
|
|
|
|
|
/* Force Flush the IOBus */
|
|
|
|
oct_read64(OCTEON_MIO_BOOT_BIST_STAT);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* octeon_uart_write_string
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
void octeon_uart_write_string (int uart_index, const char *str)
|
|
|
|
{
|
|
|
|
/* Just loop writing one byte at a time */
|
|
|
|
|
|
|
|
while (*str)
|
|
|
|
{
|
|
|
|
octeon_uart_write_byte(uart_index, *str);
|
|
|
|
if (*str == '\n') {
|
|
|
|
octeon_uart_write_byte(uart_index, '\r');
|
|
|
|
}
|
|
|
|
str++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static char wstr[30];
|
|
|
|
|
|
|
|
void octeon_led_write_hex (uint32_t wl)
|
|
|
|
{
|
|
|
|
char nbuf[80];
|
|
|
|
|
|
|
|
sprintf(nbuf, "%X", wl);
|
|
|
|
octeon_led_write_string(nbuf);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void octeon_uart_write_hex2 (uint32_t wl, uint32_t wh)
|
|
|
|
{
|
|
|
|
sprintf(wstr, "0x%X-0x%X ", wh, wl);
|
|
|
|
octeon_uart_write_string(0, wstr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void octeon_uart_write_hex (uint32_t wl)
|
|
|
|
{
|
|
|
|
sprintf(wstr, " 0x%X ", wl);
|
|
|
|
octeon_uart_write_string(0, wstr);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#define OCT_CONS_BUFLEN 200
|
|
|
|
static char console_str_buff0[OCT_CONS_BUFLEN + 1];
|
|
|
|
#include <machine/stdarg.h>
|
|
|
|
|
|
|
|
|
|
|
|
//#define USE_KERN_SUBR_PRINTF
|
|
|
|
|
|
|
|
#ifndef USE_KERN_SUBR_PRINTF
|
|
|
|
static int oct_printf (const char *fmt, va_list ap);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
int kern_cons_printf (const char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
#ifndef USE_KERN_SUBR_PRINTF
|
|
|
|
oct_printf(fmt, ap);
|
|
|
|
#else
|
|
|
|
ker_printf(fmt, ap);
|
|
|
|
#endif
|
|
|
|
va_end(ap);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef USE_KERN_SUBR_PRINTF
|
|
|
|
static int oct_printf (const char *fmt, va_list ap)
|
|
|
|
{
|
|
|
|
snprintf(console_str_buff0, OCT_CONS_BUFLEN, fmt, ap);
|
|
|
|
octeon_uart_write_string(0, console_str_buff0);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
int console_printf (const char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
sprintf(console_str_buff0, fmt, ap);
|
|
|
|
va_end(ap);
|
|
|
|
octeon_uart_write_string(0, console_str_buff0);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* octeon_wait_uart_flush
|
|
|
|
*/
|
|
|
|
void octeon_wait_uart_flush (int uart_index, uint8_t ch)
|
|
|
|
{
|
|
|
|
uint64_t val;
|
|
|
|
int64_t val3;
|
|
|
|
uint32_t cpu_status_bits;
|
|
|
|
|
|
|
|
if ((uart_index < 0) || (uart_index > 1)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cpu_status_bits = octeon_disable_interrupts();
|
|
|
|
/* Force Flush the IOBus */
|
|
|
|
oct_read64(OCTEON_MIO_BOOT_BIST_STAT);
|
|
|
|
for (val3 = 0xfffffffff; val3 > 0; val3--) {
|
|
|
|
val = oct_read64(OCTEON_MIO_UART0_LSR + (uart_index * 0x400));
|
|
|
|
if (((uint8_t) val) & LSR_TEMT) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
octeon_set_interrupts(cpu_status_bits);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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();
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint64_t ciu_get_intr_sum_reg_addr(int core_num, int intx, int enx);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static uint64_t ciu_get_intr_en_reg_addr(int core_num, int intx, int enx);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint64_t ciu_get_en_reg_addr_new (int corenum, int intx, int enx, int ciu_ip);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
|
|
|
|
if (enx < CIU_EN_0 || enx > CIU_EN_1) {
|
|
|
|
printf("%s: invalid enx value %d, should be %d or %d\n",
|
|
|
|
__FUNCTION__, 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",
|
|
|
|
__FUNCTION__, 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",
|
|
|
|
__FUNCTION__, 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 = octeon_disable_interrupts();
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
octeon_set_interrupts(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 = octeon_disable_interrupts();
|
|
|
|
|
|
|
|
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 */
|
|
|
|
|
|
|
|
octeon_set_interrupts(cpu_status_bits);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ciu_dump_interrutps_enabled (int core_num, int intx, int enx, int ciu_ip);
|
|
|
|
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", __FUNCTION__);
|
|
|
|
while(1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ciu_intr_bits = oct_read64(ciu_intr_reg_addr);
|
|
|
|
printf(" CIU core %d int: %d en: %d ip: %d Add: 0x%llX enabled: 0x%llX SR: %X\n",
|
|
|
|
core_num, intx, enx, ciu_ip, ciu_intr_reg_addr, 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 = octeon_disable_interrupts();
|
|
|
|
|
|
|
|
#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", __FUNCTION__);
|
|
|
|
while(1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
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 OCTEON_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
|
|
|
|
|
|
|
|
octeon_set_interrupts(cpu_status_bits);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
extern void mips_platform_init(void);
|
|
|
|
|
|
|
|
void mips_platform_init (void)
|
|
|
|
{
|
|
|
|
octeon_ciu_reset();
|
|
|
|
octeon_uart_write_string(0, "\nPlatform Starting");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
****************************************************************************************
|
|
|
|
*
|
|
|
|
* 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;
|
|
|
|
|
|
|
|
#if defined(__mips_n64)
|
|
|
|
extern uint64_t app_descriptor_addr;
|
|
|
|
#else
|
|
|
|
extern uint32_t app_descriptor_addr;
|
|
|
|
#endif
|
|
|
|
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_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)
|
|
|
|
{
|
|
|
|
if ((octeon_board_type == OCTEON_BOARD_TYPE_NONE) ||
|
|
|
|
(octeon_board_type == OCTEON_BOARD_TYPE_SIM) ||
|
|
|
|
!octeon_board_rev_major) {
|
|
|
|
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_cpu_clock = OCTEON_CLOCK_DEFAULT;
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
cvmx_desc_ptr = (cvmx_bootinfo_t *) ((long) app_desc_ptr->cvmx_desc_vaddr);
|
|
|
|
|
|
|
|
if ((cvmx_desc_ptr == NULL) || (cvmx_desc_ptr == (cvmx_bootinfo_t *)0xffffffff)) {
|
|
|
|
printf ("Bad cvmx_desc_ptr 0x%X\n", cvmx_desc_ptr);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
cvmx_desc_ptr = (cvmx_bootinfo_t *) (((long) 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) {
|
|
|
|
printf("Incompatible CVMX descriptor from bootloader: %d.%d 0x%X\n",
|
|
|
|
(int) cvmx_desc_ptr->major_version,
|
|
|
|
(int) cvmx_desc_ptr->minor_version, cvmx_desc_ptr);
|
|
|
|
while (1); /* Never return */
|
|
|
|
return 1; /* Satisfy the compiler */
|
|
|
|
}
|
|
|
|
|
|
|
|
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 * 1024 * 1024;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int octeon_process_app_desc_ver_3_4_5 (void)
|
|
|
|
{
|
|
|
|
|
|
|
|
octeon_cvmx_bd_ver = octeon_bd_ver;
|
|
|
|
octeon_core_mask = app_desc_ptr->core_mask;
|
|
|
|
|
|
|
|
if (app_desc_ptr->desc_version > 3) {
|
|
|
|
octeon_cpu_clock = app_desc_ptr->eclock_hz;
|
|
|
|
} else {
|
|
|
|
octeon_cpu_clock = OCTEON_CLOCK_DEFAULT;
|
|
|
|
}
|
|
|
|
|
|
|
|
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 * 1024 * 1024;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (app_desc_ptr->desc_version > 4) {
|
|
|
|
octeon_board_type = app_desc_ptr->board_type;
|
|
|
|
octeon_board_rev_major = app_desc_ptr->board_rev_major;
|
|
|
|
octeon_board_rev_minor = app_desc_ptr->board_rev_minor;
|
|
|
|
octeon_chip_type = app_desc_ptr->chip_type;
|
|
|
|
octeon_chip_rev_major = app_desc_ptr->chip_rev_major;
|
|
|
|
octeon_chip_rev_minor = app_desc_ptr->chip_rev_minor;
|
|
|
|
|
|
|
|
octeon_mac_addr[0] = app_desc_ptr->mac_addr_base[0];
|
|
|
|
octeon_mac_addr[1] = app_desc_ptr->mac_addr_base[1];
|
|
|
|
octeon_mac_addr[2] = app_desc_ptr->mac_addr_base[2];
|
|
|
|
octeon_mac_addr[3] = app_desc_ptr->mac_addr_base[3];
|
|
|
|
octeon_mac_addr[4] = app_desc_ptr->mac_addr_base[4];
|
|
|
|
octeon_mac_addr[5] = app_desc_ptr->mac_addr_base[5];
|
|
|
|
octeon_mac_addr_count = app_desc_ptr->mac_addr_count;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void mips_boot_params_init(void);
|
|
|
|
|
|
|
|
void mips_boot_params_init (void)
|
|
|
|
{
|
|
|
|
int descriptor_not_parsed = 1;
|
|
|
|
|
|
|
|
if ((app_descriptor_addr == 0) || (app_descriptor_addr >= MAX_APP_DESC_ADDR)) {
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
app_desc_ptr = (octeon_boot_descriptor_t *) app_descriptor_addr;
|
|
|
|
octeon_bd_ver = app_desc_ptr->desc_version;
|
|
|
|
|
|
|
|
if ((octeon_bd_ver >= 3) && (octeon_bd_ver <= 5)) {
|
|
|
|
descriptor_not_parsed = octeon_process_app_desc_ver_3_4_5();
|
|
|
|
|
|
|
|
} else if (app_desc_ptr->desc_version == 6) {
|
|
|
|
descriptor_not_parsed = octeon_process_app_desc_ver_6();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (descriptor_not_parsed) {
|
|
|
|
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\n", octeon_cpu_clock/1000000);
|
|
|
|
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\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]);
|
|
|
|
}
|