linux/arch/mn10300/kernel/gdb-io-ttysm.c
<<
>>
Prefs
   1/* MN10300 On-chip serial driver for gdbstub I/O
   2 *
   3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
   4 * Written by David Howells (dhowells@redhat.com)
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public Licence
   8 * as published by the Free Software Foundation; either version
   9 * 2 of the Licence, or (at your option) any later version.
  10 */
  11#include <linux/string.h>
  12#include <linux/kernel.h>
  13#include <linux/signal.h>
  14#include <linux/sched.h>
  15#include <linux/mm.h>
  16#include <linux/console.h>
  17#include <linux/init.h>
  18#include <linux/tty.h>
  19#include <asm/pgtable.h>
  20#include <asm/gdb-stub.h>
  21#include <asm/exceptions.h>
  22#include <unit/clock.h>
  23#include "mn10300-serial.h"
  24
  25#if defined(CONFIG_GDBSTUB_ON_TTYSM0)
  26struct mn10300_serial_port *const gdbstub_port = &mn10300_serial_port_sif0;
  27#elif defined(CONFIG_GDBSTUB_ON_TTYSM1)
  28struct mn10300_serial_port *const gdbstub_port = &mn10300_serial_port_sif1;
  29#else
  30struct mn10300_serial_port *const gdbstub_port = &mn10300_serial_port_sif2;
  31#endif
  32
  33
  34/*
  35 * initialise the GDB stub I/O routines
  36 */
  37void __init gdbstub_io_init(void)
  38{
  39        uint16_t scxctr;
  40        int tmp;
  41
  42        switch (gdbstub_port->clock_src) {
  43        case MNSCx_CLOCK_SRC_IOCLK:
  44                gdbstub_port->ioclk = MN10300_IOCLK;
  45                break;
  46
  47#ifdef MN10300_IOBCLK
  48        case MNSCx_CLOCK_SRC_IOBCLK:
  49                gdbstub_port->ioclk = MN10300_IOBCLK;
  50                break;
  51#endif
  52        default:
  53                BUG();
  54        }
  55
  56        /* set up the serial port */
  57        gdbstub_io_set_baud(115200);
  58
  59        /* we want to get serial receive interrupts */
  60        set_intr_level(gdbstub_port->rx_irq,
  61                NUM2GxICR_LEVEL(CONFIG_DEBUGGER_IRQ_LEVEL));
  62        set_intr_level(gdbstub_port->tx_irq,
  63                NUM2GxICR_LEVEL(CONFIG_DEBUGGER_IRQ_LEVEL));
  64        set_intr_stub(NUM2EXCEP_IRQ_LEVEL(CONFIG_DEBUGGER_IRQ_LEVEL),
  65                gdbstub_io_rx_handler);
  66
  67        *gdbstub_port->rx_icr |= GxICR_ENABLE;
  68        tmp = *gdbstub_port->rx_icr;
  69
  70        /* enable the device */
  71        scxctr = SC01CTR_CLN_8BIT;      /* 1N8 */
  72        switch (gdbstub_port->div_timer) {
  73        case MNSCx_DIV_TIMER_16BIT:
  74                scxctr |= SC0CTR_CK_TM8UFLOW_8; /* == SC1CTR_CK_TM9UFLOW_8
  75                                                   == SC2CTR_CK_TM10UFLOW_8 */
  76                break;
  77
  78        case MNSCx_DIV_TIMER_8BIT:
  79                scxctr |= SC0CTR_CK_TM2UFLOW_8;
  80                break;
  81        }
  82
  83        scxctr |= SC01CTR_TXE | SC01CTR_RXE;
  84
  85        *gdbstub_port->_control = scxctr;
  86        tmp = *gdbstub_port->_control;
  87
  88        /* permit level 0 IRQs only */
  89        arch_local_change_intr_mask_level(
  90                NUM2EPSW_IM(CONFIG_DEBUGGER_IRQ_LEVEL + 1));
  91}
  92
  93/*
  94 * set up the GDB stub serial port baud rate timers
  95 */
  96void gdbstub_io_set_baud(unsigned baud)
  97{
  98        const unsigned bits = 10; /* 1 [start] + 8 [data] + 0 [parity] +
  99                                   * 1 [stop] */
 100        unsigned long ioclk = gdbstub_port->ioclk;
 101        unsigned xdiv, tmp;
 102        uint16_t tmxbr;
 103        uint8_t tmxmd;
 104
 105        if (!baud) {
 106                baud = 9600;
 107        } else if (baud == 134) {
 108                baud = 269;     /* 134 is really 134.5 */
 109                xdiv = 2;
 110        }
 111
 112try_alternative:
 113        xdiv = 1;
 114
 115        switch (gdbstub_port->div_timer) {
 116        case MNSCx_DIV_TIMER_16BIT:
 117                tmxmd = TM8MD_SRC_IOCLK;
 118                tmxbr = tmp = (ioclk / (baud * xdiv) + 4) / 8 - 1;
 119                if (tmp > 0 && tmp <= 65535)
 120                        goto timer_okay;
 121
 122                tmxmd = TM8MD_SRC_IOCLK_8;
 123                tmxbr = tmp = (ioclk / (baud * 8 * xdiv) + 4) / 8 - 1;
 124                if (tmp > 0 && tmp <= 65535)
 125                        goto timer_okay;
 126
 127                tmxmd = TM8MD_SRC_IOCLK_32;
 128                tmxbr = tmp = (ioclk / (baud * 32 * xdiv) + 4) / 8 - 1;
 129                if (tmp > 0 && tmp <= 65535)
 130                        goto timer_okay;
 131
 132                break;
 133
 134        case MNSCx_DIV_TIMER_8BIT:
 135                tmxmd = TM2MD_SRC_IOCLK;
 136                tmxbr = tmp = (ioclk / (baud * xdiv) + 4) / 8 - 1;
 137                if (tmp > 0 && tmp <= 255)
 138                        goto timer_okay;
 139
 140                tmxmd = TM2MD_SRC_IOCLK_8;
 141                tmxbr = tmp = (ioclk / (baud * 8 * xdiv) + 4) / 8 - 1;
 142                if (tmp > 0 && tmp <= 255)
 143                        goto timer_okay;
 144
 145                tmxmd = TM2MD_SRC_IOCLK_32;
 146                tmxbr = tmp = (ioclk / (baud * 32 * xdiv) + 4) / 8 - 1;
 147                if (tmp > 0 && tmp <= 255)
 148                        goto timer_okay;
 149                break;
 150        }
 151
 152        /* as a last resort, if the quotient is zero, default to 9600 bps */
 153        baud = 9600;
 154        goto try_alternative;
 155
 156timer_okay:
 157        gdbstub_port->uart.timeout = (2 * bits * HZ) / baud;
 158        gdbstub_port->uart.timeout += HZ / 50;
 159
 160        /* set the timer to produce the required baud rate */
 161        switch (gdbstub_port->div_timer) {
 162        case MNSCx_DIV_TIMER_16BIT:
 163                *gdbstub_port->_tmxmd = 0;
 164                *gdbstub_port->_tmxbr = tmxbr;
 165                *gdbstub_port->_tmxmd = TM8MD_INIT_COUNTER;
 166                *gdbstub_port->_tmxmd = tmxmd | TM8MD_COUNT_ENABLE;
 167                break;
 168
 169        case MNSCx_DIV_TIMER_8BIT:
 170                *gdbstub_port->_tmxmd = 0;
 171                *(volatile u8 *) gdbstub_port->_tmxbr = (u8)tmxbr;
 172                *gdbstub_port->_tmxmd = TM2MD_INIT_COUNTER;
 173                *gdbstub_port->_tmxmd = tmxmd | TM2MD_COUNT_ENABLE;
 174                break;
 175        }
 176}
 177
 178/*
 179 * wait for a character to come from the debugger
 180 */
 181int gdbstub_io_rx_char(unsigned char *_ch, int nonblock)
 182{
 183        unsigned ix;
 184        u8 ch, st;
 185#if defined(CONFIG_MN10300_WD_TIMER)
 186        int cpu;
 187#endif
 188
 189        *_ch = 0xff;
 190
 191        if (gdbstub_rx_unget) {
 192                *_ch = gdbstub_rx_unget;
 193                gdbstub_rx_unget = 0;
 194                return 0;
 195        }
 196
 197try_again:
 198        /* pull chars out of the buffer */
 199        ix = gdbstub_rx_outp;
 200        barrier();
 201        if (ix == gdbstub_rx_inp) {
 202                if (nonblock)
 203                        return -EAGAIN;
 204#ifdef CONFIG_MN10300_WD_TIMER
 205        for (cpu = 0; cpu < NR_CPUS; cpu++)
 206                watchdog_alert_counter[cpu] = 0;
 207#endif
 208                goto try_again;
 209        }
 210
 211        ch = gdbstub_rx_buffer[ix++];
 212        st = gdbstub_rx_buffer[ix++];
 213        barrier();
 214        gdbstub_rx_outp = ix & (PAGE_SIZE - 1);
 215
 216        st &= SC01STR_RXF | SC01STR_RBF | SC01STR_FEF | SC01STR_PEF |
 217                SC01STR_OEF;
 218
 219        /* deal with what we've got
 220         * - note that the UART doesn't do BREAK-detection for us
 221         */
 222        if (st & SC01STR_FEF && ch == 0) {
 223                switch (gdbstub_port->rx_brk) {
 224                case 0: gdbstub_port->rx_brk = 1;       goto try_again;
 225                case 1: gdbstub_port->rx_brk = 2;       goto try_again;
 226                case 2:
 227                        gdbstub_port->rx_brk = 3;
 228                        gdbstub_proto("### GDB MNSERIAL Rx Break Detected"
 229                                      " ###\n");
 230                        return -EINTR;
 231                default:
 232                        goto try_again;
 233                }
 234        } else if (st & SC01STR_FEF) {
 235                if (gdbstub_port->rx_brk)
 236                        goto try_again;
 237
 238                gdbstub_proto("### GDB MNSERIAL Framing Error ###\n");
 239                return -EIO;
 240        } else if (st & SC01STR_OEF) {
 241                if (gdbstub_port->rx_brk)
 242                        goto try_again;
 243
 244                gdbstub_proto("### GDB MNSERIAL Overrun Error ###\n");
 245                return -EIO;
 246        } else if (st & SC01STR_PEF) {
 247                if (gdbstub_port->rx_brk)
 248                        goto try_again;
 249
 250                gdbstub_proto("### GDB MNSERIAL Parity Error ###\n");
 251                return -EIO;
 252        } else {
 253                /* look for the tail-end char on a break run */
 254                if (gdbstub_port->rx_brk == 3) {
 255                        switch (ch) {
 256                        case 0xFF:
 257                        case 0xFE:
 258                        case 0xFC:
 259                        case 0xF8:
 260                        case 0xF0:
 261                        case 0xE0:
 262                        case 0xC0:
 263                        case 0x80:
 264                        case 0x00:
 265                                gdbstub_port->rx_brk = 0;
 266                                goto try_again;
 267                        default:
 268                                break;
 269                        }
 270                }
 271
 272                gdbstub_port->rx_brk = 0;
 273                gdbstub_io("### GDB Rx %02x (st=%02x) ###\n", ch, st);
 274                *_ch = ch & 0x7f;
 275                return 0;
 276        }
 277}
 278
 279/*
 280 * send a character to the debugger
 281 */
 282void gdbstub_io_tx_char(unsigned char ch)
 283{
 284        while (*gdbstub_port->_status & SC01STR_TBF)
 285                continue;
 286
 287        if (ch == 0x0a) {
 288                *(u8 *) gdbstub_port->_txb = 0x0d;
 289                while (*gdbstub_port->_status & SC01STR_TBF)
 290                        continue;
 291        }
 292
 293        *(u8 *) gdbstub_port->_txb = ch;
 294}
 295
 296/*
 297 * flush the transmission buffers
 298 */
 299void gdbstub_io_tx_flush(void)
 300{
 301        while (*gdbstub_port->_status & (SC01STR_TBF | SC01STR_TXF))
 302                continue;
 303}
 304