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 = 0; 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 = 0; 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/* 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 */ 398