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