diff options
Diffstat (limited to 'recipes-kernel/linux/files/0008-Quark-UART-quark.patch')
-rw-r--r-- | recipes-kernel/linux/files/0008-Quark-UART-quark.patch | 909 |
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 - |