From 1db0d19afe5830f7d020c7c5386be8cc20cf0f15 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Thu, 23 May 2013 18:45:29 +0200 Subject: [PATCH 61/79] DMA: MIPS: ralink: add dmaengine driver Signed-off-by: John Crispin --- drivers/dma/Kconfig | 7 ++ drivers/dma/Makefile | 1 + drivers/dma/ralink_gdma.c | 229 +++++++++++++++++++++++++++++++++++++++++++++ drivers/dma/ralink_gdma.h | 55 +++++++++++ 4 files changed, 292 insertions(+) create mode 100644 drivers/dma/ralink_gdma.c create mode 100644 drivers/dma/ralink_gdma.h diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index d4c1218..323f684 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -320,6 +320,13 @@ config MMP_PDMA help Support the MMP PDMA engine for PXA and MMP platfrom. +config RALINK_GDMA + bool "Ralink Generic DMA support" + depends on RALINK + select DMA_ENGINE + help + Support the GDMA engine for MIPS based Ralink SoC. + config DMA_ENGINE bool diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index 7428fea..a981e2c 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -34,3 +34,4 @@ obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o obj-$(CONFIG_MMP_TDMA) += mmp_tdma.o obj-$(CONFIG_DMA_OMAP) += omap-dma.o obj-$(CONFIG_MMP_PDMA) += mmp_pdma.o +obj-$(CONFIG_RALINK_GDMA) += ralink_gdma.o diff --git a/drivers/dma/ralink_gdma.c b/drivers/dma/ralink_gdma.c new file mode 100644 index 0000000..be7c317 --- /dev/null +++ b/drivers/dma/ralink_gdma.c @@ -0,0 +1,229 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ralink_gdma.h" + +#define SURFBOARDINT_DMA 10 +#define MEMCPY_DMA_CH 8 +#define to_rt2880_dma_chan(chan) \ + container_of(chan, struct rt2880_dma_chan, common) + +static dma_cookie_t rt2880_dma_tx_submit(struct dma_async_tx_descriptor *tx) +{ + dma_cookie_t cookie; + + cookie = tx->chan->cookie; + + return cookie; +} + +#define MIN_RTDMA_PKT_LEN 128 +static struct dma_async_tx_descriptor * +rt2880_dma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, + size_t len, unsigned long flags) +{ + struct rt2880_dma_chan *rt_chan = to_rt2880_dma_chan(chan); + unsigned long mid_offset; + + spin_lock_bh(&rt_chan->lock); + + if(len < MIN_RTDMA_PKT_LEN) { + memcpy(phys_to_virt(dest), phys_to_virt(src), len); + } else { + mid_offset = len/2; + + /* Lower parts are transferred by GDMA. + * Upper parts are transferred by CPU. + */ + RT_DMA_WRITE_REG(RT_DMA_SRC_REG(MEMCPY_DMA_CH), src); + RT_DMA_WRITE_REG(RT_DMA_DST_REG(MEMCPY_DMA_CH), dest); + RT_DMA_WRITE_REG(RT_DMA_CTRL_REG(MEMCPY_DMA_CH), (mid_offset << 16) | (3 << 3) | (3 << 0)); + + memcpy(phys_to_virt(dest)+mid_offset, phys_to_virt(src)+mid_offset, len-mid_offset); + + dma_async_tx_descriptor_init(&rt_chan->txd, chan); + + while((RT_DMA_READ_REG(RT_DMA_DONEINT) & (0x1<lock); + + return &rt_chan->txd; +} + +/** + * rt2880_dma_status - poll the status of an XOR transaction + * @chan: XOR channel handle + * @cookie: XOR transaction identifier + * @txstate: XOR transactions state holder (or NULL) + */ +static enum dma_status rt2880_dma_status(struct dma_chan *chan, + dma_cookie_t cookie, + struct dma_tx_state *txstate) +{ + return 0; +} + +static irqreturn_t rt2880_dma_interrupt_handler(int irq, void *data) +{ + + printk("%s\n",__FUNCTION__); + + return IRQ_HANDLED; +} + +static void rt2880_dma_issue_pending(struct dma_chan *chan) +{ +} + +static int rt2880_dma_alloc_chan_resources(struct dma_chan *chan) +{ +// printk("%s\n",__FUNCTION__); + + return 0; +} + +static void rt2880_dma_free_chan_resources(struct dma_chan *chan) +{ +// printk("%s\n",__FUNCTION__); + +} + +static int rt2880_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned long arg) +{ + switch (cmd) { + case DMA_TERMINATE_ALL: + printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__); + break; + case DMA_SLAVE_CONFIG: + printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__); + break; + default: + return -ENXIO; + } + + return 0; +} + +static int rt2880_dma_probe(struct platform_device *pdev) +{ + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + __iomem void *membase; + struct dma_device *dma_dev; + struct rt2880_dma_chan *rt_chan; + int err; + int ret; + int reg; + int irq; + + membase = devm_request_and_ioremap(&pdev->dev, res); + if (IS_ERR(membase)) + return PTR_ERR(membase); + + dma_dev = devm_kzalloc(&pdev->dev, sizeof(*dma_dev), GFP_KERNEL); + if (!dma_dev) + return -ENOMEM; + + irq = platform_get_irq(pdev, 0); + if (!irq) { + dev_err(&pdev->dev, "failed to load irq\n"); + return -ENOENT; + } + + + INIT_LIST_HEAD(&dma_dev->channels); + dma_cap_zero(dma_dev->cap_mask); + dma_cap_set(DMA_MEMCPY, dma_dev->cap_mask); + dma_cap_set(DMA_SLAVE, dma_dev->cap_mask); + dma_dev->device_alloc_chan_resources = rt2880_dma_alloc_chan_resources; + dma_dev->device_free_chan_resources = rt2880_dma_free_chan_resources; + dma_dev->device_tx_status = rt2880_dma_status; + dma_dev->device_issue_pending = rt2880_dma_issue_pending; + dma_dev->device_prep_dma_memcpy = rt2880_dma_prep_dma_memcpy; + dma_dev->device_control = rt2880_dma_control; + dma_dev->dev = &pdev->dev; + + rt_chan = devm_kzalloc(&pdev->dev, sizeof(*rt_chan), GFP_KERNEL); + if (!rt_chan) { + return -ENOMEM; + } + + spin_lock_init(&rt_chan->lock); + INIT_LIST_HEAD(&rt_chan->chain); + INIT_LIST_HEAD(&rt_chan->completed_slots); + INIT_LIST_HEAD(&rt_chan->all_slots); + rt_chan->common.device = dma_dev; + rt_chan->txd.tx_submit = rt2880_dma_tx_submit; + + list_add_tail(&rt_chan->common.device_node, &dma_dev->channels); + + err = dma_async_device_register(dma_dev); + if (0 != err) { + pr_err("ERR_MDMA:device_register failed: %d\n", err); + return 1; + } + + ret = request_irq(irq, rt2880_dma_interrupt_handler, 0, dev_name(&pdev->dev), NULL); + if(ret){ + pr_err("IRQ %d is not free.\n", SURFBOARDINT_DMA); + return 1; + } + + //set GDMA register in advance. + reg = (32 << 16) | (32 << 8) | (MEMCPY_DMA_CH << 3); + RT_DMA_WRITE_REG(RT_DMA_CTRL_REG1(MEMCPY_DMA_CH), reg); + + dev_info(&pdev->dev, "running\n"); + + return 0; +} + +static int rt2880_dma_remove(struct platform_device *dev) +{ + struct dma_device *dma_dev = platform_get_drvdata(dev); + + printk("%s\n",__FUNCTION__); + + dma_async_device_unregister(dma_dev); + + return 0; +} + +static const struct of_device_id rt2880_dma_match[] = { + { .compatible = "ralink,rt2880-gdma" }, + {}, +}; +MODULE_DEVICE_TABLE(of, rt2880_wdt_match); + +static struct platform_driver rt2880_dma_driver = { + .probe = rt2880_dma_probe, + .remove = rt2880_dma_remove, + .driver = { + .owner = THIS_MODULE, + .name = RT_DMA_NAME, + .of_match_table = rt2880_dma_match, + }, +}; + +static int __init rt2880_dma_init(void) +{ + int rc; + + rc = platform_driver_register(&rt2880_dma_driver); + return rc; +} +module_init(rt2880_dma_init); + +MODULE_AUTHOR("Steven Liu "); +MODULE_AUTHOR("John Crispin "); +MODULE_DESCRIPTION("DMA engine driver for Ralink DMA engine"); +MODULE_LICENSE("GPL"); diff --git a/drivers/dma/ralink_gdma.h b/drivers/dma/ralink_gdma.h new file mode 100644 index 0000000..73e1948 --- /dev/null +++ b/drivers/dma/ralink_gdma.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2007, 2008, Marvell International Ltd. + * + * 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. + * + * 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. + * + * 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. + */ + +#ifndef RT_DMA_H +#define RT_DMA_H + +#include +#include +#include +#include + +#define RT_DMA_NAME "rt2880_dma" + +#define RALINK_GDMA_BASE 0xB0002800 + +struct rt2880_dma_chan { + int pending; + dma_cookie_t completed_cookie; + spinlock_t lock; /* protects the descriptor slot pool */ + void __iomem *mmr_base; + unsigned int idx; + enum dma_transaction_type current_type; + struct dma_async_tx_descriptor txd; + struct list_head chain; + struct list_head completed_slots; + struct dma_chan common; + struct list_head all_slots; + int slots_allocated; + struct tasklet_struct irq_tasklet; +}; + +#define RT_DMA_READ_REG(addr) le32_to_cpu(*(volatile u32 *)(addr)) +#define RT_DMA_WRITE_REG(addr, val) *((volatile uint32_t *)(addr)) = cpu_to_le32(val) + +#define RT_DMA_SRC_REG(ch) (RALINK_GDMA_BASE + ch*16) +#define RT_DMA_DST_REG(ch) (RT_DMA_SRC_REG(ch) + 4) +#define RT_DMA_CTRL_REG(ch) (RT_DMA_DST_REG(ch) + 4) +#define RT_DMA_CTRL_REG1(ch) (RT_DMA_CTRL_REG(ch) + 4) +#define RT_DMA_DONEINT (RALINK_GDMA_BASE + 0x204) + +#endif -- 1.7.10.4