1/*
2 * Copyright (C) 2003, Axis Communications AB.
3 */
4
5#include <linux/console.h>
6#include <linux/init.h>
7#include <linux/major.h>
8#include <linux/delay.h>
9#include <linux/tty.h>
10#include <asm/system.h>
11#include <asm/io.h>
12#include <asm/arch/hwregs/ser_defs.h>
13#include <asm/arch/hwregs/dma_defs.h>
14#include <asm/arch/pinmux.h>
15
16#include <asm/irq.h>
17#include <asm/arch/hwregs/intr_vect_defs.h>
18
19struct dbg_port
20{
21	unsigned char nbr;
22	unsigned long instance;
23	unsigned int started;
24	unsigned long baudrate;
25	unsigned char parity;
26	unsigned int bits;
27};
28
29struct dbg_port ports[] =
30{
31  {
32    0,
33    regi_ser0,
34    0,
35    115200,
36    'N',
37    8
38  },
39  {
40    1,
41    regi_ser1,
42    0,
43    115200,
44    'N',
45    8
46  },
47  {
48    2,
49    regi_ser2,
50    0,
51    115200,
52    'N',
53    8
54  },
55  {
56    3,
57    regi_ser3,
58    0,
59    115200,
60    'N',
61    8
62  }
63};
64static struct dbg_port *port =
65#if defined(CONFIG_ETRAX_DEBUG_PORT0)
66&ports[0];
67#elif defined(CONFIG_ETRAX_DEBUG_PORT1)
68&ports[1];
69#elif defined(CONFIG_ETRAX_DEBUG_PORT2)
70&ports[2];
71#elif defined(CONFIG_ETRAX_DEBUG_PORT3)
72&ports[3];
73#else
74NULL;
75#endif
76
77#ifdef CONFIG_ETRAX_KGDB
78static struct dbg_port *kgdb_port =
79#if defined(CONFIG_ETRAX_KGDB_PORT0)
80&ports[0];
81#elif defined(CONFIG_ETRAX_KGDB_PORT1)
82&ports[1];
83#elif defined(CONFIG_ETRAX_KGDB_PORT2)
84&ports[2];
85#elif defined(CONFIG_ETRAX_KGDB_PORT3)
86&ports[3];
87#else
88NULL;
89#endif
90#endif
91
92#ifdef CONFIG_ETRAXFS_SIM
93extern void print_str( const char *str );
94static char buffer[1024];
95static char msg[] = "Debug: ";
96static int buffer_pos = sizeof(msg) - 1;
97#endif
98
99extern struct tty_driver *serial_driver;
100
101static void
102start_port(struct dbg_port* p)
103{
104	if (!p)
105		return;
106
107	if (p->started)
108		return;
109	p->started = 1;
110
111	if (p->nbr == 1)
112		crisv32_pinmux_alloc_fixed(pinmux_ser1);
113	else if (p->nbr == 2)
114		crisv32_pinmux_alloc_fixed(pinmux_ser2);
115	else if (p->nbr == 3)
116		crisv32_pinmux_alloc_fixed(pinmux_ser3);
117
118	/* Set up serial port registers */
119	reg_ser_rw_tr_ctrl tr_ctrl = {0};
120	reg_ser_rw_tr_dma_en tr_dma_en = {0};
121
122	reg_ser_rw_rec_ctrl rec_ctrl = {0};
123	reg_ser_rw_tr_baud_div tr_baud_div = {0};
124	reg_ser_rw_rec_baud_div rec_baud_div = {0};
125
126	tr_ctrl.base_freq = rec_ctrl.base_freq = regk_ser_f29_493;
127	tr_dma_en.en = rec_ctrl.dma_mode = regk_ser_no;
128	tr_baud_div.div = rec_baud_div.div = 29493000 / p->baudrate / 8;
129	tr_ctrl.en = rec_ctrl.en = 1;
130
131	if (p->parity == 'O')
132	{
133		tr_ctrl.par_en = regk_ser_yes;
134		tr_ctrl.par = regk_ser_odd;
135		rec_ctrl.par_en = regk_ser_yes;
136		rec_ctrl.par = regk_ser_odd;
137	}
138	else if (p->parity == 'E')
139	{
140		tr_ctrl.par_en = regk_ser_yes;
141		tr_ctrl.par = regk_ser_even;
142		rec_ctrl.par_en = regk_ser_yes;
143		rec_ctrl.par = regk_ser_odd;
144	}
145
146	if (p->bits == 7)
147	{
148		tr_ctrl.data_bits = regk_ser_bits7;
149		rec_ctrl.data_bits = regk_ser_bits7;
150	}
151
152	REG_WR (ser, p->instance, rw_tr_baud_div, tr_baud_div);
153	REG_WR (ser, p->instance, rw_rec_baud_div, rec_baud_div);
154	REG_WR (ser, p->instance, rw_tr_dma_en, tr_dma_en);
155	REG_WR (ser, p->instance, rw_tr_ctrl, tr_ctrl);
156	REG_WR (ser, p->instance, rw_rec_ctrl, rec_ctrl);
157}
158
159/* No debug */
160#ifdef CONFIG_ETRAX_DEBUG_PORT_NULL
161
162static void
163console_write(struct console *co, const char *buf, unsigned int len)
164{
165	return;
166}
167
168/* Target debug */
169#elif !defined(CONFIG_ETRAXFS_SIM)
170
171static void
172console_write_direct(struct console *co, const char *buf, unsigned int len)
173{
174	int i;
175	reg_ser_r_stat_din stat;
176	reg_ser_rw_tr_dma_en tr_dma_en, old;
177
178	/* Switch to manual mode */
179	tr_dma_en = old = REG_RD (ser, port->instance, rw_tr_dma_en);
180	if (tr_dma_en.en == regk_ser_yes) {
181		tr_dma_en.en = regk_ser_no;
182		REG_WR(ser, port->instance, rw_tr_dma_en, tr_dma_en);
183	}
184
185	/* Send data */
186	for (i = 0; i < len; i++) {
187		/* LF -> CRLF */
188		if (buf[i] == '\n') {
189			do {
190				stat = REG_RD (ser, port->instance, r_stat_din);
191			} while (!stat.tr_rdy);
192			REG_WR_INT (ser, port->instance, rw_dout, '\r');
193		}
194		/* Wait until transmitter is ready and send.*/
195		do {
196			stat = REG_RD (ser, port->instance, r_stat_din);
197		} while (!stat.tr_rdy);
198		REG_WR_INT (ser, port->instance, rw_dout, buf[i]);
199	}
200
201	/* Restore mode */
202	if (tr_dma_en.en != old.en)
203		REG_WR(ser, port->instance, rw_tr_dma_en, old);
204}
205
206static void
207console_write(struct console *co, const char *buf, unsigned int len)
208{
209	if (!port)
210		return;
211        console_write_direct(co, buf, len);
212}
213
214
215
216#else
217
218/* VCS debug */
219
220static void
221console_write(struct console *co, const char *buf, unsigned int len)
222{
223	char* pos;
224	pos = memchr(buf, '\n', len);
225	if (pos) {
226		int l = ++pos - buf;
227		memcpy(buffer + buffer_pos, buf, l);
228		memcpy(buffer, msg, sizeof(msg) - 1);
229		buffer[buffer_pos + l] = '\0';
230		print_str(buffer);
231		buffer_pos = sizeof(msg) - 1;
232		if (pos - buf != len) {
233			memcpy(buffer + buffer_pos, pos, len - l);
234			buffer_pos += len - l;
235		}
236	} else {
237		memcpy(buffer + buffer_pos, buf, len);
238		buffer_pos += len;
239	}
240}
241
242#endif
243
244int raw_printk(const char *fmt, ...)
245{
246	static char buf[1024];
247	int printed_len;
248	va_list args;
249	va_start(args, fmt);
250	printed_len = vsnprintf(buf, sizeof(buf), fmt, args);
251	va_end(args);
252	console_write(NULL, buf, strlen(buf));
253	return printed_len;
254}
255
256void
257stupid_debug(char* buf)
258{
259  console_write(NULL, buf, strlen(buf));
260}
261
262#ifdef CONFIG_ETRAX_KGDB
263/* Use polling to get a single character from the kernel debug port */
264int
265getDebugChar(void)
266{
267	reg_ser_rs_status_data stat;
268	reg_ser_rw_ack_intr ack_intr = { 0 };
269
270	do {
271		stat = REG_RD(ser, kgdb_instance, rs_status_data);
272	} while (!stat.data_avail);
273
274	/* Ack the data_avail interrupt. */
275	ack_intr.data_avail = 1;
276	REG_WR(ser, kgdb_instance, rw_ack_intr, ack_intr);
277
278	return stat.data;
279}
280
281/* Use polling to put a single character to the kernel debug port */
282void
283putDebugChar(int val)
284{
285	reg_ser_r_status_data stat;
286	do {
287		stat = REG_RD (ser, kgdb_instance, r_status_data);
288	} while (!stat.tr_ready);
289	REG_WR (ser, kgdb_instance, rw_data_out, REG_TYPE_CONV(reg_ser_rw_data_out, int, val));
290}
291#endif /* CONFIG_ETRAX_KGDB */
292
293static int __init
294console_setup(struct console *co, char *options)
295{
296	char* s;
297
298	if (options) {
299		port = &ports[co->index];
300		port->baudrate = 115200;
301		port->parity = 'N';
302		port->bits = 8;
303		port->baudrate = simple_strtoul(options, NULL, 10);
304		s = options;
305		while(*s >= '0' && *s <= '9')
306			s++;
307		if (*s) port->parity = *s++;
308		if (*s) port->bits   = *s++ - '0';
309		port->started = 0;
310		start_port(port);
311	}
312	return 0;
313}
314
315/* This is a dummy serial device that throws away anything written to it.
316 * This is used when no debug output is wanted.
317 */
318static struct tty_driver dummy_driver;
319
320static int dummy_open(struct tty_struct *tty, struct file * filp)
321{
322	return 0;
323}
324
325static void dummy_close(struct tty_struct *tty, struct file * filp)
326{
327}
328
329static int dummy_write(struct tty_struct * tty,
330                       const unsigned char *buf, int count)
331{
332	return count;
333}
334
335static int
336dummy_write_room(struct tty_struct *tty)
337{
338	return 8192;
339}
340
341void __init
342init_dummy_console(void)
343{
344	memset(&dummy_driver, 0, sizeof(struct tty_driver));
345	dummy_driver.driver_name = "serial";
346	dummy_driver.name = "ttyS";
347	dummy_driver.major = TTY_MAJOR;
348	dummy_driver.minor_start = 68;
349	dummy_driver.num = 1;       /* etrax100 has 4 serial ports */
350	dummy_driver.type = TTY_DRIVER_TYPE_SERIAL;
351	dummy_driver.subtype = SERIAL_TYPE_NORMAL;
352	dummy_driver.init_termios = tty_std_termios;
353	dummy_driver.init_termios.c_cflag =
354		B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */
355	dummy_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
356
357	dummy_driver.open = dummy_open;
358	dummy_driver.close = dummy_close;
359	dummy_driver.write = dummy_write;
360	dummy_driver.write_room = dummy_write_room;
361	if (tty_register_driver(&dummy_driver))
362		panic("Couldn't register dummy serial driver\n");
363}
364
365static struct tty_driver*
366crisv32_console_device(struct console* co, int *index)
367{
368	if (port)
369		*index = port->nbr;
370        return port ? serial_driver : &dummy_driver;
371}
372
373static struct console sercons = {
374	name : "ttyS",
375	write: console_write,
376	read : NULL,
377	device : crisv32_console_device,
378	unblank : NULL,
379	setup : console_setup,
380	flags : CON_PRINTBUFFER,
381	index : -1,
382	cflag : 0,
383	next : NULL
384};
385static struct console sercons0 = {
386	name : "ttyS",
387	write: console_write,
388	read : NULL,
389	device : crisv32_console_device,
390	unblank : NULL,
391	setup : console_setup,
392	flags : CON_PRINTBUFFER,
393	index : 0,
394	cflag : 0,
395	next : NULL
396};
397
398static struct console sercons1 = {
399	name : "ttyS",
400	write: console_write,
401	read : NULL,
402	device : crisv32_console_device,
403	unblank : NULL,
404	setup : console_setup,
405	flags : CON_PRINTBUFFER,
406	index : 1,
407	cflag : 0,
408	next : NULL
409};
410static struct console sercons2 = {
411	name : "ttyS",
412	write: console_write,
413	read : NULL,
414	device : crisv32_console_device,
415	unblank : NULL,
416	setup : console_setup,
417	flags : CON_PRINTBUFFER,
418	index : 2,
419	cflag : 0,
420	next : NULL
421};
422static struct console sercons3 = {
423	name : "ttyS",
424	write: console_write,
425	read : NULL,
426	device : crisv32_console_device,
427	unblank : NULL,
428	setup : console_setup,
429	flags : CON_PRINTBUFFER,
430	index : 3,
431	cflag : 0,
432	next : NULL
433};
434
435/* Register console for printk's, etc. */
436int __init
437init_etrax_debug(void)
438{
439  	static int first = 1;
440
441	if (!first) {
442		unregister_console(&sercons);
443		register_console(&sercons0);
444		register_console(&sercons1);
445		register_console(&sercons2);
446		register_console(&sercons3);
447		init_dummy_console();
448		return 0;
449	}
450	first = 0;
451        register_console(&sercons);
452        start_port(port);
453
454#ifdef CONFIG_ETRAX_KGDB
455	start_port(kgdb_port);
456#endif /* CONFIG_ETRAX_KGDB */
457	return 0;
458}
459
460__initcall(init_etrax_debug);
461