patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / arch / m68k / mac / debug.c
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
31 extern char m68k_debug_device[];
32
33 extern struct compat_bootinfo compat_boot_info;
34
35 extern unsigned long mac_videobase;
36 extern unsigned long mac_videodepth;
37 extern unsigned long mac_rowbytes;
38
39 extern 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
56 static int peng=0, line=0;
57 #endif
58
59 void 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
98 void 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
140 struct 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 */
154 int 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 */
157 int mac_SCC_reset_done;
158
159 static int scc_port = -1;
160
161 static 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
182 void 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
194 static 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
206 static 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
218 void 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
228 void 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
275 static void __init mac_init_scc_port( int cflag, int port )
276 #else
277 void 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
355 void mac_init_scca_port( int cflag )
356 {
357         mac_init_scc_port(cflag, 0);
358 }
359
360 void mac_init_sccb_port( int cflag )
361 {
362         mac_init_scc_port(cflag, 1);
363 }
364
365 void __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  */