avionic design with actual uboot and tooling

submodule of avionic design uboot bootloader and with included tools to
get you started , read readme.md and readme-tk1-loader.md
This commit is contained in:
2026-03-03 21:46:32 +02:00
parent fe3ba02c96
commit 68d74d3181
11967 changed files with 2221897 additions and 0 deletions

1
u-boot/arch/blackfin/lib/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
u-boot.lds

View File

@@ -0,0 +1,27 @@
#
# U-Boot Makefile
#
# Copyright (c) 2005-2008 Analog Devices Inc.
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
# SPDX-License-Identifier: GPL-2.0+
#
obj-y += ins.o
obj-y += memcmp.o
obj-y += memcpy.o
obj-y += memmove.o
obj-y += memset.o
obj-y += outs.o
obj-$(CONFIG_CMD_KGDB) += __kgdb.o
obj-y += boot.o
obj-y += cache.o
obj-y += clocks.o
obj-$(CONFIG_CMD_CACHE_DUMP) += cmd_cache_dump.o
obj-$(CONFIG_CMD_KGDB) += kgdb.o
obj-y += muldi3.o
obj-$(CONFIG_HAS_POST) += post.o
obj-y += string.o
obj-y += sections.o

View File

@@ -0,0 +1,154 @@
#include <linux/linkage.h>
/* save stack context for non-local goto
* int kgdb_setjmp(long *buf)
*/
ENTRY(_kgdb_setjmp)
[--SP] = p0; /* Save P0 */
p0 = r0;
r0 = [SP++]; /* Load P0 into R0 */
[p0 + 0x00] = r0; /* GP address registers */
[p0 + 0x04] = p1;
[p0 + 0x08] = p2;
[p0 + 0x0C] = p3;
[p0 + 0x10] = p4;
[p0 + 0x14] = p5;
[p0 + 0x18] = FP; /* frame pointer */
[p0 + 0x1C] = SP; /* stack pointer */
[p0 + 0x20] = p0; /* data regs */
[p0 + 0x24] = r1;
[p0 + 0x28] = r2;
[p0 + 0x2C] = r3;
[p0 + 0x30] = r4;
[p0 + 0x34] = r5;
[p0 + 0x38] = r6;
[p0 + 0x3C] = r7;
r0 = ASTAT; [p0 + 0x40] = r0;
/* loop counters */
r0 = LC0; [p0 + 0x44] = r0;
r0 = LC1; [p0 + 0x48] = r0;
/* Accumulator */
r0 = A0.w; [p0 + 0x4C] = r0;
r0.l = A0.x; [p0 + 0x50] = r0;
r0 = A1.w; [p0 + 0x54] = r0;
r0.l = A1.x; [p0 + 0x58] = r0;
/* index registers */
r0 = i0; [p0 + 0x5C] = r0;
r0 = i1; [p0 + 0x60] = r0;
r0 = i2; [p0 + 0x64] = r0;
r0 = i3; [p0 + 0x68] = r0;
/* modifier registers */
r0 = m0; [p0 + 0x6C] = r0;
r0 = m1; [p0 + 0x70] = r0;
r0 = m2; [p0 + 0x74] = r0;
r0 = m3; [p0 + 0x78] = r0;
/* length registers */
r0 = l0; [p0 + 0x7C] = r0;
r0 = l1; [p0 + 0x80] = r0;
r0 = l2; [p0 + 0x84] = r0;
r0 = l3; [p0 + 0x88] = r0;
/* base registers */
r0 = b0; [p0 + 0x8C] = r0;
r0 = b1; [p0 + 0x90] = r0;
r0 = b2; [p0 + 0x94] = r0;
r0 = b3; [p0 + 0x98] = r0;
/* store return address */
r0 = RETS; [p0 + 0x9C] = r0;
R0 = 0;
RTS;
ENDPROC(_kgdb_setjmp)
/*
* non-local jump to a saved stack context
* longjmp(long *buf, int val)
*/
ENTRY(_kgdb_longjmp)
p0 = r0;
r0 = [p0 + 0x00];
[--sp] = r0;
/* GP address registers - skip p0 for now*/
p1 = [p0 + 0x04];
p2 = [p0 + 0x08];
p3 = [p0 + 0x0C];
p4 = [p0 + 0x10];
p5 = [p0 + 0x14];
/* frame pointer */
fp = [p0 + 0x18];
/* stack pointer */
r0 = [sp++];
sp = [p0 + 0x1C];
[--sp] = r0;
[--sp] = r1;
/* data regs */
r0 = [p0 + 0x20];
r1 = [p0 + 0x24];
r2 = [p0 + 0x28];
r3 = [p0 + 0x2C];
r4 = [p0 + 0x30];
r5 = [p0 + 0x34];
r6 = [p0 + 0x38];
r7 = [p0 + 0x3C];
r0 = [p0 + 0x40]; ASTAT = r0;
/* loop counters */
r0 = [p0 + 0x44]; LC0 = r0;
r0 = [p0 + 0x48]; LC1 = r0;
/* Accumulator */
r0 = [p0 + 0x4C]; A0.w = r0;
r0 = [p0 + 0x50]; A0.x = r0;
r0 = [p0 + 0x54]; A1.w = r0;
r0 = [p0 + 0x58]; A1.x = r0;
/* index registers */
r0 = [p0 + 0x5C]; i0 = r0;
r0 = [p0 + 0x60]; i1 = r0;
r0 = [p0 + 0x64]; i2 = r0;
r0 = [p0 + 0x68]; i3 = r0;
/* modifier registers */
r0 = [p0 + 0x6C]; m0 = r0;
r0 = [p0 + 0x70]; m1 = r0;
r0 = [p0 + 0x74]; m2 = r0;
r0 = [p0 + 0x78]; m3 = r0;
/* length registers */
r0 = [p0 + 0x7C]; l0 = r0;
r0 = [p0 + 0x80]; l1 = r0;
r0 = [p0 + 0x84]; l2 = r0;
r0 = [p0 + 0x88]; l3 = r0;
/* base registers */
r0 = [p0 + 0x8C]; b0 = r0;
r0 = [p0 + 0x90]; b1 = r0;
r0 = [p0 + 0x94]; b2 = r0;
r0 = [p0 + 0x98]; b3 = r0;
/* store return address */
r0 = [p0 + 0x9C]; RETS = r0;
/* fixup R0 & P0 */
r0 = [sp++];
p0 = [sp++];
CC = R0 == 0;
IF !CC JUMP .Lfinished;
R0 = 1;
.Lfinished:
RTS;
ENDPROC(_kgdb_longjmp)

View File

@@ -0,0 +1,74 @@
/*
* U-Boot - boot.c - misc boot helper functions
*
* Copyright (c) 2005-2008 Analog Devices Inc.
*
* (C) Copyright 2000-2004
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* Licensed under the GPL-2 or later.
*/
#include <common.h>
#include <command.h>
#include <image.h>
#include <asm/blackfin.h>
#ifdef SHARED_RESOURCES
extern void swap_to(int device_id);
#endif
#ifdef CONFIG_VIDEO
extern void video_stop(void);
#endif
static char *make_command_line(void)
{
char *dest = (char *)CONFIG_LINUX_CMDLINE_ADDR;
char *bootargs = getenv("bootargs");
if (bootargs == NULL)
return NULL;
strncpy(dest, bootargs, CONFIG_LINUX_CMDLINE_SIZE);
dest[CONFIG_LINUX_CMDLINE_SIZE - 1] = 0;
return dest;
}
extern ulong bfin_poweron_retx;
int do_bootm_linux(int flag, int argc, char * const argv[], bootm_headers_t *images)
{
int (*appl) (char *cmdline);
char *cmdline;
if (flag & BOOTM_STATE_OS_PREP)
return 0;
if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
return 1;
#ifdef SHARED_RESOURCES
swap_to(FLASH);
#endif
#ifdef CONFIG_VIDEO
/* maybe this should be standardized and moved to bootm ... */
video_stop();
#endif
appl = (int (*)(char *))images->ep;
printf("Starting Kernel at = %p\n", appl);
cmdline = make_command_line();
icache_disable();
dcache_disable();
asm __volatile__(
"RETX = %[retx];"
"CALL (%0);"
:
: "p"(appl), "q0"(cmdline), [retx] "d"(bfin_poweron_retx)
);
/* does not return */
return 1;
}

View File

@@ -0,0 +1,123 @@
/*
* U-Boot - cache.c
*
* Copyright (c) 2005-2008 Analog Devices Inc.
*
* (C) Copyright 2000-2004
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* Licensed under the GPL-2 or later.
*/
#include <common.h>
#include <asm/blackfin.h>
#include <asm/mach-common/bits/mpu.h>
void flush_cache(unsigned long addr, unsigned long size)
{
void *start_addr, *end_addr;
int istatus, dstatus;
/* no need to flush stuff in on chip memory (L1/L2/etc...) */
if (addr >= 0xE0000000)
return;
start_addr = (void *)addr;
end_addr = (void *)(addr + size);
istatus = icache_status();
dstatus = dcache_status();
if (istatus) {
if (dstatus)
blackfin_icache_dcache_flush_range(start_addr, end_addr);
else
blackfin_icache_flush_range(start_addr, end_addr);
} else if (dstatus)
blackfin_dcache_flush_range(start_addr, end_addr);
}
#ifdef CONFIG_DCACHE_WB
static void flushinv_all_dcache(void)
{
u32 way, bank, subbank, set;
u32 status, addr;
u32 dmem_ctl = bfin_read_DMEM_CONTROL();
for (bank = 0; bank < 2; ++bank) {
if (!(dmem_ctl & (1 << (DMC1_P - bank))))
continue;
for (way = 0; way < 2; ++way)
for (subbank = 0; subbank < 4; ++subbank)
for (set = 0; set < 64; ++set) {
bfin_write_DTEST_COMMAND(
way << 26 |
bank << 23 |
subbank << 16 |
set << 5
);
CSYNC();
status = bfin_read_DTEST_DATA0();
/* only worry about valid/dirty entries */
if ((status & 0x3) != 0x3)
continue;
/* construct the address using the tag */
addr = (status & 0xFFFFC800) | (subbank << 12) | (set << 5);
/* flush it */
__asm__ __volatile__("FLUSHINV[%0];" : : "a"(addr));
}
}
}
#endif
void icache_enable(void)
{
bfin_write_IMEM_CONTROL(IMC | ENICPLB);
SSYNC();
}
void icache_disable(void)
{
bfin_write_IMEM_CONTROL(0);
SSYNC();
}
int icache_status(void)
{
return bfin_read_IMEM_CONTROL() & IMC;
}
void dcache_enable(void)
{
bfin_write_DMEM_CONTROL(ACACHE_BCACHE | ENDCPLB | PORT_PREF0);
SSYNC();
}
void dcache_disable(void)
{
#ifdef CONFIG_DCACHE_WB
bfin_write_DMEM_CONTROL(bfin_read_DMEM_CONTROL() & ~(ENDCPLB));
flushinv_all_dcache();
#endif
bfin_write_DMEM_CONTROL(0);
SSYNC();
}
int dcache_status(void)
{
return bfin_read_DMEM_CONTROL() & ACACHE_BCACHE;
}
void invalidate_dcache_range(unsigned long start, unsigned long stop)
{
blackfin_dcache_flush_invalidate_range((const void *)start, (const void *)stop);
}
void flush_dcache_range(unsigned long start, unsigned long stop)
{
blackfin_dcache_flush_range((const void *)start, (const void *)stop);
}

View File

@@ -0,0 +1,140 @@
/*
* clocks.c - figure out sclk/cclk/vco and such
*
* Copyright (c) 2005-2008 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#include <common.h>
#include <asm/clock.h>
/* Get the voltage input multiplier */
u_long get_vco(void)
{
static u_long cached_vco_pll_ctl, cached_vco;
u_long msel, pll_ctl;
pll_ctl = bfin_read_PLL_CTL();
if (pll_ctl == cached_vco_pll_ctl)
return cached_vco;
else
cached_vco_pll_ctl = pll_ctl;
msel = (pll_ctl & MSEL) >> MSEL_P;
if (0 == msel)
msel = (MSEL >> MSEL_P) + 1;
cached_vco = CONFIG_CLKIN_HZ;
cached_vco >>= (pll_ctl & DF);
cached_vco *= msel;
return cached_vco;
}
/* Get the Core clock */
u_long get_cclk(void)
{
static u_long cached_cclk_pll_div, cached_cclk;
u_long div, csel;
#ifndef CGU_DIV
u_long ssel;
#endif
if (pll_is_bypassed())
return CONFIG_CLKIN_HZ;
div = bfin_read_PLL_DIV();
if (div == cached_cclk_pll_div)
return cached_cclk;
else
cached_cclk_pll_div = div;
csel = (div & CSEL) >> CSEL_P;
#ifndef CGU_DIV
ssel = (div & SSEL) >> SSEL_P;
if (ssel && ssel < (1 << csel)) /* SCLK > CCLK */
cached_cclk = get_vco() / ssel;
else
cached_cclk = get_vco() >> csel;
#else
cached_cclk = get_vco() / csel;
#endif
return cached_cclk;
}
/* Get the System clock */
#ifdef CGU_DIV
static u_long cached_sclk_pll_div, cached_sclk;
static u_long cached_sclk0, cached_sclk1, cached_dclk;
static u_long _get_sclk(u_long *cache)
{
u_long div, ssel;
if (pll_is_bypassed())
return CONFIG_CLKIN_HZ;
div = bfin_read_PLL_DIV();
if (div == cached_sclk_pll_div)
return *cache;
else
cached_sclk_pll_div = div;
ssel = (div & SYSSEL) >> SYSSEL_P;
cached_sclk = get_vco() / ssel;
ssel = (div & S0SEL) >> S0SEL_P;
cached_sclk0 = cached_sclk / ssel;
ssel = (div & S1SEL) >> S1SEL_P;
cached_sclk1 = cached_sclk / ssel;
ssel = (div & DSEL) >> DSEL_P;
cached_dclk = get_vco() / ssel;
return *cache;
}
u_long get_sclk(void)
{
return _get_sclk(&cached_sclk);
}
u_long get_sclk0(void)
{
return _get_sclk(&cached_sclk0);
}
u_long get_sclk1(void)
{
return _get_sclk(&cached_sclk1);
}
u_long get_dclk(void)
{
return _get_sclk(&cached_dclk);
}
#else
u_long get_sclk(void)
{
static u_long cached_sclk_pll_div, cached_sclk;
u_long div, ssel;
if (pll_is_bypassed())
return CONFIG_CLKIN_HZ;
div = bfin_read_PLL_DIV();
if (div == cached_sclk_pll_div)
return cached_sclk;
else
cached_sclk_pll_div = div;
ssel = (div & SSEL) >> SSEL_P;
cached_sclk = get_vco() / ssel;
return cached_sclk;
}
#endif

View File

@@ -0,0 +1,146 @@
/*
* U-Boot - cmd_cache_dump.c
*
* Copyright (c) 2007-2008 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#include <config.h>
#include <common.h>
#include <command.h>
#include <console.h>
#include <asm/blackfin.h>
#include <asm/mach-common/bits/mpu.h>
static int check_limit(const char *type, size_t start_limit, size_t end_limit, size_t start, size_t end)
{
if (start >= start_limit && start <= end_limit && \
end <= end_limit && end >= start_limit && \
start <= end)
return 0;
printf("%s limit violation: %zu <= (user:%zu) <= (user:%zu) <= %zu\n",
type, start_limit, start, end, end_limit);
return 1;
}
int do_icache_dump(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
int cache_status = icache_status();
if (cache_status)
icache_disable();
uint32_t cmd_base, tag, cache_upper, cache_lower;
size_t way, way_start = 0, way_end = 3;
size_t sbnk, sbnk_start = 0, sbnk_end = 3;
size_t set, set_start = 0, set_end = 31;
size_t dw;
if (argc > 1) {
way_start = way_end = simple_strtoul(argv[1], NULL, 10);
if (argc > 2) {
sbnk_start = sbnk_end = simple_strtoul(argv[2], NULL, 10);
if (argc > 3)
set_start = set_end = simple_strtoul(argv[3], NULL, 10);
}
}
if (check_limit("way", 0, 3, way_start, way_end) || \
check_limit("subbank", 0, 3, sbnk_start, sbnk_end) || \
check_limit("set", 0, 31, set_start, set_end))
return 1;
puts("Way:Subbank:Set: [valid-tag lower upper] {invalid-tag lower upper}...\n");
for (way = way_start; way <= way_end; ++way) {
for (sbnk = sbnk_start; sbnk <= sbnk_end; ++sbnk) {
for (set = set_start; set <= set_end; ++set) {
printf("%zu:%zu:%2zu: ", way, sbnk, set);
for (dw = 0; dw < 4; ++dw) {
if (ctrlc())
return 1;
cmd_base = \
(way << 26) | \
(sbnk << 16) | \
(set << 5) | \
(dw << 3);
/* first read the tag */
bfin_write_ITEST_COMMAND(cmd_base | 0x0);
SSYNC();
tag = bfin_read_ITEST_DATA0();
printf("%c%08x ", (tag & 0x1 ? ' ' : '{'), tag);
/* grab the data at this loc */
bfin_write_ITEST_COMMAND(cmd_base | 0x4);
SSYNC();
cache_lower = bfin_read_ITEST_DATA0();
cache_upper = bfin_read_ITEST_DATA1();
printf("%08x %08x%c ", cache_lower, cache_upper, (tag & 0x1 ? ' ' : '}'));
}
puts("\n");
}
}
}
if (cache_status)
icache_enable();
return 0;
}
U_BOOT_CMD(icache_dump, 4, 0, do_icache_dump,
"icache_dump - dump current instruction cache\n",
"[way] [subbank] [set]");
int do_dcache_dump(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
u32 way, bank, subbank, set;
u32 status, addr;
u32 dmem_ctl = bfin_read_DMEM_CONTROL();
for (bank = 0; bank < 2; ++bank) {
if (!(dmem_ctl & (1 << (DMC1_P - bank))))
continue;
for (way = 0; way < 2; ++way)
for (subbank = 0; subbank < 4; ++subbank) {
printf("%i:%i:%i:\t", bank, way, subbank);
for (set = 0; set < 64; ++set) {
if (ctrlc())
return 1;
/* retrieve a cache tag */
bfin_write_DTEST_COMMAND(
way << 26 |
bank << 23 |
subbank << 16 |
set << 5
);
CSYNC();
status = bfin_read_DTEST_DATA0();
/* construct the address using the tag */
addr = (status & 0xFFFFC800) | (subbank << 12) | (set << 5);
/* show it */
if (set && !(set % 4))
puts("\n\t");
printf("%c%08x%c%08x%c ", (status & 0x1 ? '[' : '{'), status, (status & 0x2 ? 'd' : ' '), addr, (status & 0x1 ? ']' : '}'));
}
puts("\n");
}
}
return 0;
}
U_BOOT_CMD(dcache_dump, 4, 0, do_dcache_dump,
"dcache_dump - dump current data cache\n",
"[bank] [way] [subbank] [set]");

View File

@@ -0,0 +1,118 @@
/*
* arch/blackfin/lib/ins.S - ins{bwl} using hardware loops
*
* Copyright 2004-2008 Analog Devices Inc.
* Copyright (C) 2005 Bas Vermeulen, BuyWays BV <bas@buyways.nl>
* Licensed under the GPL-2 or later.
*/
#include <asm/blackfin.h>
.align 2
#ifdef CONFIG_IPIPE
# define DO_CLI \
[--sp] = rets; \
[--sp] = (P5:0); \
sp += -12; \
call ___ipipe_disable_root_irqs_hw; \
sp += 12; \
(P5:0) = [sp++];
# define CLI_INNER_NOP
#else
# define DO_CLI cli R3;
# define CLI_INNER_NOP nop; nop; nop;
#endif
#ifdef CONFIG_IPIPE
# define DO_STI \
sp += -12; \
call ___ipipe_enable_root_irqs_hw; \
sp += 12; \
2: rets = [sp++];
#else
# define DO_STI 2: sti R3;
#endif
#ifdef CONFIG_BFIN_INS_LOWOVERHEAD
# define CLI_OUTER DO_CLI;
# define STI_OUTER DO_STI;
# define CLI_INNER 1:
# if ANOMALY_05000416
# define STI_INNER nop; 2: nop;
# else
# define STI_INNER 2:
# endif
#else
# define CLI_OUTER
# define STI_OUTER
# define CLI_INNER 1: DO_CLI; CLI_INNER_NOP;
# define STI_INNER DO_STI;
#endif
/*
* Reads on the Blackfin are speculative. In Blackfin terms, this means they
* can be interrupted at any time (even after they have been issued on to the
* external bus), and re-issued after the interrupt occurs.
*
* If a FIFO is sitting on the end of the read, it will see two reads,
* when the core only sees one. The FIFO receives the read which is cancelled,
* and not delivered to the core.
*
* To solve this, interrupts are turned off before reads occur to I/O space.
* There are 3 versions of all these functions
* - turns interrupts off every read (higher overhead, but lower latency)
* - turns interrupts off every loop (low overhead, but longer latency)
* - DMA version, which do not suffer from this issue. DMA versions have
* different name (prefixed by dma_ ), and are located in
* ../kernel/bfin_dma_5xx.c
* Using the dma related functions are recommended for transfering large
* buffers in/out of FIFOs.
*/
#define COMMON_INS(func, ops) \
.section .text._ins##func; \
ENTRY(_ins##func) \
P0 = R0; /* P0 = port */ \
CLI_OUTER; /* 3 instructions before first read access */ \
P1 = R1; /* P1 = address */ \
P2 = R2; /* P2 = count */ \
SSYNC; \
\
LSETUP(1f, 2f) LC0 = P2; \
CLI_INNER; \
ops; \
STI_INNER; \
\
STI_OUTER; \
RTS; \
ENDPROC(_ins##func)
COMMON_INS(l, \
R0 = [P0]; \
[P1++] = R0; \
)
COMMON_INS(w, \
R0 = W[P0]; \
W[P1++] = R0; \
)
COMMON_INS(w_8, \
R0 = W[P0]; \
B[P1++] = R0; \
R0 = R0 >> 8; \
B[P1++] = R0; \
)
COMMON_INS(b, \
R0 = B[P0]; \
B[P1++] = R0; \
)
COMMON_INS(l_16, \
R0 = [P0]; \
W[P1++] = R0; \
R0 = R0 >> 16; \
W[P1++] = R0; \
)

View File

@@ -0,0 +1,423 @@
/*
* U-Boot - architecture specific kgdb code
*
* Copyright 2009 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#include <common.h>
#include <command.h>
#include <kgdb.h>
#include <asm/processor.h>
#include <asm/mach-common/bits/core.h>
#include "kgdb.h"
#include <asm/deferred.h>
#include <asm/traps.h>
#include <asm/signal.h>
void kgdb_enter(struct pt_regs *regs, kgdb_data *kdp)
{
/* disable interrupts */
disable_interrupts();
/* reply to host that an exception has occurred */
kdp->sigval = kgdb_trap(regs);
/* send the PC and the Stack Pointer */
kdp->nregs = 2;
kdp->regs[0].num = BFIN_PC;
kdp->regs[0].val = regs->pc;
kdp->regs[1].num = BFIN_SP;
kdp->regs[1].val = (unsigned long)regs;
}
void kgdb_exit(struct pt_regs *regs, kgdb_data *kdp)
{
if (kdp->extype & KGDBEXIT_WITHADDR)
printf("KGDBEXIT_WITHADDR\n");
switch (kdp->extype & KGDBEXIT_TYPEMASK) {
case KGDBEXIT_KILL:
printf("KGDBEXIT_KILL:\n");
break;
case KGDBEXIT_CONTINUE:
/* Make sure the supervisor single step bit is clear */
regs->syscfg &= ~1;
break;
case KGDBEXIT_SINGLE:
/* set the supervisor single step bit */
regs->syscfg |= 1;
break;
default:
printf("KGDBEXIT : %d\n", kdp->extype);
}
/* enable interrupts */
enable_interrupts();
}
int kgdb_trap(struct pt_regs *regs)
{
/* ipend doesn't get filled in properly */
switch (regs->seqstat & EXCAUSE) {
case VEC_EXCPT01:
return SIGTRAP;
case VEC_EXCPT03:
return SIGSEGV;
case VEC_EXCPT02:
return SIGTRAP;
case VEC_EXCPT04 ... VEC_EXCPT15:
return SIGILL;
case VEC_STEP:
return SIGTRAP;
case VEC_OVFLOW:
return SIGTRAP;
case VEC_UNDEF_I:
return SIGILL;
case VEC_ILGAL_I:
return SIGILL;
case VEC_CPLB_VL:
return SIGSEGV;
case VEC_MISALI_D:
return SIGBUS;
case VEC_UNCOV:
return SIGILL;
case VEC_CPLB_MHIT:
return SIGSEGV;
case VEC_MISALI_I:
return SIGBUS;
case VEC_CPLB_I_VL:
return SIGBUS;
case VEC_CPLB_I_MHIT:
return SIGSEGV;
default:
return SIGBUS;
}
}
/*
* getregs - gets the pt_regs, and gives them to kgdb's buffer
*/
int kgdb_getregs(struct pt_regs *regs, char *buf, int max)
{
unsigned long *gdb_regs = (unsigned long *)buf;
if (max < NUMREGBYTES)
kgdb_error(KGDBERR_NOSPACE);
if ((unsigned long)gdb_regs & 3)
kgdb_error(KGDBERR_ALIGNFAULT);
gdb_regs[BFIN_R0] = regs->r0;
gdb_regs[BFIN_R1] = regs->r1;
gdb_regs[BFIN_R2] = regs->r2;
gdb_regs[BFIN_R3] = regs->r3;
gdb_regs[BFIN_R4] = regs->r4;
gdb_regs[BFIN_R5] = regs->r5;
gdb_regs[BFIN_R6] = regs->r6;
gdb_regs[BFIN_R7] = regs->r7;
gdb_regs[BFIN_P0] = regs->p0;
gdb_regs[BFIN_P1] = regs->p1;
gdb_regs[BFIN_P2] = regs->p2;
gdb_regs[BFIN_P3] = regs->p3;
gdb_regs[BFIN_P4] = regs->p4;
gdb_regs[BFIN_P5] = regs->p5;
gdb_regs[BFIN_SP] = (unsigned long)regs;
gdb_regs[BFIN_FP] = regs->fp;
gdb_regs[BFIN_I0] = regs->i0;
gdb_regs[BFIN_I1] = regs->i1;
gdb_regs[BFIN_I2] = regs->i2;
gdb_regs[BFIN_I3] = regs->i3;
gdb_regs[BFIN_M0] = regs->m0;
gdb_regs[BFIN_M1] = regs->m1;
gdb_regs[BFIN_M2] = regs->m2;
gdb_regs[BFIN_M3] = regs->m3;
gdb_regs[BFIN_B0] = regs->b0;
gdb_regs[BFIN_B1] = regs->b1;
gdb_regs[BFIN_B2] = regs->b2;
gdb_regs[BFIN_B3] = regs->b3;
gdb_regs[BFIN_L0] = regs->l0;
gdb_regs[BFIN_L1] = regs->l1;
gdb_regs[BFIN_L2] = regs->l2;
gdb_regs[BFIN_L3] = regs->l3;
gdb_regs[BFIN_A0_DOT_X] = regs->a0x;
gdb_regs[BFIN_A0_DOT_W] = regs->a0w;
gdb_regs[BFIN_A1_DOT_X] = regs->a1x;
gdb_regs[BFIN_A1_DOT_W] = regs->a1w;
gdb_regs[BFIN_ASTAT] = regs->astat;
gdb_regs[BFIN_RETS] = regs->rets;
gdb_regs[BFIN_LC0] = regs->lc0;
gdb_regs[BFIN_LT0] = regs->lt0;
gdb_regs[BFIN_LB0] = regs->lb0;
gdb_regs[BFIN_LC1] = regs->lc1;
gdb_regs[BFIN_LT1] = regs->lt1;
gdb_regs[BFIN_LB1] = regs->lb1;
gdb_regs[BFIN_CYCLES] = 0;
gdb_regs[BFIN_CYCLES2] = 0;
gdb_regs[BFIN_USP] = regs->usp;
gdb_regs[BFIN_SEQSTAT] = regs->seqstat;
gdb_regs[BFIN_SYSCFG] = regs->syscfg;
gdb_regs[BFIN_RETI] = regs->pc;
gdb_regs[BFIN_RETX] = regs->retx;
gdb_regs[BFIN_RETN] = regs->retn;
gdb_regs[BFIN_RETE] = regs->rete;
gdb_regs[BFIN_PC] = regs->pc;
gdb_regs[BFIN_CC] = 0;
gdb_regs[BFIN_EXTRA1] = 0;
gdb_regs[BFIN_EXTRA2] = 0;
gdb_regs[BFIN_EXTRA3] = 0;
gdb_regs[BFIN_IPEND] = regs->ipend;
return NUMREGBYTES;
}
/*
* putreg - put kgdb's reg (regno) into the pt_regs
*/
void kgdb_putreg(struct pt_regs *regs, int regno, char *buf, int length)
{
unsigned long *ptr = (unsigned long *)buf;
if (regno < 0 || regno > BFIN_NUM_REGS)
kgdb_error(KGDBERR_BADPARAMS);
if (length < 4)
kgdb_error(KGDBERR_NOSPACE);
if ((unsigned long)ptr & 3)
kgdb_error(KGDBERR_ALIGNFAULT);
switch (regno) {
case BFIN_R0:
regs->r0 = *ptr;
break;
case BFIN_R1:
regs->r1 = *ptr;
break;
case BFIN_R2:
regs->r2 = *ptr;
break;
case BFIN_R3:
regs->r3 = *ptr;
break;
case BFIN_R4:
regs->r4 = *ptr;
break;
case BFIN_R5:
regs->r5 = *ptr;
break;
case BFIN_R6:
regs->r6 = *ptr;
break;
case BFIN_R7:
regs->r7 = *ptr;
break;
case BFIN_P0:
regs->p0 = *ptr;
break;
case BFIN_P1:
regs->p1 = *ptr;
break;
case BFIN_P2:
regs->p2 = *ptr;
break;
case BFIN_P3:
regs->p3 = *ptr;
break;
case BFIN_P4:
regs->p4 = *ptr;
break;
case BFIN_P5:
regs->p5 = *ptr;
break;
case BFIN_SP:
regs->reserved = *ptr;
break;
case BFIN_FP:
regs->fp = *ptr;
break;
case BFIN_I0:
regs->i0 = *ptr;
break;
case BFIN_I1:
regs->i1 = *ptr;
break;
case BFIN_I2:
regs->i2 = *ptr;
break;
case BFIN_I3:
regs->i3 = *ptr;
break;
case BFIN_M0:
regs->m0 = *ptr;
break;
case BFIN_M1:
regs->m1 = *ptr;
break;
case BFIN_M2:
regs->m2 = *ptr;
break;
case BFIN_M3:
regs->m3 = *ptr;
break;
case BFIN_B0:
regs->b0 = *ptr;
break;
case BFIN_B1:
regs->b1 = *ptr;
break;
case BFIN_B2:
regs->b2 = *ptr;
break;
case BFIN_B3:
regs->b3 = *ptr;
break;
case BFIN_L0:
regs->l0 = *ptr;
break;
case BFIN_L1:
regs->l1 = *ptr;
break;
case BFIN_L2:
regs->l2 = *ptr;
break;
case BFIN_L3:
regs->l3 = *ptr;
break;
case BFIN_A0_DOT_X:
regs->a0x = *ptr;
break;
case BFIN_A0_DOT_W:
regs->a0w = *ptr;
break;
case BFIN_A1_DOT_X:
regs->a1x = *ptr;
break;
case BFIN_A1_DOT_W:
regs->a1w = *ptr;
break;
case BFIN_ASTAT:
regs->astat = *ptr;
break;
case BFIN_RETS:
regs->rets = *ptr;
break;
case BFIN_LC0:
regs->lc0 = *ptr;
break;
case BFIN_LT0:
regs->lt0 = *ptr;
break;
case BFIN_LB0:
regs->lb0 = *ptr;
break;
case BFIN_LC1:
regs->lc1 = *ptr;
break;
case BFIN_LT1:
regs->lt1 = *ptr;
break;
case BFIN_LB1:
regs->lb1 = *ptr;
break;
/*
BFIN_CYCLES,
BFIN_CYCLES2,
BFIN_USP,
BFIN_SEQSTAT,
BFIN_SYSCFG,
*/
case BFIN_RETX:
regs->retx = *ptr;
break;
case BFIN_RETN:
regs->retn = *ptr;
break;
case BFIN_RETE:
regs->rete = *ptr;
break;
case BFIN_PC:
regs->pc = *ptr;
break;
default:
kgdb_error(KGDBERR_BADPARAMS);
}
}
void kgdb_putregs(struct pt_regs *regs, char *buf, int length)
{
unsigned long *gdb_regs = (unsigned long *)buf;
if (length != BFIN_NUM_REGS)
kgdb_error(KGDBERR_NOSPACE);
if ((unsigned long)gdb_regs & 3)
kgdb_error(KGDBERR_ALIGNFAULT);
regs->r0 = gdb_regs[BFIN_R0];
regs->r1 = gdb_regs[BFIN_R1];
regs->r2 = gdb_regs[BFIN_R2];
regs->r3 = gdb_regs[BFIN_R3];
regs->r4 = gdb_regs[BFIN_R4];
regs->r5 = gdb_regs[BFIN_R5];
regs->r6 = gdb_regs[BFIN_R6];
regs->r7 = gdb_regs[BFIN_R7];
regs->p0 = gdb_regs[BFIN_P0];
regs->p1 = gdb_regs[BFIN_P1];
regs->p2 = gdb_regs[BFIN_P2];
regs->p3 = gdb_regs[BFIN_P3];
regs->p4 = gdb_regs[BFIN_P4];
regs->p5 = gdb_regs[BFIN_P5];
regs->fp = gdb_regs[BFIN_FP];
/* regs->sp = gdb_regs[BFIN_ ]; */
regs->i0 = gdb_regs[BFIN_I0];
regs->i1 = gdb_regs[BFIN_I1];
regs->i2 = gdb_regs[BFIN_I2];
regs->i3 = gdb_regs[BFIN_I3];
regs->m0 = gdb_regs[BFIN_M0];
regs->m1 = gdb_regs[BFIN_M1];
regs->m2 = gdb_regs[BFIN_M2];
regs->m3 = gdb_regs[BFIN_M3];
regs->b0 = gdb_regs[BFIN_B0];
regs->b1 = gdb_regs[BFIN_B1];
regs->b2 = gdb_regs[BFIN_B2];
regs->b3 = gdb_regs[BFIN_B3];
regs->l0 = gdb_regs[BFIN_L0];
regs->l1 = gdb_regs[BFIN_L1];
regs->l2 = gdb_regs[BFIN_L2];
regs->l3 = gdb_regs[BFIN_L3];
regs->a0x = gdb_regs[BFIN_A0_DOT_X];
regs->a0w = gdb_regs[BFIN_A0_DOT_W];
regs->a1x = gdb_regs[BFIN_A1_DOT_X];
regs->a1w = gdb_regs[BFIN_A1_DOT_W];
regs->rets = gdb_regs[BFIN_RETS];
regs->lc0 = gdb_regs[BFIN_LC0];
regs->lt0 = gdb_regs[BFIN_LT0];
regs->lb0 = gdb_regs[BFIN_LB0];
regs->lc1 = gdb_regs[BFIN_LC1];
regs->lt1 = gdb_regs[BFIN_LT1];
regs->lb1 = gdb_regs[BFIN_LB1];
regs->usp = gdb_regs[BFIN_USP];
regs->syscfg = gdb_regs[BFIN_SYSCFG];
regs->retx = gdb_regs[BFIN_PC];
regs->retn = gdb_regs[BFIN_RETN];
regs->rete = gdb_regs[BFIN_RETE];
regs->pc = gdb_regs[BFIN_PC];
#if 0 /* can't change these */
regs->astat = gdb_regs[BFIN_ASTAT];
regs->seqstat = gdb_regs[BFIN_SEQSTAT];
regs->ipend = gdb_regs[BFIN_IPEND];
#endif
}
void kgdb_breakpoint(int argc, char * const argv[])
{
asm volatile ("excpt 0x1\n");
}

View File

@@ -0,0 +1,160 @@
/* Blackfin KGDB header
*
* Copyright 2005-2009 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#ifndef __ASM_BLACKFIN_KGDB_H__
#define __ASM_BLACKFIN_KGDB_H__
/* gdb locks */
#define KGDB_MAX_NO_CPUS 8
/*
* BUFMAX defines the maximum number of characters in inbound/outbound buffers.
* At least NUMREGBYTES*2 are needed for register packets.
* Longer buffer is needed to list all threads.
*/
#define BUFMAX 2048
enum regnames {
/* Core Registers */
BFIN_R0 = 0,
BFIN_R1,
BFIN_R2,
BFIN_R3,
BFIN_R4,
BFIN_R5,
BFIN_R6,
BFIN_R7,
BFIN_P0,
BFIN_P1,
BFIN_P2,
BFIN_P3,
BFIN_P4,
BFIN_P5,
BFIN_SP,
BFIN_FP,
BFIN_I0,
BFIN_I1,
BFIN_I2,
BFIN_I3,
BFIN_M0,
BFIN_M1,
BFIN_M2,
BFIN_M3,
BFIN_B0,
BFIN_B1,
BFIN_B2,
BFIN_B3,
BFIN_L0,
BFIN_L1,
BFIN_L2,
BFIN_L3,
BFIN_A0_DOT_X,
BFIN_A0_DOT_W,
BFIN_A1_DOT_X,
BFIN_A1_DOT_W,
BFIN_ASTAT,
BFIN_RETS,
BFIN_LC0,
BFIN_LT0,
BFIN_LB0,
BFIN_LC1,
BFIN_LT1,
BFIN_LB1,
BFIN_CYCLES,
BFIN_CYCLES2,
BFIN_USP,
BFIN_SEQSTAT,
BFIN_SYSCFG,
BFIN_RETI,
BFIN_RETX,
BFIN_RETN,
BFIN_RETE,
/* Pseudo Registers */
BFIN_PC,
BFIN_CC,
BFIN_EXTRA1, /* Address of .text section. */
BFIN_EXTRA2, /* Address of .data section. */
BFIN_EXTRA3, /* Address of .bss section. */
BFIN_FDPIC_EXEC,
BFIN_FDPIC_INTERP,
/* MMRs */
BFIN_IPEND,
/* LAST ENTRY SHOULD NOT BE CHANGED. */
BFIN_NUM_REGS /* The number of all registers. */
};
/* Number of bytes of registers. */
#define NUMREGBYTES (BFIN_NUM_REGS * 4)
static inline void arch_kgdb_breakpoint(void)
{
asm volatile ("EXCPT 2;");
}
#define BREAK_INSTR_SIZE 2
#define CACHE_FLUSH_IS_SAFE 1
#define GDB_ADJUSTS_BREAK_OFFSET
#define GDB_SKIP_HW_WATCH_TEST
#define HW_INST_WATCHPOINT_NUM 6
#define HW_WATCHPOINT_NUM 8
#define TYPE_INST_WATCHPOINT 0
#define TYPE_DATA_WATCHPOINT 1
/* Instruction watchpoint address control register bits mask */
#define WPPWR 0x1
#define WPIREN01 0x2
#define WPIRINV01 0x4
#define WPIAEN0 0x8
#define WPIAEN1 0x10
#define WPICNTEN0 0x20
#define WPICNTEN1 0x40
#define EMUSW0 0x80
#define EMUSW1 0x100
#define WPIREN23 0x200
#define WPIRINV23 0x400
#define WPIAEN2 0x800
#define WPIAEN3 0x1000
#define WPICNTEN2 0x2000
#define WPICNTEN3 0x4000
#define EMUSW2 0x8000
#define EMUSW3 0x10000
#define WPIREN45 0x20000
#define WPIRINV45 0x40000
#define WPIAEN4 0x80000
#define WPIAEN5 0x100000
#define WPICNTEN4 0x200000
#define WPICNTEN5 0x400000
#define EMUSW4 0x800000
#define EMUSW5 0x1000000
#define WPAND 0x2000000
/* Data watchpoint address control register bits mask */
#define WPDREN01 0x1
#define WPDRINV01 0x2
#define WPDAEN0 0x4
#define WPDAEN1 0x8
#define WPDCNTEN0 0x10
#define WPDCNTEN1 0x20
#define WPDSRC0 0xc0
#define WPDACC0_OFFSET 8
#define WPDSRC1 0xc00
#define WPDACC1_OFFSET 12
/* Watchpoint status register bits mask */
#define STATIA0 0x1
#define STATIA1 0x2
#define STATIA2 0x4
#define STATIA3 0x8
#define STATIA4 0x10
#define STATIA5 0x20
#define STATDA0 0x40
#define STATDA1 0x80
#endif

View File

@@ -0,0 +1,90 @@
/*
* File: memcmp.S
*
* Copyright 2004-2007 Analog Devices Inc.
* Enter bugs at http://blackfin.uclinux.org/
*
* SPDX-License-Identifier: GPL-2.0+
*/
.align 2
/*
* C Library function MEMCMP
* R0 = First Address
* R1 = Second Address
* R2 = count
* Favours word aligned data.
*/
.globl _memcmp;
.type _memcmp, STT_FUNC;
_memcmp:
I1 = P3;
P0 = R0; /* P0 = s1 address */
P3 = R1; /* P3 = s2 Address */
P2 = R2 ; /* P2 = count */
CC = R2 <= 7(IU);
IF CC JUMP .Ltoo_small;
I0 = R1; /* s2 */
R1 = R1 | R0; /* OR addresses together */
R1 <<= 30; /* check bottom two bits */
CC = AZ; /* AZ set if zero. */
IF !CC JUMP .Lbytes ; /* Jump if addrs not aligned. */
P1 = P2 >> 2; /* count = n/4 */
R3 = 3;
R2 = R2 & R3; /* remainder */
P2 = R2; /* set remainder */
LSETUP (.Lquad_loop_s , .Lquad_loop_e) LC0=P1;
.Lquad_loop_s:
NOP;
R0 = [P0++];
R1 = [I0++];
CC = R0 == R1;
IF !CC JUMP .Lquad_different;
.Lquad_loop_e:
NOP;
P3 = I0; /* s2 */
.Ltoo_small:
CC = P2 == 0; /* Check zero count*/
IF CC JUMP .Lfinished; /* very unlikely*/
.Lbytes:
LSETUP (.Lbyte_loop_s , .Lbyte_loop_e) LC0=P2;
.Lbyte_loop_s:
R1 = B[P3++](Z); /* *s2 */
R0 = B[P0++](Z); /* *s1 */
CC = R0 == R1;
IF !CC JUMP .Ldifferent;
.Lbyte_loop_e:
NOP;
.Ldifferent:
R0 = R0 - R1;
P3 = I1;
RTS;
.Lquad_different:
/* We've read two quads which don't match.
* Can't just compare them, because we're
* a little-endian machine, so the MSBs of
* the regs occur at later addresses in the
* string.
* Arrange to re-read those two quads again,
* byte-by-byte.
*/
P0 += -4; /* back up to the start of the */
P3 = I0; /* quads, and increase the*/
P2 += 4; /* remainder count*/
P3 += -4;
JUMP .Lbytes;
.Lfinished:
R0 = 0;
P3 = I1;
RTS;
.size _memcmp, .-_memcmp

View File

@@ -0,0 +1,104 @@
/*
* File: memcpy.S
*
* Copyright 2004-2007 Analog Devices Inc.
* Enter bugs at http://blackfin.uclinux.org/
*
* SPDX-License-Identifier: GPL-2.0+
*/
.align 2
.globl _memcpy_ASM;
.type _memcpy_ASM, STT_FUNC;
_memcpy_ASM:
CC = R2 <= 0; /* length not positive?*/
IF CC JUMP .L_P1L2147483647; /* Nothing to do */
P0 = R0 ; /* dst*/
P1 = R1 ; /* src*/
P2 = R2 ; /* length */
/* check for overlapping data */
CC = R1 < R0; /* src < dst */
IF !CC JUMP .Lno_overlap;
R3 = R1 + R2;
CC = R0 < R3; /* and dst < src+len */
IF CC JUMP .Lhas_overlap;
.Lno_overlap:
/* Check for aligned data.*/
R3 = R1 | R0;
R0 = 0x3;
R3 = R3 & R0;
CC = R3; /* low bits set on either address? */
IF CC JUMP .Lnot_aligned;
/* Both addresses are word-aligned, so we can copy
at least part of the data using word copies.*/
P2 = P2 >> 2;
CC = P2 <= 2;
IF !CC JUMP .Lmore_than_seven;
/* less than eight bytes... */
P2 = R2;
LSETUP(.Lthree_start, .Lthree_end) LC0=P2;
R0 = R1; /* setup src address for return */
.Lthree_start:
R3 = B[P1++] (X);
.Lthree_end:
B[P0++] = R3;
RTS;
.Lmore_than_seven:
/* There's at least eight bytes to copy. */
P2 += -1; /* because we unroll one iteration */
LSETUP(.Lword_loop, .Lword_loop) LC0=P2;
R0 = R1;
I1 = P1;
R3 = [I1++];
.Lword_loop:
MNOP || [P0++] = R3 || R3 = [I1++];
[P0++] = R3;
/* Any remaining bytes to copy? */
R3 = 0x3;
R3 = R2 & R3;
CC = R3 == 0;
P1 = I1; /* in case there's something left, */
IF !CC JUMP .Lbytes_left;
RTS;
.Lbytes_left: P2 = R3;
.Lnot_aligned:
/* From here, we're copying byte-by-byte. */
LSETUP (.Lbyte_start , .Lbyte_end) LC0=P2;
R0 = R1; /* Save src address for return */
.Lbyte_start:
R1 = B[P1++] (X);
.Lbyte_end:
B[P0++] = R1;
.L_P1L2147483647:
RTS;
.Lhas_overlap:
/* Need to reverse the copying, because the
* dst would clobber the src.
* Don't bother to work out alignment for
* the reverse case.
*/
R0 = R1; /* save src for later. */
P0 = P0 + P2;
P0 += -1;
P1 = P1 + P2;
P1 += -1;
LSETUP(.Lover_start, .Lover_end) LC0=P2;
.Lover_start:
R1 = B[P1--] (X);
.Lover_end:
B[P0--] = R1;
RTS;
.size _memcpy_ASM, .-_memcpy_ASM

View File

@@ -0,0 +1,83 @@
/*
* File: memmove.S
*
* Copyright 2004-2007 Analog Devices Inc.
* Enter bugs at http://blackfin.uclinux.org/
*
* SPDX-License-Identifier: GPL-2.0+
*/
.align 2
/*
* C Library function MEMMOVE
* R0 = To Address (leave unchanged to form result)
* R1 = From Address
* R2 = count
* Data may overlap
*/
.globl _memmove;
.type _memmove, STT_FUNC;
_memmove:
I1 = P3;
P0 = R0; /* P0 = To address */
P3 = R1; /* P3 = From Address */
P2 = R2 ; /* P2 = count */
CC = P2 == 0; /* Check zero count*/
IF CC JUMP .Lfinished; /* very unlikely */
CC = R1 < R0 (IU); /* From < To */
IF !CC JUMP .Lno_overlap;
R3 = R1 + R2;
CC = R0 <= R3 (IU); /* (From+len) >= To */
IF CC JUMP .Loverlap;
.Lno_overlap:
R3 = 11;
CC = R2 <= R3;
IF CC JUMP .Lbytes;
R3 = R1 | R0; /* OR addresses together */
R3 <<= 30; /* check bottom two bits */
CC = AZ; /* AZ set if zero.*/
IF !CC JUMP .Lbytes ; /* Jump if addrs not aligned.*/
I0 = P3;
P1 = P2 >> 2; /* count = n/4 */
P1 += -1;
R3 = 3;
R2 = R2 & R3; /* remainder */
P2 = R2; /* set remainder */
R1 = [I0++];
LSETUP (.Lquad_loop , .Lquad_loop) LC0=P1;
.Lquad_loop: MNOP || [P0++] = R1 || R1 = [I0++];
[P0++] = R1;
CC = P2 == 0; /* any remaining bytes? */
P3 = I0; /* Ammend P3 to updated ptr. */
IF !CC JUMP .Lbytes;
P3 = I1;
RTS;
.Lbytes: LSETUP (.Lbyte2_s , .Lbyte2_e) LC0=P2;
.Lbyte2_s: R1 = B[P3++](Z);
.Lbyte2_e: B[P0++] = R1;
.Lfinished: P3 = I1;
RTS;
.Loverlap:
P2 += -1;
P0 = P0 + P2;
P3 = P3 + P2;
R1 = B[P3--] (Z);
CC = P2 == 0;
IF CC JUMP .Lno_loop;
LSETUP (.Lol_s, .Lol_e) LC0 = P2;
.Lol_s: B[P0--] = R1;
.Lol_e: R1 = B[P3--] (Z);
.Lno_loop: B[P0] = R1;
P3 = I1;
RTS;
.size _memmove, .-_memmove

View File

@@ -0,0 +1,83 @@
/*
* File: memset.S
*
* Copyright 2004-2007 Analog Devices Inc.
* Enter bugs at http://blackfin.uclinux.org/
*
* SPDX-License-Identifier: GPL-2.0+
*/
.align 2
/*
* C Library function MEMSET
* R0 = address (leave unchanged to form result)
* R1 = filler byte
* R2 = count
* Favours word aligned data.
*/
.globl _memset;
.type _memset, STT_FUNC;
_memset:
P0 = R0 ; /* P0 = address */
P2 = R2 ; /* P2 = count */
R3 = R0 + R2; /* end */
CC = R2 <= 7(IU);
IF CC JUMP .Ltoo_small;
R1 = R1.B (Z); /* R1 = fill char */
R2 = 3;
R2 = R0 & R2; /* addr bottom two bits */
CC = R2 == 0; /* AZ set if zero. */
IF !CC JUMP .Lforce_align ; /* Jump if addr not aligned. */
.Laligned:
P1 = P2 >> 2; /* count = n/4 */
R2 = R1 << 8; /* create quad filler */
R2.L = R2.L + R1.L(NS);
R2.H = R2.L + R1.H(NS);
P2 = R3;
LSETUP (.Lquad_loop , .Lquad_loop) LC0=P1;
.Lquad_loop:
[P0++] = R2;
CC = P0 == P2;
IF !CC JUMP .Lbytes_left;
RTS;
.Lbytes_left:
R2 = R3; /* end point */
R3 = P0; /* current position */
R2 = R2 - R3; /* bytes left */
P2 = R2;
.Ltoo_small:
CC = P2 == 0; /* Check zero count */
IF CC JUMP .Lfinished; /* Unusual */
.Lbytes:
LSETUP (.Lbyte_loop , .Lbyte_loop) LC0=P2;
.Lbyte_loop:
B[P0++] = R1;
.Lfinished:
RTS;
.Lforce_align:
CC = BITTST (R0, 0); /* odd byte */
R0 = 4;
R0 = R0 - R2;
P1 = R0;
R0 = P0; /* Recover return address */
IF !CC JUMP .Lskip1;
B[P0++] = R1;
.Lskip1:
CC = R2 <= 2; /* 2 bytes */
P2 -= P1; /* reduce count */
IF !CC JUMP .Laligned;
B[P0++] = R1;
B[P0++] = R1;
JUMP .Laligned;
.size _memset, .-_memset

View File

@@ -0,0 +1,76 @@
/*
* U-Boot - muldi3.c contains routines for mult and div
*
* Copyright (c) 2005-2007 Analog Devices Inc.
*
* SPDX-License-Identifier: GPL-2.0+
*/
/* Generic function got from GNU gcc package, libgcc2.c */
#ifndef SI_TYPE_SIZE
#define SI_TYPE_SIZE 32
#endif
#define __ll_B (1L << (SI_TYPE_SIZE / 2))
#define __ll_lowpart(t) ((USItype) (t) % __ll_B)
#define __ll_highpart(t) ((USItype) (t) / __ll_B)
#define BITS_PER_UNIT 8
#if !defined (umul_ppmm)
#define umul_ppmm(w1, w0, u, v) \
do { \
USItype __x0, __x1, __x2, __x3; \
USItype __ul, __vl, __uh, __vh; \
\
__ul = __ll_lowpart (u); \
__uh = __ll_highpart (u); \
__vl = __ll_lowpart (v); \
__vh = __ll_highpart (v); \
\
__x0 = (USItype) __ul * __vl; \
__x1 = (USItype) __ul * __vh; \
__x2 = (USItype) __uh * __vl; \
__x3 = (USItype) __uh * __vh; \
\
__x1 += __ll_highpart (__x0);/* this can't give carry */ \
__x1 += __x2; /* but this indeed can */ \
if (__x1 < __x2) /* did we get it? */ \
__x3 += __ll_B; /* yes, add it in the proper pos. */ \
\
(w1) = __x3 + __ll_highpart (__x1); \
(w0) = __ll_lowpart (__x1) * __ll_B + __ll_lowpart (__x0); \
} while (0)
#endif
#if !defined (__umulsidi3)
#define __umulsidi3(u, v) \
({DIunion __w; \
umul_ppmm (__w.s.high, __w.s.low, u, v); \
__w.ll; })
#endif
typedef unsigned int USItype __attribute__ ((mode(SI)));
typedef int SItype __attribute__ ((mode(SI)));
typedef int DItype __attribute__ ((mode(DI)));
typedef int word_type __attribute__ ((mode(__word__)));
struct DIstruct {
SItype low, high;
};
typedef union {
struct DIstruct s;
DItype ll;
} DIunion;
DItype __muldi3(DItype u, DItype v)
{
DIunion w;
DIunion uu, vv;
uu.ll = u, vv.ll = v;
/* panic("kernel panic for __muldi3"); */
w.ll = __umulsidi3(uu.s.low, vv.s.low);
w.s.high += ((USItype) uu.s.low * (USItype) vv.s.high
+ (USItype) uu.s.high * (USItype) vv.s.low);
return w.ll;
}

View File

@@ -0,0 +1,64 @@
/*
* Implementation of outs{bwl} for BlackFin processors using zero overhead loops.
*
* Copyright 2005-2009 Analog Devices Inc.
* 2005 BuyWays BV
* Bas Vermeulen <bas@buyways.nl>
*
* Licensed under the GPL-2.
*/
#include <linux/linkage.h>
.align 2
.section .text._outsl
ENTRY(_outsl)
P0 = R0; /* P0 = port */
P1 = R1; /* P1 = address */
P2 = R2; /* P2 = count */
LSETUP( .Llong_loop_s, .Llong_loop_e) LC0 = P2;
.Llong_loop_s: R0 = [P1++];
.Llong_loop_e: [P0] = R0;
RTS;
ENDPROC(_outsl)
.section .text._outsw
ENTRY(_outsw)
P0 = R0; /* P0 = port */
P1 = R1; /* P1 = address */
P2 = R2; /* P2 = count */
LSETUP( .Lword_loop_s, .Lword_loop_e) LC0 = P2;
.Lword_loop_s: R0 = W[P1++];
.Lword_loop_e: W[P0] = R0;
RTS;
ENDPROC(_outsw)
.section .text._outsb
ENTRY(_outsb)
P0 = R0; /* P0 = port */
P1 = R1; /* P1 = address */
P2 = R2; /* P2 = count */
LSETUP( .Lbyte_loop_s, .Lbyte_loop_e) LC0 = P2;
.Lbyte_loop_s: R0 = B[P1++];
.Lbyte_loop_e: B[P0] = R0;
RTS;
ENDPROC(_outsb)
.section .text._outsw_8
ENTRY(_outsw_8)
P0 = R0; /* P0 = port */
P1 = R1; /* P1 = address */
P2 = R2; /* P2 = count */
LSETUP( .Lword8_loop_s, .Lword8_loop_e) LC0 = P2;
.Lword8_loop_s: R1 = B[P1++];
R0 = B[P1++];
R0 = R0 << 8;
R0 = R0 + R1;
.Lword8_loop_e: W[P0] = R0;
RTS;
ENDPROC(_outsw_8)

View File

@@ -0,0 +1,85 @@
/*
* Blackfin POST code
*
* Copyright (c) 2005-2011 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#include <common.h>
#include <config.h>
#include <post.h>
#include <asm/gpio.h>
#if CONFIG_POST & CONFIG_SYS_POST_BSPEC1
int led_post_test(int flags)
{
unsigned leds[] = { CONFIG_POST_BSPEC1_GPIO_LEDS };
int i;
/* First turn them all off */
for (i = 0; i < ARRAY_SIZE(leds); ++i) {
if (gpio_request(leds[i], "post")) {
printf("could not request gpio %u\n", leds[i]);
continue;
}
gpio_direction_output(leds[i], 0);
}
/* Now turn them on one by one */
for (i = 0; i < ARRAY_SIZE(leds); ++i) {
printf("LED%i on", i + 1);
gpio_set_value(leds[i], 1);
udelay(1000000);
printf("\b\b\b\b\b\b\b");
gpio_free(leds[i]);
}
return 0;
}
#endif
#if CONFIG_POST & CONFIG_SYS_POST_BSPEC2
int button_post_test(int flags)
{
unsigned buttons[] = { CONFIG_POST_BSPEC2_GPIO_BUTTONS };
unsigned int sws[] = { CONFIG_POST_BSPEC2_GPIO_NAMES };
int i, delay = 5;
unsigned short value = 0;
int result = 0;
for (i = 0; i < ARRAY_SIZE(buttons); ++i) {
if (gpio_request(buttons[i], "post")) {
printf("could not request gpio %u\n", buttons[i]);
continue;
}
gpio_direction_input(buttons[i]);
delay = 5;
printf("\n--------Press SW%i: %2d ", sws[i], delay);
while (delay--) {
int j;
for (j = 0; j < 100; j++) {
value = gpio_get_value(buttons[i]);
if (value != 0)
break;
udelay(10000);
}
printf("\b\b\b%2d ", delay);
}
if (value != 0)
puts("\b\bOK");
else {
result = -1;
puts("\b\bfailed");
}
gpio_free(buttons[i]);
}
puts("\n");
return result;
}
#endif

View File

@@ -0,0 +1,11 @@
/*
* U-Boot - section.c
*
* Copyright (c) 2014 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
char __bss_start[0] __attribute__((section(".__bss_start")));
char __bss_end[0] __attribute__((section(".__bss_end")));
char __init_end[0] __attribute__((section(".__init_end")));

View File

@@ -0,0 +1,268 @@
/*
* U-Boot - string.c Contains library routines.
*
* Copyright (c) 2005-2008 Analog Devices Inc.
*
* (C) Copyright 2000-2004
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <config.h>
#include <asm/blackfin.h>
#include <asm/io.h>
#include <asm/dma.h>
char *strcpy(char *dest, const char *src)
{
char *xdest = dest;
char temp = 0;
__asm__ __volatile__ (
"1:\t%2 = B [%1++] (Z);\n\t"
"B [%0++] = %2;\n\t"
"CC = %2;\n\t"
"if cc jump 1b (bp);\n"
: "=a"(dest), "=a"(src), "=d"(temp)
: "0"(dest), "1"(src), "2"(temp)
: "memory");
return xdest;
}
char *strncpy(char *dest, const char *src, size_t n)
{
char *xdest = dest;
char temp = 0;
if (n == 0)
return xdest;
__asm__ __volatile__ (
"1:\t%3 = B [%1++] (Z);\n\t"
"B [%0++] = %3;\n\t"
"CC = %3;\n\t"
"if ! cc jump 2f;\n\t"
"%2 += -1;\n\t"
"CC = %2 == 0;\n\t"
"if ! cc jump 1b (bp);\n"
"2:\n"
: "=a"(dest), "=a"(src), "=da"(n), "=d"(temp)
: "0"(dest), "1"(src), "2"(n), "3"(temp)
: "memory");
return xdest;
}
int strcmp(const char *cs, const char *ct)
{
char __res1, __res2;
__asm__ (
"1:\t%2 = B[%0++] (Z);\n\t" /* get *cs */
"%3 = B[%1++] (Z);\n\t" /* get *ct */
"CC = %2 == %3;\n\t" /* compare a byte */
"if ! cc jump 2f;\n\t" /* not equal, break out */
"CC = %2;\n\t" /* at end of cs? */
"if cc jump 1b (bp);\n\t" /* no, keep going */
"jump.s 3f;\n" /* strings are equal */
"2:\t%2 = %2 - %3;\n" /* *cs - *ct */
"3:\n"
: "=a"(cs), "=a"(ct), "=d"(__res1), "=d"(__res2)
: "0"(cs), "1"(ct));
return __res1;
}
int strncmp(const char *cs, const char *ct, size_t count)
{
char __res1, __res2;
if (!count)
return 0;
__asm__(
"1:\t%3 = B[%0++] (Z);\n\t" /* get *cs */
"%4 = B[%1++] (Z);\n\t" /* get *ct */
"CC = %3 == %4;\n\t" /* compare a byte */
"if ! cc jump 3f;\n\t" /* not equal, break out */
"CC = %3;\n\t" /* at end of cs? */
"if ! cc jump 4f;\n\t" /* yes, all done */
"%2 += -1;\n\t" /* no, adjust count */
"CC = %2 == 0;\n\t" "if ! cc jump 1b;\n" /* more to do, keep going */
"2:\t%3 = 0;\n\t" /* strings are equal */
"jump.s 4f;\n" "3:\t%3 = %3 - %4;\n" /* *cs - *ct */
"4:"
: "=a"(cs), "=a"(ct), "=da"(count), "=d"(__res1), "=d"(__res2)
: "0"(cs), "1"(ct), "2"(count));
return __res1;
}
#ifdef MDMA1_D0_NEXT_DESC_PTR
# define MDMA_D0_NEXT_DESC_PTR MDMA1_D0_NEXT_DESC_PTR
# define MDMA_S0_NEXT_DESC_PTR MDMA1_S0_NEXT_DESC_PTR
#endif
static void dma_calc_size(unsigned long ldst, unsigned long lsrc, size_t count,
unsigned long *dshift, unsigned long *bpos)
{
unsigned long limit;
#ifdef MSIZE
/* The max memory DMA memory transfer size is 32 bytes. */
limit = 5;
*dshift = MSIZE_P;
#else
/* The max memory DMA memory transfer size is 4 bytes. */
limit = 2;
*dshift = WDSIZE_P;
#endif
*bpos = min(limit, (unsigned long)ffs(ldst | lsrc | count)) - 1;
}
/* This version misbehaves for count values of 0 and 2^16+.
* Perhaps we should detect that ? Nowhere do we actually
* use dma memcpy for those types of lengths though ...
*/
void dma_memcpy_nocache(void *dst, const void *src, size_t count)
{
struct dma_register *mdma_d0 = (void *)MDMA_D0_NEXT_DESC_PTR;
struct dma_register *mdma_s0 = (void *)MDMA_S0_NEXT_DESC_PTR;
unsigned long ldst = (unsigned long)dst;
unsigned long lsrc = (unsigned long)src;
unsigned long dshift, bpos;
uint32_t dsize, mod;
/* Disable DMA in case it's still running (older u-boot's did not
* always turn them off). Do it before the if statement below so
* we can be cheap and not do a SSYNC() due to the forced abort.
*/
bfin_write(&mdma_d0->config, 0);
bfin_write(&mdma_s0->config, 0);
bfin_write(&mdma_d0->status, DMA_RUN | DMA_DONE | DMA_ERR);
/* Scratchpad cannot be a DMA source or destination */
if ((lsrc >= L1_SRAM_SCRATCH && lsrc < L1_SRAM_SCRATCH_END) ||
(ldst >= L1_SRAM_SCRATCH && ldst < L1_SRAM_SCRATCH_END))
hang();
dma_calc_size(ldst, lsrc, count, &dshift, &bpos);
dsize = bpos << dshift;
count >>= bpos;
mod = 1 << bpos;
#ifdef PSIZE
/* The max memory DMA peripheral transfer size is 4 bytes. */
dsize |= min(2UL, bpos) << PSIZE_P;
#endif
/* Copy sram functions from sdram to sram */
/* Setup destination start address */
bfin_write(&mdma_d0->start_addr, ldst);
/* Setup destination xcount */
bfin_write(&mdma_d0->x_count, count);
/* Setup destination xmodify */
bfin_write(&mdma_d0->x_modify, mod);
/* Setup Source start address */
bfin_write(&mdma_s0->start_addr, lsrc);
/* Setup Source xcount */
bfin_write(&mdma_s0->x_count, count);
/* Setup Source xmodify */
bfin_write(&mdma_s0->x_modify, mod);
/* Enable source DMA */
bfin_write(&mdma_s0->config, dsize | DMAEN);
bfin_write(&mdma_d0->config, dsize | DMAEN | WNR | DI_EN);
SSYNC();
while (!(bfin_read(&mdma_d0->status) & DMA_DONE))
continue;
bfin_write(&mdma_d0->status, DMA_RUN | DMA_DONE | DMA_ERR);
bfin_write(&mdma_d0->config, 0);
bfin_write(&mdma_s0->config, 0);
}
/* We should do a dcache invalidate on the destination after the dma, but since
* we lack such hardware capability, we'll flush/invalidate the destination
* before the dma and bank on the idea that u-boot is single threaded.
*/
void *dma_memcpy(void *dst, const void *src, size_t count)
{
if (dcache_status()) {
blackfin_dcache_flush_range(src, src + count);
blackfin_dcache_flush_invalidate_range(dst, dst + count);
}
dma_memcpy_nocache(dst, src, count);
if (icache_status())
blackfin_icache_flush_range(dst, dst + count);
return dst;
}
/*
* memcpy - Copy one area of memory to another
* @dest: Where to copy to
* @src: Where to copy from
* @count: The size of the area.
*
* We need to have this wrapper in memcpy() as common code may call memcpy()
* to load up L1 regions. Consider loading an ELF which has sections with
* LMA's pointing to L1. The common code ELF loader will simply use memcpy()
* to move the ELF's sections into the right place. We need to catch that
* here and redirect to dma_memcpy().
*/
extern void *memcpy_ASM(void *dst, const void *src, size_t count);
void *memcpy(void *dst, const void *src, size_t count)
{
if (!count)
return dst;
#ifdef CONFIG_CMD_KGDB
if (src >= (void *)SYSMMR_BASE) {
if (count == 2 && (unsigned long)src % 2 == 0) {
u16 mmr = bfin_read16(src);
memcpy(dst, &mmr, sizeof(mmr));
return dst;
}
if (count == 4 && (unsigned long)src % 4 == 0) {
u32 mmr = bfin_read32(src);
memcpy(dst, &mmr, sizeof(mmr));
return dst;
}
/* Failed for some reason */
memset(dst, 0xad, count);
return dst;
}
if (dst >= (void *)SYSMMR_BASE) {
if (count == 2 && (unsigned long)dst % 2 == 0) {
u16 mmr;
memcpy(&mmr, src, sizeof(mmr));
bfin_write16(dst, mmr);
return dst;
}
if (count == 4 && (unsigned long)dst % 4 == 0) {
u32 mmr;
memcpy(&mmr, src, sizeof(mmr));
bfin_write32(dst, mmr);
return dst;
}
/* Failed for some reason */
memset(dst, 0xad, count);
return dst;
}
#endif
/* if L1 is the source or dst, use DMA */
if (addr_bfin_on_chip_mem(dst) || addr_bfin_on_chip_mem(src))
return dma_memcpy(dst, src, count);
else
/* No L1 is involved, so just call regular memcpy */
return memcpy_ASM(dst, src, count);
}