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