aboutsummaryrefslogtreecommitdiffstats
path: root/recipes-kernel/linux/files/0008-Quark-UART-quark.patch
diff options
context:
space:
mode:
Diffstat (limited to 'recipes-kernel/linux/files/0008-Quark-UART-quark.patch')
-rw-r--r--recipes-kernel/linux/files/0008-Quark-UART-quark.patch909
1 files changed, 480 insertions, 429 deletions
diff --git a/recipes-kernel/linux/files/0008-Quark-UART-quark.patch b/recipes-kernel/linux/files/0008-Quark-UART-quark.patch
index 15b0ffd..336e171 100644
--- a/recipes-kernel/linux/files/0008-Quark-UART-quark.patch
+++ b/recipes-kernel/linux/files/0008-Quark-UART-quark.patch
@@ -1,6 +1,6 @@
From xxxx Mon Sep 17 00:00:00 2001
From: Bryan O'Donoghue <bryan.odonoghue@intel.com>
-Date: Thu, 13 Feb 2014 13:03:44 +0000
+Date: Thu, 24 Apr 2014 13:32:03 +0100
Subject: [PATCH 08/21] Quark UART
---
@@ -8,23 +8,23 @@ Subject: [PATCH 08/21] Quark UART
drivers/dma/Makefile | 1 +
drivers/dma/intel_mid_dma.c | 1460 -----------------------
drivers/dma/intel_mid_dma/Makefile | 3 +
- drivers/dma/intel_mid_dma_core.c | 1295 +++++++++++++++++++++
- drivers/dma/intel_mid_dma_pci.c | 290 +++++
- drivers/dma/intel_mid_dma_regs.h | 107 +--
- drivers/dma/intel_qrk_dma_pci.c | 155 +++
+ drivers/dma/intel_mid_dma_core.c | 1336 ++++++++++++++++++++++
+ drivers/dma/intel_mid_dma_pci.c | 292 +++++
+ drivers/dma/intel_mid_dma_regs.h | 109 +-
+ drivers/dma/intel_qrk_dma_pci.c | 147 +++
drivers/tty/serial/8250/8250.c | 53 +
drivers/tty/serial/8250/8250_pci.c | 52 +-
drivers/tty/serial/Kconfig | 20 +
drivers/tty/serial/Makefile | 1 +
- drivers/tty/serial/intel_quark_uart.c | 2032 +++++++++++++++++++++++++++++++++
- include/linux/intel_mid_dma.h | 186 +++
- 14 files changed, 4099 insertions(+), 1562 deletions(-)
+ drivers/tty/serial/intel_quark_uart.c | 2034 +++++++++++++++++++++++++++++++++
+ include/linux/intel_mid_dma.h | 189 +++
+ 14 files changed, 4147 insertions(+), 1556 deletions(-)
delete mode 100644 drivers/dma/intel_mid_dma.c
create mode 100644 drivers/dma/intel_mid_dma/Makefile
create mode 100644 drivers/dma/intel_mid_dma_core.c
create mode 100644 drivers/dma/intel_mid_dma_pci.c
create mode 100644 drivers/dma/intel_qrk_dma_pci.c
- create mode 100644 drivers/tty/serial/intel_quark_uart.c
+ create mode 100755 drivers/tty/serial/intel_quark_uart.c
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index d4c1218..9867547 100644
@@ -1536,10 +1536,10 @@ index 0000000..6ec8b97
+
diff --git a/drivers/dma/intel_mid_dma_core.c b/drivers/dma/intel_mid_dma_core.c
new file mode 100644
-index 0000000..aeb7fd3
+index 0000000..b869d6c
--- /dev/null
+++ b/drivers/dma/intel_mid_dma_core.c
-@@ -0,0 +1,1295 @@
+@@ -0,0 +1,1336 @@
+/*
+ * intel_mid_dma_core.c - Intel Langwell DMA Drivers
+ *
@@ -1585,13 +1585,6 @@ index 0000000..aeb7fd3
+#define LNW_PERIPHRAL_STATUS 0x0
+#define LNW_PERIPHRAL_MASK 0x8
+
-+#define INFO(_max_chan, _ch_base, _block_size, _pimr_mask) \
-+ ((kernel_ulong_t)&(struct intel_mid_dma_probe_info) { \
-+ .max_chan = (_max_chan), \
-+ .ch_base = (_ch_base), \
-+ .block_size = (_block_size), \
-+ .pimr_mask = (_pimr_mask), \
-+ })
+
+/*****************************************************************************
+Utility Functions*/
@@ -1677,7 +1670,7 @@ index 0000000..aeb7fd3
+ *
+ * UnMasks the DMA periphral interrupt,
+ * this is valid for DMAC1 family controllers only
-+ * This controller should have periphral mask registers already mapped
++ * This controller should have peripheral mask registers already mapped
+ */
+void dmac1_unmask_periphral_intr(struct intel_mid_dma_chan *midc)
+{
@@ -1770,6 +1763,7 @@ index 0000000..aeb7fd3
+ spin_unlock_bh(&midc->lock);
+ }
+}
++
+/**
+ * midc_dostart - begin a DMA transaction
+ * @midc: channel for which txn is to be started
@@ -1790,8 +1784,9 @@ index 0000000..aeb7fd3
+ /* The tasklet will hopefully advance the queue... */
+ return;
+ }
-+ midc->busy = true;
++
+ /*write registers and en*/
++ midc->busy = true;
+ iowrite32(first->sar, midc->ch_regs + SAR);
+ iowrite32(first->dar, midc->ch_regs + DAR);
+ iowrite32(first->lli_phys, midc->ch_regs + LLP);
@@ -1828,7 +1823,6 @@ index 0000000..aeb7fd3
+ dma_cookie_complete(txd);
+ callback_txd = txd->callback;
+ param_txd = txd->callback_param;
-+
+ if (desc->lli != NULL) {
+ /*clear the DONE bit of completed LLI in memory*/
+ llitem = desc->lli + desc->current_lli;
@@ -1857,6 +1851,7 @@ index 0000000..aeb7fd3
+ spin_lock_bh(&midc->lock);
+
+}
++
+/**
+ * midc_scan_descriptors - check the descriptors in channel
+ * mark completed when tx is completete
@@ -1877,7 +1872,8 @@ index 0000000..aeb7fd3
+ midc_descriptor_complete(midc, desc);
+ }
+ return;
-+ }
++}
++
+/**
+ * midc_lli_fill_sg - Helper function to convert
+ * SG list to Linked List Items.
@@ -1923,7 +1919,7 @@ index 0000000..aeb7fd3
+ pr_debug("MDMA: LLI is configured in circular mode\n");
+ lli_next = desc->lli_phys;
+ } else {
-+ lli_next = 0;
++ lli_next = (dma_addr_t)lli_bloc_desc; /* Needs to be !0 */
+ ctl_lo.ctlx.llp_dst_en = 0;
+ ctl_lo.ctlx.llp_src_en = 0;
+ }
@@ -1941,11 +1937,10 @@ index 0000000..aeb7fd3
+ lli_bloc_desc->sar = mids->dma_slave.src_addr;
+ lli_bloc_desc->dar = sg_phy_addr;
+ }
-+ /*Copy values into block descriptor in system memroy*/
++ /*Copy values into block descriptor in system memory*/
+ lli_bloc_desc->llp = lli_next;
+ lli_bloc_desc->ctl_lo = ctl_lo.ctl_lo;
+ lli_bloc_desc->ctl_hi = ctl_hi.ctl_hi;
-+
+ lli_bloc_desc++;
+ }
+ /*Copy very first LLI values to descriptor*/
@@ -2094,7 +2089,6 @@ index 0000000..aeb7fd3
+ return 0;
+}
+
-+
+/**
+ * intel_mid_dma_prep_memcpy - Prep memcpy txn
+ * @chan: chan for DMA transfer
@@ -2131,11 +2125,11 @@ index 0000000..aeb7fd3
+ mids = midc->mid_slave;
+ BUG_ON(!mids);
+
-+ pr_debug("MDMA:called for DMA %x CH %d Length %zu\n",
-+ midc->dma->pci_id, midc->ch_id, len);
-+ pr_debug("MDMA:Cfg passed Mode %x, Dirn %x, HS %x, Width %x\n",
++ pr_debug("MDMA:called for DMA %x CH %d Length %zu src_addr 0x%08x dst 0x%08x\n",
++ midc->dma->pci_id, midc->ch_id, len, (u32)src, (u32)dest);
++ pr_debug("MDMA:Cfg passed Mode %x, Dirn %d, Handshake %s, Width %x\n",
+ mids->cfg_mode, mids->dma_slave.direction,
-+ mids->hs_mode, mids->dma_slave.src_addr_width);
++ mids->hs_mode == LNW_DMA_HW_HS ? "hardware" : "software" , mids->dma_slave.src_addr_width);
+
+ /*calculate CFG_LO*/
+ if (mids->hs_mode == LNW_DMA_SW_HS) {
@@ -2171,6 +2165,13 @@ index 0000000..aeb7fd3
+ cfg_hi.cfgx.protctl = 0x1; /*default value*/
+ cfg_hi.cfgx.src_per = cfg_hi.cfgx.dst_per =
+ midc->ch_id - midc->dma->chan_base;
++ /* Quark - set polarity active low - make a param */
++ if(midc->dma->is_quark){
++ cfg_lo.cfgx.dst_hs_pol = 0x1;
++ cfg_lo.cfgx.src_hs_pol = 0x1;
++ cfg_lo.cfgx.hs_sel_dst = 0x00;
++ cfg_lo.cfgx.hs_sel_src = 0x01;
++ }
+ }
+ }
+
@@ -2180,13 +2181,18 @@ index 0000000..aeb7fd3
+ width = mids->dma_slave.src_addr_width;
+
+ ctl_hi.ctlx.block_ts = get_block_ts(len, width, midc->dma->block_size);
-+ pr_debug("MDMA:calc len %d for block size %d\n",
++ pr_debug("MDMA:calc len (block_ts) %d for block size %d\n",
+ ctl_hi.ctlx.block_ts, midc->dma->block_size);
+ /*calculate CTL_LO*/
+ ctl_lo.ctl_lo = 0;
+ ctl_lo.ctlx.int_en = 1;
-+ ctl_lo.ctlx.dst_msize = mids->dma_slave.src_maxburst;
-+ ctl_lo.ctlx.src_msize = mids->dma_slave.dst_maxburst;
++ /* Note Quark: original driver inverted these two values - need to
++ * resolve before integration - have we missed a trick ? */
++ ctl_lo.ctlx.dst_msize = mids->dma_slave.dst_maxburst;
++ ctl_lo.ctlx.src_msize = mids->dma_slave.src_maxburst;
++ pr_debug("MDMA:Cfg dst_msize 0x%x src_msize 0x%x\n", ctl_lo.ctlx.src_msize, ctl_lo.ctlx.dst_msize);
++ pr_debug("MDMA:Cfg mids->dma_slave.dst_maxburst 0x%x mids->dma_slave.src_maxburst 0x%x\n", mids->dma_slave.src_maxburst,
++mids->dma_slave.dst_maxburst);
+
+ /*
+ * Here we need some translation from "enum dma_slave_buswidth"
@@ -2215,9 +2221,8 @@ index 0000000..aeb7fd3
+ }
+ }
+
-+ pr_debug("MDMA:Calc CTL LO %x, CTL HI %x, CFG LO %x, CFG HI %x\n",
++ pr_debug("MDMA:Calc CTL LO 0x%x, CTL HI 0x%x, CFG LO 0x%x CFG HI 0x%x\n",
+ ctl_lo.ctl_lo, ctl_hi.ctl_hi, cfg_lo.cfg_lo, cfg_hi.cfg_hi);
-+
+ enable_dma_interrupt(midc);
+
+ desc = midc_desc_get(midc);
@@ -2276,7 +2281,7 @@ index 0000000..aeb7fd3
+ mids = midc->mid_slave;
+ BUG_ON(!mids);
+
-+ if (!midc->dma->pimr_mask) {
++ if (!midc->dma->is_quark && !midc->dma->pimr_mask) {
+ /* We can still handle sg list with only one item */
+ if (sg_len == 1) {
+ txd = intel_mid_dma_prep_memcpy(chan,
@@ -2294,7 +2299,8 @@ index 0000000..aeb7fd3
+ pr_debug("MDMA: SG Length = %d, direction = %d, Flags = %#lx\n",
+ sg_len, direction, flags);
+
-+ txd = intel_mid_dma_prep_memcpy(chan, 0, 0, sg_dma_len(sgl), flags);
++ txd = intel_mid_dma_prep_memcpy(chan, mids->dma_slave.dst_addr,
++ mids->dma_slave.src_addr, sg_dma_len(sgl), flags);
+ if (NULL == txd) {
+ pr_err("MDMA: Prep memcpy failed\n");
+ return NULL;
@@ -2553,23 +2559,21 @@ index 0000000..aeb7fd3
+irqreturn_t intel_mid_dma_interrupt(int irq, void *data)
+{
+ struct middma_device *mid = data;
-+ u32 tfr_status, err_status;
++ u32 tfr_status, err_status, block_status;
+ int call_tasklet = 0;
+
+ tfr_status = ioread32(mid->dma_base + RAW_TFR);
++ block_status = ioread32(mid->dma_base + RAW_BLOCK);
+ err_status = ioread32(mid->dma_base + RAW_ERR);
-+ if (!tfr_status && !err_status)
++ if (!tfr_status && !err_status && !block_status){
+ return IRQ_NONE;
++ }
+
+ /*DMA Interrupt*/
-+#if 0
+ pr_debug("MDMA:Got an interrupt on irq %d\n", irq);
-+ pr_debug("MDMA: Status %x, Mask %x\n", tfr_status, mid->intr_mask);
-+#else
-+ pr_info("MDMA:Got an interrupt on irq %d\n", irq);
-+ pr_info("MDMA: Status %x, Mask %x\n", tfr_status, mid->intr_mask);
++ pr_debug("MDMA: raw_tfr %x, raw_err %x raw_block %x Mask %x\n",
++ tfr_status, err_status, block_status, mid->intr_mask);
+
-+#endif
+ tfr_status &= mid->intr_mask;
+ if (tfr_status) {
+ /*need to disable intr*/
@@ -2586,7 +2590,7 @@ index 0000000..aeb7fd3
+ }
+ if (call_tasklet)
+ tasklet_schedule(&mid->tasklet);
-+
++
+ return IRQ_HANDLED;
+}
+EXPORT_SYMBOL(intel_mid_dma_interrupt);
@@ -2763,7 +2767,9 @@ index 0000000..aeb7fd3
+* @state: PM message
+*
+* This function is called by OS when a power event occurs
++* TBD in 1.1 release
+*/
++#if 0
+static int dma_suspend(struct device *dev)
+{
+ struct pci_dev *pci = to_pci_dev(dev);
@@ -2775,15 +2781,18 @@ index 0000000..aeb7fd3
+ if (device->ch[i].in_use)
+ return -EAGAIN;
+ }
-+#if 0
-+ dmac1_mask_periphral_intr(device);
-+#endif
++
++ if(!device->is_quark){
++ dmac1_mask_periphral_intr(device);
++ }
++
+ device->state = SUSPENDED;
+ pci_save_state(pci);
+ pci_disable_device(pci);
+ pci_set_power_state(pci, PCI_D3hot);
+ return 0;
+}
++#endif
+
+/**
+* dma_resume - PCI resume function
@@ -2802,6 +2811,16 @@ index 0000000..aeb7fd3
+ return 0;
+}
+
++/*
++* dma_runtime_suspend - PCI suspend function
++*
++* @pci: PCI device structure
++* @state: PM message
++*
++* This function is called by OS when a power event occurs
++* TBD in 1.1 release
++*/
++#if 0
+static int dma_runtime_suspend(struct device *dev)
+{
+ struct pci_dev *pci_dev = to_pci_dev(dev);
@@ -2810,7 +2829,18 @@ index 0000000..aeb7fd3
+ device->state = SUSPENDED;
+ return 0;
+}
++#endif
+
++/*
++* dma_runtime_resume - PCI suspend function
++*
++* @pci: PCI device structure
++* @state: PM message
++*
++* This function is called by OS when a power event occurs
++* TBD in 1.1 release
++*/
++#if 0
+static int dma_runtime_resume(struct device *dev)
+{
+ struct pci_dev *pci_dev = to_pci_dev(dev);
@@ -2820,7 +2850,18 @@ index 0000000..aeb7fd3
+ iowrite32(REG_BIT0, device->dma_base + DMA_CFG);
+ return 0;
+}
++#endif
+
++/*
++* dma_runtime_idle - PCI suspend function
++*
++* @pci: PCI device structure
++* @state: PM message
++*
++* This function is called by OS when a power event occurs
++* TBD in 1.1 release
++*/
++#if 0
+static int dma_runtime_idle(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
@@ -2834,13 +2875,13 @@ index 0000000..aeb7fd3
+
+ return pm_schedule_suspend(dev, 0);
+}
-+
++#endif
diff --git a/drivers/dma/intel_mid_dma_pci.c b/drivers/dma/intel_mid_dma_pci.c
new file mode 100644
-index 0000000..bd753b9
+index 0000000..b0d3ab1
--- /dev/null
+++ b/drivers/dma/intel_mid_dma_pci.c
-@@ -0,0 +1,290 @@
+@@ -0,0 +1,292 @@
+/*
+ * intel_mid_dma.c - Intel Langwell DMA Drivers
+ *
@@ -2866,6 +2907,7 @@ index 0000000..bd753b9
+ *
+ *
+ */
++#define DEBUG
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
@@ -2873,19 +2915,19 @@ index 0000000..bd753b9
+#include <linux/module.h>
+
+#include "intel_mid_dma_regs.h"
-+//#include "intel_mid_dma_core.h"
+
+#define INTEL_MID_DMAC1_ID 0x0814
+#define INTEL_MID_DMAC2_ID 0x0813
+#define INTEL_MID_GP_DMAC2_ID 0x0827
+#define INTEL_MFLD_DMAC1_ID 0x0830
+
-+#define INFO(_max_chan, _ch_base, _block_size, _pimr_mask) \
++#define INFO(_max_chan, _ch_base, _block_size, _pimr_mask, _is_quark) \
+ ((kernel_ulong_t)&(struct intel_mid_dma_probe_info) { \
+ .max_chan = (_max_chan), \
+ .ch_base = (_ch_base), \
+ .block_size = (_block_size), \
+ .pimr_mask = (_pimr_mask), \
++ .is_quark = (_is_quark), \
+ })
+
+/**
@@ -2948,6 +2990,7 @@ index 0000000..bd753b9
+ device->chan_base = info->ch_base;
+ device->block_size = info->block_size;
+ device->pimr_mask = info->pimr_mask;
++ device->is_quark = info->is_quark;
+
+ err = mid_setup_dma(pdev, device);
+ if (err)
@@ -3085,10 +3128,10 @@ index 0000000..bd753b9
+* PCI stuff
+*/
+static struct pci_device_id intel_mid_dma_ids[] = {
-+ { PCI_VDEVICE(INTEL, INTEL_MID_DMAC1_ID), INFO(2, 6, 4095, 0x200020)},
-+ { PCI_VDEVICE(INTEL, INTEL_MID_DMAC2_ID), INFO(2, 0, 2047, 0)},
-+ { PCI_VDEVICE(INTEL, INTEL_MID_GP_DMAC2_ID), INFO(2, 0, 2047, 0)},
-+ { PCI_VDEVICE(INTEL, INTEL_MFLD_DMAC1_ID), INFO(4, 0, 4095, 0x400040)},
++ { PCI_VDEVICE(INTEL, INTEL_MID_DMAC1_ID), INFO(2, 6, 4095, 0x200020, 0)},
++ { PCI_VDEVICE(INTEL, INTEL_MID_DMAC2_ID), INFO(2, 0, 2047, 0, 0)},
++ { PCI_VDEVICE(INTEL, INTEL_MID_GP_DMAC2_ID), INFO(2, 0, 2047, 0, 0)},
++ { PCI_VDEVICE(INTEL, INTEL_MFLD_DMAC1_ID), INFO(4, 0, 4095, 0x400040, 0)},
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, intel_mid_dma_ids);
@@ -3132,7 +3175,7 @@ index 0000000..bd753b9
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(INTEL_MID_DMA_DRIVER_VERSION);
diff --git a/drivers/dma/intel_mid_dma_regs.h b/drivers/dma/intel_mid_dma_regs.h
-index 17b4219..4b2ba69 100644
+index 17b4219..f3d5597 100644
--- a/drivers/dma/intel_mid_dma_regs.h
+++ b/drivers/dma/intel_mid_dma_regs.h
@@ -27,6 +27,7 @@
@@ -3143,7 +3186,7 @@ index 17b4219..4b2ba69 100644
#include <linux/pci_ids.h>
#define INTEL_MID_DMA_DRIVER_VERSION "1.1.0"
-@@ -158,115 +159,17 @@ union intel_mid_dma_cfg_hi {
+@@ -158,114 +159,29 @@ union intel_mid_dma_cfg_hi {
};
@@ -3237,12 +3280,15 @@ index 17b4219..4b2ba69 100644
- struct list_head desc_node;
- struct dma_async_tx_descriptor txd;
- size_t len;
-- dma_addr_t sar;
-- dma_addr_t dar;
++#if CONFIG_INTEL_QUARK_X1000_SOC
++struct intel_mid_dma_lli {
+ dma_addr_t sar;
+ dma_addr_t dar;
- u32 cfg_hi;
- u32 cfg_lo;
-- u32 ctl_lo;
-- u32 ctl_hi;
++ dma_addr_t llp;
+ u32 ctl_lo;
+ u32 ctl_hi;
- struct pci_pool *lli_pool;
- struct intel_mid_dma_lli *lli;
- dma_addr_t lli_phys;
@@ -3253,13 +3299,24 @@ index 17b4219..4b2ba69 100644
- enum dma_status status;
- enum dma_slave_buswidth width; /*width of DMA txn*/
- enum intel_mid_dma_mode cfg_mode; /*mode configuration*/
--
++ u32 sstatx;
++ u32 dstatx;
++} __attribute__ ((packed));
+
-};
--
++#else
+
struct intel_mid_dma_lli {
dma_addr_t sar;
- dma_addr_t dar;
-@@ -294,6 +197,14 @@ static inline struct intel_mid_dma_slave *to_intel_mid_dma_slave
+@@ -275,6 +191,7 @@ struct intel_mid_dma_lli {
+ u32 ctl_hi;
+ } __attribute__ ((packed));
+
++#endif
+ static inline int test_ch_en(void __iomem *dma, u32 ch_no)
+ {
+ u32 en_reg = ioread32(dma + DMA_CHAN_EN);
+@@ -294,6 +211,14 @@ static inline struct intel_mid_dma_slave *to_intel_mid_dma_slave
}
@@ -3276,28 +3333,21 @@ index 17b4219..4b2ba69 100644
#endif /*__INTEL_MID_DMAC_REGS_H__*/
diff --git a/drivers/dma/intel_qrk_dma_pci.c b/drivers/dma/intel_qrk_dma_pci.c
new file mode 100644
-index 0000000..cbac334
+index 0000000..c826ad7
--- /dev/null
+++ b/drivers/dma/intel_qrk_dma_pci.c
-@@ -0,0 +1,155 @@
+@@ -0,0 +1,147 @@
+/*
+ * Copyright(c) 2013 Intel Corporation.
+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * 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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
+ *
-+ * Contact Information:
-+ * Intel Corporation
++ * This program is distributed in the hope 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.
+ */
+
+/*
@@ -3316,7 +3366,6 @@ index 0000000..cbac334
+#include <linux/intel_mid_dma.h>
+#include <linux/module.h>
+
-+//#include "intel_mid_dma_core.h"
+#include "intel_mid_dma_regs.h"
+
+/**
@@ -3648,11 +3697,11 @@ index df1b998..ccbc063 100644
obj-$(CONFIG_SERIAL_MSM_SMD) += msm_smd_tty.o
obj-$(CONFIG_SERIAL_MXS_AUART) += mxs-auart.o
diff --git a/drivers/tty/serial/intel_quark_uart.c b/drivers/tty/serial/intel_quark_uart.c
-new file mode 100644
-index 0000000..5c0a01a
+new file mode 100755
+index 0000000..5bb6a00
--- /dev/null
+++ b/drivers/tty/serial/intel_quark_uart.c
-@@ -0,0 +1,2032 @@
+@@ -0,0 +1,2034 @@
+/*
+ *Copyright (C) 2011 LAPIS Semiconductor Co., Ltd.
+ *Copyright (C) 2014 Intel Corporation.
@@ -3693,6 +3742,9 @@ index 0000000..5c0a01a
+#include <linux/intel_mid_dma.h>
+#include <linux/debugfs.h>
+#include <linux/dmaengine.h>
++#include <linux/spinlock.h>
++#include <linux/wait.h>
++#include <linux/workqueue.h>
+
+enum {
+ QUARK_UART_HANDLED_RX_INT_SHIFT,
@@ -3708,25 +3760,27 @@ index 0000000..5c0a01a
+ QUARK_UART_2LINE,
+};
+
-+#define INFO(_max_chan, _ch_base, _block_size, _pimr_mask) \
++#define INFO(_max_chan, _ch_base, _block_size, _pimr_mask, _is_quark) \
+ ((kernel_ulong_t)&(struct intel_mid_dma_probe_info) { \
+ .max_chan = (_max_chan), \
+ .ch_base = (_ch_base), \
+ .block_size = (_block_size), \
+ .pimr_mask = (_pimr_mask), \
++ .is_quark = (_is_quark), \
+ })
+
+#define QUARK_UART_DRIVER_DEVICE "ttyQRK"
+#define QUARK_UART_FIFO_LEN 16
-+//#define __QRK_DMA_DEBUG /* TODO: remove all code of this type */
-+
++#define QUARK_UART_MAXBURST 0x20
++#define QUARK_FIFO_FASTER_LEN (QUARK_UART_MAXBURST/2)
+/* Set the max number of UART port
-+ * Intel EG20T QUARK: 4 port
-+ * LAPIS Semiconductor ML7213 IOH: 3 port
-+ * LAPIS Semiconductor ML7223 IOH: 2 port
++ * Intel QUARK X1000 : 2 port
+*/
+#define QUARK_UART_NR 2
+
++/* Set the AHB address for DMA transfers */
++#define QUARK_UART_AHB_REG_BASE 0xFFFFF000
++
+#define QUARK_UART_HANDLED_RX_INT (1<<((QUARK_UART_HANDLED_RX_INT_SHIFT)<<1))
+#define QUARK_UART_HANDLED_TX_INT (1<<((QUARK_UART_HANDLED_TX_INT_SHIFT)<<1))
+#define QUARK_UART_HANDLED_RX_ERR_INT (1<<((\
@@ -3737,17 +3791,17 @@ index 0000000..5c0a01a
+
+#define QUARK_UART_HANDLED_LS_INT (1<<((QUARK_UART_HANDLED_LS_INT_SHIFT)<<1))
+
-+#define QUARK_UART_RBR 0x00
-+#define QUARK_UART_THR 0x00
++#define QUARK_UART_RBR 0x00
++#define QUARK_UART_THR 0x00
+
-+#define QUARK_UART_IER_MASK (QUARK_UART_IER_ERBFI|QUARK_UART_IER_ETBEI|\
-+ QUARK_UART_IER_ELSI|QUARK_UART_IER_EDSSI)
-+#define QUARK_UART_IER_ERBFI 0x00000001
-+#define QUARK_UART_IER_ETBEI 0x00000002
-+#define QUARK_UART_IER_ELSI 0x00000004
-+#define QUARK_UART_IER_EDSSI 0x00000008
++#define QUARK_UART_IER_MASK (QUARK_UART_IER_ERBFI|QUARK_UART_IER_ETBEI|\
++ QUARK_UART_IER_ELSI|QUARK_UART_IER_EDSSI)
++#define QUARK_UART_IER_ERBFI 0x00000001
++#define QUARK_UART_IER_ETBEI 0x00000002
++#define QUARK_UART_IER_ELSI 0x00000004
++#define QUARK_UART_IER_EDSSI 0x00000008
+
-+#define QUARK_UART_IIR_IP 0x00000001
++#define QUARK_UART_IIR_IP 0x00000001
+#define QUARK_UART_IIR_IID 0x00000006
+#define QUARK_UART_IIR_MSI 0x00000000
+#define QUARK_UART_IIR_TRI 0x00000002
@@ -3756,7 +3810,7 @@ index 0000000..5c0a01a
+#define QUARK_UART_IIR_TOI 0x00000008
+#define QUARK_UART_IIR_FIFO256 0x00000020
+#define QUARK_UART_IIR_FIFO64 QUARK_UART_IIR_FIFO256
-+#define QUARK_UART_IIR_FE 0x000000C0
++#define QUARK_UART_IIR_FE 0x000000C0
+
+#define QUARK_UART_FCR_FIFOE 0x00000001
+#define QUARK_UART_FCR_RFR 0x00000002
@@ -3775,56 +3829,56 @@ index 0000000..5c0a01a
+#define QUARK_UART_FCR_RFTL4 QUARK_UART_FCR_RFTL64
+#define QUARK_UART_FCR_RFTL8 QUARK_UART_FCR_RFTL128
+#define QUARK_UART_FCR_RFTL14 QUARK_UART_FCR_RFTL224
-+#define QUARK_UART_FCR_RFTL_SHIFT 6
++#define QUARK_UART_FCR_RFTL_SHIFT 6
+
-+#define QUARK_UART_LCR_WLS 0x00000003
-+#define QUARK_UART_LCR_STB 0x00000004
-+#define QUARK_UART_LCR_PEN 0x00000008
-+#define QUARK_UART_LCR_EPS 0x00000010
++#define QUARK_UART_LCR_WLS 0x00000003
++#define QUARK_UART_LCR_STB 0x00000004
++#define QUARK_UART_LCR_PEN 0x00000008
++#define QUARK_UART_LCR_EPS 0x00000010
+#define QUARK_UART_LCR_SP 0x00000020
+#define QUARK_UART_LCR_SB 0x00000040
-+#define QUARK_UART_LCR_DLAB 0x00000080
++#define QUARK_UART_LCR_DLAB 0x00000080
+#define QUARK_UART_LCR_NP 0x00000000
+#define QUARK_UART_LCR_OP QUARK_UART_LCR_PEN
+#define QUARK_UART_LCR_EP (QUARK_UART_LCR_PEN | QUARK_UART_LCR_EPS)
+#define QUARK_UART_LCR_1P (QUARK_UART_LCR_PEN | QUARK_UART_LCR_SP)
+#define QUARK_UART_LCR_0P (QUARK_UART_LCR_PEN | QUARK_UART_LCR_EPS |\
-+ QUARK_UART_LCR_SP)
++ QUARK_UART_LCR_SP)
+
-+#define QUARK_UART_LCR_5BIT 0x00000000
-+#define QUARK_UART_LCR_6BIT 0x00000001
-+#define QUARK_UART_LCR_7BIT 0x00000002
-+#define QUARK_UART_LCR_8BIT 0x00000003
++#define QUARK_UART_LCR_5BIT 0x00000000
++#define QUARK_UART_LCR_6BIT 0x00000001
++#define QUARK_UART_LCR_7BIT 0x00000002
++#define QUARK_UART_LCR_8BIT 0x00000003
+
-+#define QUARK_UART_MCR_DTR 0x00000001
-+#define QUARK_UART_MCR_RTS 0x00000002
-+#define QUARK_UART_MCR_OUT 0x0000000C
-+#define QUARK_UART_MCR_LOOP 0x00000010
-+#define QUARK_UART_MCR_AFE 0x00000020
++#define QUARK_UART_MCR_DTR 0x00000001
++#define QUARK_UART_MCR_RTS 0x00000002
++#define QUARK_UART_MCR_OUT 0x0000000C
++#define QUARK_UART_MCR_LOOP 0x00000010
++#define QUARK_UART_MCR_AFE 0x00000020
+
+#define QUARK_UART_LSR_DR 0x00000001
-+#define QUARK_UART_LSR_ERR (1<<7)
-+
-+#define QUARK_UART_MSR_DCTS 0x00000001
-+#define QUARK_UART_MSR_DDSR 0x00000002
-+#define QUARK_UART_MSR_TERI 0x00000004
-+#define QUARK_UART_MSR_DDCD 0x00000008
-+#define QUARK_UART_MSR_CTS 0x00000010
-+#define QUARK_UART_MSR_DSR 0x00000020
++#define QUARK_UART_LSR_ERR (1<<7)
++
++#define QUARK_UART_MSR_DCTS 0x00000001
++#define QUARK_UART_MSR_DDSR 0x00000002
++#define QUARK_UART_MSR_TERI 0x00000004
++#define QUARK_UART_MSR_DDCD 0x00000008
++#define QUARK_UART_MSR_CTS 0x00000010
++#define QUARK_UART_MSR_DSR 0x00000020
+#define QUARK_UART_MSR_RI 0x00000040
-+#define QUARK_UART_MSR_DCD 0x00000080
-+#define QUARK_UART_MSR_DELTA (QUARK_UART_MSR_DCTS | QUARK_UART_MSR_DDSR |\
-+ QUARK_UART_MSR_TERI | QUARK_UART_MSR_DDCD)
++#define QUARK_UART_MSR_DCD 0x00000080
++#define QUARK_UART_MSR_DELTA (QUARK_UART_MSR_DCTS | QUARK_UART_MSR_DDSR |\
++ QUARK_UART_MSR_TERI | QUARK_UART_MSR_DDCD)
+
-+#define QUARK_UART_DLL 0x00
-+#define QUARK_UART_DLM 0x01
++#define QUARK_UART_DLL 0x00
++#define QUARK_UART_DLM 0x01
+
+#define QUARK_UART_BRCSR 0x0E
+
-+#define QUARK_UART_IID_RLS (QUARK_UART_IIR_REI)
-+#define QUARK_UART_IID_RDR (QUARK_UART_IIR_RRI)
-+#define QUARK_UART_IID_RDR_TO (QUARK_UART_IIR_RRI | QUARK_UART_IIR_TOI)
-+#define QUARK_UART_IID_THRE (QUARK_UART_IIR_TRI)
++#define QUARK_UART_IID_RLS (QUARK_UART_IIR_REI)
++#define QUARK_UART_IID_RDR (QUARK_UART_IIR_RRI)
++#define QUARK_UART_IID_RDR_TO (QUARK_UART_IIR_RRI | QUARK_UART_IIR_TOI)
++#define QUARK_UART_IID_THRE (QUARK_UART_IIR_TRI)
+#define QUARK_UART_IID_MS (QUARK_UART_IIR_MSI)
+
+#define QUARK_UART_HAL_PARITY_NONE (QUARK_UART_LCR_NP)
@@ -3844,29 +3898,29 @@ index 0000000..5c0a01a
+#define QUARK_UART_HAL_CLR_ALL_FIFO (QUARK_UART_HAL_CLR_TX_FIFO | \
+ QUARK_UART_HAL_CLR_RX_FIFO)
+
-+#define QUARK_UART_HAL_DMA_MODE0 0
++#define QUARK_UART_HAL_DMA_MODE0 0
+#define QUARK_UART_HAL_FIFO_DIS 0
+#define QUARK_UART_HAL_FIFO16 (QUARK_UART_FCR_FIFOE)
+#define QUARK_UART_HAL_FIFO256 (QUARK_UART_FCR_FIFOE | \
+ QUARK_UART_FCR_FIFO256)
+#define QUARK_UART_HAL_FIFO64 (QUARK_UART_HAL_FIFO256)
+#define QUARK_UART_HAL_TRIGGER1 (QUARK_UART_FCR_RFTL1)
-+#define QUARK_UART_HAL_TRIGGER64 (QUARK_UART_FCR_RFTL64)
-+#define QUARK_UART_HAL_TRIGGER128 (QUARK_UART_FCR_RFTL128)
-+#define QUARK_UART_HAL_TRIGGER224 (QUARK_UART_FCR_RFTL224)
-+#define QUARK_UART_HAL_TRIGGER16 (QUARK_UART_FCR_RFTL16)
-+#define QUARK_UART_HAL_TRIGGER32 (QUARK_UART_FCR_RFTL32)
-+#define QUARK_UART_HAL_TRIGGER56 (QUARK_UART_FCR_RFTL56)
++#define QUARK_UART_HAL_TRIGGER64 (QUARK_UART_FCR_RFTL64)
++#define QUARK_UART_HAL_TRIGGER128 (QUARK_UART_FCR_RFTL128)
++#define QUARK_UART_HAL_TRIGGER224 (QUARK_UART_FCR_RFTL224)
++#define QUARK_UART_HAL_TRIGGER16 (QUARK_UART_FCR_RFTL16)
++#define QUARK_UART_HAL_TRIGGER32 (QUARK_UART_FCR_RFTL32)
++#define QUARK_UART_HAL_TRIGGER56 (QUARK_UART_FCR_RFTL56)
+#define QUARK_UART_HAL_TRIGGER4 (QUARK_UART_FCR_RFTL4)
+#define QUARK_UART_HAL_TRIGGER8 (QUARK_UART_FCR_RFTL8)
-+#define QUARK_UART_HAL_TRIGGER14 (QUARK_UART_FCR_RFTL14)
-+#define QUARK_UART_HAL_TRIGGER_L (QUARK_UART_FCR_RFTL64)
-+#define QUARK_UART_HAL_TRIGGER_M (QUARK_UART_FCR_RFTL128)
-+#define QUARK_UART_HAL_TRIGGER_H (QUARK_UART_FCR_RFTL224)
++#define QUARK_UART_HAL_TRIGGER14 (QUARK_UART_FCR_RFTL14)
++#define QUARK_UART_HAL_TRIGGER_L (QUARK_UART_FCR_RFTL64)
++#define QUARK_UART_HAL_TRIGGER_M (QUARK_UART_FCR_RFTL128)
++#define QUARK_UART_HAL_TRIGGER_H (QUARK_UART_FCR_RFTL224)
+
+#define QUARK_UART_HAL_RX_INT (QUARK_UART_IER_ERBFI)
+#define QUARK_UART_HAL_TX_INT (QUARK_UART_IER_ETBEI)
-+#define QUARK_UART_HAL_RX_ERR_INT (QUARK_UART_IER_ELSI)
++#define QUARK_UART_HAL_RX_ERR_INT (QUARK_UART_IER_ELSI)
+#define QUARK_UART_HAL_MS_INT (QUARK_UART_IER_EDSSI)
+#define QUARK_UART_HAL_ALL_INT (QUARK_UART_IER_MASK)
+
@@ -3910,36 +3964,36 @@ index 0000000..5c0a01a
+ unsigned int dmsr;
+ unsigned int fcr;
+ unsigned int mcr;
-+ unsigned int use_dma;
++ unsigned int ier;
++ bool use_dma;
+ struct dma_async_tx_descriptor *desc_tx;
+ struct dma_async_tx_descriptor *desc_rx;
-+#if 1
-+ struct dma_chan *chan_tx;
-+ struct dma_chan *chan_rx;
++ struct dma_chan *tx_chan;
++ struct dma_chan *rx_chan;
+ struct middma_device mid_dma;
+ struct quark_uart_buffer txbuf;
+ struct quark_uart_buffer rxbuf;
+ struct intel_mid_dma_slave dmas_rx;
+ struct intel_mid_dma_slave dmas_tx;
-+#else
-+ struct quark_dma_slave param_tx;
-+ struct quark_dma_slave param_rx;
-+ struct dma_chan *chan_tx;
-+ struct dma_chan *chan_rx;
-+#endif
+ struct scatterlist *sg_tx_p;
+ int nent;
+ struct scatterlist sg_rx;
+ int tx_dma_use;
+ void *rx_buf_virt;
+ dma_addr_t rx_buf_dma;
-+
+ struct dentry *debugfs;
-+
++ struct work_struct work;
++ int dma_tx_in_flight;
+ /* protect the x1000_port private structure and io access to membase */
+ spinlock_t lock;
++ struct dma_slave_config tx_conf;
++ struct dma_slave_config rx_conf;
++ wait_queue_head_t w_queue;
++
+};
+
++static struct uart_driver quark_uart_driver;
++
+/**
+ * struct quark_uart_driver_data - private data structure for UART-DMA
+ * @port_type: The number of DMA channel
@@ -3950,19 +4004,16 @@ index 0000000..5c0a01a
+ int line_no;
+};
+
-+#if 0
-+static unsigned int mem_serial_in(struct uart_port *p, int offset)
++/**
++ * intel_qrk_dma_chan_filter
++ *
++ * Simple descriptor disjunct function
++ */
++static bool intel_qrk_dma_chan_filter(struct dma_chan * chan, void *param)
+{
-+ offset = offset << p->regshift;
-+ return readb(p->membase + offset);
++ return 1;
+}
+
-+static void mem_serial_out(struct uart_port *p, int offset, int value)
-+{
-+ offset = offset << p->regshift;
-+ writeb(value, p->membase + offset);
-+}
-+#endif
+
+/**
+ * serial_in
@@ -3999,6 +4050,7 @@ index 0000000..5c0a01a
+static struct x1000_port *quark_uart_ports[QUARK_UART_NR];
+#endif
+static unsigned int default_baud = 115200;
++static bool use_dma = true;
+static const int trigger_level_256[4] = { 1, 64, 128, 224 };
+static const int trigger_level_64[4] = { 1, 16, 32, 56 };
+static const int trigger_level_16[4] = { 1, 4, 8, 14 };
@@ -4008,7 +4060,6 @@ index 0000000..5c0a01a
+
+#define QUARK_REGS_BUFSIZE 1024
+
-+
+static ssize_t port_show_regs(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
@@ -4059,6 +4110,7 @@ index 0000000..5c0a01a
+ return ret;
+}
+
++
+static const struct file_operations port_regs_ops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
@@ -4077,24 +4129,17 @@ index 0000000..5c0a01a
+ unsigned int flag)
+{
+ u8 ier = serial_in(priv, UART_IER);
-+#ifdef __QRK_DMA_DEBUG
-+// pr_info("%s read IER %x\n", __func__, ier);
-+#endif
+ ier |= flag & QUARK_UART_IER_MASK;
++ priv->ier = ier;
+ serial_out(priv, UART_IER, ier);
-+#ifdef __QRK_DMA_DEBUG
-+// pr_info("%s wrote IER %x\n", __func__, ier);
-+#endif
+}
+
+static void quark_uart_hal_disable_interrupt(struct x1000_port *priv,
+ unsigned int flag)
+{
-+#ifdef __QRK_DMA_DEBUG
-+// pr_info("%s entry\n", __func__);
-+#endif
+ u8 ier = serial_in(priv, UART_IER);
+ ier &= ~(flag & QUARK_UART_IER_MASK);
++ priv->ier = ier;
+ serial_out(priv, UART_IER, ier);
+}
+
@@ -4133,11 +4178,6 @@ index 0000000..5c0a01a
+ lcr |= bits;
+ lcr |= stb;
+
-+#ifdef __QRK_DMA_DEBUG
-+ /* TODO: change this back to dev_dbg - BOD */
-+ dev_info(priv->port.dev, "%s:baud = %u, div = %04x, lcr = %02x (%lu)\n",
-+ __func__, baud, div, lcr, jiffies);
-+#endif
+ serial_out(priv, UART_LCR, QUARK_UART_LCR_DLAB);
+ serial_out(priv, QUARK_UART_DLL, dll);
+ serial_out(priv, QUARK_UART_DLM, dlm);
@@ -4205,22 +4245,15 @@ index 0000000..5c0a01a
+ trigger_level_1[trigger >> QUARK_UART_FCR_RFTL_SHIFT];
+ break;
+ }
-+#if 0
+ fcr =
+ dmamode | fifo_size | trigger | QUARK_UART_FCR_RFR | QUARK_UART_FCR_TFR;
-+#else
-+ fcr =
-+ fifo_size | trigger | QUARK_UART_FCR_RFR | QUARK_UART_FCR_TFR;
+
-+#endif
+ serial_out(priv, UART_FCR, QUARK_UART_FCR_FIFOE);
+ serial_out(priv,
+ UART_FCR, QUARK_UART_FCR_FIFOE | QUARK_UART_FCR_RFR | QUARK_UART_FCR_TFR);
+ serial_out(priv, UART_FCR, fcr);
+ priv->fcr = fcr;
-+#ifdef __QRK_DMA_DEBUG
-+ pr_info("%s FCR set to %x\n", __func__, priv->fcr);
-+#endif
++
+ return 0;
+}
+
@@ -4346,101 +4379,6 @@ index 0000000..5c0a01a
+ return room;
+}
+
-+static void quark_free_dma(struct uart_port *port)
-+{
-+ struct x1000_port *priv;
-+ priv = container_of(port, struct x1000_port, port);
-+
-+ if (priv->chan_tx) {
-+ dma_release_channel(priv->chan_tx);
-+ priv->chan_tx = NULL;
-+ }
-+ if (priv->chan_rx) {
-+ dma_release_channel(priv->chan_rx);
-+ priv->chan_rx = NULL;
-+ }
-+
-+ if (priv->rx_buf_dma) {
-+ dma_free_coherent(port->dev, port->fifosize, priv->rx_buf_virt,
-+ priv->rx_buf_dma);
-+ priv->rx_buf_virt = NULL;
-+ priv->rx_buf_dma = 0;
-+ }
-+
-+ return;
-+}
-+
-+static bool filter(struct dma_chan *chan, void *slave)
-+{
-+ #if 0
-+ struct quark_dma_slave *param = slave;
-+
-+ if ((chan->chan_id == param->chan_id) && (param->dma_dev ==
-+ chan->device->dev)) {
-+ chan->private = param;
-+ return true;
-+ } else {
-+ return false;
-+ }
-+ #else
-+ return true;
-+ #endif
-+}
-+
-+static void quark_request_dma(struct uart_port *port)
-+{
-+ dma_cap_mask_t mask;
-+ struct dma_chan *chan;
-+ struct pci_dev *dma_dev;
-+#if 0
-+ struct quark_dma_slave *param;
-+#endif
-+ struct x1000_port *priv =
-+ container_of(port, struct x1000_port, port);
-+ dma_cap_zero(mask);
-+ dma_cap_set(DMA_SLAVE, mask);
-+
-+ dma_dev = pci_get_bus_and_slot(priv->pdev->bus->number,
-+ PCI_DEVFN(0xa, 0)); /* Get DMA's dev
-+ information */
-+ /* Set Tx DMA */
-+#if 0
-+ param = &priv->param_tx;
-+ param->dma_dev = &dma_dev->dev;
-+ param->chan_id = priv->port.line * 2; /* Tx = 0, 2, 4, ... */
-+
-+ param->tx_reg = port->mapbase + UART_TX;
-+#endif
-+ chan = dma_request_channel(mask, filter, &priv->dmas_tx);
-+ if (!chan) {
-+ dev_err(priv->port.dev, "%s:dma_request_channel FAILS(Tx)\n",
-+ __func__);
-+ return;
-+ }
-+ priv->chan_tx = chan;
-+#if 0
-+ /* Set Rx DMA */
-+ param = &priv->param_rx;
-+ param->dma_dev = &dma_dev->dev;
-+ param->chan_id = priv->port.line * 2 + 1; /* Rx = Tx + 1 */
-+
-+ param->rx_reg = port->mapbase + UART_RX;
-+#endif
-+ chan = dma_request_channel(mask, filter, &priv->dmas_rx);
-+ if (!chan) {
-+ dev_err(priv->port.dev, "%s:dma_request_channel FAILS(Rx)\n",
-+ __func__);
-+ dma_release_channel(priv->chan_tx);
-+ priv->chan_tx = NULL;
-+ return;
-+ }
-+
-+ /* Get Consistent memory for DMA */
-+ priv->rx_buf_virt = dma_alloc_coherent(port->dev, port->fifosize,
-+ &priv->rx_buf_dma, GFP_KERNEL);
-+ priv->chan_rx = chan;
-+}
-+
+static void quark_dma_rx_complete(void *arg)
+{
+ struct x1000_port *priv = arg;
@@ -4464,18 +4402,32 @@ index 0000000..5c0a01a
+ struct circ_buf *xmit = &port->state->xmit;
+ struct scatterlist *sg = priv->sg_tx_p;
+ int i;
++ unsigned long flags;
++
++ spin_lock_irqsave(&priv->lock, flags);
+
+ for (i = 0; i < priv->nent; i++, sg++) {
+ xmit->tail += sg_dma_len(sg);
+ port->icount.tx += sg_dma_len(sg);
+ }
-+ xmit->tail &= UART_XMIT_SIZE - 1;
++ /* Make sure that xmit->head and xmit->tail are equal
++ to zero at the end of a transaction */
++ if(priv->tx_dma_use == 0)
++ xmit->head = xmit->tail = 0;
++ else
++ xmit->tail &= UART_XMIT_SIZE - 1;
+ async_tx_ack(priv->desc_tx);
+ dma_unmap_sg(port->dev, sg, priv->nent, DMA_TO_DEVICE);
+ priv->tx_dma_use = 0;
+ priv->nent = 0;
++ priv->tx_empty = 1;
+ kfree(priv->sg_tx_p);
++
+ quark_uart_hal_enable_interrupt(priv, QUARK_UART_HAL_TX_INT);
++ priv->dma_tx_in_flight = 0;
++ wake_up(&priv->w_queue);
++
++ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static int pop_tx(struct x1000_port *priv, int size)
@@ -4548,10 +4500,21 @@ index 0000000..5c0a01a
+
+ sg_dma_address(sg) = priv->rx_buf_dma;
+
-+ desc = dmaengine_prep_slave_sg(priv->chan_rx,
-+ sg, 1, DMA_DEV_TO_MEM,
-+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
++ /* Configure RX */
++ priv->rx_conf.dst_addr = sg_dma_address(sg);
++ priv->rx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++ priv->rx_conf.dst_maxburst = LNW_DMA_MSIZE_1;
++
++ priv->rx_conf.src_addr = QUARK_UART_AHB_REG_BASE + QUARK_UART_THR; /* Wants an AHB address */
++ priv->rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
++ priv->rx_conf.src_maxburst = LNW_DMA_MSIZE_4;
++ priv->rx_conf.direction = DMA_DEV_TO_MEM;
++ priv->rx_conf.device_fc = false;
+
++ dmaengine_slave_config(priv->rx_chan, &priv->rx_conf);
++ desc = dmaengine_prep_slave_sg(priv->rx_chan,
++ sg, 1, DMA_DEV_TO_MEM,
++ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!desc)
+ return 0;
+
@@ -4559,7 +4522,7 @@ index 0000000..5c0a01a
+ desc->callback = quark_dma_rx_complete;
+ desc->callback_param = priv;
+ desc->tx_submit(desc);
-+ dma_async_issue_pending(priv->chan_rx);
++ dma_async_issue_pending(priv->rx_chan);
+
+ return QUARK_UART_HANDLED_RX_INT;
+}
@@ -4574,9 +4537,10 @@ index 0000000..5c0a01a
+ int tx_empty;
+
+ if (!priv->start_tx) {
-+ dev_info(priv->port.dev, "%s:Tx isn't started. (%lu)\n",
++ dev_dbg(priv->port.dev, "%s:Tx isn't started. (%lu)\n",
+ __func__, jiffies);
+ quark_uart_hal_disable_interrupt(priv, QUARK_UART_HAL_TX_INT);
++ wake_up(&priv->w_queue);
+ priv->tx_empty = 1;
+ return 0;
+ }
@@ -4600,15 +4564,17 @@ index 0000000..5c0a01a
+ }
+
+ priv->tx_empty = tx_empty;
-+
+ if (tx_empty) {
+ quark_uart_hal_disable_interrupt(priv, QUARK_UART_HAL_TX_INT);
-+ uart_write_wakeup(port);
++ wake_up(&priv->w_queue);
++ if (port->state->port.tty != NULL)
++ uart_write_wakeup(port);
+ }
+
+ return QUARK_UART_HANDLED_TX_INT;
+}
+
++
+static unsigned int dma_handle_tx(struct x1000_port *priv)
+{
+ struct uart_port *port = &priv->port;
@@ -4617,17 +4583,18 @@ index 0000000..5c0a01a
+ int nent;
+ int fifo_size;
+ int tx_empty;
-+ struct dma_async_tx_descriptor *desc;
+ int num;
+ int i;
+ int bytes;
+ int size;
+ int rem;
++ int ret;
+
+ if (!priv->start_tx) {
-+ dev_info(priv->port.dev, "%s:Tx isn't started. (%lu)\n",
++ dev_dbg(priv->port.dev, "%s:Tx isn't started. (%lu)\n",
+ __func__, jiffies);
+ quark_uart_hal_disable_interrupt(priv, QUARK_UART_HAL_TX_INT);
++ wake_up(&priv->w_queue);
+ priv->tx_empty = 1;
+ return 0;
+ }
@@ -4636,11 +4603,12 @@ index 0000000..5c0a01a
+ dev_dbg(priv->port.dev, "%s:Tx is not completed. (%lu)\n",
+ __func__, jiffies);
+ quark_uart_hal_disable_interrupt(priv, QUARK_UART_HAL_TX_INT);
++ wake_up(&priv->w_queue);
+ priv->tx_empty = 1;
+ return 0;
+ }
+
-+ fifo_size = max(priv->fifo_size, 1);
++ fifo_size = QUARK_UART_MAXBURST;
+ tx_empty = 1;
+ if (pop_tx_x(priv, xmit->buf)) {
+ quark_uart_hal_write(priv, xmit->buf, 1);
@@ -4652,15 +4620,37 @@ index 0000000..5c0a01a
+ bytes = min((int)CIRC_CNT(xmit->head, xmit->tail,
+ UART_XMIT_SIZE), CIRC_CNT_TO_END(xmit->head,
+ xmit->tail, UART_XMIT_SIZE));
++
+ if (!bytes) {
+ dev_dbg(priv->port.dev, "%s 0 bytes return\n", __func__);
+ quark_uart_hal_disable_interrupt(priv, QUARK_UART_HAL_TX_INT);
-+ uart_write_wakeup(port);
++ wake_up(&priv->w_queue);
++ if (port->state->port.tty != NULL)
++ uart_write_wakeup(port);
+ return 0;
+ }
+
++ /* DMA block doesn't do !dword aligned */
++ if (bytes % 0x04){
++ if (bytes < 4){
++ ret = handle_tx(priv);
++ /* DMA transactions want to start DWORD aligned */
++ xmit->head = xmit->tail = 0;
++ return ret;
++ }
++ bytes &= 0xFFFFFFFC;
++ }
++
++ /* For small payloads its just faster to write the FIFO directly */
++ if (bytes < QUARK_FIFO_FASTER_LEN){
++ ret = handle_tx(priv);
++ /* DMA transactions want to start DWORD aligned */
++ xmit->head = xmit->tail = 0;
++ return ret;
++ }
++
+ if (bytes > fifo_size) {
-+ num = bytes / fifo_size + 1;
++ num = bytes / fifo_size;
+ size = fifo_size;
+ rem = bytes % fifo_size;
+ } else {
@@ -4684,6 +4674,7 @@ index 0000000..5c0a01a
+ sg = priv->sg_tx_p;
+
+ for (i = 0; i < num; i++, sg++) {
++ BUG_ON((int)xmit->buf & ~PAGE_MASK);
+ if (i == (num - 1))
+ sg_set_page(sg, virt_to_page(xmit->buf),
+ rem, fifo_size * i);
@@ -4705,28 +4696,18 @@ index 0000000..5c0a01a
+ fifo_size * i;
+ sg_dma_address(sg) = (sg_dma_address(sg) &
+ ~(UART_XMIT_SIZE - 1)) + sg->offset;
++
+ if (i == (nent - 1))
-+ sg_dma_len(sg) = rem;
++ sg_dma_len(sg) = bytes;
+ else
+ sg_dma_len(sg) = size;
++ bytes -= size;
+ }
+
-+ desc = dmaengine_prep_slave_sg(priv->chan_tx,
-+ priv->sg_tx_p, nent, DMA_MEM_TO_DEV,
-+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-+ if (!desc) {
-+ dev_err(priv->port.dev, "%s:device_prep_slave_sg Failed\n",
-+ __func__);
-+ return 0;
-+ }
-+ dma_sync_sg_for_device(port->dev, priv->sg_tx_p, nent, DMA_TO_DEVICE);
-+ priv->desc_tx = desc;
-+ desc->callback = quark_dma_tx_complete;
-+ desc->callback_param = priv;
-+
-+ desc->tx_submit(desc);
-+
-+ dma_async_issue_pending(priv->chan_tx);
++ priv->dma_tx_in_flight = 1;
++ quark_uart_hal_disable_interrupt(priv, QUARK_UART_HAL_TX_INT);
++ wake_up(&priv->w_queue);
++ schedule_work(&priv->work);
+
+ return QUARK_UART_HANDLED_TX_INT;
+}
@@ -4772,6 +4753,42 @@ index 0000000..5c0a01a
+ #define unmask_pvm(x)
+#endif
+
++static void quark_uart_work(struct work_struct *work)
++{
++ struct x1000_port *priv = container_of(work, struct x1000_port,work);
++ struct dma_async_tx_descriptor *desc;
++
++ if (priv == NULL) {
++ pr_err("ERR_X1000: tasklet Null param\n");
++ return;
++ }
++ /* Configure TX */
++ priv->tx_conf.src_addr = sg_dma_address(priv->sg_tx_p);
++ priv->tx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++ priv->tx_conf.src_maxburst = LNW_DMA_MSIZE_1;
++ priv->tx_conf.dst_addr = QUARK_UART_AHB_REG_BASE + QUARK_UART_THR; /* Wants an AHB address */
++ priv->tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
++ priv->tx_conf.dst_maxburst = LNW_DMA_MSIZE_4;
++ priv->tx_conf.direction = DMA_MEM_TO_DEV;
++ priv->tx_conf.device_fc = false;
++
++ dmaengine_slave_config(priv->tx_chan, &priv->tx_conf);
++ desc = dmaengine_prep_slave_sg(priv->tx_chan,
++ priv->sg_tx_p, priv->nent, DMA_MEM_TO_DEV,
++ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
++ if (!desc) {
++ dev_err(priv->port.dev, "%s:device_prep_slave_sg Failed\n",
++ __func__);
++ return;
++ }
++ dma_sync_sg_for_device(priv->port.dev, priv->sg_tx_p, priv->nent, DMA_TO_DEVICE);
++ priv->desc_tx = desc;
++ desc->callback = quark_dma_tx_complete;
++ desc->callback_param = priv;
++ desc->tx_submit(desc);
++ dma_async_issue_pending(priv->tx_chan);
++}
++
+static irqreturn_t quark_uart_interrupt(int irq, void *dev_id)
+{
+ struct x1000_port *priv = dev_id;
@@ -4801,18 +4818,9 @@ index 0000000..5c0a01a
+ }
+ break;
+ case QUARK_UART_IID_RDR: /* Received Data Ready */
-+ if (priv->use_dma) {
-+ quark_uart_hal_disable_interrupt(priv,
-+ QUARK_UART_HAL_RX_INT |
-+ QUARK_UART_HAL_RX_ERR_INT);
-+ ret = dma_handle_rx(priv);
-+ if (!ret)
-+ quark_uart_hal_enable_interrupt(priv,
-+ QUARK_UART_HAL_RX_INT |
-+ QUARK_UART_HAL_RX_ERR_INT);
-+ } else {
-+ ret = handle_rx(priv);
-+ }
++
++ (void)dma_handle_rx; /*Not worth setup time*/
++ ret = handle_rx(priv);
+ break;
+ case QUARK_UART_IID_RDR_TO: /* Received Data Ready
+ (FIFO Timeout) */
@@ -4821,7 +4829,6 @@ index 0000000..5c0a01a
+ case QUARK_UART_IID_THRE: /* Transmitter Holding Register
+ Empty */
+ if (priv->use_dma)
-+
+ ret = dma_handle_tx(priv);
+ else
+ ret = handle_tx(priv);
@@ -4909,45 +4916,48 @@ index 0000000..5c0a01a
+static void quark_uart_stop_tx(struct uart_port *port)
+{
+ struct x1000_port *priv;
++ unsigned long flags;
+ priv = container_of(port, struct x1000_port, port);
++
++ spin_lock_irqsave(&priv->lock, flags);
+ priv->start_tx = 0;
+ priv->tx_dma_use = 0;
++
++ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void quark_uart_start_tx(struct uart_port *port)
+{
+ struct x1000_port *priv;
+
++ unsigned long flags;
+ priv = container_of(port, struct x1000_port, port);
+
++ spin_lock_irqsave(&priv->lock, flags);
+ if (priv->use_dma) {
+ if (priv->tx_dma_use) {
+ dev_dbg(priv->port.dev, "%s : Tx DMA is NOT empty.\n",
+ __func__);
-+ return;
++ goto done;
+ }
+ }
+
-+#ifdef __QRK_DMA_DEBUG
-+ unsigned char iid = quark_uart_hal_get_iid(priv);
-+ pr_info("%s enable interrupt IER %x FCR %x iid %x\n", __func__, serial_in(priv, UART_IER),
-+ serial_in(priv, UART_FCR), iid);
-+#endif
+ priv->start_tx = 1;
-+ quark_uart_hal_enable_interrupt(priv, QUARK_UART_HAL_TX_INT);
++ if( priv->dma_tx_in_flight == 0)
++ quark_uart_hal_enable_interrupt(priv, QUARK_UART_HAL_TX_INT);
++
++done:
++ spin_unlock_irqrestore(&priv->lock, flags);
++
+}
+
+static void quark_uart_stop_rx(struct uart_port *port)
+{
+ struct x1000_port *priv;
-+
+ priv = container_of(port, struct x1000_port, port);
++
++ wait_event(priv->w_queue,!(priv->ier & QUARK_UART_HAL_TX_INT) && !priv->dma_tx_in_flight);
+ priv->start_rx = 0;
-+#ifdef __QRK_DMA_DEBUG
-+ unsigned char iid;
-+ iid = quark_uart_hal_get_iid(priv);
-+ pr_info("%s IID is 0x%x USR 0x%x LSR 0x%x MSR 0x%x\n", __func__, iid, serial_in(priv,31), serial_in(priv, UART_LSR), serial_in(priv, UART_MSR));
-+#endif
+ quark_uart_hal_disable_interrupt(priv, QUARK_UART_HAL_RX_INT |
+ QUARK_UART_HAL_RX_ERR_INT);
+}
@@ -4987,9 +4997,7 @@ index 0000000..5c0a01a
+ priv->uartclk = port->uartclk;
+ else
+ port->uartclk = priv->uartclk;
-+#ifdef __QRK_DMA_DEBUG
-+ pr_info("%s entry fifo size %d!\n", __func__, priv->fifo_size);
-+#endif
++
+ quark_uart_hal_disable_interrupt(priv, QUARK_UART_HAL_ALL_INT);
+ ret = quark_uart_hal_set_line(priv, default_baud,
+ QUARK_UART_HAL_PARITY_NONE, QUARK_UART_HAL_8BIT,
@@ -5031,28 +5039,14 @@ index 0000000..5c0a01a
+ }
+
+ priv->trigger_level = trigger_level;
-+#ifdef __QRK_DMA_DEBUG
-+ pr_info("%s setting FCR fifo_size %d FIFO trig %d\n", __func__, fifo_size, priv->trigger);
-+#endif
+ ret = quark_uart_hal_set_fifo(priv, QUARK_UART_HAL_DMA_MODE0,
+ fifo_size, priv->trigger);
+ if (ret < 0)
+ return ret;
-+
-+ if (priv->use_dma)
-+ quark_request_dma(port);
-+
-+#ifdef __QRK_DMA_DEBUG
-+ pr_info("%s enable interrupt IER %x FCR %x USR %x\n", __func__, serial_in(priv, UART_IER),
-+ serial_in(priv, UART_FCR), serial_in(priv, 31));
-+#endif
+ priv->start_rx = 1;
+ quark_uart_hal_enable_interrupt(priv, QUARK_UART_HAL_RX_INT |
+ QUARK_UART_HAL_RX_ERR_INT);
+ uart_update_timeout(port, CS8, default_baud);
-+#ifdef __QRK_DMA_DEBUG
-+ pr_info("%s exit IER %x FCR %x USR %x\n", __func__, serial_in(priv, UART_IER), serial_in(priv, UART_FCR), serial_in(priv, 31));
-+#endif
+ return 0;
+}
+
@@ -5061,10 +5055,10 @@ index 0000000..5c0a01a
+ struct x1000_port *priv;
+ int ret;
+
-+#ifdef __QRK_DMA_DEBUG
-+ pr_info("%s called!\n", __func__);
-+#endif
+ priv = container_of(port, struct x1000_port, port);
++
++ wait_event(priv->w_queue, !(priv->dma_tx_in_flight));
++
+ quark_uart_hal_disable_interrupt(priv, QUARK_UART_HAL_ALL_INT);
+ quark_uart_hal_fifo_reset(priv, QUARK_UART_HAL_CLR_ALL_FIFO);
+ ret = quark_uart_hal_set_fifo(priv, QUARK_UART_HAL_DMA_MODE0,
@@ -5072,8 +5066,6 @@ index 0000000..5c0a01a
+ if (ret)
+ dev_err(priv->port.dev,
+ "quark_uart_hal_set_fifo Failed(ret=%d)\n", ret);
-+
-+ quark_free_dma(port);
+}
+
+/* Change the port parameters, including word length, parity, stop
@@ -5125,7 +5117,6 @@ index 0000000..5c0a01a
+ termios->c_cflag &= ~CMSPAR; /* Mark/Space parity is not supported */
+
+ baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
-+
+ spin_lock_irqsave(&priv->lock, flags);
+ spin_lock(&port->lock);
+
@@ -5160,23 +5151,6 @@ index 0000000..5c0a01a
+
+static int quark_uart_request_port(struct uart_port *port)
+{
-+#if 0
-+ struct x1000_port *priv;
-+ int ret;
-+ void __iomem *membase;
-+
-+ priv = container_of(port, struct x1000_port, port);
-+ ret = pci_request_regions(priv->pdev, KBUILD_MODNAME);
-+ if (ret < 0)
-+ return -EBUSY;
-+
-+ membase = pci_iomap(priv->pdev, 1, 0);
-+ if (!membase) {
-+ pci_release_regions(priv->pdev);
-+ return -EBUSY;
-+ }
-+ priv->membase = port->membase = membase;
-+#endif
+ return 0;
+}
+
@@ -5184,9 +5158,6 @@ index 0000000..5c0a01a
+{
+ struct x1000_port *priv;
+
-+#ifdef __QRK_DMA_DEBUG
-+ pr_info("%s entry!\n", __func__);
-+#endif
+ priv = container_of(port, struct x1000_port, port);
+ if (type & UART_CONFIG_TYPE) {
+ port->type = priv->port_type;
@@ -5198,25 +5169,20 @@ index 0000000..5c0a01a
+ struct serial_struct *serinfo)
+{
+ struct x1000_port *priv;
-+#ifdef __QRK_DMA_DEBUG
-+ pr_info("%s entry point !\n", __func__);
-+#endif
+ priv = container_of(port, struct x1000_port, port);
++
+ if (serinfo->flags & UPF_LOW_LATENCY) {
+ dev_info(priv->port.dev,
+ "QUARK UART : Use PIO Mode (without DMA)\n");
-+ priv->use_dma = 0;
++ priv->use_dma = false;
+ serinfo->flags &= ~UPF_LOW_LATENCY;
+ } else {
-+#ifndef CONFIG_QUARK_DMA
-+ dev_err(priv->port.dev, "%s : QUARK DMA is not Loaded.\n",
-+ __func__);
-+ return -EOPNOTSUPP;
-+#endif
+ dev_info(priv->port.dev, "QUARK UART : Use DMA Mode\n");
++ #if 0
+ if (!priv->use_dma)
+ quark_request_dma(port);
-+ priv->use_dma = 1;
++ #endif
++ priv->use_dma = true;
+ }
+
+ return 0;
@@ -5318,7 +5284,7 @@ index 0000000..5c0a01a
+ .startup = quark_uart_startup,
+ .shutdown = quark_uart_shutdown,
+ .set_termios = quark_uart_set_termios,
-+/* .pm = quark_uart_pm, Not supported yet */
++/* .pm = quark_uart_pm, Not supported yet */
+/* .set_wake = quark_uart_set_wake, Not supported yet */
+ .type = quark_uart_type,
+ .release_port = quark_uart_release_port,
@@ -5365,7 +5331,7 @@ index 0000000..5c0a01a
+ if (priv->port.sysrq) {
+ /* call to uart_handle_sysrq_char already took the priv lock */
+ priv_locked = 0;
-+ /* serial8250_handle_port() already took the port lock */
++ /* serialquark_uart_handle_port() already took the port lock */
+ port_locked = 0;
+ } else if (oops_in_progress) {
+ priv_locked = spin_trylock(&priv->lock);
@@ -5426,8 +5392,6 @@ index 0000000..5c0a01a
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
-+static struct uart_driver quark_uart_driver;
-+
+static struct console quark_console = {
+ .name = QUARK_UART_DRIVER_DEVICE,
+ .write = quark_console_write,
@@ -5447,31 +5411,29 @@ index 0000000..5c0a01a
+ .owner = THIS_MODULE,
+ .driver_name = KBUILD_MODNAME,
+ .dev_name = QUARK_UART_DRIVER_DEVICE,
-+ .major = 0,
-+ .minor = 0,
+ .nr = QUARK_UART_NR,
+ .cons = QUARK_CONSOLE,
+};
+
++static int line_no; /* eek! TODO */
++
+static struct x1000_port *quark_uart_init_port(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct x1000_port *priv;
+ int ret, len;
++ dma_cap_mask_t mask;
+ unsigned char *rxbuf;
+ char name[32]; /* for debugfs file name */
+ struct intel_mid_dma_probe_info * info = NULL;
+
-+ dev_info(&pdev->dev,"QUARK UART-DMA (ID: %04x:%04x) pdev->irq %d\n",
++ dev_dbg(&pdev->dev,"QUARK UART-DMA (ID: %04x:%04x) pdev->irq %d\n",
+ pdev->vendor, pdev->device, pdev->irq);
+
+ info = (void*)id->driver_data;
+ dev_info(&pdev->dev,"QUARK UART-DMA : CH %d base %d block len %d per mask %x\n",
+ info->max_chan, info->ch_base, info->block_size, info->pimr_mask);
-+#if 0
-+ board = &drv_dat[id->driver_data];
-+ port_type = board->port_type;
-+#endif
++
+ priv = kzalloc(sizeof(struct x1000_port), GFP_KERNEL);
+ if (priv == NULL)
+ goto init_port_alloc_err;
@@ -5480,10 +5442,12 @@ index 0000000..5c0a01a
+ if (!rxbuf)
+ goto init_port_free_txbuf;
+
++ priv->mid_dma.pdev = pci_dev_get(pdev);
+ pci_set_master(pdev);
+
+ spin_lock_init(&priv->lock);
+
++ /* UART regs */
+ priv->mapbase = pci_resource_start(pdev, 0);
+ len = pci_resource_len(pdev, 0);
+ priv->membase = ioremap_nocache(priv->mapbase, len);
@@ -5492,6 +5456,54 @@ index 0000000..5c0a01a
+ goto init_port_free_txbuf;
+ }
+
++ /* DMA driver */
++ priv->mid_dma.max_chan = info->max_chan; /* Max channels */
++ priv->mid_dma.chan_base = info->ch_base; /* Index start */
++ priv->mid_dma.block_size = info->block_size; /* MAX DMA block */
++ priv->mid_dma.pimr_mask = info->pimr_mask; /* Per int regs bool */
++ priv->mid_dma.is_quark = info->is_quark;
++
++ ret = intel_qrk_dma_probe(pdev, &priv->mid_dma);
++ if(ret != 0){
++ dev_err(&pdev->dev, "Unable to init DMA sub-system\n");
++ goto init_port_free_uart_iomem;
++ }
++
++ /* Request DMA channels TODO: move to startup() once debugged on hw */
++ dma_cap_zero(mask);
++ dma_cap_set(DMA_SLAVE, mask);
++
++ priv->rx_chan = dma_request_channel(mask, intel_qrk_dma_chan_filter, &priv->dmas_rx);
++ if(priv->rx_chan == NULL){
++ dev_err(&pdev->dev, "Unable to hook DMA RX channel\n");
++ goto init_port_free_dma_iomem;
++ };
++ priv->rx_buf_virt = dma_alloc_coherent(&pdev->dev, QUARK_UART_FIFO_LEN,
++ &priv->rx_buf_dma, GFP_KERNEL);
++ if (priv->rx_buf_virt == NULL){
++ dev_err(&pdev->dev, "Unable to allocate %d bytes for DMA\n",
++ QUARK_UART_FIFO_LEN);
++ goto init_port_free_dma_iomem;
++ }
++
++ priv->dmas_rx.hs_mode = LNW_DMA_HW_HS;
++ priv->dmas_rx.cfg_mode = LNW_DMA_PER_TO_MEM;
++ /* Configure RX */
++
++ priv->tx_chan = dma_request_channel(mask, intel_qrk_dma_chan_filter, &priv->dmas_tx);
++ if(priv->tx_chan == NULL){
++ dev_err(&pdev->dev, "Unable to hook DMA RX channel\n");
++ goto init_port_free_dma_iomem;
++ };
++ priv->dmas_tx.hs_mode = LNW_DMA_HW_HS;
++ priv->dmas_tx.cfg_mode = LNW_DMA_MEM_TO_PER;
++
++ dev_info(&pdev->dev, "using %s for DMA RX %s for DMA TX DMA %s\n",
++ dev_name(&priv->rx_chan->dev->device),
++ dev_name(&priv->tx_chan->dev->device), use_dma ?
++ "enabled" : "disabled");
++
++ /* Setup UART port descriptor */
+ priv->pdev = pdev;
+ priv->tx_empty = 1;
+ priv->rxbuf.buf = rxbuf;
@@ -5507,8 +5519,10 @@ index 0000000..5c0a01a
+ priv->port.ops = &quark_uart_ops;
+ priv->port.flags = UPF_BOOT_AUTOCONF;
+ priv->port.fifosize = QUARK_UART_FIFO_LEN;
-+ priv->port.line = pdev->dev.id;
-+ priv->trigger = QUARK_UART_HAL_TRIGGER_M;
++ priv->port.line = line_no;
++ priv->trigger = QUARK_UART_HAL_TRIGGER_L;
++ priv->use_dma = use_dma;
++ use_dma = 0;
+
+ spin_lock_init(&priv->port.lock);
+ pci_set_drvdata(pdev, priv);
@@ -5517,33 +5531,41 @@ index 0000000..5c0a01a
+
+ ret = request_irq(pdev->irq, quark_uart_interrupt, IRQF_SHARED,
+ KBUILD_MODNAME, priv);
-+#ifdef __QRK_DMA_DEBUG
-+ pr_info("%s request_irq %d use_dma %d irq=%d\n", __func__, ret, priv->use_dma, pdev->irq);
-+#endif
-+ if (ret < 0)
++ if (ret < 0){
++ dev_err(&pdev->dev, "Unable to request irq %d err %d\n",
++ pdev->irq, ret);
+ goto init_port_hal_free;
++ }
+
+#ifdef CONFIG_SERIAL_QUARK_UART_CONSOLE
-+ quark_uart_ports[board->line_no] = priv;
++ quark_uart_ports[line_no++] = priv;
+#endif
+ ret = uart_add_one_port(&quark_uart_driver, &priv->port);
+
-+ if (ret < 0)
++ if (ret < 0){
++ dev_err(&pdev->dev, "uart_add_one_port fail %d\n", ret);
+ goto init_port_hal_free;
++ }
+
+#ifdef CONFIG_DEBUG_FS
+ snprintf(name, sizeof(name), "uart%d_regs", pdev->dev.id);
+ priv->debugfs = debugfs_create_file(name, S_IFREG | S_IRUGO,
+ NULL, priv, &port_regs_ops);
+#endif
-+
++ INIT_WORK(&priv->work, quark_uart_work);
++ init_waitqueue_head(&priv->w_queue);
+ return priv;
+
+init_port_hal_free:
-+#ifdef CONFIG_SERIAL_QUARK_UART_CONSOLE
-+ quark_uart_ports[board->line_no] = NULL;
-+#endif
+ free_page((unsigned long)rxbuf);
++init_port_free_dma_iomem:
++init_port_free_uart_iomem:
++ if (sg_dma_address(&priv->sg_rx))
++ dma_free_coherent(priv->port.dev, priv->port.fifosize,
++ sg_virt(&priv->sg_rx),
++ sg_dma_address(&priv->sg_rx));
++
++ iounmap(priv->membase);
+init_port_free_txbuf:
+ kfree(priv);
+init_port_alloc_err:
@@ -5551,13 +5573,31 @@ index 0000000..5c0a01a
+ return NULL;
+}
+
-+static void quark_uart_exit_port(struct x1000_port *priv)
++static void quark_uart_exit_port(struct pci_dev *pdev, struct x1000_port *priv)
+{
+
+#ifdef CONFIG_DEBUG_FS
+ if (priv->debugfs)
+ debugfs_remove(priv->debugfs);
+#endif
++ /* Shutdown DMA */
++ intel_qrk_dma_remove(pdev, &priv->mid_dma);
++
++ /* TODO: move to remove() when h/w proved out */
++ if (priv->tx_chan) {
++ dma_release_channel(priv->tx_chan);
++ priv->tx_chan = NULL;
++ }
++ if (priv->rx_chan) {
++ dma_release_channel(priv->rx_chan);
++ priv->rx_chan = NULL;
++ }
++
++ if (sg_dma_address(&priv->sg_rx))
++ dma_free_coherent(priv->port.dev, priv->port.fifosize,
++ sg_virt(&priv->sg_rx),
++ sg_dma_address(&priv->sg_rx));
++
+ free_irq(priv->port.irq, priv);
+ uart_remove_one_port(&quark_uart_driver, &priv->port);
+ pci_set_drvdata(priv->pdev, NULL);
@@ -5573,7 +5613,7 @@ index 0000000..5c0a01a
+#ifdef CONFIG_SERIAL_QUARK_UART_CONSOLE
+ quark_uart_ports[priv->port.line] = NULL;
+#endif
-+ quark_uart_exit_port(priv);
++ quark_uart_exit_port(pdev, priv);
+ pci_disable_device(pdev);
+ kfree(priv);
+ return;
@@ -5583,6 +5623,10 @@ index 0000000..5c0a01a
+{
+ struct x1000_port *priv = pci_get_drvdata(pdev);
+
++ /* Suspend DMA regs */
++ intel_qrk_dma_suspend(&priv->mid_dma);
++
++ /* Suspend UART regs */
+ uart_suspend_port(&quark_uart_driver, &priv->port);
+
+ pci_save_state(pdev);
@@ -5605,8 +5649,12 @@ index 0000000..5c0a01a
+ return ret;
+ }
+
++ /* Resume UART regs */
+ uart_resume_port(&quark_uart_driver, &priv->port);
+
++ /* Resume DMA regs */
++ intel_qrk_dma_resume(&priv->mid_dma);
++
+ return 0;
+}
+#else
@@ -5616,7 +5664,7 @@ index 0000000..5c0a01a
+
+struct pci_device_id quark_uart_pci_ids[] = {
+ /* channels = 2, offset = 0, block size = FIFO_LEN, pimr = 0 */
-+ { PCI_VDEVICE(INTEL, 0x0936), INFO(2, 0, QUARK_UART_FIFO_LEN, 0)},
++ { PCI_VDEVICE(INTEL, 0x0936), INFO(2, 0, QUARK_UART_FIFO_LEN, 0, 1)},
+ { 0 }
+};
+
@@ -5685,8 +5733,11 @@ index 0000000..5c0a01a
+module_param(default_baud, uint, S_IRUGO);
+MODULE_PARM_DESC(default_baud,
+ "Default BAUD for initial driver state and console (default 115200)");
++module_param(use_dma, bool, S_IRUGO);
++MODULE_PARM_DESC(use_dma,
++ "Use DMA (default true)");
diff --git a/include/linux/intel_mid_dma.h b/include/linux/intel_mid_dma.h
-index 10496bd..8dd64e9 100644
+index 10496bd..717458b 100644
--- a/include/linux/intel_mid_dma.h
+++ b/include/linux/intel_mid_dma.h
@@ -26,8 +26,10 @@
@@ -5700,7 +5751,7 @@ index 10496bd..8dd64e9 100644
/*DMA mode configurations*/
enum intel_mid_dma_mode {
-@@ -73,4 +75,188 @@ struct intel_mid_dma_slave {
+@@ -73,4 +75,191 @@ struct intel_mid_dma_slave {
struct dma_slave_config dma_slave;
};
@@ -5801,6 +5852,7 @@ index 10496bd..8dd64e9 100644
+ int block_size;
+ bool ispci_fn;
+ unsigned int pimr_mask;
++ unsigned int is_quark;
+ enum intel_mid_dma_state state;
+};
+
@@ -5811,12 +5863,14 @@ index 10496bd..8dd64e9 100644
+ * @ch_base: offset from register base
+ * @block_size: TBD
+ * @pimr_mask: indicates if mask registers to be mapped
++ * @is_quark: indicates if this is quark silicon
+ */
+struct intel_mid_dma_probe_info {
+ u8 max_chan;
+ u8 ch_base;
+ u16 block_size;
+ u32 pimr_mask;
++ u8 is_quark;
+};
+
+
@@ -5889,6 +5943,3 @@ index 10496bd..8dd64e9 100644
+
+
#endif /*__INTEL_MID_DMA_H__*/
---
-1.7.4.1
-