GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)

This commit is contained in:
lai
2026-09-06 03:52:57 +08:00
commit b1928b41c0
21813 changed files with 4413081 additions and 0 deletions
@@ -0,0 +1,15 @@
# SPDX-License-Identifier: GPL-2.0+
#
# (C) Copyright 2003-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
obj-y += cache.o
obj-y += cache_init.o
obj-y += genex.o
obj-y += reloc.o
obj-y += stack.o
obj-y += traps.o
obj-$(CONFIG_CMD_BOOTM) += bootm.o
lib-$(CONFIG_USE_PRIVATE_LIBGCC) += ashldi3.o ashrdi3.o lshrdi3.o
@@ -0,0 +1,25 @@
#include "libgcc.h"
long long __ashldi3(long long u, word_type b)
{
DWunion uu, w;
word_type bm;
if (b == 0)
return u;
uu.ll = u;
bm = 32 - b;
if (bm <= 0) {
w.s.low = 0;
w.s.high = (unsigned int) uu.s.low << -bm;
} else {
const unsigned int carries = (unsigned int) uu.s.low >> bm;
w.s.low = (unsigned int) uu.s.low << b;
w.s.high = ((unsigned int) uu.s.high << b) | carries;
}
return w.ll;
}
@@ -0,0 +1,27 @@
#include "libgcc.h"
long long __ashrdi3(long long u, word_type b)
{
DWunion uu, w;
word_type bm;
if (b == 0)
return u;
uu.ll = u;
bm = 32 - b;
if (bm <= 0) {
/* w.s.high = 1..1 or 0..0 */
w.s.high =
uu.s.high >> 31;
w.s.low = uu.s.high >> -bm;
} else {
const unsigned int carries = (unsigned int) uu.s.high << bm;
w.s.high = uu.s.high >> b;
w.s.low = ((unsigned int) uu.s.low >> b) | carries;
}
return w.ll;
}
@@ -0,0 +1,60 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* offset.c: Calculate pt_regs and task_struct offsets.
*
* Copyright (C) 1996 David S. Miller
* Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003 Ralf Baechle
* Copyright (C) 1999, 2000 Silicon Graphics, Inc.
*
* Kevin Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
* Copyright (C) 2000 MIPS Technologies, Inc.
*/
#include <asm/ptrace.h>
#include <linux/stddef.h>
#include <linux/kbuild.h>
void output_ptreg_defines(void)
{
COMMENT("MIPS pt_regs offsets.");
OFFSET(PT_R0, pt_regs, regs[0]);
OFFSET(PT_R1, pt_regs, regs[1]);
OFFSET(PT_R2, pt_regs, regs[2]);
OFFSET(PT_R3, pt_regs, regs[3]);
OFFSET(PT_R4, pt_regs, regs[4]);
OFFSET(PT_R5, pt_regs, regs[5]);
OFFSET(PT_R6, pt_regs, regs[6]);
OFFSET(PT_R7, pt_regs, regs[7]);
OFFSET(PT_R8, pt_regs, regs[8]);
OFFSET(PT_R9, pt_regs, regs[9]);
OFFSET(PT_R10, pt_regs, regs[10]);
OFFSET(PT_R11, pt_regs, regs[11]);
OFFSET(PT_R12, pt_regs, regs[12]);
OFFSET(PT_R13, pt_regs, regs[13]);
OFFSET(PT_R14, pt_regs, regs[14]);
OFFSET(PT_R15, pt_regs, regs[15]);
OFFSET(PT_R16, pt_regs, regs[16]);
OFFSET(PT_R17, pt_regs, regs[17]);
OFFSET(PT_R18, pt_regs, regs[18]);
OFFSET(PT_R19, pt_regs, regs[19]);
OFFSET(PT_R20, pt_regs, regs[20]);
OFFSET(PT_R21, pt_regs, regs[21]);
OFFSET(PT_R22, pt_regs, regs[22]);
OFFSET(PT_R23, pt_regs, regs[23]);
OFFSET(PT_R24, pt_regs, regs[24]);
OFFSET(PT_R25, pt_regs, regs[25]);
OFFSET(PT_R26, pt_regs, regs[26]);
OFFSET(PT_R27, pt_regs, regs[27]);
OFFSET(PT_R28, pt_regs, regs[28]);
OFFSET(PT_R29, pt_regs, regs[29]);
OFFSET(PT_R30, pt_regs, regs[30]);
OFFSET(PT_R31, pt_regs, regs[31]);
OFFSET(PT_LO, pt_regs, lo);
OFFSET(PT_HI, pt_regs, hi);
OFFSET(PT_EPC, pt_regs, cp0_epc);
OFFSET(PT_BVADDR, pt_regs, cp0_badvaddr);
OFFSET(PT_STATUS, pt_regs, cp0_status);
OFFSET(PT_CAUSE, pt_regs, cp0_cause);
DEFINE(PT_SIZE, sizeof(struct pt_regs));
BLANK();
}
@@ -0,0 +1,331 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2003
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*/
#include <common.h>
#include <env.h>
#include <image.h>
#include <fdt_support.h>
#include <asm/addrspace.h>
#include <asm/io.h>
DECLARE_GLOBAL_DATA_PTR;
#define LINUX_MAX_ENVS 256
#define LINUX_MAX_ARGS 256
static int linux_argc;
static char **linux_argv;
static char *linux_argp;
static char **linux_env;
static char *linux_env_p;
static int linux_env_idx;
static ulong arch_get_sp(void)
{
ulong ret;
__asm__ __volatile__("move %0, $sp" : "=r"(ret) : );
return ret;
}
void arch_lmb_reserve(struct lmb *lmb)
{
ulong sp;
sp = arch_get_sp();
debug("## Current stack ends at 0x%08lx\n", sp);
/* adjust sp by 4K to be safe */
sp -= 4096;
lmb_reserve(lmb, sp, gd->ram_top - sp);
}
static void linux_cmdline_init(void)
{
linux_argc = 1;
linux_argv = (char **)UNCACHED_SDRAM(gd->bd->bi_boot_params);
linux_argv[0] = 0;
linux_argp = (char *)(linux_argv + LINUX_MAX_ARGS);
}
static void linux_cmdline_set(const char *value, size_t len)
{
linux_argv[linux_argc] = linux_argp;
memcpy(linux_argp, value, len);
linux_argp[len] = 0;
linux_argp += len + 1;
linux_argc++;
}
static void linux_cmdline_dump(void)
{
int i;
debug("## cmdline argv at 0x%p, argp at 0x%p\n",
linux_argv, linux_argp);
for (i = 1; i < linux_argc; i++)
debug(" arg %03d: %s\n", i, linux_argv[i]);
}
static void linux_cmdline_legacy(bootm_headers_t *images)
{
const char *bootargs, *next, *quote;
linux_cmdline_init();
bootargs = env_get("bootargs");
if (!bootargs)
return;
next = bootargs;
while (bootargs && *bootargs && linux_argc < LINUX_MAX_ARGS) {
quote = strchr(bootargs, '"');
next = strchr(bootargs, ' ');
while (next && quote && quote < next) {
/*
* we found a left quote before the next blank
* now we have to find the matching right quote
*/
next = strchr(quote + 1, '"');
if (next) {
quote = strchr(next + 1, '"');
next = strchr(next + 1, ' ');
}
}
if (!next)
next = bootargs + strlen(bootargs);
linux_cmdline_set(bootargs, next - bootargs);
if (*next)
next++;
bootargs = next;
}
}
static void linux_cmdline_append(bootm_headers_t *images)
{
char buf[24];
ulong mem, rd_start, rd_size;
/* append mem */
mem = gd->ram_size >> 20;
sprintf(buf, "mem=%luM", mem);
linux_cmdline_set(buf, strlen(buf));
/* append rd_start and rd_size */
rd_start = images->initrd_start;
rd_size = images->initrd_end - images->initrd_start;
if (rd_size) {
sprintf(buf, "rd_start=0x%08lX", rd_start);
linux_cmdline_set(buf, strlen(buf));
sprintf(buf, "rd_size=0x%lX", rd_size);
linux_cmdline_set(buf, strlen(buf));
}
}
static void linux_env_init(void)
{
linux_env = (char **)(((ulong) linux_argp + 15) & ~15);
linux_env[0] = 0;
linux_env_p = (char *)(linux_env + LINUX_MAX_ENVS);
linux_env_idx = 0;
}
static void linux_env_set(const char *env_name, const char *env_val)
{
if (linux_env_idx < LINUX_MAX_ENVS - 1) {
linux_env[linux_env_idx] = linux_env_p;
strcpy(linux_env_p, env_name);
linux_env_p += strlen(env_name);
if (CONFIG_IS_ENABLED(MALTA)) {
linux_env_p++;
linux_env[++linux_env_idx] = linux_env_p;
} else {
*linux_env_p++ = '=';
}
strcpy(linux_env_p, env_val);
linux_env_p += strlen(env_val);
linux_env_p++;
linux_env[++linux_env_idx] = 0;
}
}
static void linux_env_legacy(bootm_headers_t *images)
{
char env_buf[12];
const char *cp;
ulong rd_start, rd_size;
if (CONFIG_IS_ENABLED(MEMSIZE_IN_BYTES)) {
sprintf(env_buf, "%lu", (ulong)gd->ram_size);
debug("## Giving linux memsize in bytes, %lu\n",
(ulong)gd->ram_size);
} else {
sprintf(env_buf, "%lu", (ulong)(gd->ram_size >> 20));
debug("## Giving linux memsize in MB, %lu\n",
(ulong)(gd->ram_size >> 20));
}
rd_start = UNCACHED_SDRAM(images->initrd_start);
rd_size = images->initrd_end - images->initrd_start;
linux_env_init();
linux_env_set("memsize", env_buf);
sprintf(env_buf, "0x%08lX", rd_start);
linux_env_set("initrd_start", env_buf);
sprintf(env_buf, "0x%lX", rd_size);
linux_env_set("initrd_size", env_buf);
sprintf(env_buf, "0x%08X", (uint) (gd->bd->bi_flashstart));
linux_env_set("flash_start", env_buf);
sprintf(env_buf, "0x%X", (uint) (gd->bd->bi_flashsize));
linux_env_set("flash_size", env_buf);
cp = env_get("ethaddr");
if (cp)
linux_env_set("ethaddr", cp);
cp = env_get("eth1addr");
if (cp)
linux_env_set("eth1addr", cp);
if (CONFIG_IS_ENABLED(MALTA)) {
sprintf(env_buf, "%un8r", gd->baudrate);
linux_env_set("modetty0", env_buf);
}
}
static int boot_reloc_fdt(bootm_headers_t *images)
{
/*
* In case of legacy uImage's, relocation of FDT is already done
* by do_bootm_states() and should not repeated in 'bootm prep'.
*/
if (images->state & BOOTM_STATE_FDT) {
debug("## FDT already relocated\n");
return 0;
}
#if CONFIG_IS_ENABLED(MIPS_BOOT_FDT) && CONFIG_IS_ENABLED(OF_LIBFDT)
boot_fdt_add_mem_rsv_regions(&images->lmb, images->ft_addr);
return boot_relocate_fdt(&images->lmb, &images->ft_addr,
&images->ft_len);
#else
return 0;
#endif
}
#if CONFIG_IS_ENABLED(MIPS_BOOT_FDT) && CONFIG_IS_ENABLED(OF_LIBFDT)
int arch_fixup_fdt(void *blob)
{
u64 mem_start = virt_to_phys((void *)gd->bd->bi_memstart);
u64 mem_size = gd->ram_size;
return fdt_fixup_memory_banks(blob, &mem_start, &mem_size, 1);
}
#endif
static int boot_setup_fdt(bootm_headers_t *images)
{
images->initrd_start = virt_to_phys((void *)images->initrd_start);
images->initrd_end = virt_to_phys((void *)images->initrd_end);
return image_setup_libfdt(images, images->ft_addr, images->ft_len,
&images->lmb);
}
static void boot_prep_linux(bootm_headers_t *images)
{
if (CONFIG_IS_ENABLED(MIPS_BOOT_FDT) && images->ft_len) {
boot_reloc_fdt(images);
boot_setup_fdt(images);
} else {
if (CONFIG_IS_ENABLED(MIPS_BOOT_CMDLINE_LEGACY)) {
linux_cmdline_legacy(images);
if (!CONFIG_IS_ENABLED(MIPS_BOOT_ENV_LEGACY))
linux_cmdline_append(images);
linux_cmdline_dump();
}
if (CONFIG_IS_ENABLED(MIPS_BOOT_ENV_LEGACY))
linux_env_legacy(images);
}
}
static void boot_jump_linux(bootm_headers_t *images)
{
typedef void __noreturn (*kernel_entry_t)(int, ulong, ulong, ulong);
kernel_entry_t kernel = (kernel_entry_t) images->ep;
ulong linux_extra = 0;
debug("## Transferring control to Linux (at address %p) ...\n", kernel);
bootstage_mark(BOOTSTAGE_ID_RUN_OS);
if (CONFIG_IS_ENABLED(MALTA))
linux_extra = gd->ram_size;
#if CONFIG_IS_ENABLED(BOOTSTAGE_FDT)
bootstage_fdt_add_report();
#endif
#if CONFIG_IS_ENABLED(BOOTSTAGE_REPORT)
bootstage_report();
#endif
if (images->ft_len)
kernel(-2, (ulong)images->ft_addr, 0, 0);
else
kernel(linux_argc, (ulong)linux_argv, (ulong)linux_env,
linux_extra);
}
int do_bootm_linux(int flag, int argc, char * const argv[],
bootm_headers_t *images)
{
/* No need for those on MIPS */
if (flag & BOOTM_STATE_OS_BD_T)
return -1;
/*
* Cmdline init has been moved to 'bootm prep' because it has to be
* done after relocation of ramdisk to always pass correct values
* for rd_start and rd_size to Linux kernel.
*/
if (flag & BOOTM_STATE_OS_CMDLINE)
return 0;
if (flag & BOOTM_STATE_OS_PREP) {
boot_prep_linux(images);
return 0;
}
if (flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)) {
boot_jump_linux(images);
return 0;
}
/* does not return */
return 1;
}
@@ -0,0 +1,198 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2003
* Wolfgang Denk, DENX Software Engineering, <wd@denx.de>
*/
#include <common.h>
#include <cpu_func.h>
#include <asm/cacheops.h>
#ifdef CONFIG_MIPS_L2_CACHE
#include <asm/cm.h>
#endif
#include <asm/io.h>
#include <asm/mipsregs.h>
#include <asm/system.h>
DECLARE_GLOBAL_DATA_PTR;
static void probe_l2(void)
{
#ifdef CONFIG_MIPS_L2_CACHE
unsigned long conf2, sl;
bool l2c = false;
if (!(read_c0_config1() & MIPS_CONF_M))
return;
conf2 = read_c0_config2();
if (__mips_isa_rev >= 6) {
l2c = conf2 & MIPS_CONF_M;
if (l2c)
l2c = read_c0_config3() & MIPS_CONF_M;
if (l2c)
l2c = read_c0_config4() & MIPS_CONF_M;
if (l2c)
l2c = read_c0_config5() & MIPS_CONF5_L2C;
}
if (l2c && config_enabled(CONFIG_MIPS_CM)) {
gd->arch.l2_line_size = mips_cm_l2_line_size();
} else if (l2c) {
/* We don't know how to retrieve L2 config on this system */
BUG();
} else {
sl = (conf2 & MIPS_CONF2_SL) >> MIPS_CONF2_SL_SHF;
gd->arch.l2_line_size = sl ? (2 << sl) : 0;
}
#endif
}
void mips_cache_probe(void)
{
#ifdef CONFIG_SYS_CACHE_SIZE_AUTO
unsigned long conf1, il, dl;
conf1 = read_c0_config1();
il = (conf1 & MIPS_CONF1_IL) >> MIPS_CONF1_IL_SHF;
dl = (conf1 & MIPS_CONF1_DL) >> MIPS_CONF1_DL_SHF;
gd->arch.l1i_line_size = il ? (2 << il) : 0;
gd->arch.l1d_line_size = dl ? (2 << dl) : 0;
#endif
probe_l2();
}
static inline unsigned long icache_line_size(void)
{
#ifdef CONFIG_SYS_CACHE_SIZE_AUTO
return gd->arch.l1i_line_size;
#else
return CONFIG_SYS_ICACHE_LINE_SIZE;
#endif
}
static inline unsigned long dcache_line_size(void)
{
#ifdef CONFIG_SYS_CACHE_SIZE_AUTO
return gd->arch.l1d_line_size;
#else
return CONFIG_SYS_DCACHE_LINE_SIZE;
#endif
}
static inline unsigned long scache_line_size(void)
{
#ifdef CONFIG_MIPS_L2_CACHE
return gd->arch.l2_line_size;
#else
return CONFIG_SYS_SCACHE_LINE_SIZE;
#endif
}
#define cache_loop(start, end, lsize, ops...) do { \
const void *addr = (const void *)(start & ~(lsize - 1)); \
const void *aend = (const void *)((end - 1) & ~(lsize - 1)); \
const unsigned int cache_ops[] = { ops }; \
unsigned int i; \
\
if (!lsize) \
break; \
\
for (; addr <= aend; addr += lsize) { \
for (i = 0; i < ARRAY_SIZE(cache_ops); i++) \
mips_cache(cache_ops[i], addr); \
} \
} while (0)
void flush_cache(ulong start_addr, ulong size)
{
unsigned long ilsize = icache_line_size();
unsigned long dlsize = dcache_line_size();
unsigned long slsize = scache_line_size();
/* aend will be miscalculated when size is zero, so we return here */
if (size == 0)
return;
if ((ilsize == dlsize) && !slsize) {
/* flush I-cache & D-cache simultaneously */
cache_loop(start_addr, start_addr + size, ilsize,
HIT_WRITEBACK_INV_D, HIT_INVALIDATE_I);
goto ops_done;
}
/* flush D-cache */
cache_loop(start_addr, start_addr + size, dlsize, HIT_WRITEBACK_INV_D);
/* flush L2 cache */
cache_loop(start_addr, start_addr + size, slsize, HIT_WRITEBACK_INV_SD);
/* flush I-cache */
cache_loop(start_addr, start_addr + size, ilsize, HIT_INVALIDATE_I);
ops_done:
/* ensure cache ops complete before any further memory accesses */
sync();
/* ensure the pipeline doesn't contain now-invalid instructions */
instruction_hazard_barrier();
}
void flush_dcache_range(ulong start_addr, ulong stop)
{
unsigned long lsize = dcache_line_size();
unsigned long slsize = scache_line_size();
/* aend will be miscalculated when size is zero, so we return here */
if (start_addr == stop)
return;
cache_loop(start_addr, stop, lsize, HIT_WRITEBACK_INV_D);
/* flush L2 cache */
cache_loop(start_addr, stop, slsize, HIT_WRITEBACK_INV_SD);
/* ensure cache ops complete before any further memory accesses */
sync();
}
void invalidate_dcache_range(ulong start_addr, ulong stop)
{
unsigned long lsize = dcache_line_size();
unsigned long slsize = scache_line_size();
/* aend will be miscalculated when size is zero, so we return here */
if (start_addr == stop)
return;
/* invalidate L2 cache */
cache_loop(start_addr, stop, slsize, HIT_INVALIDATE_SD);
cache_loop(start_addr, stop, lsize, HIT_INVALIDATE_D);
/* ensure cache ops complete before any further memory accesses */
sync();
}
int dcache_status(void)
{
unsigned int cca = read_c0_config() & CONF_CM_CMASK;
return cca != CONF_CM_UNCACHED;
}
void dcache_enable(void)
{
puts("Not supported!\n");
}
void dcache_disable(void)
{
/* change CCA to uncached */
change_c0_config(CONF_CM_CMASK, CONF_CM_UNCACHED);
/* ensure the pipeline doesn't contain now-invalid instructions */
instruction_hazard_barrier();
}
@@ -0,0 +1,429 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Cache-handling routined for MIPS CPUs
*
* Copyright (c) 2003 Wolfgang Denk <wd@denx.de>
*/
#include <asm-offsets.h>
#include <config.h>
#include <asm/asm.h>
#include <asm/regdef.h>
#include <asm/mipsregs.h>
#include <asm/addrspace.h>
#include <asm/cacheops.h>
#include <asm/cm.h>
.macro f_fill64 dst, offset, val
LONG_S \val, (\offset + 0 * LONGSIZE)(\dst)
LONG_S \val, (\offset + 1 * LONGSIZE)(\dst)
LONG_S \val, (\offset + 2 * LONGSIZE)(\dst)
LONG_S \val, (\offset + 3 * LONGSIZE)(\dst)
LONG_S \val, (\offset + 4 * LONGSIZE)(\dst)
LONG_S \val, (\offset + 5 * LONGSIZE)(\dst)
LONG_S \val, (\offset + 6 * LONGSIZE)(\dst)
LONG_S \val, (\offset + 7 * LONGSIZE)(\dst)
#if LONGSIZE == 4
LONG_S \val, (\offset + 8 * LONGSIZE)(\dst)
LONG_S \val, (\offset + 9 * LONGSIZE)(\dst)
LONG_S \val, (\offset + 10 * LONGSIZE)(\dst)
LONG_S \val, (\offset + 11 * LONGSIZE)(\dst)
LONG_S \val, (\offset + 12 * LONGSIZE)(\dst)
LONG_S \val, (\offset + 13 * LONGSIZE)(\dst)
LONG_S \val, (\offset + 14 * LONGSIZE)(\dst)
LONG_S \val, (\offset + 15 * LONGSIZE)(\dst)
#endif
.endm
.macro cache_loop curr, end, line_sz, op
10: cache \op, 0(\curr)
PTR_ADDU \curr, \curr, \line_sz
bne \curr, \end, 10b
.endm
.macro l1_info sz, line_sz, off
.set push
.set noat
mfc0 $1, CP0_CONFIG, 1
/* detect line size */
srl \line_sz, $1, \off + MIPS_CONF1_DL_SHF - MIPS_CONF1_DA_SHF
andi \line_sz, \line_sz, (MIPS_CONF1_DL >> MIPS_CONF1_DL_SHF)
move \sz, zero
beqz \line_sz, 10f
li \sz, 2
sllv \line_sz, \sz, \line_sz
/* detect associativity */
srl \sz, $1, \off + MIPS_CONF1_DA_SHF - MIPS_CONF1_DA_SHF
andi \sz, \sz, (MIPS_CONF1_DA >> MIPS_CONF1_DA_SHF)
addiu \sz, \sz, 1
/* sz *= line_sz */
mul \sz, \sz, \line_sz
/* detect log32(sets) */
srl $1, $1, \off + MIPS_CONF1_DS_SHF - MIPS_CONF1_DA_SHF
andi $1, $1, (MIPS_CONF1_DS >> MIPS_CONF1_DS_SHF)
addiu $1, $1, 1
andi $1, $1, 0x7
/* sz <<= log32(sets) */
sllv \sz, \sz, $1
/* sz *= 32 */
li $1, 32
mul \sz, \sz, $1
10:
.set pop
.endm
/*
* mips_cache_reset - low level initialisation of the primary caches
*
* This routine initialises the primary caches to ensure that they have good
* parity. It must be called by the ROM before any cached locations are used
* to prevent the possibility of data with bad parity being written to memory.
*
* To initialise the instruction cache it is essential that a source of data
* with good parity is available. This routine will initialise an area of
* memory starting at location zero to be used as a source of parity.
*
* Note that this function does not follow the standard calling convention &
* may clobber typically callee-saved registers.
*
* RETURNS: N/A
*
*/
#define R_RETURN s0
#define R_IC_SIZE s1
#define R_IC_LINE s2
#define R_DC_SIZE s3
#define R_DC_LINE s4
#define R_L2_SIZE s5
#define R_L2_LINE s6
#define R_L2_BYPASSED s7
#define R_L2_L2C t8
LEAF(mips_cache_reset)
move R_RETURN, ra
#ifdef CONFIG_MIPS_L2_CACHE
/*
* For there to be an L2 present, Config2 must be present. If it isn't
* then we proceed knowing there's no L2 cache.
*/
move R_L2_SIZE, zero
move R_L2_LINE, zero
move R_L2_BYPASSED, zero
move R_L2_L2C, zero
mfc0 t0, CP0_CONFIG, 1
bgez t0, l2_probe_done
/*
* From MIPSr6 onwards the L2 cache configuration might not be reported
* by Config2. The Config5.L2C bit indicates whether this is the case,
* and if it is then we need knowledge of where else to look. For cores
* from Imagination Technologies this is a CM GCR.
*/
# if __mips_isa_rev >= 6
/* Check that Config5 exists */
mfc0 t0, CP0_CONFIG, 2
bgez t0, l2_probe_cop0
mfc0 t0, CP0_CONFIG, 3
bgez t0, l2_probe_cop0
mfc0 t0, CP0_CONFIG, 4
bgez t0, l2_probe_cop0
/* Check Config5.L2C is set */
mfc0 t0, CP0_CONFIG, 5
and R_L2_L2C, t0, MIPS_CONF5_L2C
beqz R_L2_L2C, l2_probe_cop0
/* Config5.L2C is set */
# ifdef CONFIG_MIPS_CM
/* The CM will provide L2 configuration */
PTR_LI t0, CKSEG1ADDR(CONFIG_MIPS_CM_BASE)
lw t1, GCR_L2_CONFIG(t0)
bgez t1, l2_probe_done
ext R_L2_LINE, t1, \
GCR_L2_CONFIG_LINESZ_SHIFT, GCR_L2_CONFIG_LINESZ_BITS
beqz R_L2_LINE, l2_probe_done
li t2, 2
sllv R_L2_LINE, t2, R_L2_LINE
ext t2, t1, GCR_L2_CONFIG_ASSOC_SHIFT, GCR_L2_CONFIG_ASSOC_BITS
addiu t2, t2, 1
mul R_L2_SIZE, R_L2_LINE, t2
ext t2, t1, GCR_L2_CONFIG_SETSZ_SHIFT, GCR_L2_CONFIG_SETSZ_BITS
sllv R_L2_SIZE, R_L2_SIZE, t2
li t2, 64
mul R_L2_SIZE, R_L2_SIZE, t2
/* Bypass the L2 cache so that we can init the L1s early */
or t1, t1, GCR_L2_CONFIG_BYPASS
sw t1, GCR_L2_CONFIG(t0)
sync
li R_L2_BYPASSED, 1
/* Zero the L2 tag registers */
sw zero, GCR_L2_TAG_ADDR(t0)
sw zero, GCR_L2_TAG_ADDR_UPPER(t0)
sw zero, GCR_L2_TAG_STATE(t0)
sw zero, GCR_L2_TAG_STATE_UPPER(t0)
sw zero, GCR_L2_DATA(t0)
sw zero, GCR_L2_DATA_UPPER(t0)
sync
# else
/* We don't know how to retrieve L2 configuration on this system */
# endif
b l2_probe_done
# endif
/*
* For pre-r6 systems, or r6 systems with Config5.L2C==0, probe the L2
* cache configuration from the cop0 Config2 register.
*/
l2_probe_cop0:
mfc0 t0, CP0_CONFIG, 2
srl R_L2_LINE, t0, MIPS_CONF2_SL_SHF
andi R_L2_LINE, R_L2_LINE, MIPS_CONF2_SL >> MIPS_CONF2_SL_SHF
beqz R_L2_LINE, l2_probe_done
li t1, 2
sllv R_L2_LINE, t1, R_L2_LINE
srl t1, t0, MIPS_CONF2_SA_SHF
andi t1, t1, MIPS_CONF2_SA >> MIPS_CONF2_SA_SHF
addiu t1, t1, 1
mul R_L2_SIZE, R_L2_LINE, t1
srl t1, t0, MIPS_CONF2_SS_SHF
andi t1, t1, MIPS_CONF2_SS >> MIPS_CONF2_SS_SHF
sllv R_L2_SIZE, R_L2_SIZE, t1
li t1, 64
mul R_L2_SIZE, R_L2_SIZE, t1
/* Attempt to bypass the L2 so that we can init the L1s early */
or t0, t0, MIPS_CONF2_L2B
mtc0 t0, CP0_CONFIG, 2
ehb
mfc0 t0, CP0_CONFIG, 2
and R_L2_BYPASSED, t0, MIPS_CONF2_L2B
/* Zero the L2 tag registers */
mtc0 zero, CP0_TAGLO, 4
ehb
l2_probe_done:
#endif
#ifndef CONFIG_SYS_CACHE_SIZE_AUTO
li R_IC_SIZE, CONFIG_SYS_ICACHE_SIZE
li R_IC_LINE, CONFIG_SYS_ICACHE_LINE_SIZE
#else
l1_info R_IC_SIZE, R_IC_LINE, MIPS_CONF1_IA_SHF
#endif
#ifndef CONFIG_SYS_CACHE_SIZE_AUTO
li R_DC_SIZE, CONFIG_SYS_DCACHE_SIZE
li R_DC_LINE, CONFIG_SYS_DCACHE_LINE_SIZE
#else
l1_info R_DC_SIZE, R_DC_LINE, MIPS_CONF1_DA_SHF
#endif
#ifdef CONFIG_SYS_MIPS_CACHE_INIT_RAM_LOAD
/* Determine the largest L1 cache size */
#ifndef CONFIG_SYS_CACHE_SIZE_AUTO
#if CONFIG_SYS_ICACHE_SIZE > CONFIG_SYS_DCACHE_SIZE
li v0, CONFIG_SYS_ICACHE_SIZE
#else
li v0, CONFIG_SYS_DCACHE_SIZE
#endif
#else
move v0, R_IC_SIZE
sltu t1, R_IC_SIZE, R_DC_SIZE
movn v0, R_DC_SIZE, t1
#endif
/*
* Now clear that much memory starting from zero.
*/
PTR_LI a0, CKSEG1ADDR(CONFIG_MIPS_CACHE_INDEX_BASE)
PTR_ADDU a1, a0, v0
2: PTR_ADDIU a0, 64
f_fill64 a0, -64, zero
bne a0, a1, 2b
#endif /* CONFIG_SYS_MIPS_CACHE_INIT_RAM_LOAD */
#ifdef CONFIG_MIPS_L2_CACHE
/*
* If the L2 is bypassed, init the L1 first so that we can execute the
* rest of the cache initialisation using the L1 instruction cache.
*/
bnez R_L2_BYPASSED, l1_init
l2_init:
PTR_LI t0, CKSEG0ADDR(CONFIG_MIPS_CACHE_INDEX_BASE)
PTR_ADDU t1, t0, R_L2_SIZE
1: cache INDEX_STORE_TAG_SD, 0(t0)
PTR_ADDU t0, t0, R_L2_LINE
bne t0, t1, 1b
/*
* If the L2 was bypassed then we already initialised the L1s before
* the L2, so we are now done.
*/
bnez R_L2_BYPASSED, l2_unbypass
#endif
/*
* The TagLo registers used depend upon the CPU implementation, but the
* architecture requires that it is safe for software to write to both
* TagLo selects 0 & 2 covering supported cases.
*/
l1_init:
mtc0 zero, CP0_TAGLO
mtc0 zero, CP0_TAGLO, 2
ehb
/*
* The caches are probably in an indeterminate state, so we force good
* parity into them by doing an invalidate for each line. If
* CONFIG_SYS_MIPS_CACHE_INIT_RAM_LOAD is set then we'll proceed to
* perform a load/fill & a further invalidate for each line, assuming
* that the bottom of RAM (having just been cleared) will generate good
* parity for the cache.
*/
/*
* Initialize the I-cache first,
*/
blez R_IC_SIZE, 1f
PTR_LI t0, CKSEG0ADDR(CONFIG_MIPS_CACHE_INDEX_BASE)
PTR_ADDU t1, t0, R_IC_SIZE
/* clear tag to invalidate */
cache_loop t0, t1, R_IC_LINE, INDEX_STORE_TAG_I
#ifdef CONFIG_SYS_MIPS_CACHE_INIT_RAM_LOAD
/* fill once, so data field parity is correct */
PTR_LI t0, CKSEG0ADDR(CONFIG_MIPS_CACHE_INDEX_BASE)
cache_loop t0, t1, R_IC_LINE, FILL
/* invalidate again - prudent but not strictly neccessary */
PTR_LI t0, CKSEG0ADDR(CONFIG_MIPS_CACHE_INDEX_BASE)
cache_loop t0, t1, R_IC_LINE, INDEX_STORE_TAG_I
#endif
sync
/*
* Enable use of the I-cache by setting Config.K0. The code for this
* must be executed from KSEG1. Jump from KSEG0 to KSEG1 to do this.
* Jump back to KSEG0 after caches are enabled and insert an
* instruction hazard barrier.
*/
PTR_LA t0, change_k0_cca
li t1, CPHYSADDR(~0)
and t0, t0, t1
PTR_LI t1, CKSEG1
or t0, t0, t1
li a0, CONF_CM_CACHABLE_NONCOHERENT
jalr.hb t0
/*
* then initialize D-cache.
*/
1: blez R_DC_SIZE, 3f
PTR_LI t0, CKSEG0ADDR(CONFIG_MIPS_CACHE_INDEX_BASE)
PTR_ADDU t1, t0, R_DC_SIZE
/* clear all tags */
cache_loop t0, t1, R_DC_LINE, INDEX_STORE_TAG_D
#ifdef CONFIG_SYS_MIPS_CACHE_INIT_RAM_LOAD
/* load from each line (in cached space) */
PTR_LI t0, CKSEG0ADDR(CONFIG_MIPS_CACHE_INDEX_BASE)
2: LONG_L zero, 0(t0)
PTR_ADDU t0, R_DC_LINE
bne t0, t1, 2b
/* clear all tags */
PTR_LI t0, CKSEG0ADDR(CONFIG_MIPS_CACHE_INDEX_BASE)
cache_loop t0, t1, R_DC_LINE, INDEX_STORE_TAG_D
#endif
3:
#ifdef CONFIG_MIPS_L2_CACHE
/* If the L2 isn't bypassed then we're done */
beqz R_L2_BYPASSED, return
/* The L2 is bypassed - go initialise it */
b l2_init
l2_unbypass:
# if __mips_isa_rev >= 6
beqz R_L2_L2C, 1f
li t0, CKSEG1ADDR(CONFIG_MIPS_CM_BASE)
lw t1, GCR_L2_CONFIG(t0)
xor t1, t1, GCR_L2_CONFIG_BYPASS
sw t1, GCR_L2_CONFIG(t0)
sync
ehb
b 2f
# endif
1: mfc0 t0, CP0_CONFIG, 2
xor t0, t0, MIPS_CONF2_L2B
mtc0 t0, CP0_CONFIG, 2
ehb
2:
# ifdef CONFIG_MIPS_CM
/* Config3 must exist for a CM to be present */
mfc0 t0, CP0_CONFIG, 1
bgez t0, 2f
mfc0 t0, CP0_CONFIG, 2
bgez t0, 2f
/* Check Config3.CMGCR to determine CM presence */
mfc0 t0, CP0_CONFIG, 3
and t0, t0, MIPS_CONF3_CMGCR
beqz t0, 2f
/* Change Config.K0 to a coherent CCA */
PTR_LA t0, change_k0_cca
li a0, CONF_CM_CACHABLE_COW
jalr t0
/*
* Join the coherent domain such that the caches of this core are kept
* coherent with those of other cores.
*/
PTR_LI t0, CKSEG1ADDR(CONFIG_MIPS_CM_BASE)
lw t1, GCR_REV(t0)
li t2, GCR_REV_CM3
li t3, GCR_Cx_COHERENCE_EN
bge t1, t2, 1f
li t3, GCR_Cx_COHERENCE_DOM_EN
1: sw t3, GCR_Cx_COHERENCE(t0)
ehb
2:
# endif
#endif
return:
/* Ensure all cache operations complete before returning */
sync
jr R_RETURN
END(mips_cache_reset)
LEAF(change_k0_cca)
mfc0 t0, CP0_CONFIG
#if __mips_isa_rev >= 2
ins t0, a0, 0, 3
#else
xor a0, a0, t0
andi a0, a0, CONF_CM_CMASK
xor a0, a0, t0
#endif
mtc0 a0, CP0_CONFIG
jr.hb ra
END(change_k0_cca)
@@ -0,0 +1,223 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 1994 - 2000, 2001, 2003 Ralf Baechle
* Copyright (C) 1999, 2000 Silicon Graphics, Inc.
* Copyright (C) 2002, 2007 Maciej W. Rozycki
* Copyright (C) 2001, 2012 MIPS Technologies, Inc. All rights reserved.
*/
#include <asm/asm.h>
#include <asm/regdef.h>
#include <asm/mipsregs.h>
#include <asm/asm-offsets.h>
#define STATMASK 0x1f
.set noreorder
/*
* Macros copied and adapted from Linux MIPS
*/
.macro SAVE_AT
.set push
.set noat
LONG_S $1, PT_R1(sp)
.set pop
.endm
.macro SAVE_TEMP
#if __mips_isa_rev < 6
mfhi v1
#endif
#ifdef CONFIG_32BIT
LONG_S $8, PT_R8(sp)
LONG_S $9, PT_R9(sp)
#endif
LONG_S $10, PT_R10(sp)
LONG_S $11, PT_R11(sp)
LONG_S $12, PT_R12(sp)
#if __mips_isa_rev < 6
LONG_S v1, PT_HI(sp)
mflo v1
#endif
LONG_S $13, PT_R13(sp)
LONG_S $14, PT_R14(sp)
LONG_S $15, PT_R15(sp)
LONG_S $24, PT_R24(sp)
#if __mips_isa_rev < 6
LONG_S v1, PT_LO(sp)
#endif
.endm
.macro SAVE_STATIC
LONG_S $16, PT_R16(sp)
LONG_S $17, PT_R17(sp)
LONG_S $18, PT_R18(sp)
LONG_S $19, PT_R19(sp)
LONG_S $20, PT_R20(sp)
LONG_S $21, PT_R21(sp)
LONG_S $22, PT_R22(sp)
LONG_S $23, PT_R23(sp)
LONG_S $30, PT_R30(sp)
.endm
.macro SAVE_SOME
.set push
.set noat
PTR_SUBU k1, sp, PT_SIZE
LONG_S sp, PT_R29(k1)
move sp, k1
LONG_S $3, PT_R3(sp)
LONG_S $0, PT_R0(sp)
mfc0 v1, CP0_STATUS
LONG_S $2, PT_R2(sp)
LONG_S v1, PT_STATUS(sp)
LONG_S $4, PT_R4(sp)
mfc0 v1, CP0_CAUSE
LONG_S $5, PT_R5(sp)
LONG_S v1, PT_CAUSE(sp)
LONG_S $6, PT_R6(sp)
MFC0 v1, CP0_EPC
LONG_S $7, PT_R7(sp)
#ifdef CONFIG_64BIT
LONG_S $8, PT_R8(sp)
LONG_S $9, PT_R9(sp)
#endif
LONG_S v1, PT_EPC(sp)
LONG_S $25, PT_R25(sp)
LONG_S $28, PT_R28(sp)
LONG_S $31, PT_R31(sp)
.set pop
.endm
.macro RESTORE_AT
.set push
.set noat
LONG_L $1, PT_R1(sp)
.set pop
.endm
.macro RESTORE_TEMP
#if __mips_isa_rev < 6
LONG_L $24, PT_LO(sp)
mtlo $24
LONG_L $24, PT_HI(sp)
mthi $24
#endif
#ifdef CONFIG_32BIT
LONG_L $8, PT_R8(sp)
LONG_L $9, PT_R9(sp)
#endif
LONG_L $10, PT_R10(sp)
LONG_L $11, PT_R11(sp)
LONG_L $12, PT_R12(sp)
LONG_L $13, PT_R13(sp)
LONG_L $14, PT_R14(sp)
LONG_L $15, PT_R15(sp)
LONG_L $24, PT_R24(sp)
.endm
.macro RESTORE_STATIC
LONG_L $16, PT_R16(sp)
LONG_L $17, PT_R17(sp)
LONG_L $18, PT_R18(sp)
LONG_L $19, PT_R19(sp)
LONG_L $20, PT_R20(sp)
LONG_L $21, PT_R21(sp)
LONG_L $22, PT_R22(sp)
LONG_L $23, PT_R23(sp)
LONG_L $30, PT_R30(sp)
.endm
.macro RESTORE_SOME
.set push
.set reorder
.set noat
mfc0 a0, CP0_STATUS
ori a0, STATMASK
xori a0, STATMASK
mtc0 a0, CP0_STATUS
li v1, ST0_CU1 | ST0_FR | ST0_IM
and a0, v1
LONG_L v0, PT_STATUS(sp)
nor v1, $0, v1
and v0, v1
or v0, a0
mtc0 v0, CP0_STATUS
LONG_L v1, PT_EPC(sp)
MTC0 v1, CP0_EPC
LONG_L $31, PT_R31(sp)
LONG_L $28, PT_R28(sp)
LONG_L $25, PT_R25(sp)
#ifdef CONFIG_64BIT
LONG_L $8, PT_R8(sp)
LONG_L $9, PT_R9(sp)
#endif
LONG_L $7, PT_R7(sp)
LONG_L $6, PT_R6(sp)
LONG_L $5, PT_R5(sp)
LONG_L $4, PT_R4(sp)
LONG_L $3, PT_R3(sp)
LONG_L $2, PT_R2(sp)
.set pop
.endm
.macro RESTORE_SP
LONG_L sp, PT_R29(sp)
.endm
NESTED(except_vec3_generic, 0, sp)
PTR_LA k1, handle_reserved
jr k1
nop
END(except_vec3_generic)
NESTED(except_vec_ejtag_debug, 0, sp)
PTR_LA k1, handle_ejtag_debug
jr k1
nop
END(except_vec_ejtag_debug)
NESTED(handle_reserved, PT_SIZE, sp)
SAVE_SOME
SAVE_AT
SAVE_TEMP
SAVE_STATIC
PTR_LA t9, do_reserved
jr t9
move a0, sp
END(handle_reserved)
NESTED(handle_ejtag_debug, PT_SIZE, sp)
.set push
.set noat
MTC0 k1, CP0_DESAVE
/* Check for SDBBP */
MFC0 k1, CP0_DEBUG
sll k1, k1, 30
bgez k1, ejtag_return
nop
SAVE_SOME
SAVE_AT
SAVE_TEMP
SAVE_STATIC
PTR_LA t9, do_ejtag_debug
jalr t9
move a0, sp
RESTORE_TEMP
RESTORE_STATIC
RESTORE_AT
RESTORE_SOME
RESTORE_SP
ejtag_return:
MFC0 k1, CP0_DESAVE
deret
.set pop
END(handle_ejtag_debug)
@@ -0,0 +1,25 @@
#ifndef __ASM_LIBGCC_H
#define __ASM_LIBGCC_H
#include <asm/byteorder.h>
typedef int word_type __attribute__ ((mode (__word__)));
#ifdef __BIG_ENDIAN
struct DWstruct {
int high, low;
};
#elif defined(__LITTLE_ENDIAN)
struct DWstruct {
int low, high;
};
#else
#error I feel sick.
#endif
typedef union {
struct DWstruct s;
long long ll;
} DWunion;
#endif /* __ASM_LIBGCC_H */
@@ -0,0 +1,25 @@
#include "libgcc.h"
long long __lshrdi3(long long u, word_type b)
{
DWunion uu, w;
word_type bm;
if (b == 0)
return u;
uu.ll = u;
bm = 32 - b;
if (bm <= 0) {
w.s.high = 0;
w.s.low = (unsigned int) uu.s.high >> -bm;
} else {
const unsigned int carries = (unsigned int) uu.s.high << bm;
w.s.high = (unsigned int) uu.s.high >> b;
w.s.low = ((unsigned int) uu.s.low >> b) | carries;
}
return w.ll;
}
@@ -0,0 +1,164 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* MIPS Relocation
*
* Copyright (c) 2017 Imagination Technologies Ltd.
*
* Relocation data, found in the .rel section, is generated by the mips-relocs
* tool & contains a record of all locations in the U-Boot binary that need to
* be fixed up during relocation.
*
* The data is a sequence of unsigned integers, which are of somewhat arbitrary
* size. This is achieved by encoding integers as a sequence of bytes, each of
* which contains 7 bits of data with the most significant bit indicating
* whether any further bytes need to be read. The least significant bits of the
* integer are found in the first byte - ie. it somewhat resembles little
* endian.
*
* Each pair of two integers represents a relocation that must be applied. The
* first integer represents the type of relocation as a standard ELF relocation
* type (ie. R_MIPS_*). The second integer represents the offset at which to
* apply the relocation, relative to the previous relocation or for the first
* relocation the start of the relocated .text section.
*
* The end of the relocation data is indicated when type R_MIPS_NONE (0) is
* read, at which point no further integers should be read. That is, the
* terminating R_MIPS_NONE reloc includes no offset.
*/
#include <common.h>
#include <cpu_func.h>
#include <asm/relocs.h>
#include <asm/sections.h>
/**
* read_uint() - Read an unsigned integer from the buffer
* @buf: pointer to a pointer to the reloc buffer
*
* Read one whole unsigned integer from the relocation data pointed to by @buf,
* advancing @buf past the bytes encoding the integer.
*
* Returns: the integer read from @buf
*/
static unsigned long read_uint(uint8_t **buf)
{
unsigned long val = 0;
unsigned int shift = 0;
uint8_t new;
do {
new = *(*buf)++;
val |= (new & 0x7f) << shift;
shift += 7;
} while (new & 0x80);
return val;
}
/**
* apply_reloc() - Apply a single relocation
* @type: the type of reloc (R_MIPS_*)
* @addr: the address that the reloc should be applied to
* @off: the relocation offset, ie. number of bytes we're moving U-Boot by
*
* Apply a single relocation of type @type at @addr. This function is
* intentionally simple, and does the bare minimum needed to fixup the
* relocated U-Boot - in particular, it does not check for overflows.
*/
static void apply_reloc(unsigned int type, void *addr, long off)
{
uint32_t u32;
switch (type) {
case R_MIPS_26:
u32 = *(uint32_t *)addr;
u32 = (u32 & GENMASK(31, 26)) |
((u32 + (off >> 2)) & GENMASK(25, 0));
*(uint32_t *)addr = u32;
break;
case R_MIPS_32:
*(uint32_t *)addr += off;
break;
case R_MIPS_64:
*(uint64_t *)addr += off;
break;
case R_MIPS_HI16:
*(uint32_t *)addr += off >> 16;
break;
default:
panic("Unhandled reloc type %u\n", type);
}
}
/**
* relocate_code() - Relocate U-Boot, generally from flash to DDR
* @start_addr_sp: new stack pointer
* @new_gd: pointer to relocated global data
* @relocaddr: the address to relocate to
*
* Relocate U-Boot from its current location (generally in flash) to a new one
* (generally in DDR). This function will copy the U-Boot binary & apply
* relocations as necessary, then jump to board_init_r in the new build of
* U-Boot. As such, this function does not return.
*/
void relocate_code(ulong start_addr_sp, gd_t *new_gd, ulong relocaddr)
{
unsigned long addr, length, bss_len;
uint8_t *buf, *bss_start;
unsigned int type;
long off;
/*
* Ensure that we're relocating by an offset which is a multiple of
* 64KiB, ie. doesn't change the least significant 16 bits of any
* addresses. This allows us to discard R_MIPS_LO16 relocs, saving
* space in the U-Boot binary & complexity in handling them.
*/
off = relocaddr - (unsigned long)__text_start;
if (off & 0xffff)
panic("Mis-aligned relocation\n");
/* Copy U-Boot to RAM */
length = __image_copy_end - __text_start;
memcpy((void *)relocaddr, __text_start, length);
/* Now apply relocations to the copy in RAM */
buf = __rel_start;
addr = relocaddr;
while (true) {
type = read_uint(&buf);
if (type == R_MIPS_NONE)
break;
addr += read_uint(&buf) << 2;
apply_reloc(type, (void *)addr, off);
}
/* Ensure the icache is coherent */
flush_cache(relocaddr, length);
/* Clear the .bss section */
bss_start = (uint8_t *)((unsigned long)__bss_start + off);
bss_len = (unsigned long)&__bss_end - (unsigned long)__bss_start;
memset(bss_start, 0, bss_len);
/* Jump to the relocated U-Boot */
asm volatile(
"move $29, %0\n"
" move $4, %1\n"
" move $5, %2\n"
" move $31, $0\n"
" jr %3"
: /* no outputs */
: "r"(start_addr_sp),
"r"(new_gd),
"r"(relocaddr),
"r"((unsigned long)board_init_r + off));
/* Since we jumped to the new U-Boot above, we won't get here */
unreachable();
}
@@ -0,0 +1,17 @@
// SPDX-License-Identifier: GPL-2.0+
#include <common.h>
DECLARE_GLOBAL_DATA_PTR;
int arch_reserve_stacks(void)
{
/* reserve space for exception vector table */
gd->start_addr_sp -= 0x500;
gd->start_addr_sp &= ~0xFFF;
gd->irq_sp = gd->start_addr_sp;
debug("Reserving %d Bytes for exception vector at: %08lx\n",
0x500, gd->start_addr_sp);
return 0;
}
@@ -0,0 +1,107 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 1994 - 1999, 2000, 01, 06 Ralf Baechle
* Copyright (C) 1995, 1996 Paul M. Antoine
* Copyright (C) 1998 Ulf Carlsson
* Copyright (C) 1999 Silicon Graphics, Inc.
* Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
* Copyright (C) 2002, 2003, 2004, 2005, 2007 Maciej W. Rozycki
* Copyright (C) 2000, 2001, 2012 MIPS Technologies, Inc. All rights reserved.
* Copyright (C) 2014, Imagination Technologies Ltd.
*/
#include <common.h>
#include <cpu_func.h>
#include <init.h>
#include <asm/mipsregs.h>
#include <asm/addrspace.h>
#include <asm/system.h>
DECLARE_GLOBAL_DATA_PTR;
static void show_regs(const struct pt_regs *regs)
{
const int field = 2 * sizeof(unsigned long);
unsigned int cause = regs->cp0_cause;
unsigned int exccode;
int i;
/*
* Saved main processor registers
*/
for (i = 0; i < 32; ) {
if ((i % 4) == 0)
printf("$%2d :", i);
if (i == 0)
printf(" %0*lx", field, 0UL);
else if (i == 26 || i == 27)
printf(" %*s", field, "");
else
printf(" %0*lx", field, regs->regs[i]);
i++;
if ((i % 4) == 0)
puts("\n");
}
printf("Hi : %0*lx\n", field, regs->hi);
printf("Lo : %0*lx\n", field, regs->lo);
/*
* Saved cp0 registers
*/
printf("epc : %0*lx (text %0*lx)\n", field, regs->cp0_epc,
field, regs->cp0_epc - gd->reloc_off);
printf("ra : %0*lx (text %0*lx)\n", field, regs->regs[31],
field, regs->regs[31] - gd->reloc_off);
printf("Status: %08x\n", (uint32_t) regs->cp0_status);
exccode = (cause & CAUSEF_EXCCODE) >> CAUSEB_EXCCODE;
printf("Cause : %08x (ExcCode %02x)\n", cause, exccode);
if (1 <= exccode && exccode <= 5)
printf("BadVA : %0*lx\n", field, regs->cp0_badvaddr);
printf("PrId : %08x\n", read_c0_prid());
}
void do_reserved(const struct pt_regs *regs)
{
puts("\nOoops:\n");
show_regs(regs);
hang();
}
void do_ejtag_debug(const struct pt_regs *regs)
{
const int field = 2 * sizeof(unsigned long);
unsigned long depc;
unsigned int debug;
depc = read_c0_depc();
debug = read_c0_debug();
printf("SDBBP EJTAG debug exception: c0_depc = %0*lx, DEBUG = %08x\n",
field, depc, debug);
}
static void set_handler(unsigned long offset, void *addr, unsigned long size)
{
unsigned long ebase = gd->irq_sp;
memcpy((void *)(ebase + offset), addr, size);
flush_cache(ebase + offset, size);
}
void trap_init(ulong reloc_addr)
{
unsigned long ebase = gd->irq_sp;
set_handler(0x180, &except_vec3_generic, 0x80);
set_handler(0x280, &except_vec_ejtag_debug, 0x80);
write_c0_ebase(ebase);
clear_c0_status(ST0_BEV);
execution_hazard_barrier();
}