[Armadeus-commitlog] SF.net SVN: armadeus:[1022] branches/tsc210x/buildroot/target/device/ armadeu
Brought to you by:
sszy
|
From: <ar...@us...> - 2009-01-19 09:21:51
|
Revision: 1022
http://armadeus.svn.sourceforge.net/armadeus/?rev=1022&view=rev
Author: artemys
Date: 2009-01-19 09:21:41 +0000 (Mon, 19 Jan 2009)
Log Message:
-----------
[LINUX] Add i.MX27 like scatter-gather support for i.MXL
Added Paths:
-----------
branches/tsc210x/buildroot/target/device/armadeus/linux/kernel-patches/2.6.27.2/linux-2.6.27.2-097-armadeus-imx-dma-improvements.patch
branches/tsc210x/buildroot/target/device/armadeus/linux/kernel-patches/2.6.27.2/linux-2.6.27.2-098-armadeus-imx-dma-announce_imx_is_supporting_scatter_gather.patch
Added: branches/tsc210x/buildroot/target/device/armadeus/linux/kernel-patches/2.6.27.2/linux-2.6.27.2-097-armadeus-imx-dma-improvements.patch
===================================================================
--- branches/tsc210x/buildroot/target/device/armadeus/linux/kernel-patches/2.6.27.2/linux-2.6.27.2-097-armadeus-imx-dma-improvements.patch (rev 0)
+++ branches/tsc210x/buildroot/target/device/armadeus/linux/kernel-patches/2.6.27.2/linux-2.6.27.2-097-armadeus-imx-dma-improvements.patch 2009-01-19 09:21:41 UTC (rev 1022)
@@ -0,0 +1,411 @@
+PATCH AUTOMATICALLY GENERATED
+DON'T EDIT IT OR YOUR MODIFICATIONS WILL BE LOST
+(Take a look at armadeus/target/linux/ directory to know how to generate it)
+--- linux-2.6.27.2.original/arch/arm/mach-imx/include/mach/imx-dma.h
++++ linux-2.6.27.2.mod/arch/arm/mach-imx/include/mach/imx-dma.h
+@@ -47,6 +47,7 @@
+ const char *name;
+ void (*irq_handler) (int, void *);
+ void (*err_handler) (int, void *, int errcode);
++ void (*prog_handler) (int, void *, struct scatterlist *);
+ void *data;
+ dmamode_t dma_mode;
+ struct scatterlist *sg;
+@@ -54,19 +55,38 @@
+ unsigned int sgcount;
+ unsigned int resbytes;
+ int dma_num;
++
++ int in_use;
++
++ int hw_chaining;
+ };
+
+ extern struct imx_dma_channel imx_dma_channels[IMX_DMA_CHANNELS];
+
+-#define IMX_DMA_ERR_BURST 1
+-#define IMX_DMA_ERR_REQUEST 2
+-#define IMX_DMA_ERR_TRANSFER 4
+-#define IMX_DMA_ERR_BUFFER 8
++#define IMX_DMA_MEMSIZE_32 (0 << 4)
++#define IMX_DMA_MEMSIZE_8 (1 << 4)
++#define IMX_DMA_MEMSIZE_16 (2 << 4)
++#define IMX_DMA_TYPE_LINEAR (0 << 10)
++#define IMX_DMA_TYPE_2D (1 << 10)
++#define IMX_DMA_TYPE_FIFO (2 << 10)
++
++#define IMX_DMA_ERR_BURST (1 << 0)
++#define IMX_DMA_ERR_REQUEST (1 << 1)
++#define IMX_DMA_ERR_TRANSFER (1 << 2)
++#define IMX_DMA_ERR_BUFFER (1 << 3)
++#define IMX_DMA_ERR_TIMEOUT (1 << 4)
+
+ /* The type to distinguish channel numbers parameter from ordinal int type */
+ typedef int imx_dmach_t;
+
+ int
++imx_dma_config_channel(int channel, unsigned int config_port,
++ unsigned int config_mem, unsigned int dmareq, int hw_chaining);
++
++void
++imx_dma_config_burstlen(int channel, unsigned int burstlen);
++
++int
+ imx_dma_setup_single(imx_dmach_t dma_ch, dma_addr_t dma_address,
+ unsigned int dma_length, unsigned int dev_addr, dmamode_t dmamode);
+
+@@ -80,6 +100,10 @@
+ void (*irq_handler) (int, void *),
+ void (*err_handler) (int, void *, int), void *data);
+
++int
++imx_dma_setup_progression_handler(int channel,
++ void (*prog_handler) (int, void*, struct scatterlist*));
++
+ void imx_dma_enable(imx_dmach_t dma_ch);
+
+ void imx_dma_disable(imx_dmach_t dma_ch);
+PATCH AUTOMATICALLY GENERATED
+DON'T EDIT IT OR YOUR MODIFICATIONS WILL BE LOST
+(Take a look at armadeus/target/linux/ directory to know how to generate it)
+--- linux-2.6.27.2.original/arch/arm/mach-imx/dma.c
++++ linux-2.6.27.2.mod/arch/arm/mach-imx/dma.c
+@@ -27,6 +27,7 @@
+ #include <linux/kernel.h>
+ #include <linux/interrupt.h>
+ #include <linux/errno.h>
++#include <linux/scatterlist.h>
+
+ #include <asm/system.h>
+ #include <asm/irq.h>
+@@ -36,6 +37,26 @@
+
+ struct imx_dma_channel imx_dma_channels[IMX_DMA_CHANNELS];
+
++static int imx_dma_hw_chain(struct imx_dma_channel *imxdma)
++{
++#ifdef CONFIG_ARCH_MX2
++ if (cpu_is_mx27())
++ return imxdma->hw_chaining;
++ else
++#endif
++ return 0;
++}
++
++static void dump_channels(void)
++{
++ int i = 0;
++
++ printk("Channel | Owner\n");
++ for (i=0; i<IMX_DMA_CHANNELS; i++) {
++ printk(" %2d | %s\n", i, imx_dma_channels[i].name);
++ }
++}
++
+ /*
+ * imx_dma_sg_next - prepare next chunk for scatter-gather DMA emulation
+ * @dma_ch: i.MX DMA channel number
+@@ -46,55 +67,31 @@
+ * during last block. Zero value can be used for @lastcount to setup DMA
+ * for the first chunk.
+ */
+-static inline int imx_dma_sg_next(imx_dmach_t dma_ch, unsigned int lastcount)
++static inline int imx_dma_sg_next(imx_dmach_t channel, struct scatterlist *sg)
+ {
+- struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch];
+- unsigned int nextcount;
+- unsigned int nextaddr;
++ struct imx_dma_channel *imxdma = &imx_dma_channels[channel];
++ unsigned long now;
+
+ if (!imxdma->name) {
+ printk(KERN_CRIT "%s: called for not allocated channel %d\n",
+- __func__, dma_ch);
+- return 0;
+- }
+-
+- imxdma->resbytes -= lastcount;
+-
+- if (!imxdma->sg) {
+- pr_debug("imxdma%d: no sg data\n", dma_ch);
++ __func__, channel);
+ return 0;
+ }
+
+- imxdma->sgbc += lastcount;
+- if ((imxdma->sgbc >= imxdma->sg->length) || !imxdma->resbytes) {
+- if ((imxdma->sgcount <= 1) || !imxdma->resbytes) {
+- pr_debug("imxdma%d: sg transfer limit reached\n",
+- dma_ch);
+- imxdma->sgcount=0;
+- imxdma->sg = NULL;
+- return 0;
+- } else {
+- imxdma->sgcount--;
+- imxdma->sg++;
+- imxdma->sgbc = 0;
+- }
+- }
+- nextcount = imxdma->sg->length - imxdma->sgbc;
+- nextaddr = imxdma->sg->dma_address + imxdma->sgbc;
+-
+- if(imxdma->resbytes < nextcount)
+- nextcount = imxdma->resbytes;
++ now = min(imxdma->resbytes, sg->length);
++ imxdma->resbytes -= now;
+
+ if ((imxdma->dma_mode & DMA_MODE_MASK) == DMA_MODE_READ)
+- DAR(dma_ch) = nextaddr;
++ DAR(channel) = sg->dma_address;
+ else
+- SAR(dma_ch) = nextaddr;
++ SAR(channel) = sg->dma_address;
+
+- CNTR(dma_ch) = nextcount;
++ CNTR(channel) = now
++;
+ pr_debug("imxdma%d: next sg chunk dst 0x%08x, src 0x%08x, size 0x%08x\n",
+- dma_ch, DAR(dma_ch), SAR(dma_ch), CNTR(dma_ch));
++ channel, DAR(channel), SAR(channel), CNTR(channel));
+
+- return nextcount;
++ return now;
+ }
+
+ /*
+@@ -145,7 +142,6 @@
+ imxdma->sg = NULL;
+ imxdma->sgcount = 0;
+ imxdma->dma_mode = dmamode;
+- imxdma->resbytes = dma_length;
+
+ if (!dma_address) {
+ printk(KERN_ERR "imxdma%d: imx_dma_setup_single null address\n",
+@@ -228,8 +224,10 @@
+ int res;
+ struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch];
+
+- imxdma->sg = NULL;
+- imxdma->sgcount = 0;
++ if (imxdma->in_use)
++ return -EBUSY;
++
++ imxdma->sg = sg;
+ imxdma->dma_mode = dmamode;
+ imxdma->resbytes = dma_length;
+
+@@ -259,14 +257,43 @@
+ return -EINVAL;
+ }
+
+- res = imx_dma_setup_sg_base(dma_ch, sg, sgcount);
+- if (res <= 0) {
+- printk(KERN_ERR "imxdma%d: no sg chunk ready\n", dma_ch);
+- return -EINVAL;
+- }
++ imx_dma_sg_next(dma_ch, sg);
++
++ return 0;
++}
++
++int
++imx_dma_config_channel(int channel, unsigned int config_dest,
++ unsigned int config_src, unsigned int dmareq, int hw_chaining)
++{
++ struct imx_dma_channel *imxdma = &imx_dma_channels[channel];
++ u32 dreq = 0;
++
++ imxdma->hw_chaining = 0;
++
++// if (hw_chaining) {
++// imxdma->hw_chaining = 1;
++// if (!imx_dma_hw_chain(imxdma))
++// return -EINVAL;
++// }
++
++ if (dmareq)
++ dreq = CCR_REN;
++
++ CCR(channel) = config_src | (config_dest << 2) | dreq;
++// imxdma->ccr_to_device = config_mem | (config_port << 2) | dreq;
++
++ RSSR(channel) = dmareq;
+
+ return 0;
+ }
++EXPORT_SYMBOL(imx_dma_config_channel);
++
++void imx_dma_config_burstlen(int channel, unsigned int burstlen)
++{
++ BLR(channel) = burstlen;
++}
++EXPORT_SYMBOL(imx_dma_config_burstlen);
+
+ /**
+ * imx_dma_setup_handlers - setup i.MX DMA channel end and error notification handlers
+@@ -302,6 +329,32 @@
+ }
+
+ /**
++ * imx_dma_setup_progression_handler - setup i.MX DMA channel progression
++ * handlers
++ * @channel: i.MX DMA channel number
++ * @prog_handler: the pointer to the function called if the transfer progresses
++ */
++int
++imx_dma_setup_progression_handler(int channel,
++ void (*prog_handler) (int, void*, struct scatterlist*))
++{
++ struct imx_dma_channel *imxdma = &imx_dma_channels[channel];
++ unsigned long flags;
++
++ if (!imxdma->name) {
++ printk(KERN_CRIT "%s: called for not allocated channel %d\n",
++ __func__, channel);
++ return -ENODEV;
++ }
++
++ local_irq_save(flags);
++ imxdma->prog_handler = prog_handler;
++ local_irq_restore(flags);
++ return 0;
++}
++EXPORT_SYMBOL(imx_dma_setup_progression_handler);
++
++/**
+ * imx_dma_enable - function to start i.MX DMA channel operation
+ * @dma_ch: i.MX DMA channel number
+ *
+@@ -325,10 +378,15 @@
+ return;
+ }
+
++ if (imxdma->in_use)
++ return;
++
+ local_irq_save(flags);
+ DISR = (1 << dma_ch);
+ DIMR &= ~(1 << dma_ch);
+ CCR(dma_ch) |= CCR_CEN;
++ imxdma->in_use = 1;
++
+ local_irq_restore(flags);
+ }
+
+@@ -336,16 +394,18 @@
+ * imx_dma_disable - stop, finish i.MX DMA channel operatin
+ * @dma_ch: i.MX DMA channel number
+ */
+-void imx_dma_disable(imx_dmach_t dma_ch)
++void imx_dma_disable(int channel)
+ {
++ struct imx_dma_channel *imxdma = &imx_dma_channels[channel];
+ unsigned long flags;
+
+- pr_debug("imxdma%d: imx_dma_disable\n", dma_ch);
++ pr_debug("imxdma%d: imx_dma_disable\n", channel);
+
+ local_irq_save(flags);
+- DIMR |= (1 << dma_ch);
+- CCR(dma_ch) &= ~CCR_CEN;
+- DISR = (1 << dma_ch);
++ DIMR |= (1 << channel);
++ CCR(channel) &= ~CCR_CEN;
++ DISR = (1 << channel);
++ imxdma->in_use = 0;
+ local_irq_restore(flags);
+ }
+
+@@ -381,6 +441,7 @@
+ imxdma->data = NULL;
+ imxdma->sg = NULL;
+ local_irq_restore(flags);
++
+ return 0;
+ }
+
+@@ -452,6 +513,7 @@
+ }
+
+ printk(KERN_ERR "%s: no free DMA channel found\n", __func__);
++ dump_channels();
+
+ return -ENODEV;
+ }
+@@ -512,6 +574,46 @@
+ return IRQ_HANDLED;
+ }
+
++static void dma_irq_handle_channel(int chno)
++{
++ struct imx_dma_channel *channel = &imx_dma_channels[chno];
++
++ if (!channel->name) {
++ /*
++ * IRQ for an unregistered DMA channel:
++ * let's clear the interrupts and disable it.
++ */
++ printk(KERN_WARNING
++ "spurious IRQ for DMA channel %d\n", chno);
++ return;
++ }
++
++ if (channel->sg) {
++ struct scatterlist *current_sg = channel->sg;
++ channel->sg = sg_next(channel->sg);
++
++ if (channel->sg) {
++ imx_dma_sg_next(chno, channel->sg);
++
++ CCR(chno) &= ~CCR_CEN;
++ mb();
++ CCR(chno) |= CCR_CEN;
++
++ if (channel->prog_handler)
++ channel->prog_handler(chno, channel->data,
++ current_sg);
++
++ return;
++ }
++ }
++
++ CCR(chno) = 0;
++ channel->in_use = 0;
++
++ if (channel->irq_handler)
++ channel->irq_handler(chno, channel->data);
++}
++
+ static irqreturn_t dma_irq_handler(int irq, void *dev_id)
+ {
+ int i, disr = DISR;
+@@ -521,27 +623,8 @@
+
+ DISR = disr;
+ for (i = 0; i < IMX_DMA_CHANNELS; i++) {
+- if (disr & (1 << i)) {
+- struct imx_dma_channel *channel = &imx_dma_channels[i];
+- if (channel->name) {
+- if (imx_dma_sg_next(i, CNTR(i))) {
+- CCR(i) &= ~CCR_CEN;
+- mb();
+- CCR(i) |= CCR_CEN;
+- } else {
+- if (channel->irq_handler)
+- channel->irq_handler(i,
+- channel->data);
+- }
+- } else {
+- /*
+- * IRQ for an unregistered DMA channel:
+- * let's clear the interrupts and disable it.
+- */
+- printk(KERN_WARNING
+- "spurious IRQ for DMA channel %d\n", i);
+- }
+- }
++ if (disr & (1 << i))
++ dma_irq_handle_channel(i);
+ }
+ return IRQ_HANDLED;
+ }
Added: branches/tsc210x/buildroot/target/device/armadeus/linux/kernel-patches/2.6.27.2/linux-2.6.27.2-098-armadeus-imx-dma-announce_imx_is_supporting_scatter_gather.patch
===================================================================
--- branches/tsc210x/buildroot/target/device/armadeus/linux/kernel-patches/2.6.27.2/linux-2.6.27.2-098-armadeus-imx-dma-announce_imx_is_supporting_scatter_gather.patch (rev 0)
+++ branches/tsc210x/buildroot/target/device/armadeus/linux/kernel-patches/2.6.27.2/linux-2.6.27.2-098-armadeus-imx-dma-announce_imx_is_supporting_scatter_gather.patch 2009-01-19 09:21:41 UTC (rev 1022)
@@ -0,0 +1,12 @@
+--- linux-2.6.27.2.org/arch/arm/mach-imx/include/mach/hardware.h 2009-01-14 16:24:29.000000000 +0100
++++ linux-2.6.27.2/arch/arm/mach-imx/include/mach/hardware.h 2009-01-12 13:50:47.000000000 +0100
+@@ -23,6 +23,9 @@
+ #include <asm/sizes.h>
+ #include "imx-regs.h"
+
++/* the DMA code supports SG list chaining */
++#define ARCH_HAS_SG_CHAIN
++
+ #ifndef __ASSEMBLY__
+ # define __REG8(x) (*((volatile u8 *)IO_ADDRESS(x)))
+
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|