1590 lines
42 KiB
Diff
1590 lines
42 KiB
Diff
|
|
|
|
From: Masayuki Ohtake <masa-korg@dsn.okisemi.com>
|
|
Subject: OKI Semiconductor PCH UART driver
|
|
|
|
This driver implements UART controls for PCH.
|
|
|
|
Signed-off-by: Masayuki Ohtake <masa-korg@dsn.okisemi.com>
|
|
Acked-by: Wang Qi <qi.wang@intel.com>
|
|
|
|
---
|
|
drivers/serial/8250.c | 8
|
|
drivers/serial/8250_pch.h | 57
|
|
drivers/serial/8250_pci.c |
|
|
drivers/serial/Kconfig | 15
|
|
drivers/serial/Makefile | 11
|
|
+++++++++++++++++++++++++++++++ 5 files changed, zz insertions(+)
|
|
diff -urN linux-2.6.33.1/drivers/serial/8250.c topcliff-2.6.33.1/drivers/serial/8250.c
|
|
--- linux-2.6.33.1/drivers/serial/8250.c 2010-03-16 01:09:39.000000000 +0900
|
|
+++ topcliff-2.6.33.1/drivers/serial/8250.c 2010-03-23 10:34:44.000000000 +0900
|
|
@@ -39,11 +39,19 @@
|
|
#include <linux/nmi.h>
|
|
#include <linux/mutex.h>
|
|
|
|
+#if defined(ENABLE_SERIAL_8250_PCH) && defined(ENABLE_PCH_DMA_FEATURE)
|
|
+/* For using DMA features. */
|
|
+#include <linux/pci.h>
|
|
+#include <linux/pci_ids.h>
|
|
+#include <linux/dma-mapping.h>
|
|
+#include "pch_dma_main.h"
|
|
+#endif
|
|
+
|
|
#include <asm/io.h>
|
|
#include <asm/irq.h>
|
|
|
|
#include "8250.h"
|
|
-
|
|
+#include "8250_pch.h"
|
|
#ifdef CONFIG_SPARC
|
|
#include "suncore.h"
|
|
#endif
|
|
@@ -129,6 +137,18 @@
|
|
static unsigned int probe_rsa_count;
|
|
#endif /* CONFIG_SERIAL_8250_RSA */
|
|
|
|
+#if defined(ENABLE_SERIAL_8250_PCH) && defined(ENABLE_PCH_DMA_FEATURE)
|
|
+/* Structure for storing the DMA channel related information. */
|
|
+struct ioh_dma_feature {
|
|
+ u32 buf;
|
|
+ u32 phy_addr;
|
|
+ s32 channel;
|
|
+ u32 size;
|
|
+};
|
|
+#endif
|
|
+
|
|
+
|
|
+
|
|
struct uart_8250_port {
|
|
struct uart_port port;
|
|
struct timer_list timer; /* "no irq" timer */
|
|
@@ -159,6 +179,17 @@
|
|
*/
|
|
void (*pm)(struct uart_port *port,
|
|
unsigned int state, unsigned int old);
|
|
+
|
|
+#if defined(ENABLE_SERIAL_8250_PCH) && defined(ENABLE_PCH_DMA_FEATURE)
|
|
+ struct ioh_dma_feature rx_dma; /* DMA operation for Receive. */
|
|
+ struct ioh_dma_feature tx_dma; /* DMA operation for Transmit. */
|
|
+ unsigned int buffer; /* The buffer for DMA descriptors.*/
|
|
+ unsigned int buffer_phy; /* The physical address of the buffer.*/
|
|
+ unsigned int dma_flag;/* DMA flag variable for enabling DMA transfer. */
|
|
+ unsigned int rx_fifo_size; /* The UART Rx fifo size.*/
|
|
+ unsigned int dma_progress; /* The DMA in progress flag.*/
|
|
+ unsigned int dma_enabled; /* The DMA enable flag. */
|
|
+#endif
|
|
};
|
|
|
|
struct irq_info {
|
|
@@ -299,6 +330,25 @@
|
|
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00,
|
|
.flags = UART_CAP_FIFO | UART_CAP_AFE,
|
|
},
|
|
+#if defined(ENABLE_SERIAL_8250_PCH)
|
|
+ [PORT_IOH_256FIFO] = {
|
|
+ .name = "IOH_256FIFO",
|
|
+ .fifo_size = 256,
|
|
+ .tx_loadsz = 256,
|
|
+ .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 |
|
|
+ UART_FCR7_256BYTE,
|
|
+ .flags = UART_CAP_FIFO | UART_CAP_AFE,
|
|
+ },
|
|
+
|
|
+ [PORT_IOH_64FIFO] = {
|
|
+ .name = "IOH_64FIFO",
|
|
+ .fifo_size = 64,
|
|
+ .tx_loadsz = 64,
|
|
+ .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 |
|
|
+ UART_FCR7_64BYTE,
|
|
+ .flags = UART_CAP_FIFO | UART_BUG_NOMSR,
|
|
+ },
|
|
+#endif
|
|
};
|
|
|
|
#if defined (CONFIG_SERIAL_8250_AU1X00)
|
|
@@ -383,6 +433,78 @@
|
|
|
|
#endif
|
|
|
|
+
|
|
+#if defined(ENABLE_SERIAL_8250_PCH) && defined(ENABLE_PCH_DMA_FEATURE)
|
|
+
|
|
+/* Function for calculating the Rx FIFO size of the IOH UART. */
|
|
+void get_rx_fifo_size(struct uart_8250_port *up, u8 fcr_value)
|
|
+{
|
|
+ unsigned fifo_size;
|
|
+
|
|
+#ifdef DEBUG
|
|
+ printk(KERN_DEBUG"get_rx_fifo -> The FCR register value: %x.\n",
|
|
+ fcr_value);
|
|
+#endif
|
|
+/* check if the UART is a 64 byte FIFO UART */
|
|
+ if ((up->port.flags & UPF_IOH_UART_64_FIFO) != 0) {
|
|
+ switch ((fcr_value & 0xC0)) {
|
|
+ case 0:
|
|
+ fifo_size = 1;
|
|
+ break;
|
|
+
|
|
+ case 0x40:
|
|
+ fifo_size = 16;
|
|
+ break;
|
|
+
|
|
+ case 0x80:
|
|
+ fifo_size = 32;
|
|
+ break;
|
|
+
|
|
+ case 0xC0:
|
|
+ fifo_size = 56;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ fifo_size = 1;
|
|
+ break;
|
|
+ }
|
|
+ } else {
|
|
+/* UART is 256 byte byte FIFO UART */
|
|
+ switch ((fcr_value & 0xC0)) {
|
|
+ case 0:
|
|
+ fifo_size = 1;
|
|
+ break;
|
|
+
|
|
+ case 0x40:
|
|
+ fifo_size = 64;
|
|
+ break;
|
|
+
|
|
+ case 0x80:
|
|
+ fifo_size = 128;
|
|
+ break;
|
|
+
|
|
+ case 0xC0:
|
|
+ fifo_size = 224;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ fifo_size = 1;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+/* save the fifo size for reference */
|
|
+ up->rx_fifo_size = fifo_size;
|
|
+#ifdef DEBUG
|
|
+ printk(KERN_DEBUG"Function get_rx_fifo_size stores fifo_size as: %u.\n",
|
|
+ fifo_size);
|
|
+#endif
|
|
+}
|
|
+
|
|
+#endif
|
|
+
|
|
+
|
|
+
|
|
+
|
|
static unsigned int hub6_serial_in(struct uart_port *p, int offset)
|
|
{
|
|
offset = map_8250_in_reg(p, offset) << p->regshift;
|
|
@@ -550,15 +672,285 @@
|
|
(up->port.serial_in(&(up)->port, (offset)))
|
|
#define serial_out(up, offset, value) \
|
|
(up->port.serial_out(&(up)->port, (offset), (value)))
|
|
+
|
|
/*
|
|
* We used to support using pause I/O for certain machines. We
|
|
* haven't supported this for a while, but just in case it's badly
|
|
* needed for certain old 386 machines, I've left these #define's
|
|
* in....
|
|
*/
|
|
+
|
|
#define serial_inp(up, offset) serial_in(up, offset)
|
|
#define serial_outp(up, offset, value) serial_out(up, offset, value)
|
|
|
|
+
|
|
+#if defined(ENABLE_SERIAL_8250_PCH) && defined(ENABLE_PCH_DMA_FEATURE)
|
|
+
|
|
+/* DMA TX callback function */
|
|
+void ioh_dma_tx_callback(int status, unsigned long data)
|
|
+{
|
|
+ struct uart_8250_port *up = (struct uart_8250_port *)data;
|
|
+/* struct circ_buf *xmit = &up->port.info->xmit;*/
|
|
+ struct circ_buf *xmit = &up->port.state->xmit;/*for 2.6.33-rc3*/
|
|
+ u8 value;
|
|
+
|
|
+#ifdef DEBUG
|
|
+ if (status == IOH_DMA_END) {
|
|
+ printk(KERN_DEBUG"ioh_dma_tx_callback -> DMA END interrupt\
|
|
+ obtained " \
|
|
+ "for transmission.\n");
|
|
+
|
|
+ }
|
|
+#endif
|
|
+ if (status == IOH_DMA_ABORT) {
|
|
+ printk(KERN_ERR"ioh_dma_tx_callback -> DMA ABORT interrupt\
|
|
+ obtained " \
|
|
+ "for transmission.\n");
|
|
+ }
|
|
+
|
|
+ /* Un-mapping the DMA buffer. */
|
|
+ if (up->tx_dma.phy_addr > 0)
|
|
+ dma_unmap_single(up->port.dev, up->tx_dma.phy_addr,
|
|
+ up->tx_dma.size, DMA_TO_DEVICE);
|
|
+
|
|
+ dma_unmap_single(up->port.dev, up->buffer_phy,
|
|
+ PAGE_SIZE, DMA_TO_DEVICE);
|
|
+
|
|
+ /*Enable TX interrupt.*/
|
|
+ if (uart_circ_chars_pending(xmit)) {
|
|
+ value = (u8)serial_in(up, UART_IER);
|
|
+ serial_out(up, UART_IER, (value | 0x02));
|
|
+ up->ier = serial_in(up, UART_IER);
|
|
+ }
|
|
+#ifdef DEBUG
|
|
+ printk(KERN_DEBUG"Function ioh_dma_tx_callback invoked.\n");
|
|
+#endif
|
|
+}
|
|
+
|
|
+/* Function for DMA setting for Scatter Gather Mode. */
|
|
+void set_scatter_gather_dma_mode(struct uart_8250_port *up, unsigned count)
|
|
+{
|
|
+ u32 in_address;
|
|
+ u32 out_address;
|
|
+ u32 desc_address;
|
|
+ u32 total_desc;
|
|
+ u32 i, j;
|
|
+ u8 value;
|
|
+ struct ioh_dma_desc *desc;
|
|
+ int channel = up->tx_dma.channel;
|
|
+ struct ioh_dma_mode_param mode = {
|
|
+ .TransferDirection = IOH_DMA_DIR_OUT_TO_IN,
|
|
+ .DMASizeType = IOH_DMA_SIZE_TYPE_8BIT,
|
|
+ .DMATransferMode = DMA_SCATTER_GATHER_MODE
|
|
+ };
|
|
+
|
|
+ desc = (struct ioh_dma_desc *)up->tx_dma.buf;
|
|
+
|
|
+ /* Mapping the DMA buffer for transfer. */
|
|
+ out_address = dma_map_single(up->port.dev, (void *)up->buffer,
|
|
+ PAGE_SIZE, DMA_TO_DEVICE);
|
|
+ in_address = up->port.mapbase + (map_8250_in_reg(up, UART_TX));
|
|
+ desc_address = dma_map_single(up->port.dev, (void *)up->tx_dma.buf,
|
|
+ up->tx_dma.size, DMA_TO_DEVICE);
|
|
+ up->buffer_phy = out_address;
|
|
+ up->tx_dma.phy_addr = desc_address;
|
|
+
|
|
+ /* Disable Transmit hardware interrupt.*/
|
|
+ value = (u8)serial_in(up, UART_IER);
|
|
+ serial_out(up, UART_IER, (value & 0xFD));
|
|
+ up->ier = serial_in(up, UART_IER);
|
|
+
|
|
+ total_desc = count/(up->tx_loadsz);
|
|
+
|
|
+ if ((count % (up->tx_loadsz)) > 0)
|
|
+ total_desc++;
|
|
+
|
|
+ dma_sync_single_for_cpu(up->port.dev, desc_address, up->tx_dma.size,
|
|
+ DMA_TO_DEVICE);
|
|
+
|
|
+ /* Organising the DMA descriptors. */
|
|
+ for (i = 0, j = 0; (i < total_desc && count > 0); i++) {
|
|
+ desc[i].insideAddress = in_address;
|
|
+ desc[i].outsideAddress = (out_address + j);
|
|
+
|
|
+ if ((int)(count - (up->tx_loadsz)) > 0) {
|
|
+ desc[i].size = up->tx_loadsz | IOH_DMA_SIZE_TYPE_8BIT;
|
|
+ count = count - (up->tx_loadsz);
|
|
+ j += (up->tx_loadsz);
|
|
+ } else {
|
|
+ desc[i].size = count | IOH_DMA_SIZE_TYPE_8BIT;
|
|
+ j += count;
|
|
+ count = 0;
|
|
+ }
|
|
+
|
|
+ desc[i].nextDesc = ((((u32)((desc_address +
|
|
+ ((i + 1)*(sizeof(struct ioh_dma_desc)))))) & 0xFFFFFFFC) |
|
|
+ DMA_DESC_FOLLOW_WITHOUT_INTERRUPT);
|
|
+ }
|
|
+
|
|
+ desc[i - 1].nextDesc = (DMA_DESC_END_WITH_INTERRUPT);
|
|
+
|
|
+ dma_sync_single_for_device(up->port.dev, desc_address, up->tx_dma.size,
|
|
+ DMA_TO_DEVICE);
|
|
+
|
|
+ /* Initiating the DMA transfer. */
|
|
+ ioh_set_dma_mode(channel, mode);
|
|
+ ioh_set_dma_desc(channel, (struct ioh_dma_desc *)((desc_address &
|
|
+ 0xFFFFFFFC) | DMA_DESC_FOLLOW_WITHOUT_INTERRUPT),\
|
|
+ (((struct ioh_dma_desc *)desc_address) + (total_desc - 1)));
|
|
+ ioh_dma_set_callback(channel, ioh_dma_tx_callback, (u32)up);
|
|
+ ioh_enable_dma(channel);
|
|
+
|
|
+#ifdef DEBUG
|
|
+ printk(KERN_DEBUG"Function set_scatter_gather_dma_mode invoked.\n");
|
|
+#endif
|
|
+}
|
|
+
|
|
+/* Function for DMA settings for ONE SHOT mode. */
|
|
+void set_one_shot_dma_mode(struct uart_8250_port *up, unsigned count)
|
|
+{
|
|
+ u32 in_address;
|
|
+ u32 out_address;
|
|
+ u8 value;
|
|
+ int channel = up->tx_dma.channel;
|
|
+ struct ioh_dma_mode_param mode = {
|
|
+ .TransferDirection = IOH_DMA_DIR_OUT_TO_IN,
|
|
+ .DMASizeType = IOH_DMA_SIZE_TYPE_8BIT,
|
|
+ .DMATransferMode = DMA_ONE_SHOT_MODE
|
|
+ };
|
|
+
|
|
+ /* Disable Receive hardware interrupt.*/
|
|
+ value = (u8)serial_in(up, UART_IER);
|
|
+ serial_out(up, UART_IER, (value & 0xFD));
|
|
+ up->ier = serial_in(up, UART_IER);
|
|
+
|
|
+ /* Mapping the DMA buffer for transfer. */
|
|
+ out_address = dma_map_single(up->port.dev, (void *)up->buffer,
|
|
+ PAGE_SIZE, DMA_TO_DEVICE);
|
|
+ in_address = up->port.mapbase + (map_8250_in_reg(up, UART_TX));
|
|
+ up->buffer_phy = out_address;
|
|
+ up->tx_dma.phy_addr = 0;
|
|
+
|
|
+ /* Initiating the DMA transfer. */
|
|
+ ioh_set_dma_mode(channel, mode);
|
|
+ ioh_set_dma_addr(channel, in_address, out_address);
|
|
+ ioh_set_dma_count(channel, count);
|
|
+ ioh_dma_set_callback(channel, ioh_dma_tx_callback, (u32)up);
|
|
+ ioh_enable_dma(channel);
|
|
+
|
|
+#ifdef DEBUG
|
|
+ printk(KERN_DEBUG"Function set_one_shot_dma_mode invoked.\n");
|
|
+#endif
|
|
+}
|
|
+
|
|
+/* Function for pushing the received characters to tty buffer. */
|
|
+/* At high baud rates tty buffer does not get emptied sufficiently fast
|
|
+ and hence multiple retries are required to push the data into the buffer */
|
|
+
|
|
+static int push_rx(struct tty_struct *tty, const unsigned char *buf, int size)
|
|
+{
|
|
+ u32 sz, i, j;
|
|
+ u32 loop;
|
|
+ u32 pushed;
|
|
+
|
|
+ for (pushed = 0, i = 0, loop = 1; (pushed < size) && loop;
|
|
+ pushed += sz, i++) {
|
|
+ sz = tty_insert_flip_string(tty, &buf[pushed], size - pushed);
|
|
+
|
|
+ for (j = 0; (j < 100000) && (sz == 0); j++) {
|
|
+ tty_flip_buffer_push(tty);
|
|
+ sz = tty_insert_flip_string(tty, &buf[pushed],
|
|
+ size - pushed);
|
|
+ }
|
|
+
|
|
+ if (sz == 0)
|
|
+ loop = 0;
|
|
+
|
|
+ }
|
|
+
|
|
+ tty_flip_buffer_push(tty);
|
|
+
|
|
+#ifdef DEBUG
|
|
+ printk(KERN_DEBUG"push_rx -> %d characters pushed. Remained " \
|
|
+ "%d characters.\n", pushed, size - pushed);
|
|
+ printk(KERN_DEBUG"Function push_rx return %u.\n", pushed);
|
|
+#endif
|
|
+
|
|
+ return pushed;
|
|
+}
|
|
+
|
|
+/* The DMA reception callback function. */
|
|
+void ioh_dma_rx_callback(int status, unsigned long data)
|
|
+{
|
|
+ struct uart_8250_port *up = (struct uart_8250_port *)data;
|
|
+ unsigned fifo_size;
|
|
+ unsigned long flags;
|
|
+ u8 value;
|
|
+
|
|
+ spin_lock_irqsave(&up->port.lock, flags);
|
|
+
|
|
+ /* Normal end. */
|
|
+ if (status == IOH_DMA_END) {
|
|
+ /* Preparing the DMA buffer to be accessed by the CPU*/
|
|
+ dma_sync_single_for_cpu(up->port.dev, up->rx_dma.phy_addr,
|
|
+ up->rx_dma.size, DMA_FROM_DEVICE);
|
|
+
|
|
+#ifdef DEBUG
|
|
+ printk(KERN_DEBUG"ioh_dma_rx_callback -> DMA END interrupt\
|
|
+ obtained for reception.\n");
|
|
+#endif
|
|
+ fifo_size = up->rx_fifo_size;
|
|
+/* push_rx(up->port.info->port.tty, (char *)up->rx_dma.buf,
|
|
+ fifo_size);*/
|
|
+ push_rx(up->port.state->port.tty, (char *)up->rx_dma.buf,
|
|
+ fifo_size); /*for 2.6.33-rc3 */
|
|
+
|
|
+ } else if (status == IOH_DMA_ABORT) { /* DMA abort. */
|
|
+ printk(KERN_ERR"ioh_dma_rx_callback -> DMA ABORT interrupt\
|
|
+ obtained for reception.\n");
|
|
+ }
|
|
+
|
|
+ /* Unmapping the buffer from DMA accesible area. */
|
|
+ dma_unmap_single(up->port.dev, up->rx_dma.phy_addr, up->rx_dma.size,
|
|
+ DMA_FROM_DEVICE);
|
|
+
|
|
+ /*Enable hardware interrupt.*/
|
|
+ value = (u8)serial_in(up, UART_IER);
|
|
+ serial_out(up, UART_IER, (value | 0x01));
|
|
+ up->ier = serial_in(up, UART_IER);
|
|
+ up->dma_progress = 0;
|
|
+
|
|
+ spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+
|
|
+#ifdef DEBUG
|
|
+ printk(KERN_DEBUG"ioh_dma_rx_callback -> Function ioh_dma_rx_callback\
|
|
+ is invoked.\n");
|
|
+#endif
|
|
+}
|
|
+
|
|
+/* For initiating the DMA operation.*/
|
|
+void handle_dma_operation(struct uart_8250_port *up)
|
|
+{
|
|
+ u8 value;
|
|
+ int channel = up->rx_dma.channel;
|
|
+
|
|
+ /* Disable Receive hardware interrupt.*/
|
|
+ value = (u8)serial_in(up, UART_IER);
|
|
+ serial_out(up, UART_IER, (value & 0xFE));
|
|
+ up->ier = serial_in(up, UART_IER);
|
|
+
|
|
+ /* Enabling the DMA transfer. */
|
|
+ ioh_enable_dma(channel);
|
|
+ up->dma_progress = 1;
|
|
+
|
|
+#ifdef DEBUG
|
|
+ printk(KERN_DEBUG"handle_dma_operation -> DMA settings for reception\
|
|
+ completed.\n");
|
|
+ printk(KERN_DEBUG"Function handle_dma_operation invoked.\n");
|
|
+#endif
|
|
+}
|
|
+#endif /*for 2.6.33-rc3 */
|
|
+
|
|
/* Uart divisor latch read */
|
|
static inline int _serial_dl_read(struct uart_8250_port *up)
|
|
{
|
|
@@ -725,7 +1117,8 @@
|
|
result = !(mode & UART_RSA_MSR_FIFO);
|
|
|
|
if (!result) {
|
|
- serial_outp(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO);
|
|
+ serial_outp(up, UART_RSA_MSR,
|
|
+ mode & ~UART_RSA_MSR_FIFO);
|
|
mode = serial_inp(up, UART_RSA_MSR);
|
|
result = !(mode & UART_RSA_MSR_FIFO);
|
|
}
|
|
@@ -1040,6 +1433,18 @@
|
|
return;
|
|
}
|
|
|
|
+#if defined(ENABLE_SERIAL_8250_PCH)
|
|
+ if ((up->port.flags & UPF_IOH_UART) != 0) {
|
|
+ if ((up->port.flags & UPF_IOH_UART_64_FIFO) != 0)
|
|
+ /* IOH 2 Line 64 FIFO UART */
|
|
+ up->port.type = PORT_IOH_64FIFO;
|
|
+ else
|
|
+ /* IOH 8 Line 256 FIFO UART */
|
|
+ up->port.type = PORT_IOH_256FIFO;
|
|
+
|
|
+ }
|
|
+#endif
|
|
+
|
|
/*
|
|
* Try writing and reading the UART_IER_UUE bit (b6).
|
|
* If it works, this is probably one of the Xscale platform's
|
|
@@ -1093,7 +1498,7 @@
|
|
return;
|
|
|
|
DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04lx, 0x%p): ",
|
|
- serial_index(&up->port), up->port.iobase, up->port.membase);
|
|
+ serial_index(&up->port), up->port.iobase, up->port.membase);
|
|
|
|
/*
|
|
* We really do need global IRQs disabled here - we're going to
|
|
@@ -1196,7 +1601,34 @@
|
|
up->port.type = PORT_16550;
|
|
break;
|
|
case 3:
|
|
- autoconfig_16550a(up);
|
|
+#ifdef ENABLE_SERIAL_8250_PCH
|
|
+ if ((up->port.type != PORT_IOH_256FIFO) &&
|
|
+ (up->port.type != PORT_IOH_64FIFO)) {
|
|
+#endif
|
|
+
|
|
+#ifdef DEBUG
|
|
+ printk(KERN_DEBUG
|
|
+ "IOH UART LOG:function autoconfig->autoconfig_16550a\
|
|
+ invoked "
|
|
+ "for port %d\n", up->port.type);
|
|
+#endif
|
|
+ autoconfig_16550a(up);
|
|
+
|
|
+#ifdef ENABLE_SERIAL_8250_PCH
|
|
+ }
|
|
+#endif
|
|
+
|
|
+#ifdef ENABLE_SERIAL_8250_PCH
|
|
+ else {
|
|
+
|
|
+#ifdef DEBUG
|
|
+ printk(KERN_DEBUG
|
|
+ "IOH UART LOG:function autoconfig->autoconfig_16550a\
|
|
+ not "
|
|
+ "invoked for IOH UART port %d\n", up->port.type);
|
|
+#endif
|
|
+ }
|
|
+#endif
|
|
break;
|
|
}
|
|
|
|
@@ -1224,18 +1656,40 @@
|
|
#endif
|
|
|
|
serial_outp(up, UART_LCR, save_lcr);
|
|
+#ifdef ENABLE_SERIAL_8250_PCH
|
|
+ if ((up->port.type != PORT_IOH_256FIFO) &&
|
|
+ (up->port.type != PORT_IOH_64FIFO)) {
|
|
+ /* autoconfig is not done for ioh uarts.
|
|
+ hence do not report any kernel warning */
|
|
+#endif
|
|
|
|
- if (up->capabilities != uart_config[up->port.type].flags) {
|
|
- printk(KERN_WARNING
|
|
- "ttyS%d: detected caps %08x should be %08x\n",
|
|
- serial_index(&up->port), up->capabilities,
|
|
- uart_config[up->port.type].flags);
|
|
+ if (up->capabilities != uart_config[up->port.type].flags) {
|
|
+ printk(KERN_WARNING "ttyS%d: detected\
|
|
+ caps %08x should be %08x\n",
|
|
+ up->port.line, up->capabilities,
|
|
+ uart_config[up->port.type].flags);
|
|
+ }
|
|
+
|
|
+#ifdef ENABLE_SERIAL_8250_PCH
|
|
}
|
|
+#endif
|
|
|
|
up->port.fifosize = uart_config[up->port.type].fifo_size;
|
|
up->capabilities = uart_config[up->port.type].flags;
|
|
up->tx_loadsz = uart_config[up->port.type].tx_loadsz;
|
|
|
|
+#ifdef DEBUG
|
|
+ printk(KERN_DEBUG
|
|
+ "IOH UART LOG:autoconfig: up->port.type = %d, up->port.fifosize =%d,"
|
|
+ "up->capabilities = %x, up->tx_loadsz = %d\n", up->port.type,
|
|
+ up->port.fifosize, up->capabilities, up->tx_loadsz);
|
|
+
|
|
+ printk(KERN_DEBUG
|
|
+ "IOH UART LOG:autoconfig: port.name = %s, port.fcr = %x\n",
|
|
+ uart_config[up->port.type].name, uart_config[up->port.type].fcr);
|
|
+
|
|
+#endif
|
|
+
|
|
if (up->port.type == PORT_UNKNOWN)
|
|
goto out;
|
|
|
|
@@ -1461,7 +1915,11 @@
|
|
static void transmit_chars(struct uart_8250_port *up)
|
|
{
|
|
struct circ_buf *xmit = &up->port.state->xmit;
|
|
- int count;
|
|
+ int count = 0;
|
|
+#if defined(ENABLE_SERIAL_8250_PCH) && defined(ENABLE_PCH_DMA_FEATURE)
|
|
+ unsigned limit = 0;
|
|
+ unsigned size = 0;
|
|
+#endif
|
|
|
|
if (up->port.x_char) {
|
|
serial_outp(up, UART_TX, up->port.x_char);
|
|
@@ -1478,15 +1936,53 @@
|
|
return;
|
|
}
|
|
|
|
+#if defined(ENABLE_SERIAL_8250_PCH) && defined(ENABLE_PCH_DMA_FEATURE)
|
|
+ if (((up->port.flags & UPF_IOH_UART) != 0)) {
|
|
+ size = uart_circ_chars_pending(xmit);
|
|
+
|
|
+ if (size > PAGE_SIZE)
|
|
+ size = PAGE_SIZE;
|
|
+
|
|
+ count = size;
|
|
+ }
|
|
+
|
|
+ else
|
|
+#endif
|
|
count = up->tx_loadsz;
|
|
do {
|
|
+#if defined(ENABLE_SERIAL_8250_PCH) && defined(ENABLE_PCH_DMA_FEATURE)
|
|
+ if ((((up->port.flags & UPF_IOH_UART) != 0)) && (size > 0)) {
|
|
+ ((char *)(up->buffer))[limit] = xmit->buf[xmit->tail];
|
|
+ limit++;
|
|
+
|
|
+ } else
|
|
+#endif
|
|
serial_out(up, UART_TX, xmit->buf[xmit->tail]);
|
|
+
|
|
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
|
up->port.icount.tx++;
|
|
if (uart_circ_empty(xmit))
|
|
break;
|
|
} while (--count > 0);
|
|
|
|
+#if defined(ENABLE_SERIAL_8250_PCH) && defined(ENABLE_PCH_DMA_FEATURE)
|
|
+ if (limit > 0) {
|
|
+ if (limit > up->tx_loadsz) {
|
|
+ set_scatter_gather_dma_mode(up, limit);
|
|
+#ifdef DEBUG
|
|
+ printk(KERN_DEBUG"transmit_chars -> Function\
|
|
+ set_scatter_gather_dma_mode invoked.\n");
|
|
+#endif
|
|
+ } else {
|
|
+ set_one_shot_dma_mode(up, limit);
|
|
+#ifdef DEBUG
|
|
+ printk(KERN_DEBUG"transmit_chars -> Function\
|
|
+ set_one_shot_dma_mode invoked.\n");
|
|
+#endif
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+
|
|
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
|
uart_write_wakeup(&up->port);
|
|
|
|
@@ -1494,6 +1990,10 @@
|
|
|
|
if (uart_circ_empty(xmit))
|
|
__stop_tx(up);
|
|
+
|
|
+#ifdef DEBUG
|
|
+ printk(KERN_DEBUG"Function transmit_chars invoked.\n");
|
|
+#endif
|
|
}
|
|
|
|
static unsigned int check_modem_status(struct uart_8250_port *up)
|
|
@@ -1509,9 +2009,11 @@
|
|
if (status & UART_MSR_DDSR)
|
|
up->port.icount.dsr++;
|
|
if (status & UART_MSR_DDCD)
|
|
- uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
|
|
+ uart_handle_dcd_change(&up->port,
|
|
+ status & UART_MSR_DCD);
|
|
if (status & UART_MSR_DCTS)
|
|
- uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
|
|
+ uart_handle_cts_change(&up->port,
|
|
+ status & UART_MSR_CTS);
|
|
|
|
wake_up_interruptible(&up->port.state->port.delta_msr_wait);
|
|
}
|
|
@@ -1533,13 +2035,36 @@
|
|
|
|
DEBUG_INTR("status = %x...", status);
|
|
|
|
- if (status & (UART_LSR_DR | UART_LSR_BI))
|
|
- receive_chars(up, &status);
|
|
+#if defined(ENABLE_SERIAL_8250_PCH) && defined(ENABLE_PCH_DMA_FEATURE)
|
|
+ if ((up->dma_flag) && (up->dma_enabled)) {
|
|
+ /* If reception has to be done through DMA. */
|
|
+#ifdef DEBUG
|
|
+ printk(KERN_DEBUG"serial8250_handle_port ->\
|
|
+ Proceeding to handle reception " \
|
|
+ "interrupt through DMA operation.\n");
|
|
+#endif
|
|
+ handle_dma_operation(up);
|
|
+ } else {
|
|
+#endif
|
|
+
|
|
+ if ((status & (UART_LSR_DR | UART_LSR_BI))
|
|
+#if defined(ENABLE_SERIAL_8250_PCH) && defined(ENABLE_PCH_DMA_FEATURE)
|
|
+ && (!up->dma_progress)
|
|
+#endif
|
|
+ )
|
|
+ receive_chars(up, &status);
|
|
+#if defined(ENABLE_SERIAL_8250_PCH) && defined(ENABLE_PCH_DMA_FEATURE)
|
|
+ }
|
|
+#endif
|
|
check_modem_status(up);
|
|
if (status & UART_LSR_THRE)
|
|
transmit_chars(up);
|
|
|
|
spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+
|
|
+#ifdef DEBUG
|
|
+ printk(KERN_DEBUG"serial8250_handle_port invoked.\n");
|
|
+#endif
|
|
}
|
|
|
|
/*
|
|
@@ -1575,6 +2100,26 @@
|
|
|
|
iir = serial_in(up, UART_IIR);
|
|
if (!(iir & UART_IIR_NO_INT)) {
|
|
+#if defined(ENABLE_SERIAL_8250_PCH) && defined(ENABLE_PCH_DMA_FEATURE)
|
|
+ /* Determing whether the receive FIFO is full. */
|
|
+ if ((iir & UART_IIR_RDI) && !(iir & 0x8) &&
|
|
+ ((up->port.flags & UPF_IOH_UART) != 0)) {
|
|
+
|
|
+ up->dma_flag = 1;
|
|
+
|
|
+#ifdef DEBUG
|
|
+ printk(KERN_DEBUG"serial8250_interrupt ->\
|
|
+ DMA Mode enabled for reception.\n");
|
|
+#endif
|
|
+ } else {
|
|
+ up->dma_flag = 0;
|
|
+#ifdef DEBUG
|
|
+ printk(KERN_DEBUG"serial8250_interrupt ->\
|
|
+ DMA Mode disabled for reception.\n");
|
|
+#endif
|
|
+ }
|
|
+#endif
|
|
+
|
|
serial8250_handle_port(up);
|
|
|
|
handled = 1;
|
|
@@ -1946,6 +2491,167 @@
|
|
unsigned char lsr, iir;
|
|
int retval;
|
|
|
|
+#if defined(ENABLE_SERIAL_8250_PCH) && defined(ENABLE_PCH_DMA_FEATURE)
|
|
+ /* Initialising the device for DMA support. */
|
|
+ int dma_flag = 0;
|
|
+ up->dma_progress = 0;
|
|
+ up->dma_enabled = 0;
|
|
+
|
|
+ if ((up->port.flags & UPF_IOH_UART) != 0) {
|
|
+ struct pci_dev pdev;
|
|
+
|
|
+/* switch((up->port.flags & 0xE000000))*/
|
|
+ switch ((up->port.flags & (UPF_IOH_UART | UPF_IOH_UART_BIT0 |
|
|
+ UPF_IOH_UART_BIT1))) {
|
|
+ case UPF_IOH_UART0:
|
|
+#ifdef DEBUG
|
|
+ printk(KERN_DEBUG"serial8250_startup ->\
|
|
+ UART0 detected.\n");
|
|
+#endif
|
|
+ pdev.device = PCI_DEVICE_ID_IOH_UART0;
|
|
+ up->port.mctrl |= TIOCM_RTS;
|
|
+ break;
|
|
+
|
|
+ case UPF_IOH_UART1:
|
|
+#ifdef DEBUG
|
|
+ printk(KERN_DEBUG"serial8250_startup ->\
|
|
+ UART1 detected.\n");
|
|
+#endif
|
|
+ pdev.device = PCI_DEVICE_ID_IOH_UART1;
|
|
+ break;
|
|
+
|
|
+ case UPF_IOH_UART2:
|
|
+#ifdef DEBUG
|
|
+ printk(KERN_DEBUG"serial8250_startup ->\
|
|
+ UART2 detected.\n");
|
|
+#endif
|
|
+ pdev.device = PCI_DEVICE_ID_IOH_UART2;
|
|
+ break;
|
|
+
|
|
+ case UPF_IOH_UART3:
|
|
+#ifdef DEBUG
|
|
+ printk(KERN_DEBUG"serial8250_startup ->\
|
|
+ UART3 detected.\n");
|
|
+#endif
|
|
+ pdev.device = PCI_DEVICE_ID_IOH_UART3;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ /* Allocating space for DMA buffer. */
|
|
+ up->rx_dma.buf = (u32)__get_free_page(GFP_KERNEL|GFP_DMA);
|
|
+ if (!(up->rx_dma.buf)) {
|
|
+ printk(KERN_ERR"serial8250_startup -> DMA buffer\
|
|
+ allocation " \
|
|
+ "failed for Rx DMA buffer.\n");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ /* For transmission process. */
|
|
+ up->tx_dma.buf = (u32)__get_free_page(GFP_KERNEL|GFP_DMA);
|
|
+ if (!(up->tx_dma.buf)) {
|
|
+ free_page(up->rx_dma.buf);
|
|
+ printk(KERN_ERR"serial8250_startup -> DMA buffer\
|
|
+ allocation " \
|
|
+ "failed for TX DMA buffer.\n");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ /* For copying of transmit data. */
|
|
+ up->buffer = (u32)__get_free_page(GFP_KERNEL|GFP_DMA);
|
|
+ if (!(up->buffer)) {
|
|
+ free_page(up->rx_dma.buf);
|
|
+ free_page(up->tx_dma.buf);
|
|
+ printk(KERN_ERR"serial8250_startup -> DMA buffer\
|
|
+ allocation " \
|
|
+ "failed for Buffer.\n");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ up->rx_dma.size = PAGE_SIZE;
|
|
+ up->tx_dma.size = PAGE_SIZE;
|
|
+
|
|
+ /* Requesting for DMA channel for reception. */
|
|
+ up->rx_dma.channel = ioh_request_dma(&pdev,
|
|
+ IOH_DMA_RX_DATA_REQ0);
|
|
+ if (up->rx_dma.channel < 0) {
|
|
+ free_page(up->rx_dma.buf);
|
|
+ free_page(up->tx_dma.buf);
|
|
+ free_page(up->buffer);
|
|
+ up->rx_dma.buf = 0;
|
|
+ up->tx_dma.buf = 0;
|
|
+ up->buffer = 0;
|
|
+
|
|
+ printk(KERN_ERR"serial8250_startup -> DMA channel\
|
|
+ allocation for " \
|
|
+ "reception failed.\n");
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ /* Requesting DMA channel for transmission. */
|
|
+ up->tx_dma.channel = ioh_request_dma(&pdev,
|
|
+ IOH_DMA_TX_DATA_REQ0);
|
|
+ if (up->tx_dma.channel < 0) {
|
|
+ free_page(up->rx_dma.buf);
|
|
+ free_page(up->tx_dma.buf);
|
|
+ free_page(up->buffer);
|
|
+ up->rx_dma.buf = 0;
|
|
+ up->tx_dma.buf = 0;
|
|
+ up->buffer = 0;
|
|
+ ioh_free_dma(up->rx_dma.channel);
|
|
+
|
|
+ printk(KERN_ERR"serial8250_startup -> DMA channel\
|
|
+ allocation for " \
|
|
+ "transmission failed.\n");
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ /* Performing DMA settings for reception. */
|
|
+ {
|
|
+ u32 in_address;
|
|
+ u32 out_address;
|
|
+ u32 size;
|
|
+ int channel = up->rx_dma.channel;
|
|
+ struct ioh_dma_mode_param mode = {
|
|
+ .TransferDirection = IOH_DMA_DIR_IN_TO_OUT,
|
|
+ .DMASizeType = IOH_DMA_SIZE_TYPE_8BIT,
|
|
+ .DMATransferMode = DMA_ONE_SHOT_MODE
|
|
+ };
|
|
+
|
|
+ /* Mapping the DMA buffer to DMA accessible area and
|
|
+ obtaining its base address. */
|
|
+ out_address = dma_map_single(up->port.dev,
|
|
+ (void *)up->rx_dma.buf,
|
|
+ up->rx_dma.size,
|
|
+ DMA_FROM_DEVICE);
|
|
+ in_address = up->port.mapbase +
|
|
+ (map_8250_in_reg(up, UART_RX));
|
|
+ size = up->rx_fifo_size;
|
|
+ up->rx_dma.phy_addr = out_address;
|
|
+
|
|
+ /* Setting the DMA settings. */
|
|
+ (void)ioh_set_dma_mode(channel, mode);
|
|
+ (void)ioh_set_dma_addr(channel, in_address,
|
|
+ out_address);
|
|
+ (void)ioh_set_dma_count(channel, size);
|
|
+ (void)ioh_dma_set_callback(channel, ioh_dma_rx_callback,
|
|
+ (u32)up);
|
|
+ }
|
|
+
|
|
+ dma_flag = 1;
|
|
+
|
|
+#ifdef DEBUG
|
|
+ printk(KERN_DEBUG"serial8250_startup -> Buffer Allocation\
|
|
+ successful and DMA " \
|
|
+ "channels obtained are Reception: %d\
|
|
+ Transmission: %d.\n", \
|
|
+ up->rx_dma.channel, up->tx_dma.channel);
|
|
+#endif
|
|
+ }
|
|
+#endif
|
|
+
|
|
up->capabilities = uart_config[up->port.type].flags;
|
|
up->mcr = 0;
|
|
|
|
@@ -1996,6 +2702,21 @@
|
|
(serial_inp(up, UART_LSR) == 0xff)) {
|
|
printk(KERN_INFO "ttyS%d: LSR safety check engaged!\n",
|
|
serial_index(&up->port));
|
|
+
|
|
+#if defined(ENABLE_SERIAL_8250_PCH) && defined(ENABLE_PCH_DMA_FEATURE)
|
|
+ /* Releasing the DMA resources on failure.*/
|
|
+ if (dma_flag == 1) {
|
|
+ ioh_free_dma(up->rx_dma.channel);
|
|
+ ioh_free_dma(up->tx_dma.channel);
|
|
+ free_page(up->rx_dma.buf);
|
|
+ free_page(up->tx_dma.buf);
|
|
+ free_page(up->buffer);
|
|
+ up->rx_dma.buf = 0;
|
|
+ up->tx_dma.buf = 0;
|
|
+ up->buffer = 0;
|
|
+ }
|
|
+#endif
|
|
+
|
|
return -ENODEV;
|
|
}
|
|
|
|
@@ -2008,9 +2729,11 @@
|
|
serial_outp(up, UART_LCR, 0xbf);
|
|
|
|
fctr = serial_inp(up, UART_FCTR) & ~(UART_FCTR_RX|UART_FCTR_TX);
|
|
- serial_outp(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_RX);
|
|
+ serial_outp(up, UART_FCTR, fctr | UART_FCTR_TRGD |
|
|
+ UART_FCTR_RX);
|
|
serial_outp(up, UART_TRG, UART_TRG_96);
|
|
- serial_outp(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_TX);
|
|
+ serial_outp(up, UART_FCTR, fctr | UART_FCTR_TRGD |
|
|
+ UART_FCTR_TX);
|
|
serial_outp(up, UART_TRG, UART_TRG_96);
|
|
|
|
serial_outp(up, UART_LCR, 0);
|
|
@@ -2076,8 +2799,22 @@
|
|
mod_timer(&up->timer, jiffies + poll_timeout(up->port.timeout));
|
|
} else {
|
|
retval = serial_link_irq_chain(up);
|
|
- if (retval)
|
|
+ if (retval) {
|
|
+#if defined(ENABLE_SERIAL_8250_PCH) && defined(ENABLE_PCH_DMA_FEATURE)
|
|
+ /* Releasing the DMA resources on failure.*/
|
|
+ if (dma_flag == 1) {
|
|
+ ioh_free_dma(up->rx_dma.channel);
|
|
+ ioh_free_dma(up->tx_dma.channel);
|
|
+ free_page(up->rx_dma.buf);
|
|
+ free_page(up->tx_dma.buf);
|
|
+ free_page(up->buffer);
|
|
+ up->rx_dma.buf = 0;
|
|
+ up->tx_dma.buf = 0;
|
|
+ up->buffer = 0;
|
|
+ }
|
|
+ #endif
|
|
return retval;
|
|
+ }
|
|
}
|
|
|
|
/*
|
|
@@ -2124,7 +2861,8 @@
|
|
if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) {
|
|
if (!(up->bugs & UART_BUG_TXEN)) {
|
|
up->bugs |= UART_BUG_TXEN;
|
|
- pr_debug("ttyS%d - enabling bad tx status workarounds\n",
|
|
+ pr_debug("ttyS%d - enabling bad tx status\
|
|
+ workarounds\n",
|
|
serial_index(port));
|
|
}
|
|
} else {
|
|
@@ -2172,6 +2910,31 @@
|
|
struct uart_8250_port *up = (struct uart_8250_port *)port;
|
|
unsigned long flags;
|
|
|
|
+#if defined(ENABLE_SERIAL_8250_PCH) && defined(ENABLE_PCH_DMA_FEATURE)
|
|
+ /* Releasing the DMA resources on exit.*/
|
|
+ if ((up->port.flags & UPF_IOH_UART) != 0) {
|
|
+ if (up->rx_dma.channel >= 0)
|
|
+ ioh_free_dma(up->rx_dma.channel);
|
|
+ if (up->tx_dma.channel >= 0)
|
|
+ ioh_free_dma(up->tx_dma.channel);
|
|
+
|
|
+ if (up->rx_dma.buf)
|
|
+ free_page(up->rx_dma.buf);
|
|
+ if (up->tx_dma.buf)
|
|
+ free_page(up->tx_dma.buf);
|
|
+ if (up->buffer)
|
|
+ free_page(up->buffer);
|
|
+
|
|
+ up->rx_dma.buf = 0;
|
|
+ up->tx_dma.buf = 0;
|
|
+ up->buffer = 0;
|
|
+
|
|
+#ifdef DEBUG
|
|
+ printk(KERN_DEBUG"serial8250_shutdown -> DMA buffers and\
|
|
+ channels released.\n");
|
|
+#endif
|
|
+ }
|
|
+#endif
|
|
/*
|
|
* Disable interrupts from this port
|
|
*/
|
|
@@ -2214,7 +2977,8 @@
|
|
serial_unlink_irq_chain(up);
|
|
}
|
|
|
|
-static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int baud)
|
|
+static unsigned int serial8250_get_divisor(struct uart_port *port,
|
|
+ unsigned int baud)
|
|
{
|
|
unsigned int quot;
|
|
|
|
@@ -2242,6 +3006,7 @@
|
|
unsigned char cval, fcr = 0;
|
|
unsigned long flags;
|
|
unsigned int baud, quot;
|
|
+ unsigned int bdrate;
|
|
|
|
switch (termios->c_cflag & CSIZE) {
|
|
case CS5:
|
|
@@ -2278,6 +3043,11 @@
|
|
port->uartclk / 16);
|
|
quot = serial8250_get_divisor(port, baud);
|
|
|
|
+#ifdef DEBUG
|
|
+ printk(KERN_DEBUG "IOH UART LOG:max_baud: %d\n,baud :%d\n quot:%d\n"
|
|
+ , max_baud, baud, quot);
|
|
+#endif
|
|
+
|
|
/*
|
|
* Oxford Semi 952 rev B workaround
|
|
*/
|
|
@@ -2285,12 +3055,37 @@
|
|
quot++;
|
|
|
|
if (up->capabilities & UART_CAP_FIFO && up->port.fifosize > 1) {
|
|
- if (baud < 2400)
|
|
+ if (baud < 2400) {
|
|
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
|
|
- else
|
|
- fcr = uart_config[up->port.type].fcr;
|
|
+
|
|
+#ifdef ENABLE_SERIAL_8250_PCH
|
|
+ if ((up->port.flags & UPF_IOH_UART) != 0)
|
|
+ /*This enables 256 byte FIFO
|
|
+ for UART 0.*/
|
|
+ fcr |= UART_FCR7_64BYTE;
|
|
+
|
|
+#endif
|
|
+ } else
|
|
+ fcr = uart_config[up->port.type].fcr;
|
|
}
|
|
|
|
+#if defined(ENABLE_SERIAL_8250_PCH) && defined(ENABLE_PCH_DMA_FEATURE)
|
|
+ /* Deciding whether to use DMA feature or not.*/
|
|
+ if ((baud >= 38400) && ((up->port.flags & UPF_IOH_UART) != 0))
|
|
+ up->dma_enabled = 1;
|
|
+ else
|
|
+ up->dma_enabled = 0;
|
|
+
|
|
+
|
|
+ get_rx_fifo_size(up, fcr);
|
|
+
|
|
+#ifdef DEBUG
|
|
+ printk(KERN_DEBUG"serial8250_set_termios -> The Rx fifo size is: %u\n",
|
|
+ up->rx_fifo_size);
|
|
+#endif
|
|
+
|
|
+#endif
|
|
+
|
|
/*
|
|
* MCR-based auto flow control. When AFE is enabled, RTS will be
|
|
* deasserted when the receive FIFO contains more characters than
|
|
@@ -2409,8 +3204,22 @@
|
|
serial8250_set_mctrl(&up->port, up->port.mctrl);
|
|
spin_unlock_irqrestore(&up->port.lock, flags);
|
|
/* Don't rewrite B0 */
|
|
- if (tty_termios_baud_rate(termios))
|
|
+
|
|
+ bdrate = tty_termios_baud_rate(termios);
|
|
+
|
|
+#ifdef DEBUG
|
|
+ printk(KERN_DEBUG "tty_termios_baud_rate value:%d\n", bdrate);
|
|
+#endif
|
|
+
|
|
+ if (bdrate) {
|
|
tty_termios_encode_baud_rate(termios, baud, baud);
|
|
+
|
|
+#ifdef DEBUG
|
|
+ printk(KERN_DEBUG "termios->c_ispeed:%d\n,\
|
|
+ termios->c_ospeed:%d\n "
|
|
+ , termios->c_ispeed, termios->c_ospeed);
|
|
+#endif
|
|
+ }
|
|
}
|
|
|
|
static void
|
|
@@ -2580,18 +3389,24 @@
|
|
if (ret < 0)
|
|
probeflags &= ~PROBE_RSA;
|
|
|
|
+
|
|
if (up->port.iotype != up->cur_iotype)
|
|
set_io_from_upio(port);
|
|
|
|
+
|
|
if (flags & UART_CONFIG_TYPE)
|
|
autoconfig(up, probeflags);
|
|
+
|
|
if (up->port.type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ)
|
|
autoconfig_irq(up);
|
|
|
|
+
|
|
if (up->port.type != PORT_RSA && probeflags & PROBE_RSA)
|
|
serial8250_release_rsa_resource(up);
|
|
+
|
|
if (up->port.type == PORT_UNKNOWN)
|
|
serial8250_release_std_resource(up);
|
|
+
|
|
}
|
|
|
|
static int
|
|
@@ -2686,6 +3501,7 @@
|
|
up->port.regshift = old_serial_port[i].iomem_reg_shift;
|
|
set_io_from_upio(&up->port);
|
|
up->port.irqflags |= irqflag;
|
|
+
|
|
}
|
|
}
|
|
|
|
@@ -2967,7 +3783,8 @@
|
|
port.irqflags |= irqflag;
|
|
ret = serial8250_register_port(&port);
|
|
if (ret < 0) {
|
|
- dev_err(&dev->dev, "unable to register port at index %d "
|
|
+ dev_err(&dev->dev, "unable to register port at\
|
|
+ index %d "
|
|
"(IO%lx MEM%llx IRQ%d): %d\n", i,
|
|
p->iobase, (unsigned long long)p->mapbase,
|
|
p->irq, ret);
|
|
@@ -3044,7 +3861,8 @@
|
|
*/
|
|
static DEFINE_MUTEX(serial_mutex);
|
|
|
|
-static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *port)
|
|
+static
|
|
+struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *port)
|
|
{
|
|
int i;
|
|
|
|
@@ -3251,7 +4069,8 @@
|
|
" (unsafe)");
|
|
|
|
module_param(nr_uarts, uint, 0644);
|
|
-MODULE_PARM_DESC(nr_uarts, "Maximum number of UARTs supported. (1-" __MODULE_STRING(CONFIG_SERIAL_8250_NR_UARTS) ")");
|
|
+MODULE_PARM_DESC(nr_uarts, "Maximum number of UARTs supported. \
|
|
+ (1-" __MODULE_STRING(CONFIG_SERIAL_8250_NR_UARTS) ")");
|
|
|
|
module_param(skip_txen_test, uint, 0644);
|
|
MODULE_PARM_DESC(skip_txen_test, "Skip checking for the TXEN bug at init time");
|
|
diff -urN linux-2.6.33.1/drivers/serial/8250_pch.h topcliff-2.6.33.1/drivers/serial/8250_pch.h
|
|
--- linux-2.6.33.1/drivers/serial/8250_pch.h 1970-01-01 09:00:00.000000000 +0900
|
|
+++ topcliff-2.6.33.1/drivers/serial/8250_pch.h 2010-03-23 10:34:44.000000000 +0900
|
|
@@ -0,0 +1,57 @@
|
|
+/*!
|
|
+ * @file 8250_pch.h
|
|
+ * @brief Provides the macro definitions used by all files.
|
|
+ * @version 1.0.0.0
|
|
+ * @section
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; version 2 of the License.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * History:
|
|
+ * Copyright (C) 2008 OKI SEMICONDUCTOR Co., LTD.
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * created:
|
|
+ * OKISEMI 03/16/2010
|
|
+ *
|
|
+ */
|
|
+
|
|
+#ifndef __IOH_8250_PCH_H__
|
|
+#define __IOH_8250_PCH_H__
|
|
+
|
|
+#define PORT_IOH_256FIFO 128 /* IOH UART with 256 byte FIFO */
|
|
+#define PORT_IOH_64FIFO 129 /* IOH UART with 64 byte FIFO */
|
|
+
|
|
+/* flags for IOH port detection */
|
|
+/* The below fields are used to identify the IOH UART port 0 to 3 */
|
|
+#define UPF_IOH_UART_BIT0 ((__force upf_t) (1 << 17))
|
|
+#define UPF_IOH_UART_BIT1 ((__force upf_t) (1 << 18))
|
|
+
|
|
+#define UPF_IOH_UART ((__force upf_t) (1 << 19))
|
|
+#define UPF_IOH_UART0 ((UPF_IOH_UART) | (0))
|
|
+#define UPF_IOH_UART1 ((UPF_IOH_UART) | ((__force upf_t) (UPF_IOH_UART_BIT0)))
|
|
+#define UPF_IOH_UART2 ((UPF_IOH_UART) | ((__force upf_t) (UPF_IOH_UART_BIT1)))
|
|
+#define UPF_IOH_UART3 ((UPF_IOH_UART) | ((__force upf_t) (UPF_IOH_UART_BIT0 |\
|
|
+ UPF_IOH_UART_BIT1)))
|
|
+#define UPF_IOH_UART_64_FIFO ((__force upf_t) (UPF_IOH_UART3))
|
|
+
|
|
+#define UART_FCR7_256BYTE 0x20 /* Go into 256 byte FIFO mode (IOH UART) */
|
|
+
|
|
+/* Intel IOH GE UART PCI device IDs */
|
|
+#define PCI_DEVICE_ID_IOH_UART0 (0x8811)
|
|
+#define PCI_DEVICE_ID_IOH_UART1 (0x8812)
|
|
+#define PCI_DEVICE_ID_IOH_UART2 (0x8813)
|
|
+#define PCI_DEVICE_ID_IOH_UART3 (0x8814)
|
|
+
|
|
+#endif
|
|
diff -urN linux-2.6.33.1/drivers/serial/8250_pci.c topcliff-2.6.33.1/drivers/serial/8250_pci.c
|
|
--- linux-2.6.33.1/drivers/serial/8250_pci.c 2010-03-16 01:09:39.000000000 +0900
|
|
+++ topcliff-2.6.33.1/drivers/serial/8250_pci.c 2010-03-23 10:34:44.000000000 +0900
|
|
@@ -14,6 +14,7 @@
|
|
#include <linux/module.h>
|
|
#include <linux/init.h>
|
|
#include <linux/pci.h>
|
|
+#include <linux/pci_ids.h>
|
|
#include <linux/string.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/slab.h>
|
|
@@ -27,7 +28,7 @@
|
|
#include <asm/io.h>
|
|
|
|
#include "8250.h"
|
|
-
|
|
+#include "8250_pch.h"
|
|
#undef SERIAL_DEBUG_PCI
|
|
|
|
/*
|
|
@@ -726,6 +727,87 @@
|
|
#define NI8430_PORTCON 0x0f
|
|
#define NI8430_PORTCON_TXVR_ENABLE (1 << 3)
|
|
|
|
+#if defined(ENABLE_SERIAL_8250_PCH)
|
|
+
|
|
+static int
|
|
+pci_ioh_init(struct pci_dev *dev)
|
|
+{
|
|
+ int retval = 0;
|
|
+
|
|
+#ifdef DEBUG
|
|
+ printk(KERN_DEBUG "IOH UART LOG:function pci_ioh_init invoked \n");
|
|
+
|
|
+ printk(KERN_DEBUG "IOH UART LOG:function pci_ioh_init->pci_enable_wake invoked \n");
|
|
+#endif
|
|
+
|
|
+ /* disable Wake on UART */
|
|
+ pci_enable_wake(dev, PCI_D3hot, 0);
|
|
+
|
|
+#ifdef DEBUG
|
|
+ printk(KERN_DEBUG "IOH UART LOG:function pci_ioh_init return = %d\n",
|
|
+ retval);
|
|
+#endif
|
|
+
|
|
+ return retval;
|
|
+}
|
|
+
|
|
+static int
|
|
+pci_ioh_setup(struct serial_private *priv, const struct pciserial_board *board,
|
|
+ struct uart_port *port, int idx)
|
|
+{
|
|
+ int retval = 1 ;
|
|
+ unsigned int bar = 0;
|
|
+ unsigned int offset = 0;
|
|
+
|
|
+ if (idx == 0) {
|
|
+ /* IOH UART has only 1 channel per device */
|
|
+ switch (priv->dev->device) {
|
|
+ case PCI_DEVICE_ID_IOH_UART0:
|
|
+ port->flags |= UPF_IOH_UART0;
|
|
+ break;
|
|
+
|
|
+ case PCI_DEVICE_ID_IOH_UART1:
|
|
+ port->flags |= UPF_IOH_UART1;
|
|
+ break;
|
|
+
|
|
+ case PCI_DEVICE_ID_IOH_UART2:
|
|
+ port->flags |= UPF_IOH_UART2;
|
|
+ break;
|
|
+
|
|
+ case PCI_DEVICE_ID_IOH_UART3:
|
|
+ port->flags |= UPF_IOH_UART3;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ retval = setup_port(priv, port, bar, offset, board->reg_shift);
|
|
+
|
|
+ #ifdef ENABLE_PCH_DMA_FEATURE
|
|
+ /* Obtaing the Memory Map base for DMA operations. */
|
|
+ port->mapbase = pci_resource_start(priv->dev, 1);
|
|
+ #ifdef DEBUG
|
|
+ printk(KERN_DEBUG"pci_ioh_setup -> The Map Base has been obtained.\n");
|
|
+ #endif
|
|
+ #endif
|
|
+ }
|
|
+
|
|
+
|
|
+#ifdef DEBUG
|
|
+ printk(KERN_DEBUG "pci_ioh_setup -> Function pci_ioh_setup invoked \n");
|
|
+ printk(KERN_DEBUG "pci_ioh_setup -> board.base_baud = %d, flags = %d,\
|
|
+ num_ports = %d,reg_shift = %d\n",
|
|
+ board->base_baud, board->flags,
|
|
+ board->num_ports, board->reg_shift);
|
|
+ printk(KERN_DEBUG "pci_ioh_setup -> port->flags =%x\n", port->flags);
|
|
+ printk(KERN_DEBUG "Function pci_ioh_setup return = %d\n", retval);
|
|
+
|
|
+#endif
|
|
+ return retval;
|
|
+}
|
|
+#endif
|
|
+
|
|
static int
|
|
pci_ni8430_setup(struct serial_private *priv,
|
|
const struct pciserial_board *board,
|
|
@@ -918,7 +1000,8 @@
|
|
(dev->device & 0xF000) != 0xC000)
|
|
return 0;
|
|
|
|
- p = pci_iomap(dev, 0, 5);
|
|
+ /*p = pci_iomap(dev, 0, 5);*/
|
|
+ p = pci_iomap(dev, 1, 5);
|
|
if (p == NULL)
|
|
return -ENOMEM;
|
|
|
|
@@ -1393,6 +1476,43 @@
|
|
.setup = pci_default_setup,
|
|
},
|
|
/*
|
|
+ * IOH UART
|
|
+ */
|
|
+#if defined(ENABLE_SERIAL_8250_PCH)
|
|
+ {
|
|
+ .vendor = PCI_VENDOR_ID_INTEL,
|
|
+ .device = PCI_DEVICE_ID_IOH_UART0,
|
|
+ .subvendor = PCI_ANY_ID,
|
|
+ .subdevice = PCI_ANY_ID,
|
|
+ .init = pci_ioh_init,
|
|
+ .setup = pci_ioh_setup,
|
|
+ },
|
|
+ {
|
|
+ .vendor = PCI_VENDOR_ID_INTEL,
|
|
+ .device = PCI_DEVICE_ID_IOH_UART1,
|
|
+ .subvendor = PCI_ANY_ID,
|
|
+ .subdevice = PCI_ANY_ID,
|
|
+ .init = pci_ioh_init,
|
|
+ .setup = pci_ioh_setup,
|
|
+ },
|
|
+ {
|
|
+ .vendor = PCI_VENDOR_ID_INTEL,
|
|
+ .device = PCI_DEVICE_ID_IOH_UART2,
|
|
+ .subvendor = PCI_ANY_ID,
|
|
+ .subdevice = PCI_ANY_ID,
|
|
+ .init = pci_ioh_init,
|
|
+ .setup = pci_ioh_setup,
|
|
+ },
|
|
+ {
|
|
+ .vendor = PCI_VENDOR_ID_INTEL,
|
|
+ .device = PCI_DEVICE_ID_IOH_UART3,
|
|
+ .subvendor = PCI_ANY_ID,
|
|
+ .subdevice = PCI_ANY_ID,
|
|
+ .init = pci_ioh_init,
|
|
+ .setup = pci_ioh_setup,
|
|
+ },
|
|
+#endif
|
|
+ /*
|
|
* Default "match everything" terminator entry
|
|
*/
|
|
{
|
|
@@ -1571,6 +1691,10 @@
|
|
pbn_ADDIDATA_PCIe_2_3906250,
|
|
pbn_ADDIDATA_PCIe_4_3906250,
|
|
pbn_ADDIDATA_PCIe_8_3906250,
|
|
+#if defined(ENABLE_SERIAL_8250_PCH)
|
|
+ pbn_ioh_uart_8L_256FIFO, /* ioh 8 Line UART with 256 byte FIFO */
|
|
+ pbn_ioh_uart_2L_64FIFO /* ioh 2 Line UART with 64 byte FIFO */
|
|
+#endif
|
|
};
|
|
|
|
/*
|
|
@@ -2228,6 +2352,27 @@
|
|
.uart_offset = 0x200,
|
|
.first_offset = 0x1000,
|
|
},
|
|
+
|
|
+#if defined(ENABLE_SERIAL_8250_PCH)
|
|
+
|
|
+ /*
|
|
+ * IOH UART
|
|
+ */
|
|
+ [pbn_ioh_uart_8L_256FIFO] = {
|
|
+ .flags = FL_BASE0,
|
|
+ .num_ports = 1,
|
|
+ .base_baud = 115200, /* OKISEMI For LSI */
|
|
+ .reg_shift = 0,
|
|
+ },
|
|
+
|
|
+ [pbn_ioh_uart_2L_64FIFO] = {
|
|
+ .flags = FL_BASE0,
|
|
+ .num_ports = 1,
|
|
+ .base_baud = 115200, /* OKISEMI For LSI*/
|
|
+ .reg_shift = 0,
|
|
+ },
|
|
+#endif
|
|
+
|
|
};
|
|
|
|
static const struct pci_device_id softmodem_blacklist[] = {
|
|
@@ -2473,8 +2618,20 @@
|
|
return -EINVAL;
|
|
}
|
|
|
|
+#ifdef DEBUG
|
|
+ printk(KERN_DEBUG "IOH UART LOG:function pciserial_init_one ent->vendor"
|
|
+ " = %x\n, ent->device = %x, ent->driver_data = %ld\n ",
|
|
+ ent->vendor, ent->device, ent->driver_data);
|
|
+#endif
|
|
+
|
|
board = &pci_boards[ent->driver_data];
|
|
|
|
+#ifdef DEBUG
|
|
+ printk(KERN_DEBUG "IOH UART LOG:function pciserial_init_one board->"
|
|
+ "base_baud = %u\n, board->flags = %d, board->num_ports = %d\n "
|
|
+ , board->base_baud, board->flags, board->num_ports);
|
|
+#endif
|
|
+
|
|
rc = pci_enable_device(dev);
|
|
if (rc)
|
|
return rc;
|
|
@@ -2540,6 +2697,17 @@
|
|
if (priv)
|
|
pciserial_suspend_ports(priv);
|
|
|
|
+#if defined(ENABLE_SERIAL_8250_PCH)
|
|
+
|
|
+#ifdef DEBUG
|
|
+ printk(KERN_DEBUG "IOH UART LOG:pciserial_suspend_one->pci_enable_wake"
|
|
+ "invoked \n");
|
|
+#endif
|
|
+
|
|
+
|
|
+ pci_enable_wake(dev, PCI_D3hot, 1);
|
|
+#endif
|
|
+
|
|
pci_save_state(dev);
|
|
pci_set_power_state(dev, pci_choose_state(dev, state));
|
|
return 0;
|
|
@@ -2561,6 +2729,17 @@
|
|
/* FIXME: We cannot simply error out here */
|
|
if (err)
|
|
printk(KERN_ERR "pciserial: Unable to re-enable ports, trying to continue.\n");
|
|
+
|
|
+#if defined(ENABLE_SERIAL_8250_PCH)
|
|
+
|
|
+#ifdef DEBUG
|
|
+ printk(KERN_DEBUG "IOH UART LOG:pciserial_resume_one->pci_enable_wake"
|
|
+ "invoked \n");
|
|
+#endif
|
|
+
|
|
+ pci_enable_wake(dev, PCI_D3hot, 0);
|
|
+#endif
|
|
+
|
|
pciserial_resume_ports(priv);
|
|
}
|
|
return 0;
|
|
@@ -3649,6 +3828,48 @@
|
|
0, 0, pbn_b0_1_115200 },
|
|
|
|
/*
|
|
+ * IOH UART
|
|
+ */
|
|
+#if defined(ENABLE_SERIAL_8250_PCH)
|
|
+
|
|
+ { PCI_VENDOR_ID_INTEL,
|
|
+ /*device id for ioh uart with 8 i/o lines and 256 byte fifo. */
|
|
+ PCI_DEVICE_ID_IOH_UART0,
|
|
+ PCI_ANY_ID,
|
|
+ PCI_ANY_ID,
|
|
+ 0,
|
|
+ 0,
|
|
+ pbn_ioh_uart_8L_256FIFO },
|
|
+
|
|
+ { PCI_VENDOR_ID_INTEL,
|
|
+ /*device id for ioh uart with 2 i/o lines and 256 byte fifo. */
|
|
+ PCI_DEVICE_ID_IOH_UART1,
|
|
+ PCI_ANY_ID,
|
|
+ PCI_ANY_ID,
|
|
+ 0,
|
|
+ 0,
|
|
+ pbn_ioh_uart_2L_64FIFO },
|
|
+
|
|
+ { PCI_VENDOR_ID_INTEL,
|
|
+ /*device id for ioh uart with 8 i/o lines and 64 byte fifo. */
|
|
+ PCI_DEVICE_ID_IOH_UART2,
|
|
+ PCI_ANY_ID,
|
|
+ PCI_ANY_ID,
|
|
+ 0,
|
|
+ 0,
|
|
+ pbn_ioh_uart_2L_64FIFO },
|
|
+
|
|
+ { PCI_VENDOR_ID_INTEL,
|
|
+ /*device id for ioh uart with 2 i/o lines and 64 byte fifo. */
|
|
+ PCI_DEVICE_ID_IOH_UART3,
|
|
+ PCI_ANY_ID,
|
|
+ PCI_ANY_ID,
|
|
+ 0,
|
|
+ 0,
|
|
+ pbn_ioh_uart_2L_64FIFO },
|
|
+#endif
|
|
+
|
|
+ /*
|
|
* These entries match devices with class COMMUNICATION_SERIAL,
|
|
* COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL
|
|
*/
|
|
diff -urN linux-2.6.33.1/drivers/serial/Kconfig topcliff-2.6.33.1/drivers/serial/Kconfig
|
|
--- linux-2.6.33.1/drivers/serial/Kconfig 2010-03-16 01:09:39.000000000 +0900
|
|
+++ topcliff-2.6.33.1/drivers/serial/Kconfig 2010-03-23 10:34:44.000000000 +0900
|
|
@@ -89,6 +89,21 @@
|
|
disable this feature if you only need legacy serial support.
|
|
Saves about 9K.
|
|
|
|
+config SERIAL_8250_PCH
|
|
+ tristate "PCH PCI serial device support"
|
|
+ depends on SERIAL_8250 && PCI && SERIAL_8250_PCI
|
|
+ default SERIAL_8250_PCI
|
|
+ help
|
|
+ This makes the PCH PCI serial driver to support high speed PCH serial ports.
|
|
+
|
|
+config SERIAL_8250_PCH_DMA
|
|
+ bool "Enable DMA mode of PCH PCI serial device"
|
|
+ depends on SERIAL_8250_PCH
|
|
+ select PCH_UART_DMA
|
|
+ default y
|
|
+ help
|
|
+ This makes the PCH PCI serial driver with DMA mode.
|
|
+
|
|
config SERIAL_8250_PNP
|
|
tristate "8250/16550 PNP device support" if EMBEDDED
|
|
depends on SERIAL_8250 && PNP
|
|
diff -urN linux-2.6.33.1/drivers/serial/Makefile topcliff-2.6.33.1/drivers/serial/Makefile
|
|
--- linux-2.6.33.1/drivers/serial/Makefile 2010-03-16 01:09:39.000000000 +0900
|
|
+++ topcliff-2.6.33.1/drivers/serial/Makefile 2010-03-23 10:34:44.000000000 +0900
|
|
@@ -1,6 +1,17 @@
|
|
#
|
|
# Makefile for the kernel serial device drivers.
|
|
#
|
|
+#
|
|
+#This is needed to enable ioh dma#
|
|
+#EXTRA_CFLAGS +=-DENABLE_IOH_DMA_FEATURE
|
|
+ifdef CONFIG_SERIAL_8250_PCH
|
|
+EXTRA_CFLAGS +=-DENABLE_SERIAL_8250_PCH
|
|
+endif
|
|
+
|
|
+ifdef CONFIG_PCH_UART_DMA
|
|
+EXTRA_CFLAGS +=-DENABLE_PCH_DMA_FEATURE
|
|
+EXTRA_CFLAGS +=-Idrivers/dma/pch_dma/
|
|
+endif
|
|
|
|
obj-$(CONFIG_SERIAL_CORE) += serial_core.o
|
|
obj-$(CONFIG_SERIAL_21285) += 21285.o
|