Merge branch 'master' of git://git.denx.de/u-boot-blackfin
This commit is contained in:
@@ -16,7 +16,7 @@ LIB = $(obj)lib$(CPU).a
|
||||
EXTRA :=
|
||||
CEXTRA := initcode.o
|
||||
SEXTRA := start.o
|
||||
SOBJS := interrupt.o cache.o flush.o
|
||||
SOBJS := interrupt.o cache.o
|
||||
COBJS := cpu.o traps.o interrupts.o reset.o serial.o i2c.o watchdog.o
|
||||
|
||||
ifeq ($(CONFIG_BFIN_BOOT_MODE),BFIN_BOOT_BYPASS)
|
||||
|
||||
@@ -14,46 +14,11 @@
|
||||
#include <asm/blackfin.h>
|
||||
#include <asm/cplb.h>
|
||||
#include <asm/mach-common/bits/core.h>
|
||||
#include <asm/mach-common/bits/mpu.h>
|
||||
#include <asm/mach-common/bits/trace.h>
|
||||
|
||||
#include "cpu.h"
|
||||
#include "serial.h"
|
||||
|
||||
void icache_enable(void)
|
||||
{
|
||||
bfin_write_IMEM_CONTROL(bfin_read_IMEM_CONTROL() | (IMC | ENICPLB));
|
||||
SSYNC();
|
||||
}
|
||||
|
||||
void icache_disable(void)
|
||||
{
|
||||
bfin_write_IMEM_CONTROL(bfin_read_IMEM_CONTROL() & ~(IMC | ENICPLB));
|
||||
SSYNC();
|
||||
}
|
||||
|
||||
int icache_status(void)
|
||||
{
|
||||
return bfin_read_IMEM_CONTROL() & ENICPLB;
|
||||
}
|
||||
|
||||
void dcache_enable(void)
|
||||
{
|
||||
bfin_write_DMEM_CONTROL(bfin_read_DMEM_CONTROL() | (ACACHE_BCACHE | ENDCPLB | PORT_PREF0));
|
||||
SSYNC();
|
||||
}
|
||||
|
||||
void dcache_disable(void)
|
||||
{
|
||||
bfin_write_DMEM_CONTROL(bfin_read_DMEM_CONTROL() & ~(ACACHE_BCACHE | ENDCPLB | PORT_PREF0));
|
||||
SSYNC();
|
||||
}
|
||||
|
||||
int dcache_status(void)
|
||||
{
|
||||
return bfin_read_DMEM_CONTROL() & ENDCPLB;
|
||||
}
|
||||
|
||||
__attribute__ ((__noreturn__))
|
||||
void cpu_init_f(ulong bootflag, ulong loaded_from_ldr)
|
||||
{
|
||||
@@ -133,9 +98,8 @@ int irq_init(void)
|
||||
bfin_write_EVT15(evt_default);
|
||||
bfin_write_ILAT(0);
|
||||
CSYNC();
|
||||
/* enable all interrupts except for core timer */
|
||||
irq_flags = 0xffffffbf;
|
||||
/* enable hardware error irq */
|
||||
irq_flags = 0x3f;
|
||||
local_irq_enable();
|
||||
CSYNC();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,230 +0,0 @@
|
||||
/* flush.S - low level cache flushing routines
|
||||
* Copyright (C) 2003-2007 Analog Devices Inc.
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <asm/blackfin.h>
|
||||
#include <asm/cplb.h>
|
||||
#include <asm/mach-common/bits/mpu.h>
|
||||
|
||||
.text
|
||||
|
||||
/* This is an external function being called by the user
|
||||
* application through __flush_cache_all. Currently this function
|
||||
* serves the purpose of flushing all the pending writes in
|
||||
* in the data cache.
|
||||
*/
|
||||
|
||||
ENTRY(_flush_data_cache)
|
||||
[--SP] = ( R7:6, P5:4 );
|
||||
LINK 12;
|
||||
SP += -12;
|
||||
P5.H = HI(DCPLB_ADDR0);
|
||||
P5.L = LO(DCPLB_ADDR0);
|
||||
P4.H = HI(DCPLB_DATA0);
|
||||
P4.L = LO(DCPLB_DATA0);
|
||||
R7 = CPLB_VALID | CPLB_L1_CHBL | CPLB_DIRTY (Z);
|
||||
R6 = 16;
|
||||
.Lnext: R0 = [P5++];
|
||||
R1 = [P4++];
|
||||
CC = BITTST(R1, 14); /* Is it write-through?*/
|
||||
IF CC JUMP .Lskip; /* If so, ignore it.*/
|
||||
R2 = R1 & R7; /* Is it a dirty, cached page?*/
|
||||
CC = R2;
|
||||
IF !CC JUMP .Lskip; /* If not, ignore it.*/
|
||||
[--SP] = RETS;
|
||||
CALL _dcplb_flush; /* R0 = page, R1 = data*/
|
||||
RETS = [SP++];
|
||||
.Lskip: R6 += -1;
|
||||
CC = R6;
|
||||
IF CC JUMP .Lnext;
|
||||
SSYNC;
|
||||
SP += 12;
|
||||
UNLINK;
|
||||
( R7:6, P5:4 ) = [SP++];
|
||||
RTS;
|
||||
ENDPROC(_flush_data_cache)
|
||||
|
||||
/* This is an internal function to flush all pending
|
||||
* writes in the cache associated with a particular DCPLB.
|
||||
*
|
||||
* R0 - page's start address
|
||||
* R1 - CPLB's data field.
|
||||
*/
|
||||
|
||||
.align 2
|
||||
ENTRY(_dcplb_flush)
|
||||
[--SP] = ( R7:0, P5:0 );
|
||||
[--SP] = LC0;
|
||||
[--SP] = LT0;
|
||||
[--SP] = LB0;
|
||||
[--SP] = LC1;
|
||||
[--SP] = LT1;
|
||||
[--SP] = LB1;
|
||||
|
||||
/* If it's a 1K or 4K page, then it's quickest to
|
||||
* just systematically flush all the addresses in
|
||||
* the page, regardless of whether they're in the
|
||||
* cache, or dirty. If it's a 1M or 4M page, there
|
||||
* are too many addresses, and we have to search the
|
||||
* cache for lines corresponding to the page.
|
||||
*/
|
||||
|
||||
CC = BITTST(R1, 17); /* 1MB or 4MB */
|
||||
IF !CC JUMP .Ldflush_whole_page;
|
||||
|
||||
/* We're only interested in the page's size, so extract
|
||||
* this from the CPLB (bits 17:16), and scale to give an
|
||||
* offset into the page_size and page_prefix tables.
|
||||
*/
|
||||
|
||||
R1 <<= 14;
|
||||
R1 >>= 30;
|
||||
R1 <<= 2;
|
||||
|
||||
/* The page could be mapped into Bank A or Bank B, depending
|
||||
* on (a) whether both banks are configured as cache, and
|
||||
* (b) on whether address bit A[x] is set. x is determined
|
||||
* by DCBS in DMEM_CONTROL
|
||||
*/
|
||||
|
||||
R2 = 0; /* Default to Bank A (Bank B would be 1)*/
|
||||
|
||||
P0.L = LO(DMEM_CONTROL);
|
||||
P0.H = HI(DMEM_CONTROL);
|
||||
|
||||
R3 = [P0]; /* If Bank B is not enabled as cache*/
|
||||
CC = BITTST(R3, 2); /* then Bank A is our only option.*/
|
||||
IF CC JUMP .Lbank_chosen;
|
||||
|
||||
R4 = 1<<14; /* If DCBS==0, use A[14].*/
|
||||
R5 = R4 << 7; /* If DCBS==1, use A[23];*/
|
||||
CC = BITTST(R3, 4);
|
||||
IF CC R4 = R5; /* R4 now has either bit 14 or bit 23 set.*/
|
||||
R5 = R0 & R4; /* Use it to test the Page address*/
|
||||
CC = R5; /* and if that bit is set, we use Bank B,*/
|
||||
R2 = CC; /* else we use Bank A.*/
|
||||
R2 <<= 23; /* The Bank selection's at posn 23.*/
|
||||
|
||||
.Lbank_chosen:
|
||||
|
||||
/* We can also determine the sub-bank used, because this is
|
||||
* taken from bits 13:12 of the address.
|
||||
*/
|
||||
|
||||
R3 = ((12<<8)|2); /* Extraction pattern */
|
||||
nop; /*Anamoly 05000209*/
|
||||
R4 = EXTRACT(R0, R3.L) (Z); /* Extract bits*/
|
||||
/* Save in extraction pattern for later deposit.*/
|
||||
R3.H = R4.L << 0;
|
||||
|
||||
/* So:
|
||||
* R0 = Page start
|
||||
* R1 = Page length (actually, offset into size/prefix tables)
|
||||
* R2 = Bank select mask
|
||||
* R3 = sub-bank deposit values
|
||||
*
|
||||
* The cache has 2 Ways, and 64 sets, so we iterate through
|
||||
* the sets, accessing the tag for each Way, for our Bank and
|
||||
* sub-bank, looking for dirty, valid tags that match our
|
||||
* address prefix.
|
||||
*/
|
||||
|
||||
P5.L = LO(DTEST_COMMAND);
|
||||
P5.H = HI(DTEST_COMMAND);
|
||||
P4.L = LO(DTEST_DATA0);
|
||||
P4.H = HI(DTEST_DATA0);
|
||||
|
||||
P0.L = page_prefix_table;
|
||||
P0.H = page_prefix_table;
|
||||
P1 = R1;
|
||||
R5 = 0; /* Set counter*/
|
||||
P0 = P1 + P0;
|
||||
R4 = [P0]; /* This is the address prefix*/
|
||||
|
||||
|
||||
/* We're reading (bit 1==0) the tag (bit 2==0), and we
|
||||
* don't care about which double-word, since we're only
|
||||
* fetching tags, so we only have to set Set, Bank,
|
||||
* Sub-bank and Way.
|
||||
*/
|
||||
|
||||
P2 = 2;
|
||||
LSETUP (.Lfs1, .Lfe1) LC1 = P2;
|
||||
.Lfs1: P0 = 64; /* iterate over all sets*/
|
||||
LSETUP (.Lfs0, .Lfe0) LC0 = P0;
|
||||
.Lfs0: R6 = R5 << 5; /* Combine set*/
|
||||
R6.H = R3.H << 0 ; /* and sub-bank*/
|
||||
R6 = R6 | R2; /* and Bank. Leave Way==0 at first.*/
|
||||
BITSET(R6,14);
|
||||
[P5] = R6; /* Issue Command*/
|
||||
SSYNC;
|
||||
R7 = [P4]; /* and read Tag.*/
|
||||
CC = BITTST(R7, 0); /* Check if valid*/
|
||||
IF !CC JUMP .Lfskip; /* and skip if not.*/
|
||||
CC = BITTST(R7, 1); /* Check if dirty*/
|
||||
IF !CC JUMP .Lfskip; /* and skip if not.*/
|
||||
|
||||
/* Compare against the page address. First, plant bits 13:12
|
||||
* into the tag, since those aren't part of the returned data.
|
||||
*/
|
||||
|
||||
R7 = DEPOSIT(R7, R3); /* set 13:12*/
|
||||
R1 = R7 & R4; /* Mask off lower bits*/
|
||||
CC = R1 == R0; /* Compare against page start.*/
|
||||
IF !CC JUMP .Lfskip; /* Skip it if it doesn't match.*/
|
||||
|
||||
/* Tag address matches against page, so this is an entry
|
||||
* we must flush.
|
||||
*/
|
||||
|
||||
R7 >>= 10; /* Mask off the non-address bits*/
|
||||
R7 <<= 10;
|
||||
P3 = R7;
|
||||
SSYNC;
|
||||
FLUSHINV [P3]; /* And flush the entry*/
|
||||
.Lfskip:
|
||||
.Lfe0: R5 += 1; /* Advance to next Set*/
|
||||
.Lfe1: BITSET(R2, 26); /* Go to next Way.*/
|
||||
|
||||
.Ldfinished:
|
||||
SSYNC; /* Ensure the data gets out to mem.*/
|
||||
|
||||
/*Finished. Restore context.*/
|
||||
LB1 = [SP++];
|
||||
LT1 = [SP++];
|
||||
LC1 = [SP++];
|
||||
LB0 = [SP++];
|
||||
LT0 = [SP++];
|
||||
LC0 = [SP++];
|
||||
( R7:0, P5:0 ) = [SP++];
|
||||
RTS;
|
||||
|
||||
.Ldflush_whole_page:
|
||||
|
||||
/* It's a 1K or 4K page, so quicker to just flush the
|
||||
* entire page.
|
||||
*/
|
||||
|
||||
P1 = 32; /* For 1K pages*/
|
||||
P2 = P1 << 2; /* For 4K pages*/
|
||||
P0 = R0; /* Start of page*/
|
||||
CC = BITTST(R1, 16); /* Whether 1K or 4K*/
|
||||
IF CC P1 = P2;
|
||||
P1 += -1; /* Unroll one iteration*/
|
||||
SSYNC;
|
||||
FLUSHINV [P0++]; /* because CSYNC can't end loops.*/
|
||||
LSETUP (.Leall, .Leall) LC0 = P1;
|
||||
.Leall: FLUSHINV [P0++];
|
||||
SSYNC;
|
||||
JUMP .Ldfinished;
|
||||
ENDPROC(_dcplb_flush)
|
||||
|
||||
.align 4;
|
||||
page_prefix_table:
|
||||
.byte4 0xFFFFFC00; /* 1K */
|
||||
.byte4 0xFFFFF000; /* 4K */
|
||||
.byte4 0xFFF00000; /* 1M */
|
||||
.byte4 0xFFC00000; /* 4M */
|
||||
.page_prefix_table.end:
|
||||
@@ -35,6 +35,32 @@
|
||||
|
||||
#include "serial.h"
|
||||
|
||||
#ifdef CONFIG_DEBUG_SERIAL
|
||||
uint16_t cached_lsr[256];
|
||||
uint16_t cached_rbr[256];
|
||||
size_t cache_count;
|
||||
|
||||
/* The LSR is read-to-clear on some parts, so we have to make sure status
|
||||
* bits aren't inadvertently lost when doing various tests.
|
||||
*/
|
||||
static uint16_t uart_lsr_save;
|
||||
static uint16_t uart_lsr_read(void)
|
||||
{
|
||||
uint16_t lsr = *pUART_LSR;
|
||||
uart_lsr_save |= (lsr & (OE|PE|FE|BI));
|
||||
return lsr | uart_lsr_save;
|
||||
}
|
||||
/* Just do the clear for everyone since it can't hurt. */
|
||||
static void uart_lsr_clear(void)
|
||||
{
|
||||
uart_lsr_save = 0;
|
||||
*pUART_LSR |= -1;
|
||||
}
|
||||
#else
|
||||
static inline uint16_t uart_lsr_read(void) { return *pUART_LSR; }
|
||||
static inline void uart_lsr_clear(void) { *pUART_LSR = -1; }
|
||||
#endif
|
||||
|
||||
/* Symbol for our assembly to call. */
|
||||
void serial_set_baud(uint32_t baud)
|
||||
{
|
||||
@@ -61,6 +87,12 @@ int serial_init(void)
|
||||
{
|
||||
serial_initialize();
|
||||
serial_setbrg();
|
||||
uart_lsr_clear();
|
||||
#ifdef CONFIG_DEBUG_SERIAL
|
||||
cache_count = 0;
|
||||
memset(cached_lsr, 0x00, sizeof(cached_lsr));
|
||||
memset(cached_rbr, 0x00, sizeof(cached_rbr));
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -73,7 +105,7 @@ void serial_putc(const char c)
|
||||
WATCHDOG_RESET();
|
||||
|
||||
/* wait for the hardware fifo to clear up */
|
||||
while (!(*pUART_LSR & THRE))
|
||||
while (!(uart_lsr_read() & THRE))
|
||||
continue;
|
||||
|
||||
/* queue the character for transmission */
|
||||
@@ -83,38 +115,54 @@ void serial_putc(const char c)
|
||||
WATCHDOG_RESET();
|
||||
|
||||
/* wait for the byte to be shifted over the line */
|
||||
while (!(*pUART_LSR & TEMT))
|
||||
while (!(uart_lsr_read() & TEMT))
|
||||
continue;
|
||||
}
|
||||
|
||||
int serial_tstc(void)
|
||||
{
|
||||
WATCHDOG_RESET();
|
||||
return (*pUART_LSR & DR) ? 1 : 0;
|
||||
return (uart_lsr_read() & DR) ? 1 : 0;
|
||||
}
|
||||
|
||||
int serial_getc(void)
|
||||
{
|
||||
uint16_t uart_lsr_val, uart_rbr_val;
|
||||
uint16_t uart_rbr_val;
|
||||
|
||||
/* wait for data ! */
|
||||
while (!serial_tstc())
|
||||
continue;
|
||||
|
||||
/* clear the status and grab the new byte */
|
||||
uart_lsr_val = *pUART_LSR;
|
||||
/* grab the new byte */
|
||||
uart_rbr_val = *pUART_RBR;
|
||||
|
||||
#ifdef CONFIG_DEBUG_SERIAL
|
||||
/* grab & clear the LSR */
|
||||
uint16_t uart_lsr_val = uart_lsr_read();
|
||||
|
||||
cached_lsr[cache_count] = uart_lsr_val;
|
||||
cached_rbr[cache_count] = uart_rbr_val;
|
||||
cache_count = (cache_count + 1) % ARRAY_SIZE(cached_lsr);
|
||||
|
||||
if (uart_lsr_val & (OE|PE|FE|BI)) {
|
||||
/* Some parts are read-to-clear while others are
|
||||
* write-to-clear. Just do the write for everyone
|
||||
* since it cant hurt (other than code size).
|
||||
*/
|
||||
*pUART_LSR = (OE|PE|FE|BI);
|
||||
uint16_t dll, dlh;
|
||||
printf("\n[SERIAL ERROR]\n");
|
||||
ACCESS_LATCH();
|
||||
dll = *pUART_DLL;
|
||||
dlh = *pUART_DLH;
|
||||
ACCESS_PORT_IER();
|
||||
printf("\tDLL=0x%x DLH=0x%x\n", dll, dlh);
|
||||
do {
|
||||
--cache_count;
|
||||
printf("\t%3i: RBR=0x%02x LSR=0x%02x\n", cache_count,
|
||||
cached_rbr[cache_count], cached_lsr[cache_count]);
|
||||
} while (cache_count > 0);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
uart_lsr_clear();
|
||||
|
||||
return uart_rbr_val & 0xFF;
|
||||
return uart_rbr_val;
|
||||
}
|
||||
|
||||
void serial_puts(const char *s)
|
||||
|
||||
@@ -175,11 +175,11 @@ static inline uint32_t serial_early_get_baud(void)
|
||||
__attribute__((always_inline))
|
||||
static inline void serial_early_set_baud(uint32_t baud)
|
||||
{
|
||||
/* Translate from baud into divisor in terms of SCLK.
|
||||
* The +1 is to make sure we over sample just a little
|
||||
* rather than under sample the incoming signals.
|
||||
/* Translate from baud into divisor in terms of SCLK. The
|
||||
* weird multiplication is to make sure we over sample just
|
||||
* a little rather than under sample the incoming signals.
|
||||
*/
|
||||
uint16_t divisor = (get_sclk() / (baud * 16)) + 1;
|
||||
uint16_t divisor = (get_sclk() + (baud * 8)) / (baud * 16) - ANOMALY_05000230;
|
||||
|
||||
/* Set DLAB in LCR to Access DLL and DLH */
|
||||
ACCESS_LATCH();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* U-boot - start.S Startup file for Blackfin u-boot
|
||||
*
|
||||
* Copyright (c) 2005-2007 Analog Devices Inc.
|
||||
* Copyright (c) 2005-2008 Analog Devices Inc.
|
||||
*
|
||||
* This file is based on head.S
|
||||
* Copyright (c) 2003 Metrowerks/Motorola
|
||||
@@ -49,8 +49,8 @@
|
||||
ENTRY(_start)
|
||||
|
||||
/* Set our initial stack to L1 scratch space */
|
||||
sp.l = LO(L1_SRAM_SCRATCH + L1_SRAM_SCRATCH_SIZE);
|
||||
sp.h = HI(L1_SRAM_SCRATCH + L1_SRAM_SCRATCH_SIZE);
|
||||
sp.l = LO(L1_SRAM_SCRATCH_END - 20);
|
||||
sp.h = HI(L1_SRAM_SCRATCH_END - 20);
|
||||
|
||||
#ifdef CONFIG_HW_WATCHDOG
|
||||
# ifndef CONFIG_HW_WATCHDOG_TIMEOUT_START
|
||||
@@ -75,7 +75,7 @@ ENTRY(_start)
|
||||
|
||||
serial_early_puts("Init Registers");
|
||||
|
||||
/* Disable nested interrupts and enable CYCLES for udelay() */
|
||||
/* Disable self-nested interrupts and enable CYCLES for udelay() */
|
||||
R0 = CCEN | 0x30;
|
||||
SYSCFG = R0;
|
||||
|
||||
@@ -180,7 +180,7 @@ ENTRY(_start)
|
||||
|
||||
/* Now lower ourselves from the highest interrupt level to
|
||||
* the lowest. We do this by masking all interrupts but 15,
|
||||
* setting the 15 handler to "board_init_f", raising the 15
|
||||
* setting the 15 handler to ".Lenable_nested", raising the 15
|
||||
* interrupt, and then returning from the highest interrupt
|
||||
* level to the dummy "jump" until the interrupt controller
|
||||
* services the pending 15 interrupt.
|
||||
@@ -190,20 +190,23 @@ ENTRY(_start)
|
||||
r1 = r6;
|
||||
p0.l = LO(EVT15);
|
||||
p0.h = HI(EVT15);
|
||||
p1.l = _cpu_init_f;
|
||||
p1.h = _cpu_init_f;
|
||||
p1.l = .Lenable_nested;
|
||||
p1.h = .Lenable_nested;
|
||||
[p0] = p1;
|
||||
p2.l = LO(IMASK);
|
||||
p2.h = HI(IMASK);
|
||||
p3.l = LO(EVT_IVG15);
|
||||
p3.h = HI(EVT_IVG15);
|
||||
[p2] = p3;
|
||||
r7 = EVT_IVG15 (z);
|
||||
sti r7;
|
||||
raise 15;
|
||||
p4.l = .LWAIT_HERE;
|
||||
p4.h = .LWAIT_HERE;
|
||||
reti = p4;
|
||||
rti;
|
||||
|
||||
/* Enable nested interrupts before continuing with cpu init */
|
||||
.Lenable_nested:
|
||||
cli r7;
|
||||
[--sp] = reti;
|
||||
jump.l _cpu_init_f;
|
||||
|
||||
.LWAIT_HERE:
|
||||
jump .LWAIT_HERE;
|
||||
ENDPROC(_start)
|
||||
|
||||
@@ -236,19 +236,60 @@ static void decode_address(char *buf, unsigned long address)
|
||||
sprintf(buf, "<0x%p> /* unknown address */", address);
|
||||
}
|
||||
|
||||
static char *strhwerrcause(uint16_t hwerrcause)
|
||||
{
|
||||
switch (hwerrcause) {
|
||||
case 0x02: return "system mmr error";
|
||||
case 0x03: return "external memory addressing error";
|
||||
case 0x12: return "performance monitor overflow";
|
||||
case 0x18: return "raise 5 instruction";
|
||||
default: return "undef";
|
||||
}
|
||||
}
|
||||
|
||||
static char *strexcause(uint16_t excause)
|
||||
{
|
||||
switch (excause) {
|
||||
case 0x00 ... 0xf: return "custom exception";
|
||||
case 0x10: return "single step";
|
||||
case 0x11: return "trace buffer full";
|
||||
case 0x21: return "undef inst";
|
||||
case 0x22: return "illegal inst";
|
||||
case 0x23: return "dcplb prot violation";
|
||||
case 0x24: return "misaligned data";
|
||||
case 0x25: return "unrecoverable event";
|
||||
case 0x26: return "dcplb miss";
|
||||
case 0x27: return "multiple dcplb hit";
|
||||
case 0x28: return "emulation watchpoint";
|
||||
case 0x2a: return "misaligned inst";
|
||||
case 0x2b: return "icplb prot violation";
|
||||
case 0x2c: return "icplb miss";
|
||||
case 0x2d: return "multiple icplb hit";
|
||||
case 0x2e: return "illegal use of supervisor resource";
|
||||
default: return "undef";
|
||||
}
|
||||
}
|
||||
|
||||
void dump(struct pt_regs *fp)
|
||||
{
|
||||
char buf[150];
|
||||
size_t i;
|
||||
uint16_t hwerrcause, excause;
|
||||
|
||||
if (!ENABLE_DUMP)
|
||||
return;
|
||||
|
||||
/* fp->ipend is garbage, so load it ourself */
|
||||
fp->ipend = bfin_read_IPEND();
|
||||
|
||||
hwerrcause = (fp->seqstat & HWERRCAUSE) >> HWERRCAUSE_P;
|
||||
excause = (fp->seqstat & EXCAUSE) >> EXCAUSE_P;
|
||||
|
||||
printf("SEQUENCER STATUS:\n");
|
||||
printf(" SEQSTAT: %08lx IPEND: %04lx SYSCFG: %04lx\n",
|
||||
fp->seqstat, fp->ipend, fp->syscfg);
|
||||
printf(" HWERRCAUSE: 0x%lx\n", (fp->seqstat & HWERRCAUSE) >> HWERRCAUSE_P);
|
||||
printf(" EXCAUSE : 0x%lx\n", (fp->seqstat & EXCAUSE) >> EXCAUSE_P);
|
||||
printf(" HWERRCAUSE: 0x%lx: %s\n", hwerrcause, strhwerrcause(hwerrcause));
|
||||
printf(" EXCAUSE : 0x%lx: %s\n", excause, strexcause(excause));
|
||||
for (i = 6; i <= 15; ++i) {
|
||||
if (fp->ipend & (1 << i)) {
|
||||
decode_address(buf, bfin_read32(EVT0 + 4*i));
|
||||
@@ -263,8 +304,9 @@ void dump(struct pt_regs *fp)
|
||||
printf(" RETX: %s\n", buf);
|
||||
decode_address(buf, fp->rets);
|
||||
printf(" RETS: %s\n", buf);
|
||||
/* we lie and store RETI in "pc" */
|
||||
decode_address(buf, fp->pc);
|
||||
printf(" PC : %s\n", buf);
|
||||
printf(" RETI: %s\n", buf);
|
||||
|
||||
if (fp->seqstat & EXCAUSE) {
|
||||
decode_address(buf, bfin_read_DCPLB_FAULT_ADDR());
|
||||
@@ -344,10 +386,6 @@ void bfin_panic(struct pt_regs *regs)
|
||||
);
|
||||
dump(regs);
|
||||
dump_bfin_trace_buffer();
|
||||
printf(
|
||||
"\n"
|
||||
"Please reset the board\n"
|
||||
"\n"
|
||||
);
|
||||
puts("\n");
|
||||
bfin_reset_or_hang();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user