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