Commit db783d52 authored by Mikael Starvik's avatar Mikael Starvik Committed by Linus Torvalds

[PATCH] CRIS: Console setup handling

Handled console setup arguments on kernel command line.
Signed-off-by: default avatarMikael Starvik <starvik@axis.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 6410393a
...@@ -12,6 +12,21 @@ ...@@ -12,6 +12,21 @@
* init_etrax_debug() * init_etrax_debug()
* *
* $Log: debugport.c,v $ * $Log: debugport.c,v $
* Revision 1.19 2004/10/21 07:26:16 starvik
* Made it possible to specify console settings on kernel command line.
*
* Revision 1.18 2004/10/19 13:07:37 starvik
* Merge of Linux 2.6.9
*
* Revision 1.17 2004/09/29 10:33:46 starvik
* Resolved a dealock when printing debug from kernel.
*
* Revision 1.16 2004/08/24 06:12:19 starvik
* Whitespace cleanup
*
* Revision 1.15 2004/08/16 12:37:19 starvik
* Merge of Linux 2.6.8
*
* Revision 1.14 2004/05/17 13:11:29 starvik * Revision 1.14 2004/05/17 13:11:29 starvik
* Disable DMA until real serial driver is up * Disable DMA until real serial driver is up
* *
...@@ -73,111 +88,275 @@ ...@@ -73,111 +88,275 @@
#include <asm/arch/svinto.h> #include <asm/arch/svinto.h>
#include <asm/io.h> /* Get SIMCOUT. */ #include <asm/io.h> /* Get SIMCOUT. */
/* Which serial-port is our debug port ? */ struct dbg_port
{
#if defined(CONFIG_ETRAX_DEBUG_PORT0) || defined(CONFIG_ETRAX_DEBUG_PORT_NULL) unsigned int index;
#define DEBUG_PORT_IDX 0 const volatile unsigned* read;
#define DEBUG_OCMD R_DMA_CH6_CMD volatile char* write;
#define DEBUG_FIRST R_DMA_CH6_FIRST volatile unsigned* xoff;
#define DEBUG_OCLRINT R_DMA_CH6_CLR_INTR volatile char* baud;
#define DEBUG_STATUS R_DMA_CH6_STATUS volatile char* tr_ctrl;
#define DEBUG_READ R_SERIAL0_READ volatile char* rec_ctrl;
#define DEBUG_WRITE R_SERIAL0_TR_DATA unsigned long irq;
#define DEBUG_TR_CTRL R_SERIAL0_TR_CTRL unsigned int started;
#define DEBUG_REC_CTRL R_SERIAL0_REC_CTRL unsigned long baudrate;
#define DEBUG_IRQ IO_STATE(R_IRQ_MASK1_SET, ser0_data, set) unsigned char parity;
#define DEBUG_DMA_IRQ_CLR IO_STATE(R_IRQ_MASK2_CLR, dma6_descr, clr) unsigned int bits;
#endif };
#ifdef CONFIG_ETRAX_DEBUG_PORT1 struct dbg_port ports[]=
#define DEBUG_PORT_IDX 1 {
#define DEBUG_OCMD R_DMA_CH8_CMD {
#define DEBUG_FIRST R_DMA_CH8_FIRST 0,
#define DEBUG_OCLRINT R_DMA_CH8_CLR_INTR R_SERIAL0_READ,
#define DEBUG_STATUS R_DMA_CH8_STATUS R_SERIAL0_TR_DATA,
#define DEBUG_READ R_SERIAL1_READ R_SERIAL0_XOFF,
#define DEBUG_WRITE R_SERIAL1_TR_DATA R_SERIAL0_BAUD,
#define DEBUG_TR_CTRL R_SERIAL1_TR_CTRL R_SERIAL0_TR_CTRL,
#define DEBUG_REC_CTRL R_SERIAL1_REC_CTRL R_SERIAL0_REC_CTRL,
#define DEBUG_IRQ IO_STATE(R_IRQ_MASK1_SET, ser1_data, set) IO_STATE(R_IRQ_MASK1_SET, ser0_data, set)
#define DEBUG_DMA_IRQ_CLR IO_STATE(R_IRQ_MASK2_CLR, dma8_descr, clr) },
#endif {
1,
R_SERIAL1_READ,
R_SERIAL1_TR_DATA,
R_SERIAL1_XOFF,
R_SERIAL1_BAUD,
R_SERIAL1_TR_CTRL,
R_SERIAL1_REC_CTRL,
IO_STATE(R_IRQ_MASK1_SET, ser1_data, set)
},
{
2,
R_SERIAL2_READ,
R_SERIAL2_TR_DATA,
R_SERIAL2_XOFF,
R_SERIAL2_BAUD,
R_SERIAL2_TR_CTRL,
R_SERIAL2_REC_CTRL,
IO_STATE(R_IRQ_MASK1_SET, ser2_data, set)
},
{
3,
R_SERIAL3_READ,
R_SERIAL3_TR_DATA,
R_SERIAL3_XOFF,
R_SERIAL3_BAUD,
R_SERIAL3_TR_CTRL,
R_SERIAL3_REC_CTRL,
IO_STATE(R_IRQ_MASK1_SET, ser3_data, set)
}
};
#ifdef CONFIG_ETRAX_DEBUG_PORT2 static struct tty_driver *serial_driver;
#define DEBUG_PORT_IDX 2
#define DEBUG_OCMD R_DMA_CH2_CMD
#define DEBUG_FIRST R_DMA_CH2_FIRST
#define DEBUG_OCLRINT R_DMA_CH2_CLR_INTR
#define DEBUG_STATUS R_DMA_CH2_STATUS
#define DEBUG_READ R_SERIAL2_READ
#define DEBUG_WRITE R_SERIAL2_TR_DATA
#define DEBUG_TR_CTRL R_SERIAL2_TR_CTRL
#define DEBUG_REC_CTRL R_SERIAL2_REC_CTRL
#define DEBUG_IRQ IO_STATE(R_IRQ_MASK1_SET, ser2_data, set)
#define DEBUG_DMA_IRQ_CLR IO_STATE(R_IRQ_MASK2_CLR, dma2_descr, clr)
#endif
#ifdef CONFIG_ETRAX_DEBUG_PORT3 struct dbg_port* port =
#define DEBUG_PORT_IDX 3 #if defined(CONFIG_ETRAX_DEBUG_PORT0)
#define DEBUG_OCMD R_DMA_CH4_CMD &ports[0];
#define DEBUG_FIRST R_DMA_CH4_FIRST #elif defined(CONFIG_ETRAX_DEBUG_PORT1)
#define DEBUG_OCLRINT R_DMA_CH4_CLR_INTR &ports[1];
#define DEBUG_STATUS R_DMA_CH4_STATUS #elif defined(CONFIG_ETRAX_DEBUG_PORT2)
#define DEBUG_READ R_SERIAL3_READ &ports[2];
#define DEBUG_WRITE R_SERIAL3_TR_DATA #elif defined(CONFIG_ETRAX_DEBUG_PORT3)
#define DEBUG_TR_CTRL R_SERIAL3_TR_CTRL &ports[3];
#define DEBUG_REC_CTRL R_SERIAL3_REC_CTRL #else
#define DEBUG_IRQ IO_STATE(R_IRQ_MASK1_SET, ser3_data, set) NULL;
#define DEBUG_DMA_IRQ_CLR IO_STATE(R_IRQ_MASK2_CLR, dma4_descr, clr)
#endif #endif
/* Used by serial.c to register a debug_write_function so that the normal
* serial driver is used for kernel debug output
*/
typedef int (*debugport_write_function)(int i, const char *buf, unsigned int len);
#define MIN_SIZE 32 /* Size that triggers the FIFO to flush characters to interface */ debugport_write_function debug_write_function = NULL;
static struct tty_driver *serial_driver; static void
start_port(void)
{
unsigned long rec_ctrl = 0;
unsigned long tr_ctrl = 0;
typedef int (*debugport_write_function)(int i, const char *buf, unsigned int len); if (!port)
return;
debugport_write_function debug_write_function = NULL; if (port->started)
return;
port->started = 1;
if (port->index == 0)
{
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma6);
genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, unused);
}
else if (port->index == 1)
{
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma8);
genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, usb);
}
else if (port->index == 2)
{
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma2);
genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, par0);
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma3);
genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma3, par0);
genconfig_shadow |= IO_STATE(R_GEN_CONFIG, ser2, select);
}
else
{
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma4);
genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, par1);
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma5);
genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma5, par1);
genconfig_shadow |= IO_STATE(R_GEN_CONFIG, ser3, select);
}
*R_GEN_CONFIG = genconfig_shadow;
*port->xoff =
IO_STATE(R_SERIAL0_XOFF, tx_stop, enable) |
IO_STATE(R_SERIAL0_XOFF, auto_xoff, disable) |
IO_FIELD(R_SERIAL0_XOFF, xoff_char, 0);
switch (port->baudrate)
{
case 0:
case 115200:
*port->baud =
IO_STATE(R_SERIAL0_BAUD, tr_baud, c115k2Hz) |
IO_STATE(R_SERIAL0_BAUD, rec_baud, c115k2Hz);
break;
case 1200:
*port->baud =
IO_STATE(R_SERIAL0_BAUD, tr_baud, c1200Hz) |
IO_STATE(R_SERIAL0_BAUD, rec_baud, c1200Hz);
break;
case 2400:
*port->baud =
IO_STATE(R_SERIAL0_BAUD, tr_baud, c2400Hz) |
IO_STATE(R_SERIAL0_BAUD, rec_baud, c2400Hz);
break;
case 4800:
*port->baud =
IO_STATE(R_SERIAL0_BAUD, tr_baud, c4800Hz) |
IO_STATE(R_SERIAL0_BAUD, rec_baud, c4800Hz);
break;
case 9600:
*port->baud =
IO_STATE(R_SERIAL0_BAUD, tr_baud, c9600Hz) |
IO_STATE(R_SERIAL0_BAUD, rec_baud, c9600Hz);
break;
case 19200:
*port->baud =
IO_STATE(R_SERIAL0_BAUD, tr_baud, c19k2Hz) |
IO_STATE(R_SERIAL0_BAUD, rec_baud, c19k2Hz);
break;
case 38400:
*port->baud =
IO_STATE(R_SERIAL0_BAUD, tr_baud, c38k4Hz) |
IO_STATE(R_SERIAL0_BAUD, rec_baud, c38k4Hz);
break;
case 57600:
*port->baud =
IO_STATE(R_SERIAL0_BAUD, tr_baud, c57k6Hz) |
IO_STATE(R_SERIAL0_BAUD, rec_baud, c57k6Hz);
break;
default:
*port->baud =
IO_STATE(R_SERIAL0_BAUD, tr_baud, c115k2Hz) |
IO_STATE(R_SERIAL0_BAUD, rec_baud, c115k2Hz);
break;
}
if (port->parity == 'E') {
rec_ctrl =
IO_STATE(R_SERIAL0_REC_CTRL, rec_par, even) |
IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, enable);
tr_ctrl =
IO_STATE(R_SERIAL0_TR_CTRL, tr_par, even) |
IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, enable);
} else if (port->parity == 'O') {
rec_ctrl =
IO_STATE(R_SERIAL0_REC_CTRL, rec_par, odd) |
IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, enable);
tr_ctrl =
IO_STATE(R_SERIAL0_TR_CTRL, tr_par, odd) |
IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, enable);
} else {
rec_ctrl =
IO_STATE(R_SERIAL0_REC_CTRL, rec_par, even) |
IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, disable);
tr_ctrl =
IO_STATE(R_SERIAL0_TR_CTRL, tr_par, even) |
IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, disable);
}
if (port->bits == 7)
{
rec_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_bitnr, rec_7bit);
tr_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_bitnr, tr_7bit);
}
else
{
rec_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_bitnr, rec_8bit);
tr_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_bitnr, tr_8bit);
}
*port->rec_ctrl =
IO_STATE(R_SERIAL0_REC_CTRL, dma_err, stop) |
IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable) |
IO_STATE(R_SERIAL0_REC_CTRL, rts_, active) |
IO_STATE(R_SERIAL0_REC_CTRL, sampling, middle) |
IO_STATE(R_SERIAL0_REC_CTRL, rec_stick_par, normal) |
rec_ctrl;
*port->tr_ctrl =
IO_FIELD(R_SERIAL0_TR_CTRL, txd, 0) |
IO_STATE(R_SERIAL0_TR_CTRL, tr_enable, enable) |
IO_STATE(R_SERIAL0_TR_CTRL, auto_cts, disabled) |
IO_STATE(R_SERIAL0_TR_CTRL, stop_bits, one_bit) |
IO_STATE(R_SERIAL0_TR_CTRL, tr_stick_par, normal) |
tr_ctrl;
}
static void static void
console_write_direct(struct console *co, const char *buf, unsigned int len) console_write_direct(struct console *co, const char *buf, unsigned int len)
{ {
int i; int i;
unsigned long flags;
local_irq_save(flags);
/* Send data */ /* Send data */
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
/* Wait until transmitter is ready and send.*/ /* Wait until transmitter is ready and send.*/
while(!(*DEBUG_READ & IO_MASK(R_SERIAL0_READ, tr_ready))); while (!(*port->read & IO_MASK(R_SERIAL0_READ, tr_ready)))
*DEBUG_WRITE = buf[i]; ;
*port->write = buf[i];
} }
local_irq_restore(flags);
} }
static void static void
console_write(struct console *co, const char *buf, unsigned int len) console_write(struct console *co, const char *buf, unsigned int len)
{ {
unsigned long flags; if (!port)
#ifdef CONFIG_ETRAX_DEBUG_PORT_NULL return;
/* no debug printout at all */
return;
#endif
#ifdef CONFIG_SVINTO_SIM #ifdef CONFIG_SVINTO_SIM
/* no use to simulate the serial debug output */ /* no use to simulate the serial debug output */
SIMCOUT(buf,len); SIMCOUT(buf, len);
return; return;
#endif #endif
start_port();
#ifdef CONFIG_ETRAX_KGDB #ifdef CONFIG_ETRAX_KGDB
/* kgdb needs to output debug info using the gdb protocol */ /* kgdb needs to output debug info using the gdb protocol */
putDebugString(buf, len); putDebugString(buf, len);
return; return;
#endif #endif
local_irq_save(flags);
if (debug_write_function) if (debug_write_function)
if (debug_write_function(co->index, buf, len)) debug_write_function(co->index, buf, len);
return; else
console_write_direct(co, buf, len); console_write_direct(co, buf, len);
local_irq_restore(flags);
} }
/* legacy function */ /* legacy function */
...@@ -194,10 +373,10 @@ int ...@@ -194,10 +373,10 @@ int
getDebugChar(void) getDebugChar(void)
{ {
unsigned long readval; unsigned long readval;
do { do {
readval = *DEBUG_READ; readval = *port->read;
} while(!(readval & IO_MASK(R_SERIAL0_READ, data_avail))); } while (!(readval & IO_MASK(R_SERIAL0_READ, data_avail)));
return (readval & IO_MASK(R_SERIAL0_READ, data_in)); return (readval & IO_MASK(R_SERIAL0_READ, data_in));
} }
...@@ -207,9 +386,9 @@ getDebugChar(void) ...@@ -207,9 +386,9 @@ getDebugChar(void)
void void
putDebugChar(int val) putDebugChar(int val)
{ {
while(!(*DEBUG_READ & IO_MASK(R_SERIAL0_READ, tr_ready))) ; while (!(*port->read & IO_MASK(R_SERIAL0_READ, tr_ready)))
; ;
*DEBUG_WRITE = val; *port->write = val;
} }
/* Enable irq for receiving chars on the debug port, used by kgdb */ /* Enable irq for receiving chars on the debug port, used by kgdb */
...@@ -217,68 +396,127 @@ putDebugChar(int val) ...@@ -217,68 +396,127 @@ putDebugChar(int val)
void void
enableDebugIRQ(void) enableDebugIRQ(void)
{ {
*R_IRQ_MASK1_SET = DEBUG_IRQ; *R_IRQ_MASK1_SET = port->irq;
/* use R_VECT_MASK directly, since we really bypass Linux normal /* use R_VECT_MASK directly, since we really bypass Linux normal
* IRQ handling in kgdb anyway, we don't need to use enable_irq * IRQ handling in kgdb anyway, we don't need to use enable_irq
*/ */
*R_VECT_MASK_SET = IO_STATE(R_VECT_MASK_SET, serial, set); *R_VECT_MASK_SET = IO_STATE(R_VECT_MASK_SET, serial, set);
*DEBUG_REC_CTRL = IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable); *port->rec_ctrl = IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable);
} }
static struct tty_driver* static struct tty_driver*
console_device(struct console *c, int *index) etrax_console_device(struct console* co, int *index)
{ {
*index = c->index;
return serial_driver; return serial_driver;
} }
static int __init static int __init
console_setup(struct console *co, char *options) console_setup(struct console *co, char *options)
{ {
return 0; char* s;
if (options) {
port = &ports[co->index];
port->baudrate = 115200;
port->parity = 'N';
port->bits = 8;
port->baudrate = simple_strtoul(options, NULL, 10);
s = options;
while(*s >= '0' && *s <= '9')
s++;
if (*s) port->parity = *s++;
if (*s) port->bits = *s++ - '0';
port->started = 0;
start_port();
}
return 0;
} }
static struct console sercons = { static struct console sercons = {
.name = "ttyS", name : "ttyS",
.write = console_write, write: console_write,
.read = NULL, read : NULL,
.device = console_device, device : etrax_console_device,
.unblank = NULL, unblank : NULL,
.setup = console_setup, setup : console_setup,
.flags = CON_PRINTBUFFER, flags : CON_PRINTBUFFER,
.index = DEBUG_PORT_IDX, index : -1,
.cflag = 0, cflag : 0,
.next = NULL next : NULL
};
static struct console sercons0 = {
name : "ttyS",
write: console_write,
read : NULL,
device : etrax_console_device,
unblank : NULL,
setup : console_setup,
flags : CON_PRINTBUFFER,
index : 0,
cflag : 0,
next : NULL
}; };
static struct console sercons1 = {
name : "ttyS",
write: console_write,
read : NULL,
device : etrax_console_device,
unblank : NULL,
setup : console_setup,
flags : CON_PRINTBUFFER,
index : 1,
cflag : 0,
next : NULL
};
static struct console sercons2 = {
name : "ttyS",
write: console_write,
read : NULL,
device : etrax_console_device,
unblank : NULL,
setup : console_setup,
flags : CON_PRINTBUFFER,
index : 2,
cflag : 0,
next : NULL
};
static struct console sercons3 = {
name : "ttyS",
write: console_write,
read : NULL,
device : etrax_console_device,
unblank : NULL,
setup : console_setup,
flags : CON_PRINTBUFFER,
index : 3,
cflag : 0,
next : NULL
};
/* /*
* Register console (for printk's etc) * Register console (for printk's etc)
*/ */
void __init int __init
init_etrax_debug(void) init_etrax_debug(void)
{ {
#ifdef CONFIG_ETRAX_DEBUG_PORT_NULL static int first = 1;
return;
#endif if (!first) {
if (!port) {
#if DEBUG_PORT_IDX == 0 register_console(&sercons0);
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma6); register_console(&sercons1);
genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, unused); register_console(&sercons2);
#elif DEBUG_PORT_IDX == 1 register_console(&sercons3);
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma8); unregister_console(&sercons);
genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, usb); }
#elif DEBUG_PORT_IDX == 2 return 0;
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma2); }
genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, par0); first = 0;
#elif DEBUG_PORT_IDX == 3 if (port)
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma4); register_console(&sercons);
genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, par1); return 0;
#endif
*R_GEN_CONFIG = genconfig_shadow;
register_console(&sercons);
} }
int __init int __init
...@@ -289,3 +527,5 @@ init_console(void) ...@@ -289,3 +527,5 @@ init_console(void)
return -ENOMEM; return -ENOMEM;
return 0; return 0;
} }
__initcall(init_etrax_debug);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment