linux/arch/m68k/mac/debug.c
<<
>>
Prefs
   1/*
   2 * linux/arch/m68k/mac/debug.c
   3 *
   4 * Shamelessly stolen (SCC code and general framework) from:
   5 *
   6 * linux/arch/m68k/atari/debug.c
   7 *
   8 * Atari debugging and serial console stuff
   9 *
  10 * Assembled of parts of former atari/config.c 97-12-18 by Roman Hodek
  11 *
  12 * This file is subject to the terms and conditions of the GNU General Public
  13 * License.  See the file COPYING in the main directory of this archive
  14 * for more details.
  15 */
  16
  17#include <linux/types.h>
  18#include <linux/sched.h>
  19#include <linux/tty.h>
  20#include <linux/console.h>
  21#include <linux/init.h>
  22#include <linux/delay.h>
  23
  24#define BOOTINFO_COMPAT_1_0
  25#include <asm/setup.h>
  26#include <asm/bootinfo.h>
  27#include <asm/machw.h>
  28#include <asm/macints.h>
  29
  30extern unsigned long mac_videobase;
  31extern unsigned long mac_videodepth;
  32extern unsigned long mac_rowbytes;
  33
  34extern void mac_serial_print(const char *);
  35
  36#define DEBUG_HEADS
  37#undef DEBUG_SCREEN
  38#define DEBUG_SERIAL
  39
  40/*
  41 * These two auxiliary debug functions should go away ASAP. Only usage:
  42 * before the console output is up (after head.S come some other crucial
  43 * setup routines :-) it permits writing 'data' to the screen as bit patterns
  44 * (good luck reading those). Helped to figure that the bootinfo contained
  45 * garbage data on the amount and size of memory chunks ...
  46 *
  47 * The 'pos' argument now simply means 'linefeed after print' ...
  48 */
  49
  50#ifdef DEBUG_SCREEN
  51static int peng, line;
  52#endif
  53
  54void mac_debugging_short(int pos, short num)
  55{
  56#ifdef DEBUG_SCREEN
  57        unsigned char *pengoffset;
  58        unsigned char *pptr;
  59        int i;
  60#endif
  61
  62#ifdef DEBUG_SERIAL
  63        printk("debug: %d !\n", num);
  64#endif
  65
  66#ifdef DEBUG_SCREEN
  67        if (!MACH_IS_MAC) {
  68                /* printk("debug: %d !\n", num); */
  69                return;
  70        }
  71
  72        /* calculate current offset */
  73        pengoffset = (unsigned char *)mac_videobase +
  74                (150+line*2) * mac_rowbytes + 80 * peng;
  75
  76        pptr = pengoffset;
  77
  78        for (i = 0; i < 8 * sizeof(short); i++) { /* # of bits */
  79                /*        value        mask for bit i, reverse order */
  80                *pptr++ = (num & (1 << (8*sizeof(short)-i-1)) ? 0xFF : 0x00);
  81        }
  82
  83        peng++;
  84
  85        if (pos) {
  86                line++;
  87                peng = 0;
  88        }
  89#endif
  90}
  91
  92void mac_debugging_long(int pos, long addr)
  93{
  94#ifdef DEBUG_SCREEN
  95        unsigned char *pengoffset;
  96        unsigned char *pptr;
  97        int i;
  98#endif
  99
 100#ifdef DEBUG_SERIAL
 101        printk("debug: #%ld !\n", addr);
 102#endif
 103
 104#ifdef DEBUG_SCREEN
 105        if (!MACH_IS_MAC) {
 106                /* printk("debug: #%ld !\n", addr); */
 107                return;
 108        }
 109
 110        pengoffset=(unsigned char *)(mac_videobase+(150+line*2)*mac_rowbytes)
 111                    +80*peng;
 112
 113        pptr = pengoffset;
 114
 115        for (i = 0; i < 8 * sizeof(long); i++) { /* # of bits */
 116                *pptr++ = (addr & (1 << (8*sizeof(long)-i-1)) ? 0xFF : 0x00);
 117        }
 118
 119        peng++;
 120
 121        if (pos) {
 122                line++;
 123                peng = 0;
 124        }
 125#endif
 126}
 127
 128#ifdef DEBUG_SERIAL
 129/*
 130 * TODO: serial debug code
 131 */
 132
 133struct mac_SCC {
 134        u_char cha_b_ctrl;
 135        u_char char_dummy1;
 136        u_char cha_a_ctrl;
 137        u_char char_dummy2;
 138        u_char cha_b_data;
 139        u_char char_dummy3;
 140        u_char cha_a_data;
 141};
 142
 143# define scc (*((volatile struct mac_SCC*)mac_bi_data.sccbase))
 144
 145/* Flag that serial port is already initialized and used */
 146int mac_SCC_init_done;
 147/* Can be set somewhere, if a SCC master reset has already be done and should
 148 * not be repeated; used by kgdb */
 149int mac_SCC_reset_done;
 150
 151static int scc_port = -1;
 152
 153static struct console mac_console_driver = {
 154        .name   = "debug",
 155        .flags  = CON_PRINTBUFFER,
 156        .index  = -1,
 157};
 158
 159/*
 160 * Crude hack to get console output to the screen before the framebuffer
 161 * is initialized (happens a lot later in 2.1!).
 162 * We just use the console routines declared in head.S, this will interfere
 163 * with regular framebuffer console output and should be used exclusively
 164 * to debug kernel problems manifesting before framebuffer init (aka WSOD)
 165 *
 166 * To keep this hack from interfering with the regular console driver, either
 167 * deregister this driver before/on framebuffer console init, or silence this
 168 * function after the fbcon driver is running (will lose console messages!?).
 169 * To debug real early bugs, need to write a 'mac_register_console_hack()'
 170 * that is called from start_kernel() before setup_arch() and just registers
 171 * this driver if Mac.
 172 */
 173
 174void mac_debug_console_write(struct console *co, const char *str,
 175                             unsigned int count)
 176{
 177        mac_serial_print(str);
 178}
 179
 180
 181
 182/* Mac: loops_per_jiffy min. 19000 ^= .5 us; MFPDELAY was 0.6 us*/
 183
 184#define uSEC 1
 185
 186static inline void mac_sccb_out(char c)
 187{
 188        int i;
 189
 190        do {
 191                for (i = uSEC; i > 0; --i)
 192                        barrier();
 193        } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */
 194        for (i = uSEC; i > 0; --i)
 195                barrier();
 196        scc.cha_b_data = c;
 197}
 198
 199static inline void mac_scca_out(char c)
 200{
 201        int i;
 202
 203        do {
 204                for (i = uSEC; i > 0; --i)
 205                        barrier();
 206        } while (!(scc.cha_a_ctrl & 0x04)); /* wait for tx buf empty */
 207        for (i = uSEC; i > 0; --i)
 208                barrier();
 209        scc.cha_a_data = c;
 210}
 211
 212void mac_sccb_console_write(struct console *co, const char *str,
 213                            unsigned int count)
 214{
 215        while (count--) {
 216                if (*str == '\n')
 217                        mac_sccb_out('\r');
 218                mac_sccb_out(*str++);
 219        }
 220}
 221
 222void mac_scca_console_write(struct console *co, const char *str,
 223                            unsigned int count)
 224{
 225        while (count--) {
 226                if (*str == '\n')
 227                        mac_scca_out('\r');
 228                mac_scca_out(*str++);
 229        }
 230}
 231
 232
 233/* The following two functions do a quick'n'dirty initialization of the MFP or
 234 * SCC serial ports. They're used by the debugging interface, kgdb, and the
 235 * serial console code. */
 236#define SCCB_WRITE(reg,val)                             \
 237        do {                                            \
 238                int i;                                  \
 239                scc.cha_b_ctrl = (reg);                 \
 240                for (i = uSEC; i > 0; --i)              \
 241                        barrier();                      \
 242                scc.cha_b_ctrl = (val);                 \
 243                for (i = uSEC; i > 0; --i)              \
 244                        barrier();                      \
 245        } while(0)
 246
 247#define SCCA_WRITE(reg,val)                             \
 248        do {                                            \
 249                int i;                                  \
 250                scc.cha_a_ctrl = (reg);                 \
 251                for (i = uSEC; i > 0; --i)              \
 252                        barrier();                      \
 253                scc.cha_a_ctrl = (val);                 \
 254                for (i = uSEC; i > 0; --i)              \
 255                        barrier();                      \
 256        } while(0)
 257
 258/* loops_per_jiffy isn't initialized yet, so we can't use udelay(). This does a
 259 * delay of ~ 60us. */
 260/* Mac: loops_per_jiffy min. 19000 ^= .5 us; MFPDELAY was 0.6 us*/
 261#define LONG_DELAY()                                    \
 262        do {                                            \
 263                int i;                                  \
 264                for (i = 60*uSEC; i > 0; --i)           \
 265                    barrier();                          \
 266        } while(0)
 267
 268#ifndef CONFIG_SERIAL_CONSOLE
 269static void __init mac_init_scc_port(int cflag, int port)
 270#else
 271void mac_init_scc_port(int cflag, int port)
 272#endif
 273{
 274        extern int mac_SCC_reset_done;
 275
 276        /*
 277         * baud rates: 1200, 1800, 2400, 4800, 9600, 19.2k, 38.4k, 57.6k, 115.2k
 278         */
 279
 280        static int clksrc_table[9] =
 281                /* reg 11: 0x50 = BRG, 0x00 = RTxC, 0x28 = TRxC */
 282                { 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x00, 0x00 };
 283        static int clkmode_table[9] =
 284                /* reg 4: 0x40 = x16, 0x80 = x32, 0xc0 = x64 */
 285                { 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xc0, 0x80 };
 286        static int div_table[9] =
 287                /* reg12 (BRG low) */
 288                { 94, 62, 46, 22, 10, 4, 1, 0, 0 };
 289
 290        int baud = cflag & CBAUD;
 291        int clksrc, clkmode, div, reg3, reg5;
 292
 293        if (cflag & CBAUDEX)
 294                baud += B38400;
 295        if (baud < B1200 || baud > B38400+2)
 296                baud = B9600; /* use default 9600bps for non-implemented rates */
 297        baud -= B1200; /* tables starts at 1200bps */
 298
 299        clksrc  = clksrc_table[baud];
 300        clkmode = clkmode_table[baud];
 301        div     = div_table[baud];
 302
 303        reg3 = (((cflag & CSIZE) == CS8) ? 0xc0 : 0x40);
 304        reg5 = (((cflag & CSIZE) == CS8) ? 0x60 : 0x20) | 0x82 /* assert DTR/RTS */;
 305
 306        if (port == 1) {
 307                (void)scc.cha_b_ctrl;   /* reset reg pointer */
 308                SCCB_WRITE(9, 0xc0);    /* reset */
 309                LONG_DELAY();           /* extra delay after WR9 access */
 310                SCCB_WRITE(4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 |
 311                           0x04 /* 1 stopbit */ |
 312                           clkmode);
 313                SCCB_WRITE(3, reg3);
 314                SCCB_WRITE(5, reg5);
 315                SCCB_WRITE(9, 0);       /* no interrupts */
 316                LONG_DELAY();           /* extra delay after WR9 access */
 317                SCCB_WRITE(10, 0);      /* NRZ mode */
 318                SCCB_WRITE(11, clksrc); /* main clock source */
 319                SCCB_WRITE(12, div);    /* BRG value */
 320                SCCB_WRITE(13, 0);      /* BRG high byte */
 321                SCCB_WRITE(14, 1);
 322                SCCB_WRITE(3, reg3 | 1);
 323                SCCB_WRITE(5, reg5 | 8);
 324        } else if (port == 0) {
 325                (void)scc.cha_a_ctrl;   /* reset reg pointer */
 326                SCCA_WRITE(9, 0xc0);    /* reset */
 327                LONG_DELAY();           /* extra delay after WR9 access */
 328                SCCA_WRITE(4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 |
 329                          0x04 /* 1 stopbit */ |
 330                          clkmode);
 331                SCCA_WRITE(3, reg3);
 332                SCCA_WRITE(5, reg5);
 333                SCCA_WRITE(9, 0);       /* no interrupts */
 334                LONG_DELAY();           /* extra delay after WR9 access */
 335                SCCA_WRITE(10, 0);      /* NRZ mode */
 336                SCCA_WRITE(11, clksrc); /* main clock source */
 337                SCCA_WRITE(12, div);    /* BRG value */
 338                SCCA_WRITE(13, 0);      /* BRG high byte */
 339                SCCA_WRITE(14, 1);
 340                SCCA_WRITE(3, reg3 | 1);
 341                SCCA_WRITE(5, reg5 | 8);
 342        }
 343
 344        mac_SCC_reset_done = 1;
 345        mac_SCC_init_done = 1;
 346}
 347#endif /* DEBUG_SERIAL */
 348
 349void mac_init_scca_port(int cflag)
 350{
 351        mac_init_scc_port(cflag, 0);
 352}
 353
 354void mac_init_sccb_port(int cflag)
 355{
 356        mac_init_scc_port(cflag, 1);
 357}
 358
 359static int __init mac_debug_setup(char *arg)
 360{
 361        if (!MACH_IS_MAC)
 362                return 0;
 363
 364#ifdef DEBUG_SERIAL
 365        if (!strcmp(arg, "ser") || !strcmp(arg, "ser1")) {
 366                /* Mac modem port */
 367                mac_init_scc_port(B9600|CS8, 0);
 368                mac_console_driver.write = mac_scca_console_write;
 369                scc_port = 0;
 370        } else if (!strcmp(arg, "ser2")) {
 371                /* Mac printer port */
 372                mac_init_scc_port(B9600|CS8, 1);
 373                mac_console_driver.write = mac_sccb_console_write;
 374                scc_port = 1;
 375        }
 376#endif
 377#ifdef DEBUG_HEADS
 378        if (!strcmp(arg, "scn") || !strcmp(arg, "con")) {
 379                /* display, using head.S console routines */
 380                mac_console_driver.write = mac_debug_console_write;
 381        }
 382#endif
 383        if (mac_console_driver.write)
 384                register_console(&mac_console_driver);
 385        return 0;
 386}
 387
 388early_param("debug", mac_debug_setup);
 389