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