uboot/arch/blackfin/cpu/jtag-console.c
<<
>>
Prefs
   1/*
   2 * jtag-console.c - console driver over Blackfin JTAG
   3 *
   4 * Copyright (c) 2008-2010 Analog Devices Inc.
   5 *
   6 * Licensed under the GPL-2 or later.
   7 */
   8
   9#include <common.h>
  10#include <malloc.h>
  11#include <stdio_dev.h>
  12#include <asm/blackfin.h>
  13
  14#ifdef DEBUG
  15# define dprintf(...) serial_printf(__VA_ARGS__)
  16#else
  17# define dprintf(...) do { if (0) printf(__VA_ARGS__); } while (0)
  18#endif
  19
  20static inline void dprintf_decode(const char *s, uint32_t len)
  21{
  22        uint32_t i;
  23        for (i = 0; i < len; ++i)
  24                if (s[i] < 0x20 || s[i] >= 0x7f)
  25                        dprintf("\\%o", s[i]);
  26                else
  27                        dprintf("%c", s[i]);
  28}
  29
  30static inline uint32_t bfin_write_emudat(uint32_t emudat)
  31{
  32        __asm__ __volatile__("emudat = %0;" : : "d"(emudat));
  33        return emudat;
  34}
  35
  36static inline uint32_t bfin_read_emudat(void)
  37{
  38        uint32_t emudat;
  39        __asm__ __volatile__("%0 = emudat;" : "=d"(emudat));
  40        return emudat;
  41}
  42
  43#ifndef CONFIG_JTAG_CONSOLE_TIMEOUT
  44# define CONFIG_JTAG_CONSOLE_TIMEOUT 500
  45#endif
  46
  47/* The Blackfin tends to be much much faster than the JTAG hardware. */
  48static bool jtag_write_emudat(uint32_t emudat)
  49{
  50        static bool overflowed = false;
  51        ulong timeout = get_timer(0) + CONFIG_JTAG_CONSOLE_TIMEOUT;
  52        while (bfin_read_DBGSTAT() & 0x1) {
  53                if (overflowed)
  54                        return overflowed;
  55                if (timeout < get_timer(0))
  56                        overflowed = true;
  57        }
  58        overflowed = false;
  59        bfin_write_emudat(emudat);
  60        return overflowed;
  61}
  62/* Transmit a buffer.  The format is:
  63 * [32bit length][actual data]
  64 */
  65static void jtag_send(const char *raw_str, uint32_t len)
  66{
  67        const char *cooked_str;
  68        uint32_t i, ex;
  69
  70        if (len == 0)
  71                return;
  72
  73        /* Ugh, need to output \r after \n */
  74        ex = 0;
  75        for (i = 0; i < len; ++i)
  76                if (raw_str[i] == '\n')
  77                        ++ex;
  78        if (ex) {
  79                char *c = malloc(len + ex);
  80                cooked_str = c;
  81                for (i = 0; i < len; ++i) {
  82                        *c++ = raw_str[i];
  83                        if (raw_str[i] == '\n')
  84                                *c++ = '\r';
  85                }
  86                len += ex;
  87        } else
  88                cooked_str = raw_str;
  89
  90        dprintf("%s(\"", __func__);
  91        dprintf_decode(cooked_str, len);
  92        dprintf("\", %i)\n", len);
  93
  94        /* First send the length */
  95        if (jtag_write_emudat(len))
  96                goto done;
  97
  98        /* Then send the data */
  99        for (i = 0; i < len; i += 4) {
 100                uint32_t emudat =
 101                        (cooked_str[i + 0] <<  0) |
 102                        (cooked_str[i + 1] <<  8) |
 103                        (cooked_str[i + 2] << 16) |
 104                        (cooked_str[i + 3] << 24);
 105                if (jtag_write_emudat(emudat)) {
 106                        bfin_write_emudat(0);
 107                        goto done;
 108                }
 109        }
 110
 111 done:
 112        if (cooked_str != raw_str)
 113                free((char *)cooked_str);
 114}
 115static void jtag_putc(const char c)
 116{
 117        jtag_send(&c, 1);
 118}
 119static void jtag_puts(const char *s)
 120{
 121        jtag_send(s, strlen(s));
 122}
 123
 124static size_t inbound_len, leftovers_len;
 125
 126/* Lower layers want to know when jtag has data */
 127static int jtag_tstc_dbg(void)
 128{
 129        int ret = (bfin_read_DBGSTAT() & 0x2);
 130        if (ret)
 131                dprintf("%s: ret:%i\n", __func__, ret);
 132        return ret;
 133}
 134
 135/* Higher layers want to know when any data is available */
 136static int jtag_tstc(void)
 137{
 138        return jtag_tstc_dbg() || leftovers_len;
 139}
 140
 141/* Receive a buffer.  The format is:
 142 * [32bit length][actual data]
 143 */
 144static uint32_t leftovers;
 145static int jtag_getc(void)
 146{
 147        int ret;
 148        uint32_t emudat;
 149
 150        dprintf("%s: inlen:%zu leftlen:%zu left:%x\n", __func__,
 151                inbound_len, leftovers_len, leftovers);
 152
 153        /* see if any data is left over */
 154        if (leftovers_len) {
 155                --leftovers_len;
 156                ret = leftovers & 0xff;
 157                leftovers >>= 8;
 158                return ret;
 159        }
 160
 161        /* wait for new data ! */
 162        while (!jtag_tstc_dbg())
 163                continue;
 164        emudat = bfin_read_emudat();
 165
 166        if (inbound_len == 0) {
 167                /* grab the length */
 168                inbound_len = emudat;
 169        } else {
 170                /* store the bytes */
 171                leftovers_len = min(4, inbound_len);
 172                inbound_len -= leftovers_len;
 173                leftovers = emudat;
 174        }
 175
 176        return jtag_getc();
 177}
 178
 179int drv_jtag_console_init(void)
 180{
 181        struct stdio_dev dev;
 182        int ret;
 183
 184        memset(&dev, 0x00, sizeof(dev));
 185        strcpy(dev.name, "jtag");
 186        dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
 187        dev.putc = jtag_putc;
 188        dev.puts = jtag_puts;
 189        dev.tstc = jtag_tstc;
 190        dev.getc = jtag_getc;
 191
 192        ret = stdio_register(&dev);
 193        return (ret == 0 ? 1 : ret);
 194}
 195
 196#ifdef CONFIG_UART_CONSOLE_IS_JTAG
 197/* Since the JTAG is always available (at power on), allow it to fake a UART */
 198void serial_set_baud(uint32_t baud) {}
 199void serial_setbrg(void)            {}
 200int serial_init(void)               { return 0; }
 201void serial_putc(const char c)      __attribute__((alias("jtag_putc")));
 202void serial_puts(const char *s)     __attribute__((alias("jtag_puts")));
 203int serial_tstc(void)               __attribute__((alias("jtag_tstc")));
 204int serial_getc(void)               __attribute__((alias("jtag_getc")));
 205#endif
 206