at v2.6.26-rc6 388 lines 9.5 kB view raw
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);