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