Path: blob/master/arch/cris/arch-v10/kernel/debugport.c
15125 views
/* Serialport functions for debugging1*2* Copyright (c) 2000-2007 Axis Communications AB3*4* Authors: Bjorn Wesen5*6* Exports:7* console_print_etrax(char *buf)8* int getDebugChar()9* putDebugChar(int)10* enableDebugIRQ()11* init_etrax_debug()12*13*/1415#include <linux/console.h>16#include <linux/init.h>17#include <linux/major.h>18#include <linux/delay.h>19#include <linux/tty.h>20#include <asm/system.h>21#include <arch/svinto.h>22#include <asm/io.h> /* Get SIMCOUT. */2324extern void reset_watchdog(void);2526struct dbg_port27{28unsigned int index;29const volatile unsigned* read;30volatile char* write;31volatile unsigned* xoff;32volatile char* baud;33volatile char* tr_ctrl;34volatile char* rec_ctrl;35unsigned long irq;36unsigned int started;37unsigned long baudrate;38unsigned char parity;39unsigned int bits;40};4142struct dbg_port ports[]=43{44{450,46R_SERIAL0_READ,47R_SERIAL0_TR_DATA,48R_SERIAL0_XOFF,49R_SERIAL0_BAUD,50R_SERIAL0_TR_CTRL,51R_SERIAL0_REC_CTRL,52IO_STATE(R_IRQ_MASK1_SET, ser0_data, set),530,54115200,55'N',56857},58{591,60R_SERIAL1_READ,61R_SERIAL1_TR_DATA,62R_SERIAL1_XOFF,63R_SERIAL1_BAUD,64R_SERIAL1_TR_CTRL,65R_SERIAL1_REC_CTRL,66IO_STATE(R_IRQ_MASK1_SET, ser1_data, set),670,68115200,69'N',70871},72{732,74R_SERIAL2_READ,75R_SERIAL2_TR_DATA,76R_SERIAL2_XOFF,77R_SERIAL2_BAUD,78R_SERIAL2_TR_CTRL,79R_SERIAL2_REC_CTRL,80IO_STATE(R_IRQ_MASK1_SET, ser2_data, set),810,82115200,83'N',84885},86{873,88R_SERIAL3_READ,89R_SERIAL3_TR_DATA,90R_SERIAL3_XOFF,91R_SERIAL3_BAUD,92R_SERIAL3_TR_CTRL,93R_SERIAL3_REC_CTRL,94IO_STATE(R_IRQ_MASK1_SET, ser3_data, set),950,96115200,97'N',98899}100};101102#ifdef CONFIG_ETRAX_SERIAL103extern struct tty_driver *serial_driver;104#endif105106struct dbg_port* port =107#if defined(CONFIG_ETRAX_DEBUG_PORT0)108&ports[0];109#elif defined(CONFIG_ETRAX_DEBUG_PORT1)110&ports[1];111#elif defined(CONFIG_ETRAX_DEBUG_PORT2)112&ports[2];113#elif defined(CONFIG_ETRAX_DEBUG_PORT3)114&ports[3];115#else116NULL;117#endif118119static struct dbg_port* kgdb_port =120#if defined(CONFIG_ETRAX_KGDB_PORT0)121&ports[0];122#elif defined(CONFIG_ETRAX_KGDB_PORT1)123&ports[1];124#elif defined(CONFIG_ETRAX_KGDB_PORT2)125&ports[2];126#elif defined(CONFIG_ETRAX_KGDB_PORT3)127&ports[3];128#else129NULL;130#endif131132static void133start_port(struct dbg_port* p)134{135unsigned long rec_ctrl = 0;136unsigned long tr_ctrl = 0;137138if (!p)139return;140141if (p->started)142return;143p->started = 1;144145if (p->index == 0)146{147genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma6);148genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, unused);149}150else if (p->index == 1)151{152genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma8);153genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, usb);154}155else if (p->index == 2)156{157genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma2);158genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, par0);159genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma3);160genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma3, par0);161genconfig_shadow |= IO_STATE(R_GEN_CONFIG, ser2, select);162}163else164{165genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma4);166genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, par1);167genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma5);168genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma5, par1);169genconfig_shadow |= IO_STATE(R_GEN_CONFIG, ser3, select);170}171172*R_GEN_CONFIG = genconfig_shadow;173174*p->xoff =175IO_STATE(R_SERIAL0_XOFF, tx_stop, enable) |176IO_STATE(R_SERIAL0_XOFF, auto_xoff, disable) |177IO_FIELD(R_SERIAL0_XOFF, xoff_char, 0);178179switch (p->baudrate)180{181case 0:182case 115200:183*p->baud =184IO_STATE(R_SERIAL0_BAUD, tr_baud, c115k2Hz) |185IO_STATE(R_SERIAL0_BAUD, rec_baud, c115k2Hz);186break;187case 1200:188*p->baud =189IO_STATE(R_SERIAL0_BAUD, tr_baud, c1200Hz) |190IO_STATE(R_SERIAL0_BAUD, rec_baud, c1200Hz);191break;192case 2400:193*p->baud =194IO_STATE(R_SERIAL0_BAUD, tr_baud, c2400Hz) |195IO_STATE(R_SERIAL0_BAUD, rec_baud, c2400Hz);196break;197case 4800:198*p->baud =199IO_STATE(R_SERIAL0_BAUD, tr_baud, c4800Hz) |200IO_STATE(R_SERIAL0_BAUD, rec_baud, c4800Hz);201break;202case 9600:203*p->baud =204IO_STATE(R_SERIAL0_BAUD, tr_baud, c9600Hz) |205IO_STATE(R_SERIAL0_BAUD, rec_baud, c9600Hz);206break;207case 19200:208*p->baud =209IO_STATE(R_SERIAL0_BAUD, tr_baud, c19k2Hz) |210IO_STATE(R_SERIAL0_BAUD, rec_baud, c19k2Hz);211break;212case 38400:213*p->baud =214IO_STATE(R_SERIAL0_BAUD, tr_baud, c38k4Hz) |215IO_STATE(R_SERIAL0_BAUD, rec_baud, c38k4Hz);216break;217case 57600:218*p->baud =219IO_STATE(R_SERIAL0_BAUD, tr_baud, c57k6Hz) |220IO_STATE(R_SERIAL0_BAUD, rec_baud, c57k6Hz);221break;222default:223*p->baud =224IO_STATE(R_SERIAL0_BAUD, tr_baud, c115k2Hz) |225IO_STATE(R_SERIAL0_BAUD, rec_baud, c115k2Hz);226break;227}228229if (p->parity == 'E') {230rec_ctrl =231IO_STATE(R_SERIAL0_REC_CTRL, rec_par, even) |232IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, enable);233tr_ctrl =234IO_STATE(R_SERIAL0_TR_CTRL, tr_par, even) |235IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, enable);236} else if (p->parity == 'O') {237rec_ctrl =238IO_STATE(R_SERIAL0_REC_CTRL, rec_par, odd) |239IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, enable);240tr_ctrl =241IO_STATE(R_SERIAL0_TR_CTRL, tr_par, odd) |242IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, enable);243} else {244rec_ctrl =245IO_STATE(R_SERIAL0_REC_CTRL, rec_par, even) |246IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, disable);247tr_ctrl =248IO_STATE(R_SERIAL0_TR_CTRL, tr_par, even) |249IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, disable);250}251if (p->bits == 7)252{253rec_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_bitnr, rec_7bit);254tr_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_bitnr, tr_7bit);255}256else257{258rec_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_bitnr, rec_8bit);259tr_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_bitnr, tr_8bit);260}261262*p->rec_ctrl =263IO_STATE(R_SERIAL0_REC_CTRL, dma_err, stop) |264IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable) |265IO_STATE(R_SERIAL0_REC_CTRL, rts_, active) |266IO_STATE(R_SERIAL0_REC_CTRL, sampling, middle) |267IO_STATE(R_SERIAL0_REC_CTRL, rec_stick_par, normal) |268rec_ctrl;269270*p->tr_ctrl =271IO_FIELD(R_SERIAL0_TR_CTRL, txd, 0) |272IO_STATE(R_SERIAL0_TR_CTRL, tr_enable, enable) |273IO_STATE(R_SERIAL0_TR_CTRL, auto_cts, disabled) |274IO_STATE(R_SERIAL0_TR_CTRL, stop_bits, one_bit) |275IO_STATE(R_SERIAL0_TR_CTRL, tr_stick_par, normal) |276tr_ctrl;277}278279static void280console_write_direct(struct console *co, const char *buf, unsigned int len)281{282int i;283unsigned long flags;284285if (!port)286return;287288local_irq_save(flags);289290/* Send data */291for (i = 0; i < len; i++) {292/* LF -> CRLF */293if (buf[i] == '\n') {294while (!(*port->read & IO_MASK(R_SERIAL0_READ, tr_ready)))295;296*port->write = '\r';297}298/* Wait until transmitter is ready and send.*/299while (!(*port->read & IO_MASK(R_SERIAL0_READ, tr_ready)))300;301*port->write = buf[i];302}303304/*305* Feed the watchdog, otherwise it will reset the chip during boot.306* The time to send an ordinary boot message line (10-90 chars)307* varies between 1-8ms at 115200. What makes up for the additional308* 90ms that allows the watchdog to bite?309*/310reset_watchdog();311312local_irq_restore(flags);313}314315static void316console_write(struct console *co, const char *buf, unsigned int len)317{318if (!port)319return;320321#ifdef CONFIG_SVINTO_SIM322/* no use to simulate the serial debug output */323SIMCOUT(buf, len);324return;325#endif326327console_write_direct(co, buf, len);328}329330/* legacy function */331332void333console_print_etrax(const char *buf)334{335console_write(NULL, buf, strlen(buf));336}337338/* Use polling to get a single character FROM the debug port */339340int341getDebugChar(void)342{343unsigned long readval;344345if (!kgdb_port)346return 0;347348do {349readval = *kgdb_port->read;350} while (!(readval & IO_MASK(R_SERIAL0_READ, data_avail)));351352return (readval & IO_MASK(R_SERIAL0_READ, data_in));353}354355/* Use polling to put a single character to the debug port */356357void358putDebugChar(int val)359{360if (!kgdb_port)361return;362363while (!(*kgdb_port->read & IO_MASK(R_SERIAL0_READ, tr_ready)))364;365*kgdb_port->write = val;366}367368/* Enable irq for receiving chars on the debug port, used by kgdb */369370void371enableDebugIRQ(void)372{373if (!kgdb_port)374return;375376*R_IRQ_MASK1_SET = kgdb_port->irq;377/* use R_VECT_MASK directly, since we really bypass Linux normal378* IRQ handling in kgdb anyway, we don't need to use enable_irq379*/380*R_VECT_MASK_SET = IO_STATE(R_VECT_MASK_SET, serial, set);381382*kgdb_port->rec_ctrl = IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable);383}384385static int __init386console_setup(struct console *co, char *options)387{388char* s;389390if (options) {391port = &ports[co->index];392port->baudrate = 115200;393port->parity = 'N';394port->bits = 8;395port->baudrate = simple_strtoul(options, NULL, 10);396s = options;397while(*s >= '0' && *s <= '9')398s++;399if (*s) port->parity = *s++;400if (*s) port->bits = *s++ - '0';401port->started = 0;402start_port(0);403}404return 0;405}406407408/* This is a dummy serial device that throws away anything written to it.409* This is used when no debug output is wanted.410*/411static struct tty_driver dummy_driver;412413static int dummy_open(struct tty_struct *tty, struct file * filp)414{415return 0;416}417418static void dummy_close(struct tty_struct *tty, struct file * filp)419{420}421422static int dummy_write(struct tty_struct * tty,423const unsigned char *buf, int count)424{425return count;426}427428static int dummy_write_room(struct tty_struct *tty)429{430return 8192;431}432433static const struct tty_operations dummy_ops = {434.open = dummy_open,435.close = dummy_close,436.write = dummy_write,437.write_room = dummy_write_room,438};439440void __init441init_dummy_console(void)442{443memset(&dummy_driver, 0, sizeof(struct tty_driver));444dummy_driver.driver_name = "serial";445dummy_driver.name = "ttyS";446dummy_driver.major = TTY_MAJOR;447dummy_driver.minor_start = 68;448dummy_driver.num = 1; /* etrax100 has 4 serial ports */449dummy_driver.type = TTY_DRIVER_TYPE_SERIAL;450dummy_driver.subtype = SERIAL_TYPE_NORMAL;451dummy_driver.init_termios = tty_std_termios;452/* Normally B9600 default... */453dummy_driver.init_termios.c_cflag =454B115200 | CS8 | CREAD | HUPCL | CLOCAL;455dummy_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;456dummy_driver.init_termios.c_ispeed = 115200;457dummy_driver.init_termios.c_ospeed = 115200;458459dummy_driver.ops = &dummy_ops;460if (tty_register_driver(&dummy_driver))461panic("Couldn't register dummy serial driver\n");462}463464static struct tty_driver*465etrax_console_device(struct console* co, int *index)466{467if (port)468*index = port->index;469else470*index = 0;471#ifdef CONFIG_ETRAX_SERIAL472return port ? serial_driver : &dummy_driver;473#else474return &dummy_driver;475#endif476}477478static struct console sercons = {479name : "ttyS",480write: console_write,481read : NULL,482device : etrax_console_device,483unblank : NULL,484setup : console_setup,485flags : CON_PRINTBUFFER,486index : -1,487cflag : 0,488next : NULL489};490static struct console sercons0 = {491name : "ttyS",492write: console_write,493read : NULL,494device : etrax_console_device,495unblank : NULL,496setup : console_setup,497flags : CON_PRINTBUFFER,498index : 0,499cflag : 0,500next : NULL501};502503static struct console sercons1 = {504name : "ttyS",505write: console_write,506read : NULL,507device : etrax_console_device,508unblank : NULL,509setup : console_setup,510flags : CON_PRINTBUFFER,511index : 1,512cflag : 0,513next : NULL514};515static struct console sercons2 = {516name : "ttyS",517write: console_write,518read : NULL,519device : etrax_console_device,520unblank : NULL,521setup : console_setup,522flags : CON_PRINTBUFFER,523index : 2,524cflag : 0,525next : NULL526};527static struct console sercons3 = {528name : "ttyS",529write: console_write,530read : NULL,531device : etrax_console_device,532unblank : NULL,533setup : console_setup,534flags : CON_PRINTBUFFER,535index : 3,536cflag : 0,537next : NULL538};539/*540* Register console (for printk's etc)541*/542543int __init544init_etrax_debug(void)545{546static int first = 1;547548if (!first) {549unregister_console(&sercons);550register_console(&sercons0);551register_console(&sercons1);552register_console(&sercons2);553register_console(&sercons3);554init_dummy_console();555return 0;556}557558first = 0;559register_console(&sercons);560start_port(port);561#ifdef CONFIG_ETRAX_KGDB562start_port(kgdb_port);563#endif564return 0;565}566__initcall(init_etrax_debug);567568569