The Blackfin JTAG has the ability to pass data via a back-channel without halting the processor. Utilize that channel to emulate a console. Signed-off-by: Mike Frysinger <vapier@gentoo.org>master
parent
cf8f2efb5f
commit
36ea8e9ad1
@ -0,0 +1,125 @@ |
||||
/*
|
||||
* jtag-console.c - console driver over Blackfin JTAG |
||||
* |
||||
* Copyright (c) 2008 Analog Devices Inc. |
||||
* |
||||
* Licensed under the GPL-2 or later. |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <devices.h> |
||||
#include <asm/blackfin.h> |
||||
|
||||
#ifndef CONFIG_JTAG_CONSOLE_TIMEOUT |
||||
# define CONFIG_JTAG_CONSOLE_TIMEOUT 100 |
||||
#endif |
||||
|
||||
/* The Blackfin tends to be much much faster than the JTAG hardware. */ |
||||
static void jtag_write_emudat(uint32_t emudat) |
||||
{ |
||||
static bool overflowed = false; |
||||
ulong timeout = get_timer(0) + CONFIG_JTAG_CONSOLE_TIMEOUT; |
||||
while (bfin_read_DBGSTAT() & 0x1) { |
||||
if (overflowed) |
||||
return; |
||||
if (timeout < get_timer(0)) |
||||
overflowed = true; |
||||
} |
||||
overflowed = false; |
||||
__asm__ __volatile__("emudat = %0;" : : "d"(emudat)); |
||||
} |
||||
/* Transmit a buffer. The format is:
|
||||
* [32bit length][actual data] |
||||
*/ |
||||
static void jtag_send(const char *c, uint32_t len) |
||||
{ |
||||
uint32_t i; |
||||
|
||||
if (len == 0) |
||||
return; |
||||
|
||||
/* First send the length */ |
||||
jtag_write_emudat(len); |
||||
|
||||
/* Then send the data */ |
||||
for (i = 0; i < len; i += 4) |
||||
jtag_write_emudat((c[i] << 0) | (c[i+1] << 8) | (c[i+2] << 16) | (c[i+3] << 24)); |
||||
} |
||||
static void jtag_putc(const char c) |
||||
{ |
||||
jtag_send(&c, 1); |
||||
} |
||||
static void jtag_puts(const char *s) |
||||
{ |
||||
jtag_send(s, strlen(s)); |
||||
} |
||||
|
||||
static int jtag_tstc(void) |
||||
{ |
||||
return (bfin_read_DBGSTAT() & 0x2); |
||||
} |
||||
|
||||
/* Receive a buffer. The format is:
|
||||
* [32bit length][actual data] |
||||
*/ |
||||
static size_t inbound_len; |
||||
static int leftovers_len; |
||||
static uint32_t leftovers; |
||||
static int jtag_getc(void) |
||||
{ |
||||
int ret; |
||||
uint32_t emudat; |
||||
|
||||
/* see if any data is left over */ |
||||
if (leftovers_len) { |
||||
--leftovers_len; |
||||
ret = leftovers & 0xff; |
||||
leftovers >>= 8; |
||||
return ret; |
||||
} |
||||
|
||||
/* wait for new data ! */ |
||||
while (!jtag_tstc()) |
||||
continue; |
||||
__asm__("%0 = emudat;" : "=d"(emudat)); |
||||
|
||||
if (inbound_len == 0) { |
||||
/* grab the length */ |
||||
inbound_len = emudat; |
||||
} else { |
||||
/* store the bytes */ |
||||
leftovers_len = min(4, inbound_len); |
||||
inbound_len -= leftovers_len; |
||||
leftovers = emudat; |
||||
} |
||||
|
||||
return jtag_getc(); |
||||
} |
||||
|
||||
int drv_jtag_console_init(void) |
||||
{ |
||||
device_t dev; |
||||
int ret; |
||||
|
||||
memset(&dev, 0x00, sizeof(dev)); |
||||
strcpy(dev.name, "jtag"); |
||||
dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM; |
||||
dev.putc = jtag_putc; |
||||
dev.puts = jtag_puts; |
||||
dev.tstc = jtag_tstc; |
||||
dev.getc = jtag_getc; |
||||
|
||||
ret = device_register(&dev); |
||||
return (ret == 0 ? 1 : ret); |
||||
} |
||||
|
||||
#ifdef CONFIG_UART_CONSOLE_IS_JTAG |
||||
/* Since the JTAG is always available (at power on), allow it to fake a UART */ |
||||
void serial_set_baud(uint32_t baud) {} |
||||
void serial_setbrg(void) {} |
||||
int serial_init(void) { return 0; } |
||||
void serial_putc(const char c) __attribute__((alias("jtag_putc"))); |
||||
void serial_puts(const char *s) __attribute__((alias("jtag_puts"))); |
||||
int serial_tstc(void) __attribute__((alias("jtag_tstc"))); |
||||
int serial_getc(void) __attribute__((alias("jtag_getc"))); |
||||
#endif |
Loading…
Reference in new issue