Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / u-boot / arch / blackfin / cpu / jtag-console.c
diff --git a/qemu/roms/u-boot/arch/blackfin/cpu/jtag-console.c b/qemu/roms/u-boot/arch/blackfin/cpu/jtag-console.c
new file mode 100644 (file)
index 0000000..7cddb85
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * jtag-console.c - console driver over Blackfin JTAG
+ *
+ * Copyright (c) 2008-2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <stdio_dev.h>
+#include <asm/blackfin.h>
+
+#ifdef DEBUG
+# define dprintf(...) serial_printf(__VA_ARGS__)
+#else
+# define dprintf(...) do { if (0) printf(__VA_ARGS__); } while (0)
+#endif
+
+static inline void dprintf_decode(const char *s, uint32_t len)
+{
+       uint32_t i;
+       for (i = 0; i < len; ++i)
+               if (s[i] < 0x20 || s[i] >= 0x7f)
+                       dprintf("\\%o", s[i]);
+               else
+                       dprintf("%c", s[i]);
+}
+
+static inline uint32_t bfin_write_emudat(uint32_t emudat)
+{
+       __asm__ __volatile__("emudat = %0;" : : "d"(emudat));
+       return emudat;
+}
+
+static inline uint32_t bfin_read_emudat(void)
+{
+       uint32_t emudat;
+       __asm__ __volatile__("%0 = emudat;" : "=d"(emudat));
+       return emudat;
+}
+
+#ifndef CONFIG_JTAG_CONSOLE_TIMEOUT
+# define CONFIG_JTAG_CONSOLE_TIMEOUT 500
+#endif
+
+/* The Blackfin tends to be much much faster than the JTAG hardware. */
+static bool jtag_write_emudat(uint32_t emudat)
+{
+       static bool overflowed = false;
+       ulong timeout = get_timer(0);
+       while (bfin_read_DBGSTAT() & 0x1) {
+               if (overflowed)
+                       return overflowed;
+               if (get_timer(timeout) > CONFIG_JTAG_CONSOLE_TIMEOUT)
+                       overflowed = true;
+       }
+       overflowed = false;
+       bfin_write_emudat(emudat);
+       return overflowed;
+}
+/* Transmit a buffer.  The format is:
+ * [32bit length][actual data]
+ */
+static void jtag_send(const char *raw_str, uint32_t len)
+{
+       const char *cooked_str;
+       uint32_t i, ex;
+
+       if (len == 0)
+               return;
+
+       /* Ugh, need to output \r after \n */
+       ex = 0;
+       for (i = 0; i < len; ++i)
+               if (raw_str[i] == '\n')
+                       ++ex;
+       if (ex) {
+               char *c = malloc(len + ex);
+               cooked_str = c;
+               for (i = 0; i < len; ++i) {
+                       *c++ = raw_str[i];
+                       if (raw_str[i] == '\n')
+                               *c++ = '\r';
+               }
+               len += ex;
+       } else
+               cooked_str = raw_str;
+
+       dprintf("%s(\"", __func__);
+       dprintf_decode(cooked_str, len);
+       dprintf("\", %i)\n", len);
+
+       /* First send the length */
+       if (jtag_write_emudat(len))
+               goto done;
+
+       /* Then send the data */
+       for (i = 0; i < len; i += 4) {
+               uint32_t emudat =
+                       (cooked_str[i + 0] <<  0) |
+                       (cooked_str[i + 1] <<  8) |
+                       (cooked_str[i + 2] << 16) |
+                       (cooked_str[i + 3] << 24);
+               if (jtag_write_emudat(emudat)) {
+                       bfin_write_emudat(0);
+                       goto done;
+               }
+       }
+
+ done:
+       if (cooked_str != raw_str)
+               free((char *)cooked_str);
+}
+static void jtag_putc(const char c)
+{
+       jtag_send(&c, 1);
+}
+static void jtag_puts(const char *s)
+{
+       jtag_send(s, strlen(s));
+}
+
+static size_t inbound_len, leftovers_len;
+
+/* Lower layers want to know when jtag has data */
+static int jtag_tstc_dbg(void)
+{
+       int ret = (bfin_read_DBGSTAT() & 0x2);
+       if (ret)
+               dprintf("%s: ret:%i\n", __func__, ret);
+       return ret;
+}
+
+/* Higher layers want to know when any data is available */
+static int jtag_tstc(void)
+{
+       return jtag_tstc_dbg() || leftovers_len;
+}
+
+/* Receive a buffer.  The format is:
+ * [32bit length][actual data]
+ */
+static uint32_t leftovers;
+static int jtag_getc(void)
+{
+       int ret;
+       uint32_t emudat;
+
+       dprintf("%s: inlen:%zu leftlen:%zu left:%x\n", __func__,
+               inbound_len, leftovers_len, leftovers);
+
+       /* 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_dbg())
+               continue;
+       emudat = bfin_read_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)
+{
+       struct stdio_dev 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 = stdio_register(&dev);
+       return (ret == 0 ? 1 : ret);
+}
+
+#ifdef CONFIG_UART_CONSOLE_IS_JTAG
+#include <serial.h>
+/* Since the JTAG is always available (at power on), allow it to fake a UART */
+void jtag_serial_setbrg(void)
+{
+}
+
+int jtag_serial_init(void)
+{
+       return 0;
+}
+
+static struct serial_device serial_jtag_drv = {
+       .name   = "jtag",
+       .start  = jtag_serial_init,
+       .stop   = NULL,
+       .setbrg = jtag_serial_setbrg,
+       .putc   = jtag_putc,
+       .puts   = jtag_puts,
+       .tstc   = jtag_tstc,
+       .getc   = jtag_getc,
+};
+
+void bfin_jtag_initialize(void)
+{
+       serial_register(&serial_jtag_drv);
+}
+
+struct serial_device *default_serial_console(void)
+{
+       return &serial_jtag_drv;
+}
+#endif