summaryrefslogtreecommitdiff
path: root/target/linux
diff options
context:
space:
mode:
authorWaldemar Brodkorb <wbx@openadk.org>2015-05-25 17:52:32 +0200
committerWaldemar Brodkorb <wbx@openadk.org>2015-05-25 17:52:50 +0200
commit67e2da6a84f50c0b0e43f4d4fb9eae91671e81ad (patch)
tree1406e2b59fe929d08261173bf21d886c07f04c06 /target/linux
parentcc0c042aafec40d93b06be3b6d7e94f38c5ac69f (diff)
add serial driver patch for crisv32
Diffstat (limited to 'target/linux')
-rw-r--r--target/linux/Config.in1
-rw-r--r--target/linux/config/Config.in.gpio10
-rw-r--r--target/linux/config/Config.in.serial11
-rw-r--r--target/linux/patches/4.0.3/cris32-serial.patch2886
4 files changed, 2908 insertions, 0 deletions
diff --git a/target/linux/Config.in b/target/linux/Config.in
index 4595a730b..80cc14627 100644
--- a/target/linux/Config.in
+++ b/target/linux/Config.in
@@ -8,6 +8,7 @@ source target/linux/config/Config.in.flash
source target/linux/config/Config.in.fs
source target/linux/config/Config.in.netdevice
source target/linux/config/Config.in.usb
+source target/linux/config/Config.in.serial
source target/linux/config/Config.in.graphics
source target/linux/config/Config.in.input
source target/linux/config/Config.in.pcmcia
diff --git a/target/linux/config/Config.in.gpio b/target/linux/config/Config.in.gpio
index 03f7ea5b0..535f9c668 100644
--- a/target/linux/config/Config.in.gpio
+++ b/target/linux/config/Config.in.gpio
@@ -10,6 +10,9 @@ config ADK_KERNEL_GPIO_SYSFS
config ADK_KERNEL_GPIO_GENERIC
bool
+config ADK_KERNEL_GPIO_DEVRES
+ bool
+
config ADK_KERNEL_BCM2708_GPIO
bool
select ADK_KERNEL_GPIOLIB
@@ -30,3 +33,10 @@ config ADK_KERNEL_GPIO_MXC
depends on ADK_TARGET_SYSTEM_SOLIDRUN_IMX6
default y if ADK_TARGET_SYSTEM_SOLIDRUN_IMX6
default n
+
+config ADK_KERNEL_ETRAX_GPIO
+ bool
+ select ADK_KERNEL_GPIO_DEVRES
+ depends on ADK_TARGET_SYSTEM_QEMU_CRIS
+ default y if ADK_TARGET_SYSTEM_QEMU_CRIS
+ default n
diff --git a/target/linux/config/Config.in.serial b/target/linux/config/Config.in.serial
new file mode 100644
index 000000000..79daca3ef
--- /dev/null
+++ b/target/linux/config/Config.in.serial
@@ -0,0 +1,11 @@
+menu "Serial devices support"
+depends on ADK_TARGET_WITH_SERIAL || ADK_TARGET_QEMU || ADK_TARGET_VBOX
+
+config ADK_KERNEL_ETRAXFS_SERIAL
+ bool "ETRAXFS serial driver"
+ default y if ADK_TARGET_SYSTEM_QEMU_CRIS
+ default n
+ help
+ Serial driver for ETRAXFS CRISv32 Qemu Emulation.
+
+endmenu
diff --git a/target/linux/patches/4.0.3/cris32-serial.patch b/target/linux/patches/4.0.3/cris32-serial.patch
new file mode 100644
index 000000000..0f071cffb
--- /dev/null
+++ b/target/linux/patches/4.0.3/cris32-serial.patch
@@ -0,0 +1,2886 @@
+diff -Nur linux-4.0.3.orig/arch/cris/arch-v32/drivers/Kconfig linux-4.0.3/arch/cris/arch-v32/drivers/Kconfig
+--- linux-4.0.3.orig/arch/cris/arch-v32/drivers/Kconfig 2015-05-13 14:14:53.000000000 +0200
++++ linux-4.0.3/arch/cris/arch-v32/drivers/Kconfig 2015-05-25 17:20:55.000000000 +0200
+@@ -49,24 +49,261 @@
+ if you do not need DMA to something else.
+ ser0 can use dma4 or dma6 for output and dma5 or dma7 for input.
+
++choice
++ prompt "Ser0 default port type "
++ depends on ETRAX_SERIAL_PORT0
++ default ETRAX_SERIAL_PORT0_TYPE_232
++ help
++ Type of serial port.
++
++config ETRAX_SERIAL_PORT0_TYPE_232
++ bool "Ser0 is a RS-232 port"
++ help
++ Configure serial port 0 to be a RS-232 port.
++
++config ETRAX_SERIAL_PORT0_TYPE_485HD
++ bool "Ser0 is a half duplex RS-485 port"
++ depends on ETRAX_RS485
++ help
++ Configure serial port 0 to be a half duplex (two wires) RS-485 port.
++
++config ETRAX_SERIAL_PORT0_TYPE_485FD
++ bool "Ser0 is a full duplex RS-485 port"
++ depends on ETRAX_RS485
++ help
++ Configure serial port 0 to be a full duplex (four wires) RS-485 port.
++endchoice
++
++config ETRAX_SER0_DTR_BIT
++ string "Ser 0 DTR bit (empty = not used)"
++ depends on ETRAX_SERIAL_PORT0
++
++config ETRAX_SER0_RI_BIT
++ string "Ser 0 RI bit (empty = not used)"
++ depends on ETRAX_SERIAL_PORT0
++
++config ETRAX_SER0_DSR_BIT
++ string "Ser 0 DSR bit (empty = not used)"
++ depends on ETRAX_SERIAL_PORT0
++
++config ETRAX_SER0_CD_BIT
++ string "Ser 0 CD bit (empty = not used)"
++ depends on ETRAX_SERIAL_PORT0
++
+ config ETRAX_SERIAL_PORT1
+ bool "Serial port 1 enabled"
+ depends on ETRAXFS_SERIAL
+ help
+ Enables the ETRAX FS serial driver for ser1 (ttyS1).
+
++choice
++ prompt "Ser1 default port type"
++ depends on ETRAX_SERIAL_PORT1
++ default ETRAX_SERIAL_PORT1_TYPE_232
++ help
++ Type of serial port.
++
++config ETRAX_SERIAL_PORT1_TYPE_232
++ bool "Ser1 is a RS-232 port"
++ help
++ Configure serial port 1 to be a RS-232 port.
++
++config ETRAX_SERIAL_PORT1_TYPE_485HD
++ bool "Ser1 is a half duplex RS-485 port"
++ depends on ETRAX_RS485
++ help
++ Configure serial port 1 to be a half duplex (two wires) RS-485 port.
++
++config ETRAX_SERIAL_PORT1_TYPE_485FD
++ bool "Ser1 is a full duplex RS-485 port"
++ depends on ETRAX_RS485
++ help
++ Configure serial port 1 to be a full duplex (four wires) RS-485 port.
++endchoice
++
++config ETRAX_SER1_DTR_BIT
++ string "Ser 1 DTR bit (empty = not used)"
++ depends on ETRAX_SERIAL_PORT1
++
++config ETRAX_SER1_RI_BIT
++ string "Ser 1 RI bit (empty = not used)"
++ depends on ETRAX_SERIAL_PORT1
++
++config ETRAX_SER1_DSR_BIT
++ string "Ser 1 DSR bit (empty = not used)"
++ depends on ETRAX_SERIAL_PORT1
++
++config ETRAX_SER1_CD_BIT
++ string "Ser 1 CD bit (empty = not used)"
++ depends on ETRAX_SERIAL_PORT1
++
+ config ETRAX_SERIAL_PORT2
+ bool "Serial port 2 enabled"
+ depends on ETRAXFS_SERIAL
+ help
+ Enables the ETRAX FS serial driver for ser2 (ttyS2).
+
++choice
++ prompt "Ser2 default port type"
++ depends on ETRAX_SERIAL_PORT2
++ default ETRAX_SERIAL_PORT2_TYPE_232
++ help
++ What DMA channel to use for ser2
++
++config ETRAX_SERIAL_PORT2_TYPE_232
++ bool "Ser2 is a RS-232 port"
++ help
++ Configure serial port 2 to be a RS-232 port.
++
++config ETRAX_SERIAL_PORT2_TYPE_485HD
++ bool "Ser2 is a half duplex RS-485 port"
++ depends on ETRAX_RS485
++ help
++ Configure serial port 2 to be a half duplex (two wires) RS-485 port.
++
++config ETRAX_SERIAL_PORT2_TYPE_485FD
++ bool "Ser2 is a full duplex RS-485 port"
++ depends on ETRAX_RS485
++ help
++ Configure serial port 2 to be a full duplex (four wires) RS-485 port.
++endchoice
++
++
++config ETRAX_SER2_DTR_BIT
++ string "Ser 2 DTR bit (empty = not used)"
++ depends on ETRAX_SERIAL_PORT2
++
++config ETRAX_SER2_RI_BIT
++ string "Ser 2 RI bit (empty = not used)"
++ depends on ETRAX_SERIAL_PORT2
++
++config ETRAX_SER2_DSR_BIT
++ string "Ser 2 DSR bit (empty = not used)"
++ depends on ETRAX_SERIAL_PORT2
++
++config ETRAX_SER2_CD_BIT
++ string "Ser 2 CD bit (empty = not used)"
++ depends on ETRAX_SERIAL_PORT2
++
+ config ETRAX_SERIAL_PORT3
+ bool "Serial port 3 enabled"
+ depends on ETRAXFS_SERIAL
+ help
+ Enables the ETRAX FS serial driver for ser3 (ttyS3).
+
++choice
++ prompt "Ser3 default port type"
++ depends on ETRAX_SERIAL_PORT3
++ default ETRAX_SERIAL_PORT3_TYPE_232
++ help
++ What DMA channel to use for ser3.
++
++config ETRAX_SERIAL_PORT3_TYPE_232
++ bool "Ser3 is a RS-232 port"
++ help
++ Configure serial port 3 to be a RS-232 port.
++
++config ETRAX_SERIAL_PORT3_TYPE_485HD
++ bool "Ser3 is a half duplex RS-485 port"
++ depends on ETRAX_RS485
++ help
++ Configure serial port 3 to be a half duplex (two wires) RS-485 port.
++
++config ETRAX_SERIAL_PORT3_TYPE_485FD
++ bool "Ser3 is a full duplex RS-485 port"
++ depends on ETRAX_RS485
++ help
++ Configure serial port 3 to be a full duplex (four wires) RS-485 port.
++endchoice
++
++config ETRAX_SER3_DTR_BIT
++ string "Ser 3 DTR bit (empty = not used)"
++ depends on ETRAX_SERIAL_PORT3
++
++config ETRAX_SER3_RI_BIT
++ string "Ser 3 RI bit (empty = not used)"
++ depends on ETRAX_SERIAL_PORT3
++
++config ETRAX_SER3_DSR_BIT
++ string "Ser 3 DSR bit (empty = not used)"
++ depends on ETRAX_SERIAL_PORT3
++
++config ETRAX_SER3_CD_BIT
++ string "Ser 3 CD bit (empty = not used)"
++ depends on ETRAX_SERIAL_PORT3
++
++config ETRAX_SERIAL_PORT4
++ bool "Serial port 4 enabled"
++ depends on ETRAXFS_SERIAL && CRIS_MACH_ARTPEC3
++ help
++ Enables the ETRAX FS serial driver for ser4 (ttyS4).
++
++choice
++ prompt "Ser4 default port type"
++ depends on ETRAX_SERIAL_PORT4
++ default ETRAX_SERIAL_PORT4_TYPE_232
++ help
++ What DMA channel to use for ser4.
++
++config ETRAX_SERIAL_PORT4_TYPE_232
++ bool "Ser4 is a RS-232 port"
++ help
++ Configure serial port 4 to be a RS-232 port.
++
++config ETRAX_SERIAL_PORT4_TYPE_485HD
++ bool "Ser4 is a half duplex RS-485 port"
++ depends on ETRAX_RS485
++ help
++ Configure serial port 4 to be a half duplex (two wires) RS-485 port.
++
++config ETRAX_SERIAL_PORT4_TYPE_485FD
++ bool "Ser4 is a full duplex RS-485 port"
++ depends on ETRAX_RS485
++ help
++ Configure serial port 4 to be a full duplex (four wires) RS-485 port.
++endchoice
++
++choice
++ prompt "Ser4 DMA in channel "
++ depends on ETRAX_SERIAL_PORT4
++ default ETRAX_SERIAL_PORT4_NO_DMA_IN
++ help
++ What DMA channel to use for ser4.
++
++
++config ETRAX_SERIAL_PORT4_NO_DMA_IN
++ bool "Ser4 uses no DMA for input"
++ help
++ Do not use DMA for ser4 input.
++
++config ETRAX_SERIAL_PORT4_DMA9_IN
++ bool "Ser4 uses DMA9 for input"
++ depends on ETRAX_SERIAL_PORT4
++ help
++ Enables the DMA9 input channel for ser4 (ttyS4).
++ If you do not enable DMA, an interrupt for each character will be
++ used when receiving data.
++ Normally you want to use DMA, unless you use the DMA channel for
++ something else.
++
++endchoice
++
++config ETRAX_SER4_DTR_BIT
++ string "Ser 4 DTR bit (empty = not used)"
++ depends on ETRAX_SERIAL_PORT4
++
++config ETRAX_SER4_RI_BIT
++ string "Ser 4 RI bit (empty = not used)"
++ depends on ETRAX_SERIAL_PORT4
++
++config ETRAX_SER4_DSR_BIT
++ string "Ser 4 DSR bit (empty = not used)"
++ depends on ETRAX_SERIAL_PORT4
++
++config ETRAX_SER4_CD_BIT
++ string "Ser 4 CD bit (empty = not used)"
++ depends on ETRAX_SERIAL_PORT4
++
+ config ETRAX_SYNCHRONOUS_SERIAL
+ bool "Synchronous serial-port support"
+ depends on ETRAX_ARCH_V32
+diff -Nur linux-4.0.3.orig/arch/cris/include/uapi/asm/ioctls.h linux-4.0.3/arch/cris/include/uapi/asm/ioctls.h
+--- linux-4.0.3.orig/arch/cris/include/uapi/asm/ioctls.h 2015-05-13 14:14:53.000000000 +0200
++++ linux-4.0.3/arch/cris/include/uapi/asm/ioctls.h 2015-05-25 17:20:56.000000000 +0200
+@@ -5,6 +5,10 @@
+ #define TIOCSERSETRS485 0x5461 /* enable rs-485 (deprecated) */
+ #define TIOCSERWRRS485 0x5462 /* write rs-485 */
+ #define TIOCSRS485 0x5463 /* enable rs-485 */
++#define TIOCSERSETRS485FD 0x5464 /* set rs-485 full/half duplex mode */
++
++
++#define TIOCSERSETDIVISOR 0x5465 /* set the divisor for non standard bauds */
+
+ #include <asm-generic/ioctls.h>
+
+diff -Nur linux-4.0.3.orig/drivers/tty/serial/crisv32.c linux-4.0.3/drivers/tty/serial/crisv32.c
+--- linux-4.0.3.orig/drivers/tty/serial/crisv32.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.0.3/drivers/tty/serial/crisv32.c 2015-05-25 17:20:56.000000000 +0200
+@@ -0,0 +1,2581 @@
++/* $Id: crisv32.c,v 1.109 2010-07-09 15:00:44 jespern Exp $
++ *
++ * Serial port driver for the ETRAX FS chip
++ *
++ * Copyright (C) 1998-2006 Axis Communications AB
++ *
++ * Many, many authors. Based once upon a time on serial.c for 16x50.
++ *
++ * Johan Adolfsson - port to ETRAX FS
++ * Mikael Starvik - port to serial_core framework
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/console.h>
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/serial_core.h>
++#include <linux/delay.h>
++#include <linux/slab.h>
++#include <linux/tty_flip.h>
++
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/uaccess.h>
++
++#include <dma.h>
++#include <arch/system.h>
++#include <mach/pinmux.h>
++#include <hwregs/dma.h>
++#include <hwregs/reg_rdwr.h>
++#include <hwregs/ser_defs.h>
++#include <hwregs/dma_defs.h>
++#include <hwregs/gio_defs.h>
++#include <hwregs/intr_vect_defs.h>
++#include <hwregs/reg_map.h>
++
++#define UART_NR CONFIG_ETRAX_SERIAL_PORTS + 1 /* Ports + dummy port */
++#define SERIAL_RECV_DESCRIPTORS 8
++
++/* We only buffer 255 characters here, no need for more tx descriptors. */
++#define SERIAL_TX_DESCRIPTORS 4
++
++/* Kept for experimental purposes. */
++#define SERIAL_DESCR_BUF_SIZE 256
++#define regi_NULL 0
++#define DMA_WAIT_UNTIL_RESET(inst) \
++ do { \
++ reg_dma_rw_stat r; \
++ do { \
++ r = REG_RD(dma, (inst), rw_stat); \
++ } while (r.mode != regk_dma_rst); \
++ } while (0)
++
++#define __DMA(ch) regi_dma##ch
++#define DMA(ch) __DMA(ch)
++#define DMA_IRQ(ch) (DMA0_INTR_VECT + (ch))
++
++/* Macro to set up control lines for a port. */
++#define SETUP_PINS(port) \
++ if (serial_cris_ports[port].used) { \
++ if (strcmp(CONFIG_ETRAX_SER##port##_DTR_BIT, "")) \
++ crisv32_io_get_name(&serial_cris_ports[port].dtr_pin, \
++ CONFIG_ETRAX_SER##port##_DTR_BIT); \
++ else \
++ serial_cris_ports[port].dtr_pin = dummy_pin; \
++ if (strcmp(CONFIG_ETRAX_SER##port##_DSR_BIT, "")) \
++ crisv32_io_get_name(&serial_cris_ports[port].dsr_pin, \
++ CONFIG_ETRAX_SER##port##_DSR_BIT); \
++ else \
++ serial_cris_ports[port].dsr_pin = dummy_pin; \
++ if (strcmp(CONFIG_ETRAX_SER##port##_RI_BIT, "")) \
++ crisv32_io_get_name(&serial_cris_ports[port].ri_pin, \
++ CONFIG_ETRAX_SER##port##_RI_BIT); \
++ else \
++ serial_cris_ports[port].ri_pin = dummy_pin; \
++ if (strcmp(CONFIG_ETRAX_SER##port##_CD_BIT, "")) \
++ crisv32_io_get_name(&serial_cris_ports[port].cd_pin, \
++ CONFIG_ETRAX_SER##port##_CD_BIT); \
++ else \
++ serial_cris_ports[port].cd_pin = dummy_pin; \
++ }
++
++/* Set a serial port register if anything has changed. */
++#define MODIFY_REG(instance, reg, var) \
++ if (REG_RD_INT(ser, instance, reg) \
++ != REG_TYPE_CONV(int, reg_ser_##reg, var)) \
++ REG_WR(ser, instance, reg, var);
++
++/*
++ * Regarding RS485 operation in crisv32 serial driver.
++ * ---------------------------------------------------
++ * RS485 can be run in two modes, full duplex using four wires (485FD) and
++ * half duplex using two wires (485HD). The default mode of each serial port
++ * is configured in the kernel configuration. The available modes are:
++ * RS-232, RS-485 half duplex, and RS-485 full duplex.
++ *
++ * In the 485HD mode the direction of the data bus must be able to switch.
++ * The direction of the transceiver is controlled by the RTS signal. Hence
++ * the auto_rts function in the ETRAX FS chip is enabled in this mode, which
++ * automatically toggle RTS when transmitting. The initial direction of the
++ * port is receiving.
++ *
++ * In the 485FD mode two transceivers will be used, one in each direction.
++ * Usually the hardware can handle both 485HD and 485FD, which implies that
++ * one of the transceivers can change direction. Consequently that transceiver
++ * must be tied to operate in the opposite direction of the other one, setting
++ * and keeping RTS to a fixed value do this.
++ *
++ * There are two special "ioctl" that can configure the ports. These two are
++ * left for backward compatible with older applications. The effects of using
++ * them are described below:
++ * The TIOCSERSETRS485:
++ * This ioctl sets a serial port in 232 mode to 485HD mode or vise versa. The
++ * state of the port is kept when closing the port. Note that this ioctl has no
++ * effect on a serial port in the 485FD mode.
++ * The TIOCSERWRRS485:
++ * This ioctl set a serial port in 232 mode to 485HD mode and writes the data
++ * "included" in the ioctl to the port. The port will then stay in 485HD mode.
++ * Using this ioctl on a serial port in the 485HD mode will transmit the data
++ * without changing the mode. Using this ioctl on a serial port in 485FD mode
++ * will not change the mode and simply send the data using the 485FD mode.
++ */
++
++#define TYPE_232 0
++#define TYPE_485HD 1
++#define TYPE_485FD 2
++
++struct etrax_recv_buffer {
++ struct etrax_recv_buffer *next;
++ unsigned short length;
++ unsigned char error;
++ unsigned char pad;
++
++ unsigned char buffer[0];
++};
++
++struct uart_cris_port {
++ struct uart_port port;
++
++ int initialized;
++ int used;
++ int irq;
++
++ /* Used to check if port enabled as well by testing for zero. */
++ reg_scope_instances regi_ser;
++ reg_scope_instances regi_dmain;
++ reg_scope_instances regi_dmaout;
++
++ struct crisv32_iopin dtr_pin;
++ struct crisv32_iopin dsr_pin;
++ struct crisv32_iopin ri_pin;
++ struct crisv32_iopin cd_pin;
++
++ struct dma_descr_context tr_context_descr
++ __attribute__ ((__aligned__(32)));
++ struct dma_descr_data tr_descr[SERIAL_TX_DESCRIPTORS]
++ __attribute__ ((__aligned__(32)));
++ struct dma_descr_context rec_context_descr
++ __attribute__ ((__aligned__(32)));
++ struct dma_descr_data rec_descr[SERIAL_RECV_DESCRIPTORS]
++ __attribute__ ((__aligned__(32)));
++
++ /* This is the first one in the list the HW is working on now. */
++ struct dma_descr_data* first_tx_descr;
++
++ /* This is the last one in the list the HW is working on now. */
++ struct dma_descr_data* last_tx_descr;
++
++ /* This is how many characters the HW is working on now. */
++ unsigned int tx_pending_chars;
++
++ int tx_started;
++ unsigned int cur_rec_descr;
++ struct etrax_recv_buffer *first_recv_buffer;
++ struct etrax_recv_buffer *last_recv_buffer;
++
++ unsigned int recv_cnt;
++ unsigned int max_recv_cnt;
++
++ /* The time for 1 char, in usecs. */
++ unsigned long char_time_usec;
++
++ /* Last tx usec in the jiffies. */
++ unsigned long last_tx_active_usec;
++
++ /* Last tx time in jiffies. */
++ unsigned long last_tx_active;
++
++ /* Last rx usec in the jiffies. */
++ unsigned long last_rx_active_usec;
++
++ /* Last rx time in jiffies. */
++ unsigned long last_rx_active;
++
++#ifdef CONFIG_ETRAX_RS485
++ /* RS-485 support, duh. */
++ struct rs485_control rs485;
++#endif
++ int port_type;
++ int write_ongoing;
++};
++
++extern struct uart_driver serial_cris_driver;
++static struct uart_port *console_port;
++static int console_baud = 115200;
++static struct uart_cris_port serial_cris_ports[UART_NR] = {
++{
++#ifdef CONFIG_ETRAX_SERIAL_PORT0
++ .used = 1,
++ .irq = SER0_INTR_VECT,
++ .regi_ser = regi_ser0,
++ /*
++ * We initialize the dma stuff like this to get a compiler error
++ * if a CONFIG is missing
++ */
++ .regi_dmain =
++# ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN
++ regi_dma7,
++# elif defined(CONFIG_ETRAX_SERIAL_PORT0_DMA1_IN)
++ regi_dma1,
++# elif defined CONFIG_ETRAX_SERIAL_PORT0_NO_DMA_IN
++ regi_NULL,
++# endif
++
++ .regi_dmaout =
++# ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT
++ regi_dma6,
++# elif defined(CONFIG_ETRAX_SERIAL_PORT0_DMA7_OUT)
++ regi_dma7,
++# else
++ regi_NULL,
++# endif
++
++# ifdef CONFIG_ETRAX_RS485
++# ifdef CONFIG_ETRAX_SERIAL_PORT0_TYPE_485HD
++ .port_type = TYPE_485HD,
++# endif
++# ifdef CONFIG_ETRAX_SERIAL_PORT0_TYPE_485FD
++ .port_type = TYPE_485FD,
++# endif
++# endif
++#else
++ .regi_ser = regi_NULL,
++ .regi_dmain = regi_NULL,
++ .regi_dmaout = regi_NULL,
++#endif
++ .write_ongoing = 0
++}, /* ttyS0 */
++{
++#ifdef CONFIG_ETRAX_SERIAL_PORT1
++ .used = 1,
++ .irq = SER1_INTR_VECT,
++ .regi_ser = regi_ser1,
++ .regi_dmain =
++# ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA5_IN
++ regi_dma5,
++# elif defined(CONFIG_ETRAX_SERIAL_PORT1_NO_DMA_IN)
++ regi_NULL,
++# endif
++
++ .regi_dmaout =
++# ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA4_OUT
++ regi_dma4,
++# elif defined(CONFIG_ETRAX_SERIAL_PORT1_NO_DMA_OUT)
++ regi_NULL,
++# endif
++
++# ifdef CONFIG_ETRAX_RS485
++# ifdef CONFIG_ETRAX_SERIAL_PORT1_TYPE_485HD
++ .port_type = TYPE_485HD,
++# endif
++# ifdef CONFIG_ETRAX_SERIAL_PORT1_TYPE_485FD
++ .port_type = TYPE_485FD,
++# endif
++# endif
++#else
++ .regi_ser = regi_NULL,
++ .regi_dmain = regi_NULL,
++ .regi_dmaout = regi_NULL,
++#endif
++ .write_ongoing = 0
++}, /* ttyS1 */
++{
++#ifdef CONFIG_ETRAX_SERIAL_PORT2
++ .used = 1,
++ .irq = SER2_INTR_VECT,
++ .regi_ser = regi_ser2,
++ .regi_dmain =
++# ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN
++ regi_dma3,
++# elif defined(CONFIG_ETRAX_SERIAL_PORT2_DMA7_IN)
++ regi_dma7,
++# elif defined(CONFIG_ETRAX_SERIAL_PORT2_NO_DMA_IN)
++ regi_NULL,
++# endif
++
++ .regi_dmaout =
++# ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT
++ regi_dma2,
++# elif defined(CONFIG_ETRAX_SERIAL_PORT2_DMA6_OUT)
++ regi_dma6,
++# elif defined(CONFIG_ETRAX_SERIAL_PORT2_NO_DMA_OUT)
++ regi_NULL,
++# endif
++
++# ifdef CONFIG_ETRAX_RS485
++# ifdef CONFIG_ETRAX_SERIAL_PORT2_TYPE_485HD
++ .port_type = TYPE_485HD,
++# endif
++# ifdef CONFIG_ETRAX_SERIAL_PORT2_TYPE_485FD
++ .port_type = TYPE_485FD,
++# endif
++# endif
++#else
++ .regi_ser = regi_NULL,
++ .regi_dmain = regi_NULL,
++ .regi_dmaout = regi_NULL,
++#endif
++ .write_ongoing = 0
++}, /* ttyS2 */
++{
++#ifdef CONFIG_ETRAX_SERIAL_PORT3
++ .used = 1,
++ .irq = SER3_INTR_VECT,
++ .regi_ser = regi_ser3,
++ .regi_dmain =
++# ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA9_IN
++ regi_dma9,
++# elif defined(CONFIG_ETRAX_SERIAL_PORT3_DMA4_IN)
++ regi_dma3,
++# else
++ regi_NULL,
++# endif
++
++ .regi_dmaout =
++# ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA8_OUT
++ regi_dma8,
++# elif defined(CONFIG_ETRAX_SERIAL_PORT3_DMA2_OUT)
++ regi_dma2,
++# else
++ regi_NULL,
++# endif
++# ifdef CONFIG_ETRAX_RS485
++# ifdef CONFIG_ETRAX_SERIAL_PORT3_TYPE_485HD
++ .port_type = TYPE_485HD,
++# endif
++# ifdef CONFIG_ETRAX_SERIAL_PORT3_TYPE_485FD
++ .port_type = TYPE_485FD,
++# endif
++# endif
++#else
++ .regi_ser = regi_NULL,
++ .regi_dmain = regi_NULL,
++ .regi_dmaout = regi_NULL,
++#endif
++ .write_ongoing = 0
++}, /* ttyS3 */
++#if CONFIG_ETRAX_SERIAL_PORTS == 5
++{
++#ifdef CONFIG_ETRAX_SERIAL_PORT4
++ .used = 1,
++ .irq = SER4_INTR_VECT,
++ .regi_ser = regi_ser4,
++ .regi_dmain =
++# ifdef CONFIG_ETRAX_SERIAL_PORT4_DMA9_IN
++ regi_dma9,
++# else
++ regi_NULL,
++# endif
++
++ .regi_dmaout = regi_NULL,
++# ifdef CONFIG_ETRAX_RS485
++# ifdef CONFIG_ETRAX_SERIAL_PORT4_TYPE_485HD
++ .port_type = TYPE_485HD,
++# endif
++# ifdef CONFIG_ETRAX_SERIAL_PORT4_TYPE_485FD
++ .port_type = TYPE_485FD,
++# endif
++# endif
++#else
++ .regi_ser = regi_NULL,
++ .regi_dmain = regi_NULL,
++ .regi_dmaout = regi_NULL,
++#endif
++ .write_ongoing = 0
++}, /* ttyS4 */
++#endif
++{
++#ifdef CONFIG_ETRAX_DEBUG_PORT_NULL
++ .used = 1,
++#endif
++ .regi_ser = regi_NULL,
++ .write_ongoing = 0
++} /* Dummy console port */
++
++};
++
++/* Dummy pin used for unused CD, DSR, DTR and RI signals. */
++static unsigned long io_dummy;
++static struct crisv32_ioport dummy_port =
++{
++ &io_dummy,
++ &io_dummy,
++ &io_dummy,
++ 32
++};
++static struct crisv32_iopin dummy_pin =
++{
++ &dummy_port,
++ 0
++};
++
++static int selected_console =
++#if defined(CONFIG_ETRAX_DEBUG_PORT0)
++0;
++#elif defined(CONFIG_ETRAX_DEBUG_PORT1)
++1;
++#elif defined(CONFIG_ETRAX_DEBUG_PORT2)
++2;
++#elif defined(CONFIG_ETRAX_DEBUG_PORT3)
++3;
++#elif defined(CONFIG_ETRAX_DEBUG_PORT4)
++4;
++#else /* CONFIG_ETRAX_DEBUG_PORT_NULL */
++#if CONFIG_ETRAX_SERIAL_PORTS == 5
++5;
++#else
++4;
++#endif
++#endif
++
++extern void reset_watchdog(void);
++
++static void serial_cris_stop_rx(struct uart_port *port);
++
++/*
++ * Interrupts are disabled on entering
++ */
++#ifndef CONFIG_ETRAX_VCS_SIM
++static void
++cris_console_write(struct console *co, const char *s, unsigned int count)
++{
++ struct uart_cris_port *up;
++ int i;
++ reg_ser_r_stat_din stat;
++ reg_ser_rw_tr_dma_en tr_dma_en, old;
++
++ up = &serial_cris_ports[selected_console];
++
++ /*
++ * This function isn't covered by the struct uart_ops, so we
++ * have to check manually that the port really is there,
++ * configured and live.
++ */
++ if (!up->regi_ser)
++ return;
++
++ /* Switch to manual mode. */
++ tr_dma_en = old = REG_RD (ser, up->regi_ser, rw_tr_dma_en);
++ if (tr_dma_en.en == regk_ser_yes) {
++ tr_dma_en.en = regk_ser_no;
++ REG_WR(ser, up->regi_ser, rw_tr_dma_en, tr_dma_en);
++ }
++
++ /* Send data. */
++ for (i = 0; i < count; i++) {
++ /* LF -> CRLF */
++ if (s[i] == '\n') {
++ do {
++ stat = REG_RD (ser, up->regi_ser, r_stat_din);
++ } while (!stat.tr_rdy);
++ REG_WR_INT (ser, up->regi_ser, rw_dout, '\r');
++ }
++ /* Wait until transmitter is ready and send. */
++ do {
++ stat = REG_RD (ser, up->regi_ser, r_stat_din);
++ } while (!stat.tr_rdy);
++ REG_WR_INT (ser, up->regi_ser, rw_dout, s[i]);
++
++ /* Feed watchdog, because this may take looong time. */
++ reset_watchdog();
++ }
++
++ /* Restore mode. */
++ if (tr_dma_en.en != old.en)
++ REG_WR(ser, up->regi_ser, rw_tr_dma_en, old);
++}
++#else
++
++extern void print_str( const char *str );
++static char buffer[1024];
++static char msg[] = "Debug: ";
++static int buffer_pos = sizeof(msg) - 1;
++
++static void
++cris_console_write(struct console *co, const char *buf, unsigned int len)
++{
++ char* pos;
++ pos = memchr(buf, '\n', len);
++ if (pos) {
++ int l = ++pos - buf;
++ memcpy(buffer + buffer_pos, buf, l);
++ memcpy(buffer, msg, sizeof(msg) - 1);
++ buffer[buffer_pos + l] = '\0';
++ print_str(buffer);
++ buffer_pos = sizeof(msg) - 1;
++ if (pos - buf != len) {
++ memcpy(buffer + buffer_pos, pos, len - l);
++ buffer_pos += len - l;
++ }
++ } else {
++ memcpy(buffer + buffer_pos, buf, len);
++ buffer_pos += len;
++ }
++}
++#endif
++
++static void cris_serial_port_init(struct uart_port *port, int line);
++static int __init
++cris_console_setup(struct console *co, char *options)
++{
++ struct uart_port *port;
++ int baud = 115200;
++ int bits = 8;
++ int parity = 'n';
++ int flow = 'n';
++
++ if (co->index >= UART_NR)
++ co->index = 0;
++ if (options)
++ selected_console = co->index;
++ port = &serial_cris_ports[selected_console].port;
++ console_port = port;
++
++ co->flags |= CON_CONSDEV;
++
++ if (options)
++ uart_parse_options(options, &baud, &parity, &bits, &flow);
++ console_baud = baud;
++ cris_serial_port_init(port, selected_console);
++ co->index = port->line;
++ uart_set_options(port, co, baud, parity, bits, flow);
++
++ return 0;
++}
++
++static struct tty_driver*
++cris_console_device(struct console* co, int *index)
++{
++ struct uart_driver *p = co->data;
++ *index = selected_console;
++ return p->tty_driver;
++}
++
++static struct console cris_console = {
++ .name = "ttyS",
++ .write = cris_console_write,
++ .device = cris_console_device,
++ .setup = cris_console_setup,
++ .flags = CON_PRINTBUFFER,
++ .index = -1,
++ .data = &serial_cris_driver,
++};
++
++#define SERIAL_CRIS_CONSOLE &cris_console
++
++struct uart_driver serial_cris_driver = {
++ .owner = THIS_MODULE,
++ .driver_name = "serial",
++ .dev_name = "ttyS",
++ .major = TTY_MAJOR,
++ .minor = 64,
++ .nr = UART_NR,
++ .cons = SERIAL_CRIS_CONSOLE,
++};
++
++static int inline crisv32_serial_get_rts(struct uart_cris_port *up)
++{
++ reg_scope_instances regi_ser = up->regi_ser;
++ /*
++ * Return what the user has controlled rts to or
++ * what the pin is? (if auto_rts is used it differs during tx)
++ */
++ reg_ser_r_stat_din rstat = REG_RD(ser, regi_ser, r_stat_din);
++ return !(rstat.rts_n == regk_ser_active);
++}
++
++/*
++ * A set = 0 means 3.3V on the pin, bitvalue: 0=active, 1=inactive
++ * 0=0V , 1=3.3V
++ */
++static inline void crisv32_serial_set_rts(struct uart_cris_port *up, int set, int force)
++{
++ reg_scope_instances regi_ser = up->regi_ser;
++
++#ifdef CONFIG_ETRAX_RS485
++ /* Never toggle RTS if port is in 485 mode. If port is in 485FD mode we
++ * do not want to send with the reciever and for 485HD mode auto_rts
++ * take care of the RTS for us.
++ */
++ if (force || !up->rs485.enabled) {
++#else
++ {
++#endif
++ unsigned long flags;
++ reg_ser_rw_rec_ctrl rec_ctrl;
++
++ local_irq_save(flags);
++ rec_ctrl = REG_RD(ser, regi_ser, rw_rec_ctrl);
++
++ if (set)
++ rec_ctrl.rts_n = regk_ser_active;
++ else
++ rec_ctrl.rts_n = regk_ser_inactive;
++ REG_WR(ser, regi_ser, rw_rec_ctrl, rec_ctrl);
++ local_irq_restore(flags);
++ }
++}
++
++/* Input */
++static int inline crisv32_serial_get_cts(struct uart_cris_port *up)
++{
++ reg_scope_instances regi_ser = up->regi_ser;
++ reg_ser_r_stat_din rstat = REG_RD(ser, regi_ser, r_stat_din);
++ return (rstat.cts_n == regk_ser_active);
++}
++
++/*
++ * Send a single character for XON/XOFF purposes. We do it in this separate
++ * function instead of the alternative support port.x_char, in the ...start_tx
++ * function, so we don't mix up this case with possibly enabling transmission
++ * of queued-up data (in case that's disabled after *receiving* an XOFF or
++ * negative CTS). This function is used for both DMA and non-DMA case; see HW
++ * docs specifically blessing sending characters manually when DMA for
++ * transmission is enabled and running. We may be asked to transmit despite
++ * the transmitter being disabled by a ..._stop_tx call so we need to enable
++ * it temporarily but restore the state afterwards.
++ *
++ * Beware: I'm not sure how the RS-485 stuff is supposed to work. Using
++ * XON/XOFF seems problematic if there are several controllers, but if it's
++ * actually RS-422 (multi-drop; one sender and multiple receivers), it might
++ * Just Work, so don't bail out just because it looks a little suspicious.
++ */
++
++void serial_cris_send_xchar(struct uart_port *port, char ch)
++{
++ struct uart_cris_port *up = (struct uart_cris_port *)port;
++ reg_ser_rw_dout dout = { .data = ch };
++ reg_ser_rw_ack_intr ack_intr = { .tr_rdy = regk_ser_yes };
++ reg_ser_r_stat_din rstat;
++ reg_ser_rw_tr_ctrl prev_tr_ctrl, tr_ctrl;
++ reg_scope_instances regi_ser = up->regi_ser;
++ unsigned long flags;
++
++ /*
++ * Wait for tr_rdy in case a character is already being output. Make
++ * sure we have integrity between the register reads and the writes
++ * below, but don't busy-wait with interrupts off and the port lock
++ * taken.
++ */
++ spin_lock_irqsave(&port->lock, flags);
++ do {
++ spin_unlock_irqrestore(&port->lock, flags);
++ spin_lock_irqsave(&port->lock, flags);
++ prev_tr_ctrl = tr_ctrl = REG_RD(ser, regi_ser, rw_tr_ctrl);
++ rstat = REG_RD(ser, regi_ser, r_stat_din);
++ } while (!rstat.tr_rdy);
++
++ /*
++ * Ack an interrupt if one was just issued for the previous character
++ * that was output. This is required for non-DMA as the interrupt is
++ * used as the only indicator that the transmitter is ready and it
++ * isn't while this x_char is being transmitted.
++ */
++ REG_WR(ser, regi_ser, rw_ack_intr, ack_intr);
++
++ /* Enable the transmitter in case it was disabled. */
++ tr_ctrl.stop = 0;
++ REG_WR(ser, regi_ser, rw_tr_ctrl, tr_ctrl);
++
++ /*
++ * Finally, send the blessed character; nothing should stop it now,
++ * except for an xoff-detected state, which we'll handle below.
++ */
++ REG_WR(ser, regi_ser, rw_dout, dout);
++ up->port.icount.tx++;
++
++ /* There might be an xoff state to clear. */
++ rstat = REG_RD(ser, up->regi_ser, r_stat_din);
++
++ /*
++ * Clear any xoff state that *may* have been there to
++ * inhibit transmission of the character.
++ */
++ if (rstat.xoff_detect) {
++ reg_ser_rw_xoff_clr xoff_clr = { .clr = 1 };
++ reg_ser_rw_tr_dma_en tr_dma_en;
++ REG_WR(ser, regi_ser, rw_xoff_clr, xoff_clr);
++ tr_dma_en = REG_RD(ser, regi_ser, rw_tr_dma_en);
++
++ /*
++ * If we had an xoff state but cleared it, instead sneak in a
++ * disabled state for the transmitter, after the character we
++ * sent. Thus we keep the port disabled, just as if the xoff
++ * state was still in effect (or actually, as if stop_tx had
++ * been called, as we stop DMA too).
++ */
++ prev_tr_ctrl.stop = 1;
++
++ tr_dma_en.en = 0;
++ REG_WR(ser, regi_ser, rw_tr_dma_en, tr_dma_en);
++ }
++
++ /* Restore "previous" enabled/disabled state of the transmitter. */
++ REG_WR(ser, regi_ser, rw_tr_ctrl, prev_tr_ctrl);
++
++ spin_unlock_irqrestore(&port->lock, flags);
++}
++
++static void transmit_chars_dma(struct uart_cris_port *up);
++
++/*
++ * Do not spin_lock_irqsave or disable interrupts by other means here; it's
++ * already done by the caller.
++ */
++
++static void serial_cris_start_tx(struct uart_port *port)
++{
++ struct uart_cris_port *up = (struct uart_cris_port *)port;
++ reg_scope_instances regi_ser = up->regi_ser;
++ reg_ser_rw_tr_ctrl tr_ctrl;
++
++ /* we have already done below if a write is ongoing */
++ if (!up->regi_dmaout && up->write_ongoing)
++ return;
++
++#ifdef CONFIG_ETRAX_RS485
++ if (up->rs485.enabled)
++ {
++ /* If we are in RS-485 mode, we need to toggle RTS and disable
++ * the receiver before initiating a DMA transfer
++ */
++
++ if (up->rs485.delay_rts_before_send > 0) {
++ reg_ser_rw_tr_ctrl tr_ctrl = REG_RD(ser, regi_ser, rw_tr_ctrl);
++ tr_ctrl.auto_rts = regk_ser_no;
++ REG_WR(ser, regi_ser, rw_tr_ctrl, tr_ctrl);
++ crisv32_serial_set_rts(up, up->rs485.rts_on_send, 1);
++ msleep(up->rs485.delay_rts_before_send);
++ tr_ctrl.auto_rts =