GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# (C) Copyright 2007 - 2013 Tensilica Inc.
|
||||
# (C) Copyright 2014 - 2016 Cadence Design Systems Inc.
|
||||
|
||||
obj-$(CONFIG_CMD_BOOTM) += bootm.o
|
||||
|
||||
obj-y += cache.o misc.o relocate.o time.o
|
||||
@@ -0,0 +1,198 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2008 - 2013 Tensilica Inc.
|
||||
* (C) Copyright 2014 Cadence Design Systems Inc.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <cpu_func.h>
|
||||
#include <env.h>
|
||||
#include <u-boot/zlib.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include <asm/addrspace.h>
|
||||
#include <asm/bootparam.h>
|
||||
#include <asm/cache.h>
|
||||
#include <image.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/*
|
||||
* Setup boot-parameters.
|
||||
*/
|
||||
|
||||
static struct bp_tag *setup_first_tag(struct bp_tag *params)
|
||||
{
|
||||
params->id = BP_TAG_FIRST;
|
||||
params->size = sizeof(long);
|
||||
*(unsigned long *)¶ms->data = BP_VERSION;
|
||||
|
||||
return bp_tag_next(params);
|
||||
}
|
||||
|
||||
static struct bp_tag *setup_last_tag(struct bp_tag *params)
|
||||
{
|
||||
params->id = BP_TAG_LAST;
|
||||
params->size = 0;
|
||||
|
||||
return bp_tag_next(params);
|
||||
}
|
||||
|
||||
static struct bp_tag *setup_memory_tag(struct bp_tag *params)
|
||||
{
|
||||
struct bd_info *bd = gd->bd;
|
||||
struct meminfo *mem;
|
||||
|
||||
params->id = BP_TAG_MEMORY;
|
||||
params->size = sizeof(struct meminfo);
|
||||
mem = (struct meminfo *)params->data;
|
||||
mem->type = MEMORY_TYPE_CONVENTIONAL;
|
||||
mem->start = bd->bi_memstart;
|
||||
mem->end = bd->bi_memstart + bd->bi_memsize;
|
||||
|
||||
printf(" MEMORY: tag:0x%04x, type:0X%lx, start:0X%lx, end:0X%lx\n",
|
||||
BP_TAG_MEMORY, mem->type, mem->start, mem->end);
|
||||
|
||||
return bp_tag_next(params);
|
||||
}
|
||||
|
||||
static struct bp_tag *setup_commandline_tag(struct bp_tag *params,
|
||||
char *cmdline)
|
||||
{
|
||||
int len;
|
||||
|
||||
if (!cmdline)
|
||||
return params;
|
||||
|
||||
len = strlen(cmdline);
|
||||
|
||||
params->id = BP_TAG_COMMAND_LINE;
|
||||
params->size = (len + 3) & -4;
|
||||
strcpy((char *)params->data, cmdline);
|
||||
|
||||
printf(" COMMAND_LINE: tag:0x%04x, size:%u, data:'%s'\n",
|
||||
BP_TAG_COMMAND_LINE, params->size, cmdline);
|
||||
|
||||
return bp_tag_next(params);
|
||||
}
|
||||
|
||||
static struct bp_tag *setup_ramdisk_tag(struct bp_tag *params,
|
||||
unsigned long rd_start,
|
||||
unsigned long rd_end)
|
||||
{
|
||||
struct meminfo *mem;
|
||||
|
||||
if (rd_start == rd_end)
|
||||
return params;
|
||||
|
||||
/* Add a single banked memory */
|
||||
|
||||
params->id = BP_TAG_INITRD;
|
||||
params->size = sizeof(struct meminfo);
|
||||
|
||||
mem = (struct meminfo *)params->data;
|
||||
mem->type = MEMORY_TYPE_CONVENTIONAL;
|
||||
mem->start = PHYSADDR(rd_start);
|
||||
mem->end = PHYSADDR(rd_end);
|
||||
|
||||
printf(" INITRD: tag:0x%x, type:0X%04lx, start:0X%lx, end:0X%lx\n",
|
||||
BP_TAG_INITRD, mem->type, mem->start, mem->end);
|
||||
|
||||
return bp_tag_next(params);
|
||||
}
|
||||
|
||||
static struct bp_tag *setup_serial_tag(struct bp_tag *params)
|
||||
{
|
||||
params->id = BP_TAG_SERIAL_BAUDRATE;
|
||||
params->size = sizeof(unsigned long);
|
||||
params->data[0] = gd->baudrate;
|
||||
|
||||
printf(" SERIAL_BAUDRATE: tag:0x%04x, size:%u, baudrate:%lu\n",
|
||||
BP_TAG_SERIAL_BAUDRATE, params->size, params->data[0]);
|
||||
|
||||
return bp_tag_next(params);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF_LIBFDT
|
||||
|
||||
static struct bp_tag *setup_fdt_tag(struct bp_tag *params, void *fdt_start)
|
||||
{
|
||||
params->id = BP_TAG_FDT;
|
||||
params->size = sizeof(unsigned long);
|
||||
params->data[0] = (unsigned long)fdt_start;
|
||||
|
||||
printf(" FDT: tag:0x%04x, size:%u, start:0x%lx\n",
|
||||
BP_TAG_FDT, params->size, params->data[0]);
|
||||
|
||||
return bp_tag_next(params);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Boot Linux.
|
||||
*/
|
||||
|
||||
int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
|
||||
{
|
||||
struct bp_tag *params, *params_start;
|
||||
ulong initrd_start, initrd_end;
|
||||
char *commandline = env_get("bootargs");
|
||||
|
||||
if (!(flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)))
|
||||
return 0;
|
||||
|
||||
show_boot_progress(15);
|
||||
|
||||
if (images->rd_start) {
|
||||
initrd_start = images->rd_start;
|
||||
initrd_end = images->rd_end;
|
||||
} else {
|
||||
initrd_start = 0;
|
||||
initrd_end = 0;
|
||||
}
|
||||
|
||||
params_start = (struct bp_tag *)gd->bd->bi_boot_params;
|
||||
params = params_start;
|
||||
params = setup_first_tag(params);
|
||||
params = setup_memory_tag(params);
|
||||
params = setup_commandline_tag(params, commandline);
|
||||
params = setup_serial_tag(params);
|
||||
|
||||
if (initrd_start)
|
||||
params = setup_ramdisk_tag(params, initrd_start, initrd_end);
|
||||
|
||||
#ifdef CONFIG_OF_LIBFDT
|
||||
if (images->ft_addr)
|
||||
params = setup_fdt_tag(params, images->ft_addr);
|
||||
#endif
|
||||
|
||||
printf("\n");
|
||||
|
||||
params = setup_last_tag(params);
|
||||
|
||||
show_boot_progress(15);
|
||||
|
||||
printf("Transferring Control to Linux @0x%08lx ...\n\n",
|
||||
(ulong)images->ep);
|
||||
|
||||
flush_dcache_range((unsigned long)params_start, (unsigned long)params);
|
||||
|
||||
if (flag & BOOTM_STATE_OS_FAKE_GO)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* _start() in vmlinux expects boot params in register a2.
|
||||
* NOTE:
|
||||
* Disable/delete your u-boot breakpoints before stepping into linux.
|
||||
*/
|
||||
asm volatile ("mov a2, %0\n\t"
|
||||
"jx %1\n\t"
|
||||
: : "a" (params_start), "a" (images->ep)
|
||||
: "a2");
|
||||
|
||||
/* Does not return */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2008 - 2013 Tensilica Inc.
|
||||
* (C) Copyright 2014 - 2016 Cadence Design Systems Inc.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <cpu_func.h>
|
||||
#include <asm/cache.h>
|
||||
|
||||
/*
|
||||
* We currently run always with caches enabled when running from memory.
|
||||
* Xtensa version D or later will support changing cache behavior, so
|
||||
* we could implement it if necessary.
|
||||
*/
|
||||
|
||||
int dcache_status(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void dcache_enable(void)
|
||||
{
|
||||
}
|
||||
|
||||
void dcache_disable(void)
|
||||
{
|
||||
}
|
||||
|
||||
void flush_cache(ulong start_addr, ulong size)
|
||||
{
|
||||
__flush_invalidate_dcache_range(start_addr, size);
|
||||
__invalidate_icache_range(start_addr, size);
|
||||
}
|
||||
|
||||
void flush_dcache_all(void)
|
||||
{
|
||||
__flush_dcache_all();
|
||||
__invalidate_icache_all();
|
||||
}
|
||||
|
||||
void flush_dcache_range(ulong start_addr, ulong end_addr)
|
||||
{
|
||||
__flush_invalidate_dcache_range(start_addr, end_addr - start_addr);
|
||||
}
|
||||
|
||||
void invalidate_dcache_range(ulong start, ulong stop)
|
||||
{
|
||||
__invalidate_dcache_range(start, stop - start);
|
||||
}
|
||||
|
||||
void invalidate_dcache_all(void)
|
||||
{
|
||||
__invalidate_dcache_all();
|
||||
}
|
||||
|
||||
void invalidate_icache_all(void)
|
||||
{
|
||||
__invalidate_icache_all();
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Miscellaneous assembly functions.
|
||||
*
|
||||
* Copyright (C) 2001 - 2007 Tensilica Inc.
|
||||
* Copyright (C) 2014 - 2016 Cadence Design Systems Inc.
|
||||
*
|
||||
* Chris Zankel <chris@zankel.net>
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/asmmacro.h>
|
||||
#include <asm/cacheasm.h>
|
||||
|
||||
/*
|
||||
* void __invalidate_icache_page(ulong start)
|
||||
*/
|
||||
|
||||
ENTRY(__invalidate_icache_page)
|
||||
|
||||
abi_entry
|
||||
|
||||
___invalidate_icache_page a2 a3
|
||||
isync
|
||||
|
||||
abi_ret
|
||||
|
||||
ENDPROC(__invalidate_icache_page)
|
||||
|
||||
/*
|
||||
* void __invalidate_dcache_page(ulong start)
|
||||
*/
|
||||
|
||||
ENTRY(__invalidate_dcache_page)
|
||||
|
||||
abi_entry
|
||||
|
||||
___invalidate_dcache_page a2 a3
|
||||
dsync
|
||||
|
||||
abi_ret
|
||||
|
||||
ENDPROC(__invalidate_dcache_page)
|
||||
|
||||
/*
|
||||
* void __flush_invalidate_dcache_page(ulong start)
|
||||
*/
|
||||
|
||||
ENTRY(__flush_invalidate_dcache_page)
|
||||
|
||||
abi_entry
|
||||
|
||||
___flush_invalidate_dcache_page a2 a3
|
||||
|
||||
dsync
|
||||
abi_ret
|
||||
|
||||
ENDPROC(__flush_invalidate_dcache_page)
|
||||
|
||||
/*
|
||||
* void __flush_dcache_page(ulong start)
|
||||
*/
|
||||
|
||||
ENTRY(__flush_dcache_page)
|
||||
|
||||
abi_entry
|
||||
|
||||
___flush_dcache_page a2 a3
|
||||
|
||||
dsync
|
||||
abi_ret
|
||||
|
||||
ENDPROC(__flush_dcache_page)
|
||||
|
||||
/*
|
||||
* void __invalidate_icache_range(ulong start, ulong size)
|
||||
*/
|
||||
|
||||
ENTRY(__invalidate_icache_range)
|
||||
|
||||
abi_entry
|
||||
|
||||
___invalidate_icache_range a2 a3 a4
|
||||
isync
|
||||
|
||||
abi_ret
|
||||
|
||||
ENDPROC(__invalidate_icache_range)
|
||||
|
||||
/*
|
||||
* void __flush_invalidate_dcache_range(ulong start, ulong size)
|
||||
*/
|
||||
|
||||
ENTRY(__flush_invalidate_dcache_range)
|
||||
|
||||
abi_entry
|
||||
|
||||
___flush_invalidate_dcache_range a2 a3 a4
|
||||
dsync
|
||||
|
||||
abi_ret
|
||||
|
||||
ENDPROC(__flush_invalidate_dcache_range)
|
||||
|
||||
/*
|
||||
* void _flush_dcache_range(ulong start, ulong size)
|
||||
*/
|
||||
|
||||
ENTRY(__flush_dcache_range)
|
||||
|
||||
abi_entry
|
||||
|
||||
___flush_dcache_range a2 a3 a4
|
||||
dsync
|
||||
|
||||
abi_ret
|
||||
|
||||
ENDPROC(__flush_dcache_range)
|
||||
|
||||
/*
|
||||
* void _invalidate_dcache_range(ulong start, ulong size)
|
||||
*/
|
||||
|
||||
ENTRY(__invalidate_dcache_range)
|
||||
|
||||
abi_entry
|
||||
|
||||
___invalidate_dcache_range a2 a3 a4
|
||||
|
||||
abi_ret
|
||||
|
||||
ENDPROC(__invalidate_dcache_range)
|
||||
|
||||
/*
|
||||
* void _invalidate_icache_all(void)
|
||||
*/
|
||||
|
||||
ENTRY(__invalidate_icache_all)
|
||||
|
||||
abi_entry
|
||||
|
||||
___invalidate_icache_all a2 a3
|
||||
isync
|
||||
|
||||
abi_ret
|
||||
|
||||
ENDPROC(__invalidate_icache_all)
|
||||
|
||||
/*
|
||||
* void _flush_invalidate_dcache_all(void)
|
||||
*/
|
||||
|
||||
ENTRY(__flush_invalidate_dcache_all)
|
||||
|
||||
abi_entry
|
||||
|
||||
___flush_invalidate_dcache_all a2 a3
|
||||
dsync
|
||||
|
||||
abi_ret
|
||||
|
||||
ENDPROC(__flush_invalidate_dcache_all)
|
||||
|
||||
/*
|
||||
* void _invalidate_dcache_all(void)
|
||||
*/
|
||||
|
||||
ENTRY(__invalidate_dcache_all)
|
||||
|
||||
abi_entry
|
||||
|
||||
___invalidate_dcache_all a2 a3
|
||||
dsync
|
||||
|
||||
abi_ret
|
||||
|
||||
ENDPROC(__invalidate_dcache_all)
|
||||
@@ -0,0 +1,17 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2016 Cadence Design Systems Inc.
|
||||
*/
|
||||
|
||||
#include <relocate.h>
|
||||
#include <asm/sections.h>
|
||||
#include <asm/string.h>
|
||||
|
||||
int clear_bss(void)
|
||||
{
|
||||
size_t len = (size_t)&__bss_end - (size_t)&__bss_start;
|
||||
|
||||
memset((void *)&__bss_start, 0x00, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2008 - 2013 Tensilica Inc.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <time.h>
|
||||
#include <asm/global_data.h>
|
||||
#include <linux/stringify.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#if XCHAL_HAVE_CCOUNT
|
||||
static ulong get_ccount(void)
|
||||
{
|
||||
ulong ccount;
|
||||
asm volatile ("rsr %0,"__stringify(CCOUNT) : "=a" (ccount));
|
||||
return ccount;
|
||||
}
|
||||
#else
|
||||
static ulong fake_ccount;
|
||||
#define get_ccount() fake_ccount
|
||||
#endif
|
||||
|
||||
static void delay_cycles(unsigned cycles)
|
||||
{
|
||||
#if XCHAL_HAVE_CCOUNT
|
||||
unsigned expiry = get_ccount() + cycles;
|
||||
while ((signed)(expiry - get_ccount()) > 0)
|
||||
;
|
||||
#else
|
||||
#warning "Without Xtensa timer option, timing will not be accurate."
|
||||
|
||||
/*
|
||||
* Approximate the cycle count by a loop iteration count.
|
||||
* This is highly dependent on config and optimization.
|
||||
*/
|
||||
|
||||
volatile unsigned i;
|
||||
for (i = cycles >> 4U; i > 0; --i)
|
||||
;
|
||||
fake_ccount += cycles;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Delay (busy-wait) for a number of microseconds.
|
||||
*/
|
||||
|
||||
void __udelay(unsigned long usec)
|
||||
{
|
||||
ulong lo, hi, i;
|
||||
ulong mhz = CONFIG_SYS_CLK_FREQ / 1000000;
|
||||
|
||||
/* Scale to support full 32-bit usec range */
|
||||
|
||||
lo = usec & ((1<<22)-1);
|
||||
hi = usec >> 22UL;
|
||||
for (i = 0; i < hi; ++i)
|
||||
delay_cycles(mhz << 22);
|
||||
delay_cycles(mhz * lo);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return the elapsed time (ticks) since 'base'.
|
||||
*/
|
||||
|
||||
ulong get_timer(ulong base)
|
||||
{
|
||||
/* Don't tie up a timer; use cycle counter if available (or fake it) */
|
||||
|
||||
#if XCHAL_HAVE_CCOUNT
|
||||
register ulong ccount;
|
||||
__asm__ volatile ("rsr %0, CCOUNT" : "=a"(ccount));
|
||||
return ccount / (CONFIG_SYS_CLK_FREQ / CONFIG_SYS_HZ) - base;
|
||||
#else
|
||||
/*
|
||||
* Add at least the overhead of this call (in cycles).
|
||||
* Avoids hanging in case caller doesn't use udelay().
|
||||
* Note that functions that don't call udelay() (such as
|
||||
* the "sleep" command) will not get a significant delay
|
||||
* because there is no time reference.
|
||||
*/
|
||||
|
||||
fake_ccount += 20;
|
||||
return fake_ccount / (CONFIG_SYS_CLK_FREQ / CONFIG_SYS_HZ) - base;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is derived from ARM/PowerPC code (read timebase as long long).
|
||||
* On Xtensa it just returns the timer value.
|
||||
*/
|
||||
unsigned long long get_ticks(void)
|
||||
{
|
||||
return get_timer(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is derived from ARM/PowerPC code (timebase clock frequency).
|
||||
* On Xtensa it returns the number of timer ticks per second.
|
||||
*/
|
||||
ulong get_tbclk(void)
|
||||
{
|
||||
return CONFIG_SYS_HZ;
|
||||
}
|
||||
|
||||
#if XCHAL_HAVE_CCOUNT
|
||||
unsigned long timer_get_us(void)
|
||||
{
|
||||
unsigned long ccount;
|
||||
|
||||
__asm__ volatile ("rsr %0, CCOUNT" : "=a"(ccount));
|
||||
return ccount / (CONFIG_SYS_CLK_FREQ / 1000000);
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user