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,45 @@
# SPDX-License-Identifier: GPL-2.0+
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
## Build a couple of necessary functions into a private libgcc
## if the user asked for it
lib-$(CONFIG_USE_PRIVATE_LIBGCC) += _ashldi3.o _ashrdi3.o _lshrdi3.o
MINIMAL=
ifdef CONFIG_SPL_BUILD
ifdef CONFIG_SPL_INIT_MINIMAL
MINIMAL=y
endif
endif
ifdef MINIMAL
obj-y += cache.o time.o
ifndef CONFIG_TIMER
obj-y += ticks.o
endif
else
obj-y += ppcstring.o
obj-y += ppccache.o
ifndef CONFIG_TIMER
obj-y += ticks.o
endif
obj-y += reloc.o
obj-$(CONFIG_BAT_RW) += bat_rw.o
obj-$(CONFIG_CMD_BOOTM) += bootm.o
obj-y += cache.o
obj-y += extable.o
obj-y += interrupts.o
obj-$(CONFIG_CMD_KGDB) += kgdb.o
obj-y += stack.o
obj-y += time.o
endif # not minimal
ifdef CONFIG_SPL_BUILD
obj-$(CONFIG_$(SPL_TPL)_FRAMEWORK) += spl.o
endif
@@ -0,0 +1,41 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* This code was copied from arch/powerpc/kernel/misc_32.S in the Linux
* kernel sources (commit 85e2efbb1db9a18d218006706d6e4fbeb0216213, also
* known as 2.6.38-rc5). The source file copyrights are as follows:
*
* (C) Copyright 1995-1996 Gary Thomas (gdt@linuxppc.org)
*
* Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
* and Paul Mackerras.
*/
#include <ppc_asm.tmpl>
#include <ppc_defs.h>
#include <config.h>
/*
* Extended precision shifts.
*
* Updated to be valid for shift counts from 0 to 63 inclusive.
* -- Gabriel
*
* R3/R4 has 64 bit value
* R5 has shift count
* result in R3/R4
*
* ashrdi3: arithmetic right shift (sign propagation)
* lshrdi3: logical right shift
* ashldi3: left shift
*/
.globl __ashldi3
__ashldi3:
subfic r6,r5,32
slw r3,r3,r5 # MSW = count > 31 ? 0 : MSW << count
addi r7,r5,32 # could be xori, or addi with -32
srw r6,r4,r6 # t1 = count > 31 ? 0 : LSW >> (32-count)
slw r7,r4,r7 # t2 = count < 32 ? 0 : LSW << (count-32)
or r3,r3,r6 # MSW |= t1
slw r4,r4,r5 # LSW = LSW << count
or r3,r3,r7 # MSW |= t2
blr
@@ -0,0 +1,43 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* This code was copied from arch/powerpc/kernel/misc_32.S in the Linux
* kernel sources (commit 85e2efbb1db9a18d218006706d6e4fbeb0216213, also
* known as 2.6.38-rc5). The source file copyrights are as follows:
*
* (C) Copyright 1995-1996 Gary Thomas (gdt@linuxppc.org)
*
* Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
* and Paul Mackerras.
*/
#include <ppc_asm.tmpl>
#include <ppc_defs.h>
#include <config.h>
/*
* Extended precision shifts.
*
* Updated to be valid for shift counts from 0 to 63 inclusive.
* -- Gabriel
*
* R3/R4 has 64 bit value
* R5 has shift count
* result in R3/R4
*
* ashrdi3: arithmetic right shift (sign propagation)
* lshrdi3: logical right shift
* ashldi3: left shift
*/
.globl __ashrdi3
__ashrdi3:
subfic r6,r5,32
srw r4,r4,r5 # LSW = count > 31 ? 0 : LSW >> count
addi r7,r5,32 # could be xori, or addi with -32
slw r6,r3,r6 # t1 = count > 31 ? 0 : MSW << (32-count)
rlwinm r8,r7,0,32 # t3 = (count < 32) ? 32 : 0
sraw r7,r3,r7 # t2 = MSW >> (count-32)
or r4,r4,r6 # LSW |= t1
slw r7,r7,r8 # t2 = (count < 32) ? 0 : t2
sraw r3,r3,r5 # MSW = MSW >> count
or r4,r4,r7 # LSW |= t2
blr
@@ -0,0 +1,41 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* This code was copied from arch/powerpc/kernel/misc_32.S in the Linux
* kernel sources (commit 85e2efbb1db9a18d218006706d6e4fbeb0216213, also
* known as 2.6.38-rc5). The source file copyrights are as follows:
*
* (C) Copyright 1995-1996 Gary Thomas (gdt@linuxppc.org)
*
* Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
* and Paul Mackerras.
*/
#include <ppc_asm.tmpl>
#include <ppc_defs.h>
#include <config.h>
/*
* Extended precision shifts.
*
* Updated to be valid for shift counts from 0 to 63 inclusive.
* -- Gabriel
*
* R3/R4 has 64 bit value
* R5 has shift count
* result in R3/R4
*
* ashrdi3: arithmetic right shift (sign propagation)
* lshrdi3: logical right shift
* ashldi3: left shift
*/
.globl __lshrdi3
__lshrdi3:
subfic r6,r5,32
srw r4,r4,r5 # LSW = count > 31 ? 0 : LSW >> count
addi r7,r5,32 # could be xori, or addi with -32
slw r6,r3,r6 # t1 = count > 31 ? 0 : MSW << (32-count)
srw r7,r3,r7 # t2 = count < 32 ? 0 : MSW >> (count-32)
or r4,r4,r6 # LSW |= t1
srw r3,r3,r5 # MSW = MSW >> count
or r4,r4,r7 # LSW |= t2
blr
@@ -0,0 +1,243 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2002
* Rich Ireland, Enterasys Networks, rireland@enterasys.com.
*/
#include <common.h>
#include <asm/processor.h>
#include <asm/mmu.h>
#include <asm/io.h>
#include <linux/compiler.h>
#ifdef CONFIG_ADDR_MAP
#include <addr_map.h>
#endif
DECLARE_GLOBAL_DATA_PTR;
int write_bat (ppc_bat_t bat, unsigned long upper, unsigned long lower)
{
__maybe_unused int batn = -1;
sync();
switch (bat) {
case DBAT0:
mtspr (DBAT0L, lower);
mtspr (DBAT0U, upper);
batn = 0;
break;
case IBAT0:
mtspr (IBAT0L, lower);
mtspr (IBAT0U, upper);
break;
case DBAT1:
mtspr (DBAT1L, lower);
mtspr (DBAT1U, upper);
batn = 1;
break;
case IBAT1:
mtspr (IBAT1L, lower);
mtspr (IBAT1U, upper);
break;
case DBAT2:
mtspr (DBAT2L, lower);
mtspr (DBAT2U, upper);
batn = 2;
break;
case IBAT2:
mtspr (IBAT2L, lower);
mtspr (IBAT2U, upper);
break;
case DBAT3:
mtspr (DBAT3L, lower);
mtspr (DBAT3U, upper);
batn = 3;
break;
case IBAT3:
mtspr (IBAT3L, lower);
mtspr (IBAT3U, upper);
break;
#ifdef CONFIG_HIGH_BATS
case DBAT4:
mtspr (DBAT4L, lower);
mtspr (DBAT4U, upper);
batn = 4;
break;
case IBAT4:
mtspr (IBAT4L, lower);
mtspr (IBAT4U, upper);
break;
case DBAT5:
mtspr (DBAT5L, lower);
mtspr (DBAT5U, upper);
batn = 5;
break;
case IBAT5:
mtspr (IBAT5L, lower);
mtspr (IBAT5U, upper);
break;
case DBAT6:
mtspr (DBAT6L, lower);
mtspr (DBAT6U, upper);
batn = 6;
break;
case IBAT6:
mtspr (IBAT6L, lower);
mtspr (IBAT6U, upper);
break;
case DBAT7:
mtspr (DBAT7L, lower);
mtspr (DBAT7U, upper);
batn = 7;
break;
case IBAT7:
mtspr (IBAT7L, lower);
mtspr (IBAT7U, upper);
break;
#endif
default:
return (-1);
}
#ifdef CONFIG_ADDR_MAP
if ((gd->flags & GD_FLG_RELOC) && (batn >= 0)) {
phys_size_t size;
if (!BATU_VALID(upper))
size = 0;
else
size = BATU_SIZE(upper);
addrmap_set_entry(BATU_VADDR(upper), BATL_PADDR(lower),
size, batn);
}
#endif
sync();
isync();
return (0);
}
int read_bat (ppc_bat_t bat, unsigned long *upper, unsigned long *lower)
{
unsigned long register u;
unsigned long register l;
switch (bat) {
case DBAT0:
l = mfspr (DBAT0L);
u = mfspr (DBAT0U);
break;
case IBAT0:
l = mfspr (IBAT0L);
u = mfspr (IBAT0U);
break;
case DBAT1:
l = mfspr (DBAT1L);
u = mfspr (DBAT1U);
break;
case IBAT1:
l = mfspr (IBAT1L);
u = mfspr (IBAT1U);
break;
case DBAT2:
l = mfspr (DBAT2L);
u = mfspr (DBAT2U);
break;
case IBAT2:
l = mfspr (IBAT2L);
u = mfspr (IBAT2U);
break;
case DBAT3:
l = mfspr (DBAT3L);
u = mfspr (DBAT3U);
break;
case IBAT3:
l = mfspr (IBAT3L);
u = mfspr (IBAT3U);
break;
#ifdef CONFIG_HIGH_BATS
case DBAT4:
l = mfspr (DBAT4L);
u = mfspr (DBAT4U);
break;
case IBAT4:
l = mfspr (IBAT4L);
u = mfspr (IBAT4U);
break;
case DBAT5:
l = mfspr (DBAT5L);
u = mfspr (DBAT5U);
break;
case IBAT5:
l = mfspr (IBAT5L);
u = mfspr (IBAT5U);
break;
case DBAT6:
l = mfspr (DBAT6L);
u = mfspr (DBAT6U);
break;
case IBAT6:
l = mfspr (IBAT6L);
u = mfspr (IBAT6U);
break;
case DBAT7:
l = mfspr (DBAT7L);
u = mfspr (DBAT7U);
break;
case IBAT7:
l = mfspr (IBAT7L);
u = mfspr (IBAT7U);
break;
#endif
default:
return (-1);
}
*upper = u;
*lower = l;
return (0);
}
void print_bats(void)
{
printf("BAT registers:\n");
printf ("\tIBAT0L = 0x%08X ", mfspr (IBAT0L));
printf ("\tIBAT0U = 0x%08X\n", mfspr (IBAT0U));
printf ("\tDBAT0L = 0x%08X ", mfspr (DBAT0L));
printf ("\tDBAT0U = 0x%08X\n", mfspr (DBAT0U));
printf ("\tIBAT1L = 0x%08X ", mfspr (IBAT1L));
printf ("\tIBAT1U = 0x%08X\n", mfspr (IBAT1U));
printf ("\tDBAT1L = 0x%08X ", mfspr (DBAT1L));
printf ("\tDBAT1U = 0x%08X\n", mfspr (DBAT1U));
printf ("\tIBAT2L = 0x%08X ", mfspr (IBAT2L));
printf ("\tIBAT2U = 0x%08X\n", mfspr (IBAT2U));
printf ("\tDBAT2L = 0x%08X ", mfspr (DBAT2L));
printf ("\tDBAT2U = 0x%08X\n", mfspr (DBAT2U));
printf ("\tIBAT3L = 0x%08X ", mfspr (IBAT3L));
printf ("\tIBAT3U = 0x%08X\n", mfspr (IBAT3U));
printf ("\tDBAT3L = 0x%08X ", mfspr (DBAT3L));
printf ("\tDBAT3U = 0x%08X\n", mfspr (DBAT3U));
#ifdef CONFIG_HIGH_BATS
printf ("\tIBAT4L = 0x%08X ", mfspr (IBAT4L));
printf ("\tIBAT4U = 0x%08X\n", mfspr (IBAT4U));
printf ("\tDBAT4L = 0x%08X ", mfspr (DBAT4L));
printf ("\tDBAT4U = 0x%08X\n", mfspr (DBAT4U));
printf ("\tIBAT5L = 0x%08X ", mfspr (IBAT5L));
printf ("\tIBAT5U = 0x%08X\n", mfspr (IBAT5U));
printf ("\tDBAT5L = 0x%08X ", mfspr (DBAT5L));
printf ("\tDBAT5U = 0x%08X\n", mfspr (DBAT5U));
printf ("\tIBAT6L = 0x%08X ", mfspr (IBAT6L));
printf ("\tIBAT6U = 0x%08X\n", mfspr (IBAT6U));
printf ("\tDBAT6L = 0x%08X ", mfspr (DBAT6L));
printf ("\tDBAT6U = 0x%08X\n", mfspr (DBAT6U));
printf ("\tIBAT7L = 0x%08X ", mfspr (IBAT7L));
printf ("\tIBAT7U = 0x%08X\n", mfspr (IBAT7U));
printf ("\tDBAT7L = 0x%08X ", mfspr (DBAT7L));
printf ("\tDBAT7U = 0x%08X\n", mfspr (DBAT7U));
#endif
}
@@ -0,0 +1,340 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2008 Semihalf
*
* (C) Copyright 2000-2006
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*/
#include <common.h>
#include <cpu_func.h>
#include <env.h>
#include <watchdog.h>
#include <command.h>
#include <image.h>
#include <malloc.h>
#include <u-boot/zlib.h>
#include <bzlib.h>
#include <asm/byteorder.h>
#include <asm/mp.h>
#include <bootm.h>
#include <vxworks.h>
#if defined(CONFIG_OF_LIBFDT)
#include <linux/libfdt.h>
#include <fdt_support.h>
#endif
#ifdef CONFIG_SYS_INIT_RAM_LOCK
#include <asm/cache.h>
#endif
DECLARE_GLOBAL_DATA_PTR;
static ulong get_sp (void);
extern void ft_fixup_num_cores(void *blob);
static void set_clocks_in_mhz (bd_t *kbd);
#ifndef CONFIG_SYS_LINUX_LOWMEM_MAX_SIZE
#define CONFIG_SYS_LINUX_LOWMEM_MAX_SIZE (768*1024*1024)
#endif
static void boot_jump_linux(bootm_headers_t *images)
{
void (*kernel)(bd_t *, ulong r4, ulong r5, ulong r6,
ulong r7, ulong r8, ulong r9);
#ifdef CONFIG_OF_LIBFDT
char *of_flat_tree = images->ft_addr;
#endif
kernel = (void (*)(bd_t *, ulong, ulong, ulong,
ulong, ulong, ulong))images->ep;
debug ("## Transferring control to Linux (at address %08lx) ...\n",
(ulong)kernel);
bootstage_mark(BOOTSTAGE_ID_RUN_OS);
#ifdef CONFIG_BOOTSTAGE_FDT
bootstage_fdt_add_report();
#endif
#ifdef CONFIG_BOOTSTAGE_REPORT
bootstage_report();
#endif
#if defined(CONFIG_SYS_INIT_RAM_LOCK) && !defined(CONFIG_E500)
unlock_ram_in_cache();
#endif
#if defined(CONFIG_OF_LIBFDT)
if (of_flat_tree) { /* device tree; boot new style */
/*
* Linux Kernel Parameters (passing device tree):
* r3: pointer to the fdt
* r4: 0
* r5: 0
* r6: epapr magic
* r7: size of IMA in bytes
* r8: 0
* r9: 0
*/
debug (" Booting using OF flat tree...\n");
WATCHDOG_RESET ();
(*kernel) ((bd_t *)of_flat_tree, 0, 0, EPAPR_MAGIC,
env_get_bootm_mapsize(), 0, 0);
/* does not return */
} else
#endif
{
/*
* Linux Kernel Parameters (passing board info data):
* r3: ptr to board info data
* r4: initrd_start or 0 if no initrd
* r5: initrd_end - unused if r4 is 0
* r6: Start of command line string
* r7: End of command line string
* r8: 0
* r9: 0
*/
ulong cmd_start = images->cmdline_start;
ulong cmd_end = images->cmdline_end;
ulong initrd_start = images->initrd_start;
ulong initrd_end = images->initrd_end;
bd_t *kbd = images->kbd;
debug (" Booting using board info...\n");
WATCHDOG_RESET ();
(*kernel) (kbd, initrd_start, initrd_end,
cmd_start, cmd_end, 0, 0);
/* does not return */
}
return ;
}
void arch_lmb_reserve(struct lmb *lmb)
{
phys_size_t bootm_size;
ulong size, sp, bootmap_base;
bootmap_base = env_get_bootm_low();
bootm_size = env_get_bootm_size();
#ifdef DEBUG
if (((u64)bootmap_base + bootm_size) >
(CONFIG_SYS_SDRAM_BASE + (u64)gd->ram_size))
puts("WARNING: bootm_low + bootm_size exceed total memory\n");
if ((bootmap_base + bootm_size) > get_effective_memsize())
puts("WARNING: bootm_low + bootm_size exceed eff. memory\n");
#endif
size = min(bootm_size, get_effective_memsize());
size = min(size, (ulong)CONFIG_SYS_LINUX_LOWMEM_MAX_SIZE);
if (size < bootm_size) {
ulong base = bootmap_base + size;
printf("WARNING: adjusting available memory to %lx\n", size);
lmb_reserve(lmb, base, bootm_size - size);
}
/*
* Booting a (Linux) kernel image
*
* Allocate space for command line and board info - the
* address should be as high as possible within the reach of
* the kernel (see CONFIG_SYS_BOOTMAPSZ settings), but in unused
* memory, which means far enough below the current stack
* pointer.
*/
sp = get_sp();
debug ("## Current stack ends at 0x%08lx\n", sp);
/* adjust sp by 4K to be safe */
sp -= 4096;
lmb_reserve(lmb, sp, (CONFIG_SYS_SDRAM_BASE + get_effective_memsize() - sp));
#ifdef CONFIG_MP
cpu_mp_lmb_reserve(lmb);
#endif
return ;
}
static void boot_prep_linux(bootm_headers_t *images)
{
#ifdef CONFIG_MP
/*
* if we are MP make sure to flush the device tree so any changes are
* made visibile to all other cores. In AMP boot scenarios the cores
* might not be HW cache coherent with each other.
*/
flush_cache((unsigned long)images->ft_addr, images->ft_len);
#endif
}
static int boot_cmdline_linux(bootm_headers_t *images)
{
ulong of_size = images->ft_len;
struct lmb *lmb = &images->lmb;
ulong *cmd_start = &images->cmdline_start;
ulong *cmd_end = &images->cmdline_end;
int ret = 0;
if (!of_size) {
/* allocate space and init command line */
ret = boot_get_cmdline (lmb, cmd_start, cmd_end);
if (ret) {
puts("ERROR with allocation of cmdline\n");
return ret;
}
}
return ret;
}
static int boot_bd_t_linux(bootm_headers_t *images)
{
ulong of_size = images->ft_len;
struct lmb *lmb = &images->lmb;
bd_t **kbd = &images->kbd;
int ret = 0;
if (!of_size) {
/* allocate space for kernel copy of board info */
ret = boot_get_kbd (lmb, kbd);
if (ret) {
puts("ERROR with allocation of kernel bd\n");
return ret;
}
set_clocks_in_mhz(*kbd);
}
return ret;
}
static int boot_body_linux(bootm_headers_t *images)
{
int ret;
/* allocate space for kernel copy of board info */
ret = boot_bd_t_linux(images);
if (ret)
return ret;
ret = image_setup_linux(images);
if (ret)
return ret;
return 0;
}
noinline
int do_bootm_linux(int flag, int argc, char * const argv[], bootm_headers_t *images)
{
int ret;
if (flag & BOOTM_STATE_OS_CMDLINE) {
boot_cmdline_linux(images);
return 0;
}
if (flag & BOOTM_STATE_OS_BD_T) {
boot_bd_t_linux(images);
return 0;
}
if (flag & BOOTM_STATE_OS_PREP) {
boot_prep_linux(images);
return 0;
}
boot_prep_linux(images);
ret = boot_body_linux(images);
if (ret)
return ret;
boot_jump_linux(images);
return 0;
}
static ulong get_sp (void)
{
ulong sp;
asm( "mr %0,1": "=r"(sp) : );
return sp;
}
static void set_clocks_in_mhz (bd_t *kbd)
{
char *s;
s = env_get("clocks_in_mhz");
if (s) {
/* convert all clock information to MHz */
kbd->bi_intfreq /= 1000000L;
kbd->bi_busfreq /= 1000000L;
#if defined(CONFIG_CPM2)
kbd->bi_cpmfreq /= 1000000L;
kbd->bi_brgfreq /= 1000000L;
kbd->bi_sccfreq /= 1000000L;
kbd->bi_vco /= 1000000L;
#endif
}
}
#if defined(CONFIG_BOOTM_VXWORKS)
void boot_prep_vxworks(bootm_headers_t *images)
{
#if defined(CONFIG_OF_LIBFDT)
int off;
u64 base, size;
if (!images->ft_addr)
return;
base = (u64)gd->bd->bi_memstart;
size = (u64)gd->bd->bi_memsize;
off = fdt_path_offset(images->ft_addr, "/memory");
if (off < 0)
fdt_fixup_memory(images->ft_addr, base, size);
#if defined(CONFIG_MP)
#if defined(CONFIG_MPC85xx)
ft_fixup_cpu(images->ft_addr, base + size);
ft_fixup_num_cores(images->ft_addr);
#elif defined(CONFIG_MPC86xx)
off = fdt_add_mem_rsv(images->ft_addr,
determine_mp_bootpg(NULL), (u64)4096);
if (off < 0)
printf("## WARNING %s: %s\n", __func__, fdt_strerror(off));
ft_fixup_num_cores(images->ft_addr);
#endif
flush_cache((unsigned long)images->ft_addr, images->ft_len);
#endif
#endif
}
void boot_jump_vxworks(bootm_headers_t *images)
{
/* PowerPC VxWorks boot interface conforms to the ePAPR standard
* general purpuse registers:
*
* r3: Effective address of the device tree image
* r4: 0
* r5: 0
* r6: ePAPR magic value
* r7: shall be the size of the boot IMA in bytes
* r8: 0
* r9: 0
* TCR: WRC = 0, no watchdog timer reset will occur
*/
WATCHDOG_RESET();
((void (*)(void *, ulong, ulong, ulong,
ulong, ulong, ulong))images->ep)(images->ft_addr,
0, 0, EPAPR_MAGIC, env_get_bootm_mapsize(), 0, 0);
}
#endif
@@ -0,0 +1,37 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2002
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*/
#include <common.h>
#include <cpu_func.h>
#include <asm/cache.h>
#include <watchdog.h>
void flush_cache(ulong start_addr, ulong size)
{
#ifndef CONFIG_5xx
ulong addr, start, end;
start = start_addr & ~(CONFIG_SYS_CACHELINE_SIZE - 1);
end = start_addr + size - 1;
for (addr = start; (addr <= end) && (addr >= start);
addr += CONFIG_SYS_CACHELINE_SIZE) {
asm volatile("dcbst 0,%0" : : "r" (addr) : "memory");
WATCHDOG_RESET();
}
/* wait for all dcbst to complete on bus */
asm volatile("sync" : : : "memory");
for (addr = start; (addr <= end) && (addr >= start);
addr += CONFIG_SYS_CACHELINE_SIZE) {
asm volatile("icbi 0,%0" : : "r" (addr) : "memory");
WATCHDOG_RESET();
}
asm volatile("sync" : : : "memory");
/* flush prefetch queue */
asm volatile("isync" : : : "memory");
#endif
}
@@ -0,0 +1,61 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 1999 Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
*
* (C) Copyright 2000
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*/
#include <common.h>
/*
* The exception table consists of pairs of addresses: the first is the
* address of an instruction that is allowed to fault, and the second is
* the address at which the program should continue. No registers are
* modified, so it is entirely up to the continuation code to figure out
* what to do.
*
* All the routines below use bits of fixup code that are out of line
* with the main instruction path. This means when everything is well,
* we don't even have to jump over them. Further, they do not intrude
* on our cache or tlb entries.
*/
struct exception_table_entry
{
unsigned long insn, fixup;
};
extern const struct exception_table_entry __start___ex_table[];
extern const struct exception_table_entry __stop___ex_table[];
static inline unsigned long
search_one_table(const struct exception_table_entry *first,
const struct exception_table_entry *last,
unsigned long value)
{
long diff;
while (first <= last) {
diff = first->insn - value;
if (diff == 0)
return first->fixup;
first++;
}
return 0;
}
unsigned long
search_exception_table(unsigned long addr)
{
unsigned long ret;
/* There is only the kernel to search. */
ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
/* if the serial port does not hang in exception, printf can be used */
#if !defined(CONFIG_SYS_SERIAL_HANG_IN_EXCEPTION)
debug("Bus Fault @ 0x%08lx, fixup 0x%08lx\n", addr, ret);
#endif
if (ret) return ret;
return 0;
}
@@ -0,0 +1,95 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2000-2002
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* (C) Copyright 2003
* Gleb Natapov <gnatapov@mrv.com>
*/
#include <common.h>
#include <irq_func.h>
#include <asm/processor.h>
#include <watchdog.h>
#ifdef CONFIG_LED_STATUS
#include <status_led.h>
#endif
#ifndef CONFIG_MPC83XX_TIMER
#ifndef CONFIG_SYS_WATCHDOG_FREQ
#define CONFIG_SYS_WATCHDOG_FREQ (CONFIG_SYS_HZ / 2)
#endif
static unsigned decrementer_count; /* count value for 1e6/HZ microseconds */
static __inline__ unsigned long get_dec (void)
{
unsigned long val;
asm volatile ("mfdec %0":"=r" (val):);
return val;
}
static __inline__ void set_dec (unsigned long val)
{
if (val)
asm volatile ("mtdec %0"::"r" (val));
}
#endif /* !CONFIG_MPC83XX_TIMER */
void enable_interrupts(void)
{
set_msr (get_msr () | MSR_EE);
}
/* returns flag if MSR_EE was set before */
int disable_interrupts(void)
{
ulong msr = get_msr ();
set_msr (msr & ~MSR_EE);
return ((msr & MSR_EE) != 0);
}
#ifndef CONFIG_MPC83XX_TIMER
int interrupt_init(void)
{
/* call cpu specific function from $(CPU)/interrupts.c */
interrupt_init_cpu (&decrementer_count);
set_dec (decrementer_count);
set_msr (get_msr () | MSR_EE);
return (0);
}
static volatile ulong timestamp = 0;
void timer_interrupt(struct pt_regs *regs)
{
/* call cpu specific function from $(CPU)/interrupts.c */
timer_interrupt_cpu (regs);
/* Restore Decrementer Count */
set_dec (decrementer_count);
timestamp++;
#if defined(CONFIG_WATCHDOG) || defined (CONFIG_HW_WATCHDOG)
if ((timestamp % (CONFIG_SYS_WATCHDOG_FREQ)) == 0)
WATCHDOG_RESET ();
#endif /* CONFIG_WATCHDOG || CONFIG_HW_WATCHDOG */
#ifdef CONFIG_LED_STATUS
status_led_tick(timestamp);
#endif /* CONFIG_LED_STATUS */
}
ulong get_timer (ulong base)
{
return (timestamp - base);
}
#endif /* !CONFIG_MPC83XX_TIMER */
@@ -0,0 +1,260 @@
#include <common.h>
#include <command.h>
#include <kgdb.h>
#include <asm/signal.h>
#include <asm/processor.h>
#define PC_REGNUM 64
#define SP_REGNUM 1
void breakinst(void);
int
kgdb_setjmp(long *buf)
{
unsigned long temp;
asm volatile("mflr %0; stw %0,0(%1);"
"stw %%r1,4(%1); stw %%r2,8(%1);"
"mfcr %0; stw %0,12(%1);"
"stmw %%r13,16(%1)"
: "=&r"(temp) : "r" (buf));
/* XXX should save fp regs as well */
return 0;
}
void
kgdb_longjmp(long *buf, int val)
{
unsigned long temp;
if (val == 0)
val = 1;
asm volatile("lmw %%r13,16(%1);"
"lwz %0,12(%1); mtcrf 0x38,%0;"
"lwz %0,0(%1); lwz %%r1,4(%1); lwz %%r2,8(%1);"
"mtlr %0; mr %%r3,%2"
: "=&r"(temp) : "r" (buf), "r" (val));
}
/* Convert the SPARC hardware trap type code to a unix signal number. */
/*
* This table contains the mapping between PowerPC hardware trap types, and
* signals, which are primarily what GDB understands.
*/
static struct hard_trap_info
{
unsigned int tt; /* Trap type code for powerpc */
unsigned char signo; /* Signal that we map this trap into */
} hard_trap_info[] = {
{ 0x200, SIGSEGV }, /* machine check */
{ 0x300, SIGSEGV }, /* address error (store) */
{ 0x400, SIGBUS }, /* instruction bus error */
{ 0x500, SIGINT }, /* interrupt */
{ 0x600, SIGBUS }, /* alignment */
{ 0x700, SIGTRAP }, /* breakpoint trap */
{ 0x800, SIGFPE }, /* fpu unavail */
{ 0x900, SIGALRM }, /* decrementer */
{ 0xa00, SIGILL }, /* reserved */
{ 0xb00, SIGILL }, /* reserved */
{ 0xc00, SIGCHLD }, /* syscall */
{ 0xd00, SIGTRAP }, /* single-step/watch */
{ 0xe00, SIGFPE }, /* fp assist */
{ 0, 0} /* Must be last */
};
static int
computeSignal(unsigned int tt)
{
struct hard_trap_info *ht;
for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
if (ht->tt == tt)
return ht->signo;
return SIGHUP; /* default for things we don't know about */
}
void
kgdb_enter(struct pt_regs *regs, kgdb_data *kdp)
{
unsigned long msr;
kdp->private[0] = msr = get_msr();
set_msr(msr & ~MSR_EE); /* disable interrupts */
if (regs->nip == (unsigned long)breakinst) {
/* Skip over breakpoint trap insn */
regs->nip += 4;
}
regs->msr &= ~MSR_SE;
/* reply to host that an exception has occurred */
kdp->sigval = computeSignal(regs->trap);
kdp->nregs = 2;
kdp->regs[0].num = PC_REGNUM;
kdp->regs[0].val = regs->nip;
kdp->regs[1].num = SP_REGNUM;
kdp->regs[1].val = regs->gpr[SP_REGNUM];
}
void
kgdb_exit(struct pt_regs *regs, kgdb_data *kdp)
{
unsigned long msr = kdp->private[0];
if (kdp->extype & KGDBEXIT_WITHADDR)
regs->nip = kdp->exaddr;
switch (kdp->extype & KGDBEXIT_TYPEMASK) {
case KGDBEXIT_KILL:
case KGDBEXIT_CONTINUE:
set_msr(msr);
break;
case KGDBEXIT_SINGLE:
regs->msr |= MSR_SE;
#if 0
set_msr(msr | MSR_SE);
#endif
break;
}
}
int
kgdb_trap(struct pt_regs *regs)
{
return (regs->trap);
}
/* return the value of the CPU registers.
* some of them are non-PowerPC names :(
* they are stored in gdb like:
* struct {
* u32 gpr[32];
* f64 fpr[32];
* u32 pc, ps, cnd, lr; (ps=msr)
* u32 cnt, xer, mq;
* }
*/
#define SPACE_REQUIRED ((32*4)+(32*8)+(6*4))
int
kgdb_getregs(struct pt_regs *regs, char *buf, int max)
{
int i;
unsigned long *ptr = (unsigned long *)buf;
if (max < SPACE_REQUIRED)
kgdb_error(KGDBERR_NOSPACE);
if ((unsigned long)ptr & 3)
kgdb_error(KGDBERR_ALIGNFAULT);
/* General Purpose Regs */
for (i = 0; i < 32; i++)
*ptr++ = regs->gpr[i];
/* Floating Point Regs */
for (i = 0; i < 32; i++) {
*ptr++ = 0;
*ptr++ = 0;
}
/* pc, msr, cr, lr, ctr, xer, (mq is unused) */
*ptr++ = regs->nip;
*ptr++ = regs->msr;
*ptr++ = regs->ccr;
*ptr++ = regs->link;
*ptr++ = regs->ctr;
*ptr++ = regs->xer;
return (SPACE_REQUIRED);
}
/* set the value of the CPU registers */
void
kgdb_putreg(struct pt_regs *regs, int regno, char *buf, int length)
{
unsigned long *ptr = (unsigned long *)buf;
if (regno < 0 || regno >= 70)
kgdb_error(KGDBERR_BADPARAMS);
else if (regno >= 32 && regno < 64) {
if (length < 8)
kgdb_error(KGDBERR_NOSPACE);
}
else {
if (length < 4)
kgdb_error(KGDBERR_NOSPACE);
}
if ((unsigned long)ptr & 3)
kgdb_error(KGDBERR_ALIGNFAULT);
if (regno >= 0 && regno < 32)
regs->gpr[regno] = *ptr;
else switch (regno) {
case 64: regs->nip = *ptr; break;
case 65: regs->msr = *ptr; break;
case 66: regs->ccr = *ptr; break;
case 67: regs->link = *ptr; break;
case 68: regs->ctr = *ptr; break;
case 69: regs->ctr = *ptr; break;
default:
kgdb_error(KGDBERR_BADPARAMS);
}
}
void
kgdb_putregs(struct pt_regs *regs, char *buf, int length)
{
int i;
unsigned long *ptr = (unsigned long *)buf;
if (length < SPACE_REQUIRED)
kgdb_error(KGDBERR_NOSPACE);
if ((unsigned long)ptr & 3)
kgdb_error(KGDBERR_ALIGNFAULT);
/*
* If the stack pointer has moved, you should pray.
* (cause only god can help you).
*/
/* General Purpose Regs */
for (i = 0; i < 32; i++)
regs->gpr[i] = *ptr++;
/* Floating Point Regs */
ptr += 32*2;
/* pc, msr, cr, lr, ctr, xer, (mq is unused) */
regs->nip = *ptr++;
regs->msr = *ptr++;
regs->ccr = *ptr++;
regs->link = *ptr++;
regs->ctr = *ptr++;
regs->xer = *ptr++;
}
/* This function will generate a breakpoint exception. It is used at the
beginning of a program to sync up with a debugger and can be used
otherwise as a quick means to stop program execution and "break" into
the debugger. */
void
kgdb_breakpoint(int argc, char * const argv[])
{
asm(" .globl breakinst\n\
breakinst: .long 0x7d821008\n\
");
}
@@ -0,0 +1,107 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 1998 Dan Malek <dmalek@jlc.net>
* Copyright (C) 1999 Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
* Copyright (C) 2000, 2001,2002 Wolfgang Denk <wd@denx.de>
* Copyright Freescale Semiconductor, Inc. 2004, 2006.
*/
#include <config.h>
#include <ppc_asm.tmpl>
#include <ppc_defs.h>
#include <asm/cache.h>
/*------------------------------------------------------------------------------- */
/* Function: ppcDcbf */
/* Description: Data Cache block flush */
/* Input: r3 = effective address */
/* Output: none. */
/*------------------------------------------------------------------------------- */
.globl ppcDcbf
ppcDcbf:
dcbf r0,r3
blr
/*------------------------------------------------------------------------------- */
/* Function: ppcDcbi */
/* Description: Data Cache block Invalidate */
/* Input: r3 = effective address */
/* Output: none. */
/*------------------------------------------------------------------------------- */
.globl ppcDcbi
ppcDcbi:
dcbi r0,r3
blr
/*--------------------------------------------------------------------------
* Function: ppcDcbz
* Description: Data Cache block zero.
* Input: r3 = effective address
* Output: none.
*-------------------------------------------------------------------------- */
.globl ppcDcbz
ppcDcbz:
dcbz r0,r3
blr
/*------------------------------------------------------------------------------- */
/* Function: ppcSync */
/* Description: Processor Synchronize */
/* Input: none. */
/* Output: none. */
/*------------------------------------------------------------------------------- */
.globl ppcSync
ppcSync:
sync
blr
/*
* Write any modified data cache blocks out to memory and invalidate them.
* Does not invalidate the corresponding instruction cache blocks.
*
* flush_dcache_range(unsigned long start, unsigned long stop)
*/
_GLOBAL(flush_dcache_range)
#if defined(CONFIG_MPC85xx) || defined(CONFIG_MPC86xx)
li r5,L1_CACHE_BYTES-1
andc r3,r3,r5
subf r4,r3,r4
add r4,r4,r5
srwi. r4,r4,L1_CACHE_SHIFT
beqlr
mtctr r4
1: dcbf 0,r3
addi r3,r3,L1_CACHE_BYTES
bdnz 1b
sync /* wait for dcbst's to get to ram */
#endif
blr
/*
* Like above, but invalidate the D-cache. This is used by the 8xx
* to invalidate the cache so the PPC core doesn't get stale data
* from the CPM (no cache snooping here :-).
*
* invalidate_dcache_range(unsigned long start, unsigned long stop)
*/
_GLOBAL(invalidate_dcache_range)
#if defined(CONFIG_MPC85xx) || defined(CONFIG_MPC86xx)
li r5,L1_CACHE_BYTES-1
andc r3,r3,r5
subf r4,r3,r4
add r4,r4,r5
srwi. r4,r4,L1_CACHE_SHIFT
beqlr
mtctr r4
sync
1: dcbi 0,r3
addi r3,r3,L1_CACHE_BYTES
bdnz 1b
sync /* wait for dcbi's to get to ram */
#endif
blr
@@ -0,0 +1,205 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* String handling functions for PowerPC.
*
* Copyright (C) 1996 Paul Mackerras.
*/
#include <ppc_asm.tmpl>
#include <linux/errno.h>
.globl strcpy
strcpy:
addi r5,r3,-1
addi r4,r4,-1
1: lbzu r0,1(r4)
cmpwi 0,r0,0
stbu r0,1(r5)
bne 1b
blr
.globl strncpy
strncpy:
cmpwi 0,r5,0
beqlr
mtctr r5
addi r6,r3,-1
addi r4,r4,-1
1: lbzu r0,1(r4)
cmpwi 0,r0,0
stbu r0,1(r6)
bdnzf 2,1b /* dec ctr, branch if ctr != 0 && !cr0.eq */
blr
.globl strcat
strcat:
addi r5,r3,-1
addi r4,r4,-1
1: lbzu r0,1(r5)
cmpwi 0,r0,0
bne 1b
addi r5,r5,-1
1: lbzu r0,1(r4)
cmpwi 0,r0,0
stbu r0,1(r5)
bne 1b
blr
.globl strcmp
strcmp:
addi r5,r3,-1
addi r4,r4,-1
1: lbzu r3,1(r5)
cmpwi 1,r3,0
lbzu r0,1(r4)
subf. r3,r0,r3
beqlr 1
beq 1b
blr
.globl strlen
strlen:
addi r4,r3,-1
1: lbzu r0,1(r4)
cmpwi 0,r0,0
bne 1b
subf r3,r3,r4
blr
.globl memset
memset:
rlwimi r4,r4,8,16,23
rlwimi r4,r4,16,0,15
addi r6,r3,-4
cmplwi 0,r5,4
blt 7f
stwu r4,4(r6)
beqlr
andi. r0,r6,3
add r5,r0,r5
subf r6,r0,r6
rlwinm r0,r5,32-2,2,31
mtctr r0
bdz 6f
1: stwu r4,4(r6)
bdnz 1b
6: andi. r5,r5,3
7: cmpwi 0,r5,0
beqlr
mtctr r5
addi r6,r6,3
8: stbu r4,1(r6)
bdnz 8b
blr
.globl memmove
memmove:
cmplw 0,r3,r4
bgt backwards_memcpy
/* fall through */
.globl memcpy
memcpy:
rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */
addi r6,r3,-4
addi r4,r4,-4
beq 2f /* if less than 8 bytes to do */
andi. r0,r6,3 /* get dest word aligned */
mtctr r7
bne 5f
1: lwz r7,4(r4)
lwzu r8,8(r4)
stw r7,4(r6)
stwu r8,8(r6)
bdnz 1b
andi. r5,r5,7
2: cmplwi 0,r5,4
blt 3f
lwzu r0,4(r4)
addi r5,r5,-4
stwu r0,4(r6)
3: cmpwi 0,r5,0
beqlr
mtctr r5
addi r4,r4,3
addi r6,r6,3
4: lbzu r0,1(r4)
stbu r0,1(r6)
bdnz 4b
blr
5: subfic r0,r0,4
mtctr r0
6: lbz r7,4(r4)
addi r4,r4,1
stb r7,4(r6)
addi r6,r6,1
bdnz 6b
subf r5,r0,r5
rlwinm. r7,r5,32-3,3,31
beq 2b
mtctr r7
b 1b
.globl backwards_memcpy
backwards_memcpy:
rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */
add r6,r3,r5
add r4,r4,r5
beq 2f
andi. r0,r6,3
mtctr r7
bne 5f
1: lwz r7,-4(r4)
lwzu r8,-8(r4)
stw r7,-4(r6)
stwu r8,-8(r6)
bdnz 1b
andi. r5,r5,7
2: cmplwi 0,r5,4
blt 3f
lwzu r0,-4(r4)
subi r5,r5,4
stwu r0,-4(r6)
3: cmpwi 0,r5,0
beqlr
mtctr r5
4: lbzu r0,-1(r4)
stbu r0,-1(r6)
bdnz 4b
blr
5: mtctr r0
6: lbzu r7,-1(r4)
stbu r7,-1(r6)
bdnz 6b
subf r5,r0,r5
rlwinm. r7,r5,32-3,3,31
beq 2b
mtctr r7
b 1b
.globl memcmp
memcmp:
cmpwi 0,r5,0
ble- 2f
mtctr r5
addi r6,r3,-1
addi r4,r4,-1
1: lbzu r3,1(r6)
lbzu r0,1(r4)
subf. r3,r0,r3
bdnzt 2,1b
blr
2: li r3,0
blr
.global memchr
memchr:
cmpwi 0,r5,0
ble- 2f
mtctr r5
addi r3,r3,-1
1: lbzu r0,1(r3)
cmpw 0,r0,r4
bdnzf 2,1b
beqlr
2: li r3,0
blr
@@ -0,0 +1,32 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2009 Wolfgang Denk <wd@denx.de>
*/
#include <ppc_asm.tmpl>
.file "reloc.S"
.text
#ifndef CONFIG_NAND_SPL
/*
* Function: relocate entries for one exception vector
*/
.globl trap_reloc
.type trap_reloc, @function
trap_reloc:
lwz r0, 0(r7) /* hdlr ... */
add r0, r0, r3 /* ... += dest_addr */
stw r0, 0(r7)
lwz r0, 4(r7) /* int_return ... */
add r0, r0, r3 /* ... += dest_addr */
stw r0, 4(r7)
lwz r0, 8(r7) /* transfer_to_handler ...*/
add r0, r0, r3 /* ... += dest_addr */
stw r0, 8(r7)
blr
.size trap_reloc, .-trap_reloc
#endif
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2012 Stefan Roese <sr@denx.de>
*/
#include <common.h>
#include <config.h>
#include <spl.h>
#include <image.h>
#include <linux/compiler.h>
/*
* This function jumps to an image with argument. Normally an FDT or ATAGS
* image.
*/
#ifdef CONFIG_SPL_OS_BOOT
void __noreturn jump_to_image_linux(struct spl_image_info *spl_image)
{
debug("Entering kernel arg pointer: 0x%p\n", spl_image->arg);
typedef void (*image_entry_arg_t)(void *, ulong r4, ulong r5, ulong r6,
ulong r7, ulong r8, ulong r9)
__attribute__ ((noreturn));
image_entry_arg_t image_entry =
(image_entry_arg_t)spl_image->entry_point;
image_entry(spl_image->arg, 0, 0, EPAPR_MAGIC, CONFIG_SYS_BOOTMAPSZ,
0, 0);
}
#endif /* CONFIG_SPL_OS_BOOT */
@@ -0,0 +1,30 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2015 Andreas Bießmann <andreas@biessmann.org>
*
* Copyright (c) 2011 The Chromium OS Authors.
* (C) Copyright 2002-2006
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* (C) Copyright 2002
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Marius Groeger <mgroeger@sysgo.de>
*/
#include <common.h>
DECLARE_GLOBAL_DATA_PTR;
int arch_reserve_stacks(void)
{
ulong *s;
/* setup stack pointer for exceptions */
gd->irq_sp = gd->start_addr_sp;
/* Clear initial stack frame */
s = (ulong *)gd->start_addr_sp;
*s = 0; /* Terminate back chain */
*++s = 0; /* NULL return address */
return 0;
}
@@ -0,0 +1,56 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* (C) Copyright 2000, 2001
* Erik Theisen, Wave 7 Optics, etheisen@mindspring.com.
* base on code by
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*/
#include <ppc_asm.tmpl>
#include <ppc_defs.h>
#include <config.h>
#include <watchdog.h>
/*
* unsigned long long get_ticks(void);
*
* read timebase as "long long"
*/
.globl get_ticks
get_ticks:
1: mftbu r3
mftb r4
mftbu r5
cmp 0,r3,r5
bne 1b
blr
/*
* Delay for a number of ticks
*/
.globl wait_ticks
wait_ticks:
stwu r1, -16(r1)
mflr r0 /* save link register */
stw r0, 20(r1) /* Use r0 or GDB will be unhappy */
stw r14, 12(r1) /* save used registers */
stw r15, 8(r1)
mr r14, r3 /* save tick count */
bl get_ticks /* Get start time */
/* Calculate end time */
addc r14, r4, r14 /* Compute end time lower */
addze r15, r3 /* and end time upper */
WATCHDOG_RESET /* Trigger watchdog, if needed */
1: bl get_ticks /* Get current time */
subfc r4, r4, r14 /* Subtract current time from end time */
subfe. r3, r3, r15
bge 1b /* Loop until time expired */
lwz r15, 8(r1) /* restore saved registers */
lwz r14, 12(r1)
lwz r0, 20(r1)
addi r1,r1,16
mtlr r0
blr
@@ -0,0 +1,74 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2000, 2001
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*/
#include <common.h>
#include <time.h>
#include <asm/io.h>
/* ------------------------------------------------------------------------- */
/*
* This function is intended for SHORT delays only.
* It will overflow at around 10 seconds @ 400MHz,
* or 20 seconds @ 200MHz.
*/
unsigned long usec2ticks(unsigned long usec)
{
ulong ticks;
if (usec < 1000) {
ticks = ((usec * (get_tbclk()/1000)) + 500) / 1000;
} else {
ticks = ((usec / 10) * (get_tbclk() / 100000));
}
return (ticks);
}
/* ------------------------------------------------------------------------- */
/*
* We implement the delay by converting the delay (the number of
* microseconds to wait) into a number of time base ticks; then we
* watch the time base until it has incremented by that amount.
*/
void __udelay(unsigned long usec)
{
ulong ticks = usec2ticks (usec);
wait_ticks (ticks);
}
/* ------------------------------------------------------------------------- */
#ifndef CONFIG_NAND_SPL
unsigned long ticks2usec(unsigned long ticks)
{
ulong tbclk = get_tbclk();
/* usec = ticks * 1000000 / tbclk
* Multiplication would overflow at ~4.2e3 ticks,
* so we break it up into
* usec = ( ( ticks * 1000) / tbclk ) * 1000;
*/
ticks *= 1000L;
ticks /= tbclk;
ticks *= 1000L;
return ((ulong)ticks);
}
#endif
/* ------------------------------------------------------------------------- */
int timer_init(void)
{
unsigned long temp;
/* reset */
asm volatile("li %0,0 ; mttbl %0 ; mttbu %0;"
: "=&r"(temp) );
return (0);
}
/* ------------------------------------------------------------------------- */