* [PATCH 1/3] VIA/Wondermedia clock support
From: Linux Mailing List Email Account @ 2011-02-27 0:05 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Tony Prisk (linux at prisktech.co.nz)
--- /dev/null 2011-02-26 19:04:30.530140059 +1300
+++ arch/arm/mach-vt8500/clock.h 2011-02-27 12:31:39.000000000 +1300
@@ -0,0 +1,136 @@
+/*
+ * arch/arm/mach-vt8500/clock.h
+ *
+ * Copyright (C) 2011 Tony Prisk
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __WMT_CLOCK_H
+#define __WMT_CLOCK_H
+
+#include <linux/list.h>
+#include <linux/clkdev.h>
+
+#define CLK_PRIMARY 0x00
+#define CLK_PROGRAMABLE 0x01
+#define CLK_ENABLE 0x02
+#define CLK_NO_PROPAGATE 0x04
+
+#define DEFINE_CKREF(_name, _rate) \
+struct clk clk_##_name = { \
+ .name = #_name, \
+ .parent = NULL, \
+ .ops = NULL, \
+ .rate = _rate, \
+ .type = CLK_PRIMARY, \
+ .delay = 0, \
+ .en_reg = 0, \
+ .en_bit = 0 \
+}
+
+#define DEFINE_CKEN(_name, _ops, _enreg, _enbit) \
+struct clk clk_##_name = { \
+ .name = #_name, \
+ .parent = NULL, \
+ .ops = _ops, \
+ .rate = 0, \
+ .type = CLK_ENABLE, \
+ .delay = 0, \
+ .en_reg = _enreg, \
+ .en_bit = _enbit, \
+ .div_reg = 0 \
+}
+
+#define DEFINE_CKPG(_name, _parent, _delay, _ops, _reg) \
+struct clk clk_##_name = { \
+ .name = #_name, \
+ .parent = _parent, \
+ .ops = _ops, \
+ .rate = 0, \
+ .type = CLK_PROGRAMABLE, \
+ .delay = _delay, \
+ .en_reg = 0, \
+ .en_bit = 0, \
+ .div_reg = _reg \
+}
+
+#define DEFINE_CKPGNP(_name, _parent, _delay, _ops, _reg) \
+struct clk clk_##_name = { \
+ .name = #_name, \
+ .parent = _parent, \
+ .ops = _ops, \
+ .rate = 0, \
+ .type = CLK_PROGRAMABLE | CLK_NO_PROPAGATE, \
+ .delay = _delay, \
+ .en_reg = 0, \
+ .en_bit = 0, \
+ .div_reg = _reg \
+}
+
+#define DEFINE_CKPGEN(_name, _parent, _delay, _ops, _reg, _enreg, _enbit) \
+struct clk clk_##_name = { \
+ .name = #_name, \
+ .parent = _parent, \
+ .ops = _ops, \
+ .rate = 0, \
+ .type = CLK_PROGRAMABLE | CLK_ENABLE, \
+ .delay = _delay, \
+ .en_reg = _enreg, \
+ .en_bit = _enbit, \
+ .div_reg = _reg \
+}
+
+
+#define INIT_CLKREG(_clk, _devid, _conid) \
+{ \
+ .clk = _clk, \
+ .dev_id = _devid, \
+ .con_id = _conid \
+}
+
+struct clkops {
+ void (*enable)(struct clk *);
+ void (*disable)(struct clk *);
+
+ unsigned long (*getrate)(struct clk *);
+ int (*setrate)(struct clk *, unsigned long rate);
+};
+
+struct clk {
+ struct list_head node;
+ struct clk *parent;
+ const struct clkops *ops;
+ const char *name;
+ unsigned long rate;
+ unsigned int type;
+ unsigned int delay;
+ unsigned int usecount;
+
+ unsigned int en_reg;
+ unsigned int en_bit;
+
+ unsigned int div_reg;
+
+ struct list_head children;
+ struct list_head childnode;
+};
+
+/* wm8505-clocks.c */
+extern int wmt_clock_init(void);
+
+int clk_register(struct clk *clk);
+
+#endif
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20110227/f0e8e49d/attachment.html>
^ permalink raw reply
* [PATCH 2/3] VIA/Wondermedia clock support
From: Linux Mailing List Email Account @ 2011-02-27 0:05 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Tony Prisk (linux at prisktech.co.nz)
--- /dev/null 2011-02-26 19:04:30.530140059 +1300
+++ arch/arm/mach-vt8500/clock.c 2011-02-27 12:12:39.000000000 +1300
@@ -0,0 +1,164 @@
+/*
+ * arch/arm/mach-vt8500/clock.c
+ *
+ * Copyright (C) 2011 Tony Prisk
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+
+#include "clock.h"
+
+static LIST_HEAD(clocks);
+
+static DEFINE_SPINLOCK(clocks_lock);
+static DEFINE_MUTEX(clocks_mutex);
+
+static void __clk_enable(struct clk *clk)
+{
+ if (clk->parent)
+ __clk_enable(clk->parent);
+ if (clk->usecount++ == 0)
+ if (clk->type & CLK_ENABLE)
+ clk->ops->enable(clk);
+}
+
+static void __clk_disable(struct clk *clk)
+{
+ if (--clk->usecount == 0)
+ if (clk->type & CLK_ENABLE)
+ clk->ops->disable(clk);
+ if (clk->parent)
+ __clk_disable(clk->parent);
+}
+
+int clk_enable(struct clk *clk)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&clocks_lock, flags);
+ __clk_enable(clk);
+ spin_unlock_irqrestore(&clocks_lock, flags);
+
+ if (clk->delay)
+ udelay(clk->delay);
+
+ return 0;
+}
+EXPORT_SYMBOL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+ unsigned long flags;
+
+ WARN_ON(clk->usecount == 0);
+
+ spin_lock_irqsave(&clocks_lock, flags);
+ __clk_disable(clk);
+ spin_unlock_irqrestore(&clocks_lock, flags);
+}
+EXPORT_SYMBOL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+ unsigned long rate;
+
+ if (clk == NULL || IS_ERR(clk))
+ return -EINVAL;
+
+ rate = clk->rate;
+ if ((clk->ops->getrate) && (clk->type & CLK_PROGRAMABLE))
+ rate = clk->ops->getrate(clk);
+
+ return rate;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+static void propagate_rate(struct clk *root)
+{
+ struct clk *clk;
+
+ list_for_each_entry(clk, &root->children, childnode) {
+ if (clk->ops->setrate)
+ clk->ops->setrate(clk, clk->rate);
+ if (clk->ops->getrate)
+ clk->rate = clk->ops->getrate(clk);
+ propagate_rate(clk);
+ }
+}
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ unsigned long flags;
+
+ if (clk == NULL || IS_ERR(clk))
+ return -EINVAL;
+
+ if (!(clk->type & CLK_PROGRAMABLE))
+ return -EINVAL;
+
+ if (clk->ops->setrate)
+ clk->ops->setrate(clk, rate);
+
+ if (clk->ops->getrate)
+ clk->rate = clk->ops->getrate(clk);
+
+ spin_lock_irqsave(&clocks_lock, flags);
+ if (!(clk->type & CLK_NO_PROPAGATE))
+ propagate_rate(clk);
+ spin_unlock_irqrestore(&clocks_lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(clk_set_rate);
+
+int clk_register(struct clk *clk)
+{
+ if (clk == NULL || IS_ERR(clk))
+ return -EINVAL;
+
+ if (clk->parent && !clk->parent->rate)
+ return -EINVAL;
+
+ INIT_LIST_HEAD(&clk->children);
+
+ mutex_lock(&clocks_mutex);
+ list_add_tail(&clk->node, &clocks);
+ if (clk->parent)
+ list_add_tail(&clk->childnode, &clk->parent->children);
+ mutex_unlock(&clocks_mutex);
+
+ /* if rate already set, use it */
+ if (clk->rate)
+ return 0;
+
+ /* see if we can calculate the rate */
+ if (clk->ops->getrate)
+ clk->ops->getrate(clk);
+ /* otherwise use the parents rate */
+ else if (clk->parent)
+ clk->rate = clk->parent->rate;
+
+ return 0;
+}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20110227/1fe5ec4a/attachment.html>
^ permalink raw reply
* [PATCH 0/3] VIA/Wondermedia clock support
From: Linux Mailing List Email Account @ 2011-02-27 0:05 UTC (permalink / raw)
To: linux-arm-kernel
Patch to provide clk_ support on the VIA VT8500/Wondermedia WM8505 SoC.
Signed-off-by: Tony Prisk (linux at prisktech.co.nz)
--- arch/arm/mach-vt8500/Makefile 2011-02-27 12:50:29.000000000 +1300
+++ arch/arm/mach-vt8500/Makefile 2011-02-27 12:50:04.000000000 +1300
@@ -4,1 +4,1 @@
-+obj-$(CONFIG_VTWM_VERSION_WM8505) += devices-wm8505.o
++obj-$(CONFIG_VTWM_VERSION_WM8505) += devices-wm8505.o clock.o wm8505-clocks.o
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20110227/a4efe74f/attachment.html>
^ permalink raw reply
* [PATCH 2/4] msm: scm: Fix improper register assignment
From: Nicolas Pitre @ 2011-02-26 20:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <8yazkpi3cfa.fsf@huya.qualcomm.com>
On Sat, 26 Feb 2011, David Brown wrote:
> On Sat, Feb 26 2011, Russell King - ARM Linux wrote:
>
> > On Fri, Feb 25, 2011 at 09:09:05PM -0800, Saravana Kannan wrote:
> > One way to look at it is that if you specify a value for r0, assign it,
> > and then call a function, how do you expect the r0 value to be preserved?
> > r0 will be corrupted by the called function as its used to pass arg0 and
> > the return value.
>
> > I'm surprised the compiler didn't spit out an error.
Me too. The compiler should have moved the content of r0 somewhere else
before the function call, and restore it back into r0 if necessary
before the point where the corresponding variable is used again. Or at
least issue a warning if it can't do that.
> The gcc docs say:
>
> * Local register variables in specific registers do not reserve the
> registers, except at the point where they are used as input or
> output operands in an `asm' statement and the `asm' statement
> itself is not deleted. The compiler's data flow analysis is
> capable of determining where the specified registers contain live
> values, and where they are available for other uses. Stores into
> local register variables may be deleted when they appear to be
> dead according to dataflow analysis. References to local register
> variables may be deleted or moved or simplified.
>
> which would suggest that it should at least detect that it can't keep
> the value in r0. What it seems to do is detect that the value can't be
> in the register, so it never bothers putting it there in the first
> place.
Right. A minimal test case may look like this if someone feels like
filling a gcc bug report:
extern int foo(int x);
int bar(int x)
{
register int a asm("r0") = 1;
x = foo(x);
asm ("add %0, %1, %2" : "=r" (x) : "r" (a), "r" (x));
return x;
}
And the produced code is:
bar:
stmfd sp!, {r3, lr}
bl foo
#APP
add r0, r0, r0
ldmfd sp!, {r3, pc}
So this is clearly bogus.
> In any case, fortunately it works with the fix.
Please add a comment in your patch to explain the issue.
Nicolas
^ permalink raw reply
* [PATCH 1/4] msm: scm: Mark inline asm as volatile
From: Nicolas Pitre @ 2011-02-26 19:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <8yapqqe3bs3.fsf@huya.qualcomm.com>
On Sat, 26 Feb 2011, David Brown wrote:
> On Fri, Feb 25 2011, Will Deacon wrote:
>
> > On Thu, 2011-02-24 at 18:44 +0000, Stephen Boyd wrote:
> >> We don't want the compiler to remove these asm statements or
> >> reorder them in any way. Mark them as volatile to be sure.
> >>
> >> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
> >> ---
> >> arch/arm/mach-msm/scm.c | 4 ++--
> >> 1 files changed, 2 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/arch/arm/mach-msm/scm.c b/arch/arm/mach-msm/scm.c
> >> index f4b9bc9..ba57b5a 100644
> >> --- a/arch/arm/mach-msm/scm.c
> >> +++ b/arch/arm/mach-msm/scm.c
> >> @@ -174,7 +174,7 @@ static u32 smc(u32 cmd_addr)
> >> register u32 r0 asm("r0") = 1;
> >> register u32 r1 asm("r1") = (u32)&context_id;
> >> register u32 r2 asm("r2") = cmd_addr;
> >> - asm(
> >> + asm volatile(
> >> __asmeq("%0", "r0")
> >> __asmeq("%1", "r0")
> >> __asmeq("%2", "r1")
> >> @@ -271,7 +271,7 @@ u32 scm_get_version(void)
> >> return version;
> >>
> >> mutex_lock(&scm_lock);
> >> - asm(
> >> + asm volatile(
> >> __asmeq("%0", "r1")
> >> __asmeq("%1", "r0")
> >> __asmeq("%2", "r1")
> >
> > These asm blocks all have sensible looking output constraints. Why
> > do they need to be marked volatile?
>
> Without the volatile, the compiler is free to assume the only side
> effects of the asm are to modify the output registers. The volatile is
> needed to indicate to the compiler that the asm has other side effects.
> There isn't enough optimization, yet, in gcc to change the generated
> code in this case, so it happens to generate the correct code without
> it.
>
> The second probably doesn't need it, unless we are expecting the version
> to change dynamically. The volatile makes the scm_get_version()
> function clearly a call to scm, though, so is probably useful to
> document the intent.
If the inline asm does have side effects which are not obvious other
than producing a result for the output operand then it is a good idea to
add a comment to that effect. Otherwise it is always best to omit the
volatile and let gcc move the inline asm around or even delete it
entirely when possible.
Nicolas
^ permalink raw reply
* [PATCH RESEND 2.6.39 0/3] ARM: simpad: Add support for GPIO attached hardware
From: Kristoffer Ericson @ 2011-02-26 18:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1298023368-27090-1-git-send-email-jochen@scram.de>
On Fri, Feb 18, 2011 at 11:02:45AM +0100, Jochen Friedrich wrote:
> This series enables GPIO API on UCB1x00 and implements the GPIO
> API on the CS3 latch. The third patch finally registers platform
> devices for the GPIO attached LED, buttons and I2C bus.
>
You gotten any feedback on those patches?
> ARM: simpad: Add ucb1x00 GPIO definitions and register GPIO
> ARM: simpad: Cleanup CS3 accessors and add GPIO API
> ARM: simpad: add GPIO based device definitions
^ permalink raw reply
* [PATCH 1/4] msm: scm: Mark inline asm as volatile
From: David Brown @ 2011-02-26 18:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1298635017.958.0.camel@e102144-lin.cambridge.arm.com>
On Fri, Feb 25 2011, Will Deacon wrote:
> On Thu, 2011-02-24 at 18:44 +0000, Stephen Boyd wrote:
>> We don't want the compiler to remove these asm statements or
>> reorder them in any way. Mark them as volatile to be sure.
>>
>> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
>> ---
>> arch/arm/mach-msm/scm.c | 4 ++--
>> 1 files changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/arch/arm/mach-msm/scm.c b/arch/arm/mach-msm/scm.c
>> index f4b9bc9..ba57b5a 100644
>> --- a/arch/arm/mach-msm/scm.c
>> +++ b/arch/arm/mach-msm/scm.c
>> @@ -174,7 +174,7 @@ static u32 smc(u32 cmd_addr)
>> register u32 r0 asm("r0") = 1;
>> register u32 r1 asm("r1") = (u32)&context_id;
>> register u32 r2 asm("r2") = cmd_addr;
>> - asm(
>> + asm volatile(
>> __asmeq("%0", "r0")
>> __asmeq("%1", "r0")
>> __asmeq("%2", "r1")
>> @@ -271,7 +271,7 @@ u32 scm_get_version(void)
>> return version;
>>
>> mutex_lock(&scm_lock);
>> - asm(
>> + asm volatile(
>> __asmeq("%0", "r1")
>> __asmeq("%1", "r0")
>> __asmeq("%2", "r1")
>
> These asm blocks all have sensible looking output constraints. Why
> do they need to be marked volatile?
Without the volatile, the compiler is free to assume the only side
effects of the asm are to modify the output registers. The volatile is
needed to indicate to the compiler that the asm has other side effects.
There isn't enough optimization, yet, in gcc to change the generated
code in this case, so it happens to generate the correct code without
it.
The second probably doesn't need it, unless we are expecting the version
to change dynamically. The volatile makes the scm_get_version()
function clearly a call to scm, though, so is probably useful to
document the intent.
David
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
^ permalink raw reply
* [PATCH 2/4] msm: scm: Fix improper register assignment
From: David Brown @ 2011-02-26 17:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110226084736.GB3640@n2100.arm.linux.org.uk>
On Sat, Feb 26 2011, Russell King - ARM Linux wrote:
> On Fri, Feb 25, 2011 at 09:09:05PM -0800, Saravana Kannan wrote:
>> Yeah, Stephen and I spent quite a bit of time discussing this and
>> experimenting to figure out what the heck GCC was doing. But it kept
>> optimizing the fake code we put in trying to force GCC to use a specific
>> register.
>
> One way to look at it is that if you specify a value for r0, assign it,
> and then call a function, how do you expect the r0 value to be preserved?
> r0 will be corrupted by the called function as its used to pass arg0 and
> the return value.
> I'm surprised the compiler didn't spit out an error.
The gcc docs say:
* Local register variables in specific registers do not reserve the
registers, except at the point where they are used as input or
output operands in an `asm' statement and the `asm' statement
itself is not deleted. The compiler's data flow analysis is
capable of determining where the specified registers contain live
values, and where they are available for other uses. Stores into
local register variables may be deleted when they appear to be
dead according to dataflow analysis. References to local register
variables may be deleted or moved or simplified.
which would suggest that it should at least detect that it can't keep
the value in r0. What it seems to do is detect that the value can't be
in the register, so it never bothers putting it there in the first
place.
In any case, fortunately it works with the fix.
David
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
^ permalink raw reply
* [PATCH 1/2] lib: vsprintf: optimised put_dec() function
From: Denys Vlasenko @ 2011-02-26 17:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110224141818.7fd0207f.akpm@linux-foundation.org>
On Thursday 24 February 2011 23:18, Andrew Morton wrote:
> On Thu, 24 Feb 2011 23:10:09 +0100
> "Michal Nazarewicz" <mnazarewicz@google.com> wrote:
>
> > On Thu, 24 Feb 2011 22:52:42 +0100, Andrew Morton wrote:
> > > Also, the funky indenting to align on the "=" is atypical for kernel
> > > code and is inconsistent with the rest of vsprintf.c. Just a single
> > > space, please.
> >
> > Want me to resubmit with spaces fixed?
>
> nah, we'll live.
>
> I'd prefer that you find a workload where it actually matters :)
/proc data has a lot of decimal numbers, and many tools parse it
repeatedly. Think {,power,io}top, mpstat with a few thousands
of processes. I observed 10% overall speedup in those tools on i386
when vsprintf was optimised last time.
While we are at it, how about adding this trivial patch?
It should speed up generation of small integers: 1,2...7.
They are quite typical values. Look at the output of, say
cat /proc/$$/stat
cat /proc/net/unix
--
vda
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index d3023df..c399d38 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -455,8 +455,8 @@ char *number(char *buf, char *end, unsigned long long num,
/* generate full string in tmp[], in reverse order */
i = 0;
- if (num == 0)
- tmp[i++] = '0';
+ if (num < 8)
+ tmp[i++] = num + '0';
/* Generic code, for any base:
else do {
tmp[i++] = (digits[do_div(num,base)] | locase);
^ permalink raw reply related
* [PATCH v5] dmaengine: mxs-dma: add dma support for i.MX23/28
From: Shawn Guo @ 2011-02-26 16:47 UTC (permalink / raw)
To: linux-arm-kernel
This patch adds dma support for Freescale MXS-based SoC i.MX23/28,
including apbh-dma and apbx-dma.
* apbh-dma and apbx-dma are supported in the driver as two mxs-dma
instances.
* apbh-dma is different between mx23 and mx28, hardware version
register is used to differentiate.
* mxs-dma supports pio function besides data transfer. The driver
uses dma_data_direction DMA_NONE to identify the pio mode, and
steals sgl and sg_len to get pio words and numbers from clients.
* mxs dmaengine has some very specific features, like sense function
and the special NAND support (nand_lock, nand_wait4ready). These
are too specific to implemented in generic dmaengine driver.
* The driver refers to imx-sdma and only a single descriptor is
statically assigned to each channel.
Signed-off-by: Shawn Guo <shawn.guo@freescale.com>
---
Change since v4:
Fix checkpatch errors (sorry for forgetting this basical requirement)
arch/arm/mach-mxs/include/mach/dma.h | 26 ++
drivers/dma/Kconfig | 8 +
drivers/dma/Makefile | 1 +
drivers/dma/mxs-dma.c | 724 ++++++++++++++++++++++++++++++++++
4 files changed, 759 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/mach-mxs/include/mach/dma.h
create mode 100644 drivers/dma/mxs-dma.c
diff --git a/arch/arm/mach-mxs/include/mach/dma.h b/arch/arm/mach-mxs/include/mach/dma.h
new file mode 100644
index 0000000..7f4aeea
--- /dev/null
+++ b/arch/arm/mach-mxs/include/mach/dma.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __MACH_MXS_DMA_H__
+#define __MACH_MXS_DMA_H__
+
+struct mxs_dma_data {
+ int chan_irq;
+};
+
+static inline int mxs_dma_is_apbh(struct dma_chan *chan)
+{
+ return !strcmp(dev_name(chan->device->dev), "mxs-dma-apbh");
+}
+
+static inline int mxs_dma_is_apbx(struct dma_chan *chan)
+{
+ return !strcmp(dev_name(chan->device->dev), "mxs-dma-apbx");
+}
+
+#endif /* __MACH_MXS_DMA_H__ */
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 1c28816..76f6472 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -227,6 +227,14 @@ config IMX_DMA
Support the i.MX DMA engine. This engine is integrated into
Freescale i.MX1/21/27 chips.
+config MXS_DMA
+ bool "MXS DMA support"
+ depends on SOC_IMX23 || SOC_IMX28
+ select DMA_ENGINE
+ help
+ Support the MXS DMA engine. This engine including APBH-DMA
+ and APBX-DMA is integrated into Freescale i.MX23/28 chips.
+
config DMA_ENGINE
bool
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 64b21f5..802b557 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_COH901318) += coh901318.o coh901318_lli.o
obj-$(CONFIG_AMCC_PPC440SPE_ADMA) += ppc4xx/
obj-$(CONFIG_IMX_SDMA) += imx-sdma.o
obj-$(CONFIG_IMX_DMA) += imx-dma.o
+obj-$(CONFIG_MXS_DMA) += mxs-dma.o
obj-$(CONFIG_TIMB_DMA) += timb_dma.o
obj-$(CONFIG_STE_DMA40) += ste_dma40.o ste_dma40_ll.o
obj-$(CONFIG_PL330_DMA) += pl330.o
diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c
new file mode 100644
index 0000000..88aad4f
--- /dev/null
+++ b/drivers/dma/mxs-dma.c
@@ -0,0 +1,724 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Refer to drivers/dma/imx-sdma.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/semaphore.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/dmaengine.h>
+#include <linux/delay.h>
+
+#include <asm/irq.h>
+#include <mach/mxs.h>
+#include <mach/dma.h>
+#include <mach/common.h>
+
+/*
+ * NOTE: The term "PIO" throughout the mxs-dma implementation means
+ * PIO mode of mxs apbh-dma and apbx-dma. With this working mode,
+ * dma can program the controller registers of peripheral devices.
+ */
+
+#define MXS_DMA_APBH 0
+#define MXS_DMA_APBX 1
+#define dma_is_apbh() (mxs_dma->dev_id == MXS_DMA_APBH)
+
+#define APBH_VERSION_LATEST 3
+#define apbh_is_old() (mxs_dma->version < APBH_VERSION_LATEST)
+
+#define HW_APBHX_CTRL0 0x000
+#define BM_APBH_CTRL0_APB_BURST8_EN (1 << 29)
+#define BM_APBH_CTRL0_APB_BURST_EN (1 << 28)
+#define BP_APBH_CTRL0_CLKGATE_CHANNEL 8
+#define BP_APBH_CTRL0_RESET_CHANNEL 16
+#define HW_APBHX_CTRL1 0x010
+#define HW_APBHX_CTRL2 0x020
+#define HW_APBHX_CHANNEL_CTRL 0x030
+#define BP_APBHX_CHANNEL_CTRL_RESET_CHANNEL 16
+#define HW_APBH_VERSION (cpu_is_mx23() ? 0x3f0 : 0x800)
+#define HW_APBX_VERSION 0x800
+#define BP_APBHX_VERSION_MAJOR 24
+#define HW_APBHX_CHn_NXTCMDAR(n) \
+ (((dma_is_apbh() && apbh_is_old()) ? 0x050 : 0x110) + (n) * 0x70)
+#define HW_APBHX_CHn_SEMA(n) \
+ (((dma_is_apbh() && apbh_is_old()) ? 0x080 : 0x140) + (n) * 0x70)
+
+/*
+ * ccw bits definitions
+ *
+ * COMMAND: 0..1 (2)
+ * CHAIN: 2 (1)
+ * IRQ: 3 (1)
+ * NAND_LOCK: 4 (1) - not implemented
+ * NAND_WAIT4READY: 5 (1) - not implemented
+ * DEC_SEM: 6 (1)
+ * WAIT4END: 7 (1)
+ * HALT_ON_TERMINATE: 8 (1)
+ * TERMINATE_FLUSH: 9 (1)
+ * RESERVED: 10..11 (2)
+ * PIO_NUM: 12..15 (4)
+ */
+#define BP_CCW_COMMAND 0
+#define BM_CCW_COMMAND (3 << 0)
+#define CCW_CHAIN (1 << 2)
+#define CCW_IRQ (1 << 3)
+#define CCW_DEC_SEM (1 << 6)
+#define CCW_WAIT4END (1 << 7)
+#define CCW_HALT_ON_TERM (1 << 8)
+#define CCW_TERM_FLUSH (1 << 9)
+#define BP_CCW_PIO_NUM 12
+#define BM_CCW_PIO_NUM (0xf << 12)
+
+#define BF_CCW(value, field) (((value) << BP_CCW_##field) & BM_CCW_##field)
+
+#define MXS_DMA_CMD_NO_XFER 0
+#define MXS_DMA_CMD_WRITE 1
+#define MXS_DMA_CMD_READ 2
+#define MXS_DMA_CMD_DMA_SENSE 3 /* not implemented */
+
+struct mxs_dma_ccw {
+ u32 next;
+ u16 bits;
+ u16 xfer_bytes;
+#define MAX_XFER_BYTES 0xff00
+ u32 bufaddr;
+#define MXS_PIO_WORDS 16
+ u32 pio_words[MXS_PIO_WORDS];
+};
+
+#define NUM_CCW (int)(PAGE_SIZE / sizeof(struct mxs_dma_ccw))
+
+struct mxs_dma_chan {
+ struct mxs_dma_engine *mxs_dma;
+ struct dma_chan chan;
+ struct dma_async_tx_descriptor desc;
+ struct tasklet_struct tasklet;
+ int chan_irq;
+ struct mxs_dma_ccw *ccw;
+ dma_addr_t ccw_phys;
+ dma_cookie_t last_completed;
+ enum dma_status status;
+ unsigned int flags;
+#define MXS_DMA_SG_LOOP (1 << 0)
+};
+
+#define MXS_DMA_CHANNELS 16
+#define MXS_DMA_CHANNELS_MASK 0xffff
+
+struct mxs_dma_engine {
+ int dev_id;
+ unsigned int version;
+ void __iomem *base;
+ struct clk *clk;
+ struct dma_device dma_device;
+ struct device_dma_parameters dma_parms;
+ struct mxs_dma_chan mxs_chans[MXS_DMA_CHANNELS];
+};
+
+static void mxs_dma_reset_chan(struct mxs_dma_chan *mxs_chan)
+{
+ struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
+ int chan_id = mxs_chan->chan.chan_id;
+
+ if (dma_is_apbh() && apbh_is_old())
+ writel(1 << (chan_id + BP_APBH_CTRL0_RESET_CHANNEL),
+ mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR);
+ else
+ writel(1 << (chan_id + BP_APBHX_CHANNEL_CTRL_RESET_CHANNEL),
+ mxs_dma->base + HW_APBHX_CHANNEL_CTRL + MXS_SET_ADDR);
+}
+
+static void mxs_dma_enable_chan(struct mxs_dma_chan *mxs_chan)
+{
+ struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
+ int chan_id = mxs_chan->chan.chan_id;
+
+ /* set cmd_addr up */
+ writel(mxs_chan->ccw_phys,
+ mxs_dma->base + HW_APBHX_CHn_NXTCMDAR(chan_id));
+
+ /* enable apbh channel clock */
+ if (dma_is_apbh()) {
+ if (apbh_is_old())
+ writel(1 << (chan_id + BP_APBH_CTRL0_CLKGATE_CHANNEL),
+ mxs_dma->base + HW_APBHX_CTRL0 + MXS_CLR_ADDR);
+ else
+ writel(1 << chan_id,
+ mxs_dma->base + HW_APBHX_CTRL0 + MXS_CLR_ADDR);
+ }
+
+ /* write 1 to SEMA to kick off the channel */
+ writel(1, mxs_dma->base + HW_APBHX_CHn_SEMA(chan_id));
+}
+
+static void mxs_dma_disable_chan(struct mxs_dma_chan *mxs_chan)
+{
+ struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
+ int chan_id = mxs_chan->chan.chan_id;
+
+ /* disable apbh channel clock */
+ if (dma_is_apbh()) {
+ if (apbh_is_old())
+ writel(1 << (chan_id + BP_APBH_CTRL0_CLKGATE_CHANNEL),
+ mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR);
+ else
+ writel(1 << chan_id,
+ mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR);
+ }
+
+ mxs_chan->status = DMA_SUCCESS;
+}
+
+static void mxs_dma_pause_chan(struct mxs_dma_chan *mxs_chan)
+{
+ struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
+ int chan_id = mxs_chan->chan.chan_id;
+
+ /* freeze the channel */
+ if (dma_is_apbh() && apbh_is_old())
+ writel(1 << chan_id,
+ mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR);
+ else
+ writel(1 << chan_id,
+ mxs_dma->base + HW_APBHX_CHANNEL_CTRL + MXS_SET_ADDR);
+
+ mxs_chan->status = DMA_PAUSED;
+}
+
+static void mxs_dma_resume_chan(struct mxs_dma_chan *mxs_chan)
+{
+ struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
+ int chan_id = mxs_chan->chan.chan_id;
+
+ /* unfreeze the channel */
+ if (dma_is_apbh() && apbh_is_old())
+ writel(1 << chan_id,
+ mxs_dma->base + HW_APBHX_CTRL0 + MXS_CLR_ADDR);
+ else
+ writel(1 << chan_id,
+ mxs_dma->base + HW_APBHX_CHANNEL_CTRL + MXS_CLR_ADDR);
+
+ mxs_chan->status = DMA_IN_PROGRESS;
+}
+
+static dma_cookie_t mxs_dma_assign_cookie(struct mxs_dma_chan *mxs_chan)
+{
+ dma_cookie_t cookie = mxs_chan->chan.cookie;
+
+ if (++cookie < 0)
+ cookie = 1;
+
+ mxs_chan->chan.cookie = cookie;
+ mxs_chan->desc.cookie = cookie;
+
+ return cookie;
+}
+
+static struct mxs_dma_chan *to_mxs_dma_chan(struct dma_chan *chan)
+{
+ return container_of(chan, struct mxs_dma_chan, chan);
+}
+
+static dma_cookie_t mxs_dma_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+ struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(tx->chan);
+
+ mxs_dma_enable_chan(mxs_chan);
+
+ return mxs_dma_assign_cookie(mxs_chan);
+}
+
+static void mxs_dma_tasklet(unsigned long data)
+{
+ struct mxs_dma_chan *mxs_chan = (struct mxs_dma_chan *) data;
+
+ if (mxs_chan->desc.callback)
+ mxs_chan->desc.callback(mxs_chan->desc.callback_param);
+}
+
+static irqreturn_t mxs_dma_int_handler(int irq, void *dev_id)
+{
+ struct mxs_dma_engine *mxs_dma = dev_id;
+ u32 stat1, stat2;
+
+ /* completion status */
+ stat1 = readl(mxs_dma->base + HW_APBHX_CTRL1);
+ stat1 &= MXS_DMA_CHANNELS_MASK;
+ writel(stat1, mxs_dma->base + HW_APBHX_CTRL1 + MXS_CLR_ADDR);
+
+ /* error status */
+ stat2 = readl(mxs_dma->base + HW_APBHX_CTRL2);
+ writel(stat2, mxs_dma->base + HW_APBHX_CTRL2 + MXS_CLR_ADDR);
+
+ /*
+ * When both completion and error of termination bits set at the
+ * same time, we do not take it as an error. IOW, it only becomes
+ * an error we need to handler here in case of ether it's (1) an bus
+ * error or (2) a termination error with no completion.
+ */
+ stat2 = ((stat2 >> MXS_DMA_CHANNELS) & stat2) | /* (1) */
+ (~(stat2 >> MXS_DMA_CHANNELS) & stat2 & ~stat1); /* (2) */
+
+ /* combine error and completion status for checking */
+ stat1 = (stat2 << MXS_DMA_CHANNELS) | stat1;
+ while (stat1) {
+ int channel = fls(stat1) - 1;
+ struct mxs_dma_chan *mxs_chan =
+ &mxs_dma->mxs_chans[channel % MXS_DMA_CHANNELS];
+
+ if (channel >= MXS_DMA_CHANNELS) {
+ dev_dbg(mxs_dma->dma_device.dev,
+ "%s: error in channel %d\n", __func__,
+ channel - MXS_DMA_CHANNELS);
+ mxs_chan->status = DMA_ERROR;
+ mxs_dma_reset_chan(mxs_chan);
+ } else {
+ if (mxs_chan->flags & MXS_DMA_SG_LOOP)
+ mxs_chan->status = DMA_IN_PROGRESS;
+ else
+ mxs_chan->status = DMA_SUCCESS;
+ }
+
+ stat1 &= ~(1 << channel);
+
+ if (mxs_chan->status == DMA_SUCCESS)
+ mxs_chan->last_completed = mxs_chan->desc.cookie;
+
+ /* schedule tasklet on this channel */
+ tasklet_schedule(&mxs_chan->tasklet);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int mxs_dma_alloc_chan_resources(struct dma_chan *chan)
+{
+ struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
+ struct mxs_dma_data *data = chan->private;
+ struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
+ int ret;
+
+ if (!data)
+ return -EINVAL;
+
+ mxs_chan->chan_irq = data->chan_irq;
+
+ mxs_chan->ccw = dma_alloc_coherent(mxs_dma->dma_device.dev, PAGE_SIZE,
+ &mxs_chan->ccw_phys, GFP_KERNEL);
+ if (!mxs_chan->ccw) {
+ ret = -ENOMEM;
+ goto err_alloc;
+ }
+
+ memset(mxs_chan->ccw, 0, PAGE_SIZE);
+
+ ret = request_irq(mxs_chan->chan_irq, mxs_dma_int_handler,
+ 0, "mxs-dma", mxs_dma);
+ if (ret)
+ goto err_irq;
+
+ ret = clk_enable(mxs_dma->clk);
+ if (ret)
+ goto err_clk;
+
+ mxs_dma_reset_chan(mxs_chan);
+
+ dma_async_tx_descriptor_init(&mxs_chan->desc, chan);
+ mxs_chan->desc.tx_submit = mxs_dma_tx_submit;
+
+ /* the descriptor is ready */
+ async_tx_ack(&mxs_chan->desc);
+
+ return 0;
+
+err_clk:
+ free_irq(mxs_chan->chan_irq, mxs_dma);
+err_irq:
+ dma_free_coherent(mxs_dma->dma_device.dev, PAGE_SIZE,
+ mxs_chan->ccw, mxs_chan->ccw_phys);
+err_alloc:
+ return ret;
+}
+
+static void mxs_dma_free_chan_resources(struct dma_chan *chan)
+{
+ struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
+ struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
+
+ mxs_dma_disable_chan(mxs_chan);
+
+ free_irq(mxs_chan->chan_irq, mxs_dma);
+
+ dma_free_coherent(mxs_dma->dma_device.dev, PAGE_SIZE,
+ mxs_chan->ccw, mxs_chan->ccw_phys);
+
+ clk_disable(mxs_dma->clk);
+}
+
+static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg(
+ struct dma_chan *chan, struct scatterlist *sgl,
+ unsigned int sg_len, enum dma_data_direction direction,
+ unsigned long append)
+{
+ struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
+ struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
+ struct mxs_dma_ccw *ccw;
+ struct scatterlist *sg;
+ int i, j;
+ u32 *pio;
+ static int idx;
+
+ if (mxs_chan->status == DMA_IN_PROGRESS && !append)
+ return NULL;
+
+ if (sg_len + (append ? idx : 0) > NUM_CCW) {
+ dev_err(mxs_dma->dma_device.dev,
+ "maximum number of sg exceeded: %d > %d\n",
+ sg_len, NUM_CCW);
+ goto err_out;
+ }
+
+ mxs_chan->status = DMA_IN_PROGRESS;
+ mxs_chan->flags = 0;
+
+ /*
+ * If the sg is prepared with append flag set, the sg
+ * will be appended to the last prepared sg.
+ */
+ if (append) {
+ BUG_ON(idx < 1);
+ ccw = &mxs_chan->ccw[idx - 1];
+ ccw->next = mxs_chan->ccw_phys + sizeof(*ccw) * idx;
+ ccw->bits |= CCW_CHAIN;
+ ccw->bits &= ~CCW_IRQ;
+ ccw->bits &= ~CCW_DEC_SEM;
+ ccw->bits &= ~CCW_WAIT4END;
+ } else {
+ idx = 0;
+ }
+
+ if (direction == DMA_NONE) {
+ ccw = &mxs_chan->ccw[idx++];
+ pio = (u32 *) sgl;
+
+ for (j = 0; j < sg_len;)
+ ccw->pio_words[j++] = *pio++;
+
+ ccw->bits = 0;
+ ccw->bits |= CCW_IRQ;
+ ccw->bits |= CCW_DEC_SEM;
+ ccw->bits |= CCW_WAIT4END;
+ ccw->bits |= CCW_HALT_ON_TERM;
+ ccw->bits |= CCW_TERM_FLUSH;
+ ccw->bits |= BF_CCW(sg_len, PIO_NUM);
+ ccw->bits |= BF_CCW(MXS_DMA_CMD_NO_XFER, COMMAND);
+ } else {
+ for_each_sg(sgl, sg, sg_len, i) {
+ if (sg->length > MAX_XFER_BYTES) {
+ dev_err(mxs_dma->dma_device.dev, "maximum bytes for sg entry exceeded: %d > %d\n",
+ sg->length, MAX_XFER_BYTES);
+ goto err_out;
+ }
+
+ ccw = &mxs_chan->ccw[idx++];
+
+ ccw->next = mxs_chan->ccw_phys + sizeof(*ccw) * idx;
+ ccw->bufaddr = sg->dma_address;
+ ccw->xfer_bytes = sg->length;
+
+ ccw->bits = 0;
+ ccw->bits |= CCW_CHAIN;
+ ccw->bits |= CCW_HALT_ON_TERM;
+ ccw->bits |= CCW_TERM_FLUSH;
+ ccw->bits |= BF_CCW(direction == DMA_FROM_DEVICE ?
+ MXS_DMA_CMD_WRITE : MXS_DMA_CMD_READ,
+ COMMAND);
+
+ if (i + 1 == sg_len) {
+ ccw->bits &= ~CCW_CHAIN;
+ ccw->bits |= CCW_IRQ;
+ ccw->bits |= CCW_DEC_SEM;
+ ccw->bits |= CCW_WAIT4END;
+ }
+ }
+ }
+
+ return &mxs_chan->desc;
+
+err_out:
+ mxs_chan->status = DMA_ERROR;
+ return NULL;
+}
+
+static struct dma_async_tx_descriptor *mxs_dma_prep_dma_cyclic(
+ struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
+ size_t period_len, enum dma_data_direction direction)
+{
+ struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
+ struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
+ int num_periods = buf_len / period_len;
+ int i = 0, buf = 0;
+
+ if (mxs_chan->status == DMA_IN_PROGRESS)
+ return NULL;
+
+ mxs_chan->status = DMA_IN_PROGRESS;
+ mxs_chan->flags |= MXS_DMA_SG_LOOP;
+
+ if (num_periods > NUM_CCW) {
+ dev_err(mxs_dma->dma_device.dev,
+ "maximum number of sg exceeded: %d > %d\n",
+ num_periods, NUM_CCW);
+ goto err_out;
+ }
+
+ if (period_len > MAX_XFER_BYTES) {
+ dev_err(mxs_dma->dma_device.dev,
+ "maximum period size exceeded: %d > %d\n",
+ period_len, MAX_XFER_BYTES);
+ goto err_out;
+ }
+
+ while (buf < buf_len) {
+ struct mxs_dma_ccw *ccw = &mxs_chan->ccw[i];
+
+ if (i + 1 == num_periods)
+ ccw->next = mxs_chan->ccw_phys;
+ else
+ ccw->next = mxs_chan->ccw_phys + sizeof(*ccw) * (i + 1);
+
+ ccw->bufaddr = dma_addr;
+ ccw->xfer_bytes = period_len;
+
+ ccw->bits = 0;
+ ccw->bits |= CCW_CHAIN;
+ ccw->bits |= CCW_IRQ;
+ ccw->bits |= CCW_HALT_ON_TERM;
+ ccw->bits |= CCW_TERM_FLUSH;
+ ccw->bits |= BF_CCW(direction == DMA_FROM_DEVICE ?
+ MXS_DMA_CMD_WRITE : MXS_DMA_CMD_READ, COMMAND);
+
+ dma_addr += period_len;
+ buf += period_len;
+
+ i++;
+ }
+
+ return &mxs_chan->desc;
+
+err_out:
+ mxs_chan->status = DMA_ERROR;
+ return NULL;
+}
+
+static int mxs_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+ unsigned long arg)
+{
+ struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
+ int ret = 0;
+
+ switch (cmd) {
+ case DMA_TERMINATE_ALL:
+ mxs_dma_disable_chan(mxs_chan);
+ break;
+ case DMA_PAUSE:
+ mxs_dma_pause_chan(mxs_chan);
+ break;
+ case DMA_RESUME:
+ mxs_dma_resume_chan(mxs_chan);
+ break;
+ default:
+ ret = -ENOSYS;
+ }
+
+ return ret;
+}
+
+static enum dma_status mxs_dma_tx_status(struct dma_chan *chan,
+ dma_cookie_t cookie, struct dma_tx_state *txstate)
+{
+ struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
+ dma_cookie_t last_used;
+
+ last_used = chan->cookie;
+ dma_set_tx_state(txstate, mxs_chan->last_completed, last_used, 0);
+
+ return mxs_chan->status;
+}
+
+static void mxs_dma_issue_pending(struct dma_chan *chan)
+{
+ /*
+ * Nothing to do. We only have a single descriptor.
+ */
+}
+
+static int __init mxs_dma_init(struct mxs_dma_engine *mxs_dma)
+{
+ int ret;
+
+ ret = clk_enable(mxs_dma->clk);
+ if (ret)
+ goto err_out;
+
+ ret = mxs_reset_block(mxs_dma->base);
+ if (ret)
+ goto err_out;
+
+ /* only major version matters */
+ mxs_dma->version = readl(mxs_dma->base +
+ ((mxs_dma->dev_id == MXS_DMA_APBX) ?
+ HW_APBX_VERSION : HW_APBH_VERSION)) >>
+ BP_APBHX_VERSION_MAJOR;
+
+ /* enable apbh burst */
+ if (dma_is_apbh()) {
+ writel(BM_APBH_CTRL0_APB_BURST_EN,
+ mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR);
+ writel(BM_APBH_CTRL0_APB_BURST8_EN,
+ mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR);
+ }
+
+ /* enable irq for all the channels */
+ writel(MXS_DMA_CHANNELS_MASK << MXS_DMA_CHANNELS,
+ mxs_dma->base + HW_APBHX_CTRL1 + MXS_SET_ADDR);
+
+ clk_disable(mxs_dma->clk);
+
+ return 0;
+
+err_out:
+ return ret;
+}
+
+static int __init mxs_dma_probe(struct platform_device *pdev)
+{
+ const struct platform_device_id *id_entry =
+ platform_get_device_id(pdev);
+ struct mxs_dma_engine *mxs_dma;
+ struct resource *iores;
+ int ret, i;
+
+ mxs_dma = kzalloc(sizeof(*mxs_dma), GFP_KERNEL);
+ if (!mxs_dma)
+ return -ENOMEM;
+
+ mxs_dma->dev_id = id_entry->driver_data;
+
+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ if (!request_mem_region(iores->start, resource_size(iores),
+ pdev->name)) {
+ ret = -EBUSY;
+ goto err_request_region;
+ }
+
+ mxs_dma->base = ioremap(iores->start, resource_size(iores));
+ if (!mxs_dma->base) {
+ ret = -ENOMEM;
+ goto err_ioremap;
+ }
+
+ mxs_dma->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(mxs_dma->clk)) {
+ ret = PTR_ERR(mxs_dma->clk);
+ goto err_clk;
+ }
+
+ dma_cap_set(DMA_SLAVE, mxs_dma->dma_device.cap_mask);
+ dma_cap_set(DMA_CYCLIC, mxs_dma->dma_device.cap_mask);
+
+ INIT_LIST_HEAD(&mxs_dma->dma_device.channels);
+
+ /* Initialize channel parameters */
+ for (i = 0; i < MXS_DMA_CHANNELS; i++) {
+ struct mxs_dma_chan *mxs_chan = &mxs_dma->mxs_chans[i];
+
+ mxs_chan->mxs_dma = mxs_dma;
+ mxs_chan->chan.device = &mxs_dma->dma_device;
+
+ tasklet_init(&mxs_chan->tasklet, mxs_dma_tasklet,
+ (unsigned long) mxs_chan);
+
+
+ /* Add the channel to mxs_chan list */
+ list_add_tail(&mxs_chan->chan.device_node,
+ &mxs_dma->dma_device.channels);
+ }
+
+ ret = mxs_dma_init(mxs_dma);
+ if (ret)
+ goto err_init;
+
+ mxs_dma->dma_device.dev = &pdev->dev;
+
+ /* mxs_dma gets 65535 bytes maximum sg size */
+ mxs_dma->dma_device.dev->dma_parms = &mxs_dma->dma_parms;
+ dma_set_max_seg_size(mxs_dma->dma_device.dev, MAX_XFER_BYTES);
+
+ mxs_dma->dma_device.device_alloc_chan_resources = mxs_dma_alloc_chan_resources;
+ mxs_dma->dma_device.device_free_chan_resources = mxs_dma_free_chan_resources;
+ mxs_dma->dma_device.device_tx_status = mxs_dma_tx_status;
+ mxs_dma->dma_device.device_prep_slave_sg = mxs_dma_prep_slave_sg;
+ mxs_dma->dma_device.device_prep_dma_cyclic = mxs_dma_prep_dma_cyclic;
+ mxs_dma->dma_device.device_control = mxs_dma_control;
+ mxs_dma->dma_device.device_issue_pending = mxs_dma_issue_pending;
+
+ ret = dma_async_device_register(&mxs_dma->dma_device);
+ if (ret) {
+ dev_err(mxs_dma->dma_device.dev, "unable to register\n");
+ goto err_init;
+ }
+
+ dev_info(mxs_dma->dma_device.dev, "initialized\n");
+
+ return 0;
+
+err_init:
+ clk_put(mxs_dma->clk);
+err_clk:
+ iounmap(mxs_dma->base);
+err_ioremap:
+ release_mem_region(iores->start, resource_size(iores));
+err_request_region:
+ kfree(mxs_dma);
+ return ret;
+}
+
+static struct platform_device_id mxs_dma_type[] = {
+ {
+ .name = "mxs-dma-apbh",
+ .driver_data = MXS_DMA_APBH,
+ }, {
+ .name = "mxs-dma-apbx",
+ .driver_data = MXS_DMA_APBX,
+ }
+};
+
+static struct platform_driver mxs_dma_driver = {
+ .driver = {
+ .name = "mxs-dma",
+ },
+ .id_table = mxs_dma_type,
+};
+
+static int __init mxs_dma_module_init(void)
+{
+ return platform_driver_probe(&mxs_dma_driver, mxs_dma_probe);
+}
+subsys_initcall(mxs_dma_module_init);
--
1.7.1
^ permalink raw reply related
* [PATCH v2 1/3] ARM: PXA: PXAFB: Fix double-free issue
From: Vasily Khoruzhick @ 2011-02-26 16:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <201102201946.20681.marek.vasut@gmail.com>
On Sunday 20 February 2011 20:46:20 Marek Vasut wrote:
> > @@ -629,6 +629,9 @@ static void overlay1fb_disable(struct pxafb_layer
> > *ofb)
> >
> > {
> >
> > uint32_t lccr5 = lcd_readl(ofb->fbi, LCCR5);
> >
> > + if (!(lcd_readl(ofb->fbi, OVL1C1) & OVLxC1_OEN))
> > + return;
> > +
>
> Maybe you can even avoid reading LCCR5 above ;-)
Agreed.
Will resend soon.
^ permalink raw reply
* [PATCH 1/2] drivers/watchdog/s3c2410_wdt.c: Convert release_resource to release_region/release_mem_region
From: Julia Lawall @ 2011-02-26 16:34 UTC (permalink / raw)
To: linux-arm-kernel
Request_mem_region should be used with release_mem_region, not
release_resource.
The semantic match that finds this problem is as follows:
(http://coccinelle.lip6.fr/)
// <smpl>
@@
expression x,E;
@@
*x = request_mem_region(...)
... when != release_mem_region(x)
when != x = E
* release_resource(x);
// </smpl>
Signed-off-by: Julia Lawall <julia@diku.dk>
---
drivers/watchdog/s3c2410_wdt.c | 19 ++++++++-----------
1 file changed, 8 insertions(+), 11 deletions(-)
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c
index 25b39bf..95ae53d 100644
--- a/drivers/watchdog/s3c2410_wdt.c
+++ b/drivers/watchdog/s3c2410_wdt.c
@@ -402,7 +402,6 @@ static inline void s3c2410wdt_cpufreq_deregister(void)
static int __devinit s3c2410wdt_probe(struct platform_device *pdev)
{
- struct resource *res;
struct device *dev;
unsigned int wtcon;
int started = 0;
@@ -416,20 +415,19 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev)
/* get the memory region for the watchdog timer */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res == NULL) {
+ wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (wdt_mem == NULL) {
dev_err(dev, "no memory resource specified\n");
return -ENOENT;
}
- size = resource_size(res);
- wdt_mem = request_mem_region(res->start, size, pdev->name);
- if (wdt_mem == NULL) {
+ size = resource_size(wdt_mem);
+ if (!request_mem_region(wdt_mem->start, size, pdev->name)) {
dev_err(dev, "failed to get memory region\n");
return -EBUSY;
}
- wdt_base = ioremap(res->start, size);
+ wdt_base = ioremap(wdt_mem->start, size);
if (wdt_base == NULL) {
dev_err(dev, "failed to ioremap() region\n");
ret = -EINVAL;
@@ -524,8 +522,8 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev)
iounmap(wdt_base);
err_req:
- release_resource(wdt_mem);
- kfree(wdt_mem);
+ release_mem_region(wdt_mem->start, size);
+ wdt_mem = NULL;
return ret;
}
@@ -545,8 +543,7 @@ static int __devexit s3c2410wdt_remove(struct platform_device *dev)
iounmap(wdt_base);
- release_resource(wdt_mem);
- kfree(wdt_mem);
+ release_mem_region(wdt_mem->start, resource_size(wdt_mem));
wdt_mem = NULL;
return 0;
}
^ permalink raw reply related
* [PATCH 1/2] eukrea_mbimxsd25-baseboard: add SD card detect
From: Wolfram Sang @ 2011-02-26 16:00 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110225125338.GC2178@pengutronix.de>
On Fri, Feb 25, 2011 at 01:53:58PM +0100, Wolfram Sang wrote:
> On Fri, Feb 25, 2011 at 01:49:14PM +0100, Eric B?nard wrote:
> > Signed-off-by: Eric B?nard <eric@eukrea.com>
>
> Please wait with those patches until the final driver modifications are
> applied to mmc-next. mx51-issues may cause some changes.
Sascha, you can go ahead now. All of Eric's SD-related patches are:
Acked-by: Wolfram Sang <w.sang@pengutronix.de>
--
Pengutronix e.K. | Wolfram Sang |
Industrial Linux Solutions | http://www.pengutronix.de/ |
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 197 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20110226/817dfe99/attachment.sig>
^ permalink raw reply
* [PATCH v4] dmaengine: mxs-dma: add dma support for i.MX23/28
From: Koul, Vinod @ 2011-02-26 15:57 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1298619259-14344-1-git-send-email-shawn.guo@freescale.com>
On Fri, 2011-02-25 at 15:34 +0800, Shawn Guo wrote:
> This patch adds dma support for Freescale MXS-based SoC i.MX23/28,
> including apbh-dma and apbx-dma.
>
> * apbh-dma and apbx-dma are supported in the driver as two mxs-dma
> instances.
>
> * apbh-dma is different between mx23 and mx28, hardware version
> register is used to differentiate.
>
> * mxs-dma supports pio function besides data transfer. The driver
> uses dma_data_direction DMA_NONE to identify the pio mode, and
> steals sgl and sg_len to get pio words and numbers from clients.
>
> * mxs dmaengine has some very specific features, like sense function
> and the special NAND support (nand_lock, nand_wait4ready). These
> are too specific to implemented in generic dmaengine driver.
>
> * The driver refers to imx-sdma and only a single descriptor is
> statically assigned to each channel.
>
> Signed-off-by: Shawn Guo <shawn.guo@freescale.com>
Please fix the checkpatch errors and warnings, at least it should have
zero errors.
ERROR: code indent should use tabs where possible
#430: FILE: drivers/dma/mxs-dma.c:250:
+ if (mxs_chan->desc.callback)$
WARNING: please, no spaces at the start of a line
#430: FILE: drivers/dma/mxs-dma.c:250:
+ if (mxs_chan->desc.callback)$
ERROR: code indent should use tabs where possible
#431: FILE: drivers/dma/mxs-dma.c:251:
+ mxs_chan->desc.callback(mxs_chan->desc.callback_param);
WARNING: please, no spaces at the start of a line
#431: FILE: drivers/dma/mxs-dma.c:251:
+ mxs_chan->desc.callback(mxs_chan->desc.callback_param);
ERROR: do not initialise statics to 0 or NULL
#564: FILE: drivers/dma/mxs-dma.c:384:
+ static int idx = 0;
~Vinod
^ permalink raw reply
* When does mach-types get updated in a tree?
From: John Linn @ 2011-02-26 15:40 UTC (permalink / raw)
To: linux-arm-kernel
> -----Original Message-----
> From: John Linn
> Sent: Wednesday, February 23, 2011 12:06 PM
> To: 'linux-arm-kernel at lists.infradead.org'; 'linux at arm.linux.org.uk'
> Cc: grant.likely at secretlab.ca
> Subject: When does mach-types get updated in a tree?
>
> I am trying to get a branch ready that could be pulled from with my
new patches.
Maybe I missed it, but I didn't notice any response to this,
or it was a really dumb question that didn't deserve an answer.
I appreciate all the community help (and patience) on my 1st ARM
patches.
I have a new branch ready with patches that's based on the Linus branch
and
Russell's p2v-stable branch.
It won't build without a hack to mach-types so I'm not sure how to
proceed.
Thanks,
John
>
> There is a new Xilinx entry when I look at the
> http://www.arm.linux.org.uk/developer/machines/download.php.
>
> But I don't see a Xilinx entry anywhere in any git trees.
>
> Maybe I overlooked it, or don't really understand the process (more
than likely).
>
> Thanks,
> John
This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.
^ permalink raw reply
* [PATCH] ARM: mach-imx: mx25_3ds: add write-protect and card-detect for SD
From: Wolfram Sang @ 2011-02-26 15:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1298733544-24659-1-git-send-email-shawn.guo@freescale.com>
On Sat, Feb 26, 2011 at 11:19:04PM +0800, Shawn Guo wrote:
> Signed-off-by: Shawn Guo <shawn.guo@freescale.com>
Acked-by: Wolfram Sang <w.sang@pengutronix.de>
--
Pengutronix e.K. | Wolfram Sang |
Industrial Linux Solutions | http://www.pengutronix.de/ |
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 197 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20110226/37c6053b/attachment.sig>
^ permalink raw reply
* [PATCH v4 3/7] arm/dt: consolidate atags setup into setup_machine_atags
From: Shawn Guo @ 2011-02-26 15:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110223022218.18318.9687.stgit@localhost6.localdomain6>
Hi Grant,
One minor nitpicking below ...
On Tue, Feb 22, 2011 at 07:22:19PM -0700, Grant Likely wrote:
> In preparation for adding device tree support, this patch consolidates
> all of the atag-specific setup into a single function.
>
> v4: - adapt to the removal of lookup_machine_type()
> - break out dump of machine_desc table into dump_machine_table()
> because the device tree probe code will use it.
> - Add for_each_machine_desc() macro
>
> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
> ---
> arch/arm/include/asm/mach/arch.h | 7 ++++
> arch/arm/kernel/setup.c | 74 +++++++++++++++++++++++---------------
> 2 files changed, 51 insertions(+), 30 deletions(-)
>
> diff --git a/arch/arm/include/asm/mach/arch.h b/arch/arm/include/asm/mach/arch.h
> index 3a0893a..ed9a10c 100644
> --- a/arch/arm/include/asm/mach/arch.h
> +++ b/arch/arm/include/asm/mach/arch.h
> @@ -52,6 +52,13 @@ struct machine_desc {
> extern struct machine_desc *machine_desc;
>
> /*
> + * Machine type table - also only accessible during boot
> + */
> +extern struct machine_desc __arch_info_begin[], __arch_info_end[];
> +#define for_each_machine_desc(p) \
> + for (p = __arch_info_begin; p < __arch_info_end; p++)
> +
> +/*
> * Set of macros to define architecture features. This is built into
> * a table by the linker.
> */
> diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
> index 8e046f1..e420565 100644
> --- a/arch/arm/kernel/setup.c
> +++ b/arch/arm/kernel/setup.c
> @@ -439,25 +439,12 @@ void cpu_init(void)
> : "r14");
> }
>
> -static struct machine_desc * __init setup_machine(unsigned int nr)
> +static void __init dump_machine_table(void)
> {
> - extern struct machine_desc __arch_info_begin[], __arch_info_end[];
> struct machine_desc *p;
>
> - /*
> - * locate machine in the list of supported machines.
> - */
> - for (p = __arch_info_begin; p < __arch_info_end; p++)
> - if (nr == p->nr) {
> - printk("Machine: %s\n", p->name);
> - return p;
> - }
> -
> - early_print("\n"
> - "Error: unrecognized/unsupported machine ID (r1 = 0x%08x).\n\n"
> - "Available machine support:\n\nID (hex)\tNAME\n", nr);
> -
> - for (p = __arch_info_begin; p < __arch_info_end; p++)
> + early_print("Available machine support:\n\nID (hex)\tNAME\n");
> + for_each_machine_desc(p)
> early_print("%08x\t%s\n", p->nr, p->name);
>
> early_print("\nPlease check your kernel config and/or bootloader.\n");
> @@ -819,21 +806,29 @@ static void __init squash_mem_tags(struct tag *tag)
> tag->hdr.tag = ATAG_NONE;
> }
>
> -void __init setup_arch(char **cmdline_p)
> +static struct machine_desc * __init setup_machine_tags(unsigned int nr)
> {
> struct tag *tags = (struct tag *)&init_tags;
> - struct machine_desc *mdesc;
> + struct machine_desc *mdesc = NULL, *p;
> char *from = default_command_line;
>
> - unwind_init();
> + /*
> + * locate machine in the list of supported machines.
> + */
> + for_each_machine_desc(p)
> + if (nr == p->nr) {
> + printk("Machine: %s\n", p->name);
Print once ...
> + mdesc = p;
> + break;
> + }
>
> - setup_processor();
> - mdesc = setup_machine(machine_arch_type);
> - machine_desc = mdesc;
> - machine_name = mdesc->name;
> + if (!mdesc) {
> + early_print("\nError: unrecognized/unsupported machine ID"
> + " (r1 = 0x%08x).\n\n", nr);
> + dump_machine_table(); /* does not return */
> + }
>
> - if (mdesc->soft_reboot)
> - reboot_setup("s");
> + printk("Machine: %s\n", mdesc->name);
>
twice, which give something like:
Uncompressing Linux... done, booting the kernel.
[...]
CPU: VIPT nonaliasing data cache, VIPT aliasing instruction cache
Machine: Freescale MX51 Babbage Board
Machine: Freescale MX51 Babbage Board
Memory policy: ECC disabled, Data cache writeback
> if (__atags_pointer)
> tags = phys_to_virt(__atags_pointer);
> @@ -861,16 +856,35 @@ void __init setup_arch(char **cmdline_p)
> parse_tags(tags);
> }
>
> - init_mm.start_code = (unsigned long) _text;
> - init_mm.end_code = (unsigned long) _etext;
> - init_mm.end_data = (unsigned long) _edata;
> - init_mm.brk = (unsigned long) _end;
> -
> /* parse_early_param needs a boot_command_line */
> strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);
>
> /* populate cmd_line too for later use, preserving boot_command_line */
> strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
> +
> + return mdesc;
> +}
> +
> +
> +void __init setup_arch(char **cmdline_p)
> +{
> + struct machine_desc *mdesc;
> +
> + unwind_init();
> +
> + setup_processor();
> + mdesc = setup_machine_tags(machine_arch_type);
> + machine_desc = mdesc;
> + machine_name = mdesc->name;
> +
> + if (mdesc->soft_reboot)
> + reboot_setup("s");
> +
> + init_mm.start_code = (unsigned long) _text;
> + init_mm.end_code = (unsigned long) _etext;
> + init_mm.end_data = (unsigned long) _edata;
> + init_mm.brk = (unsigned long) _end;
> +
> *cmdline_p = cmd_line;
>
> parse_early_param();
>
--
Regards,
Shawn
^ permalink raw reply
* [PATCH] ARM: mach-imx: mx25_3ds: add write-protect and card-detect for SD
From: Shawn Guo @ 2011-02-26 15:19 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Shawn Guo <shawn.guo@freescale.com>
---
arch/arm/mach-imx/mach-mx25_3ds.c | 13 ++++++++++++-
1 files changed, 12 insertions(+), 1 deletions(-)
diff --git a/arch/arm/mach-imx/mach-mx25_3ds.c b/arch/arm/mach-imx/mach-mx25_3ds.c
index 66b6cdd..561f07f 100644
--- a/arch/arm/mach-imx/mach-mx25_3ds.c
+++ b/arch/arm/mach-imx/mach-mx25_3ds.c
@@ -41,6 +41,7 @@
#include <mach/common.h>
#include <mach/mx25.h>
#include <mach/iomux-mx25.h>
+#include <mach/esdhc.h>
#include "devices-imx25.h"
@@ -103,6 +104,8 @@ static iomux_v3_cfg_t mx25pdk_pads[] = {
MX25_PAD_SD1_DATA1__SD1_DATA1,
MX25_PAD_SD1_DATA2__SD1_DATA2,
MX25_PAD_SD1_DATA3__SD1_DATA3,
+ MX25_PAD_A14__GPIO_2_0, /* WriteProtect */
+ MX25_PAD_A15__GPIO_2_1, /* CardDetect */
};
static const struct fec_platform_data mx25_fec_pdata __initconst = {
@@ -200,6 +203,14 @@ static const struct fsl_usb2_platform_data otg_device_pdata __initconst = {
.phy_mode = FSL_USB2_PHY_UTMI,
};
+#define SD1_GPIO_WP IMX_GPIO_NR(2, 0)
+#define SD1_GPIO_CD IMX_GPIO_NR(2, 1)
+
+static const struct esdhc_platform_data mx25pdk_esdhc_pdata __initconst = {
+ .wp_gpio = SD1_GPIO_WP,
+ .cd_gpio = SD1_GPIO_CD,
+};
+
static void __init mx25pdk_init(void)
{
mxc_iomux_v3_setup_multiple_pads(mx25pdk_pads,
@@ -217,7 +228,7 @@ static void __init mx25pdk_init(void)
imx25_add_fec(&mx25_fec_pdata);
imx25_add_imx_keypad(&mx25pdk_keymap_data);
- imx25_add_sdhci_esdhc_imx(0, NULL);
+ imx25_add_sdhci_esdhc_imx(0, &mx25pdk_esdhc_pdata);
}
static void __init mx25pdk_timer_init(void)
--
1.7.1
^ permalink raw reply related
* [PATCH] OMAP2+: sdrc: fix compile break on OMAP4-only config on current omap-for-linus
From: Sergei Shtylyov @ 2011-02-26 15:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <alpine.DEB.2.00.1102251839360.6198@utopia.booyaka.com>
Hello.
On 26-02-2011 4:40, Paul Walmsley wrote:
> On non-OMAP2 and non-OMAP3 kernel configs, turn omap2_sdrc_init() into
> a no-op. Otherwise, compilation breaks on an OMAP4-only config with
> the current omap-for-linus branch:
> arch/arm/mach-omap2/built-in.o: In function `omap2_init_common_devices':
> ../mach-omap2/io.c:421: undefined reference to `omap2_sdrc_init'
> Signed-off-by: Paul Walmsley<paul@pwsan.com>
> Cc: Tony Lindgren<tony@atomide.com>
> ---
> arch/arm/plat-omap/include/plat/sdrc.h | 5 +++++
> 1 files changed, 5 insertions(+), 0 deletions(-)
> diff --git a/arch/arm/plat-omap/include/plat/sdrc.h b/arch/arm/plat-omap/include/plat/sdrc.h
> index efd87c8..5a44b14 100644
> --- a/arch/arm/plat-omap/include/plat/sdrc.h
> +++ b/arch/arm/plat-omap/include/plat/sdrc.h
> @@ -124,8 +124,13 @@ struct omap_sdrc_params {
> u32 mr;
> };
>
> +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
> void __init omap2_sdrc_init(struct omap_sdrc_params *sdrc_cs0,
> struct omap_sdrc_params *sdrc_cs1);
> +#else
> +#define omap2_sdrc_init(x, y) 0
How about empty inline instead?
> +#endif
> +
WBR, Sergei
^ permalink raw reply
* [PATCH 1/3] ARM: S5P: Add s5p_timer support for HRT
From: Russell King - ARM Linux @ 2011-02-26 14:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1298688357-20775-2-git-send-email-sbkim73@samsung.com>
On Sat, Feb 26, 2011 at 11:45:55AM +0900, Sangbeom Kim wrote:
> +static irqreturn_t s5p_clock_event_isr(int irq, void *dev_id)
> +{
> + struct clock_event_device *evt = &time_event_device;
struct clock_event_device *evt = dev_id;
> +
> + evt->event_handler(evt);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static struct irqaction s5p_clock_event_irq = {
> + .name = "s5p_time_irq",
> + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
> + .handler = s5p_clock_event_isr,
.dev_id = &time_event_device,
> +};
...
> +static void __init s5p_timer_resources(void)
> +{
> + struct platform_device tmpdev;
> +
> + tmpdev.dev.bus = &platform_bus_type;
> +
> + timerclk = clk_get(NULL, "timers");
> + if (IS_ERR(timerclk))
> + panic("failed to get timers clock for system timer");
> +
> + clk_enable(timerclk);
> +
> + tmpdev.id = timer_source.event_id;
So Samsung clock stuff is still being idiotic. Will this ever be fixed?
> + tin_event = clk_get(&tmpdev.dev, "pwm-tin");
> + if (IS_ERR(tin_event)) {
> + clk_put(tin_event);
Don't clk_put errors.
> + panic("failed to get pwm-tin2 clock for system timer");
> + }
> +
> + tdiv_event = clk_get(&tmpdev.dev, "pwm-tdiv");
> + if (IS_ERR(tdiv_event)) {
> + clk_put(tdiv_event);
Ditto.
> + panic("failed to get pwm-tdiv2 clock for system timer");
> + }
> +
> + clk_enable(tin_event);
> +
> + tmpdev.id = timer_source.source_id;
> + tin_source = clk_get(&tmpdev.dev, "pwm-tin");
> + if (IS_ERR(tin_source)) {
> + clk_put(tin_source);
Ditto.
> + panic("failed to get pwm-tin4 clock for system timer");
> + }
> +
> + tdiv_source = clk_get(&tmpdev.dev, "pwm-tdiv");
> + if (IS_ERR(tdiv_source)) {
> + clk_put(tdiv_source);
Ditto.
^ permalink raw reply
* [PATCH 3/3] mmc: sdhci-esdhc-imx: add card detect on custom GPIO for mx25/35
From: Wolfram Sang @ 2011-02-26 13:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1298727881-12141-1-git-send-email-w.sang@pengutronix.de>
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
Tested-by: Marc Reilly <marc@cpdesign.com.au>
Tested-by: Eric Benard <eric@eukrea.com>
---
change since last version:
* BROKEN_CARD is default again for now
* i.MX5x won't apply the custom IRQ
-> same behaviour for i.MX5x as before
arch/arm/plat-mxc/include/mach/esdhc.h | 2 +
drivers/mmc/host/sdhci-esdhc-imx.c | 79 ++++++++++++++++++++++++++++++++
2 files changed, 81 insertions(+), 0 deletions(-)
diff --git a/arch/arm/plat-mxc/include/mach/esdhc.h b/arch/arm/plat-mxc/include/mach/esdhc.h
index 47da109..86003f4 100644
--- a/arch/arm/plat-mxc/include/mach/esdhc.h
+++ b/arch/arm/plat-mxc/include/mach/esdhc.h
@@ -16,9 +16,11 @@
* strongly recommended for i.MX25/35, not needed for other variants
*
* @wp_gpio: gpio for write_protect (-EINVAL if unused)
+ * @cd_gpio: gpio for card_detect interrupt (-EINVAL if unused)
*/
struct esdhc_platform_data {
unsigned int wp_gpio;
+ unsigned int cd_gpio;
};
#endif /* __ASM_ARCH_IMX_ESDHC_H */
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 49c9801..9be2c3e 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -32,6 +32,39 @@ static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, i
writel(((readl(base) & ~(mask << shift)) | (val << shift)), base);
}
+static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
+{
+ /* fake CARD_PRESENT flag on mx25/35 */
+ u32 val = readl(host->ioaddr + reg);
+
+ if (unlikely(reg == SDHCI_PRESENT_STATE)) {
+ struct esdhc_platform_data *boarddata =
+ host->mmc->parent->platform_data;
+
+ if (boarddata && gpio_is_valid(boarddata->cd_gpio)
+ && gpio_get_value(boarddata->cd_gpio))
+ /* no card, if a valid gpio says so... */
+ val &= SDHCI_CARD_PRESENT;
+ else
+ /* ... in all other cases assume card is present */
+ val |= SDHCI_CARD_PRESENT;
+ }
+
+ return val;
+}
+
+static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg)
+{
+ if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE))
+ /*
+ * these interrupts won't work with a custom card_detect gpio
+ * (only applied to mx25/35)
+ */
+ val &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT);
+
+ writel(val, host->ioaddr + reg);
+}
+
static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
{
if (unlikely(reg == SDHCI_HOST_VERSION))
@@ -121,6 +154,14 @@ static struct sdhci_ops sdhci_esdhc_ops = {
.get_min_clock = esdhc_pltfm_get_min_clock,
};
+static irqreturn_t cd_irq(int irq, void *data)
+{
+ struct sdhci_host *sdhost = (struct sdhci_host *)data;
+
+ tasklet_schedule(&sdhost->card_tasklet);
+ return IRQ_HANDLED;
+};
+
static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pdata)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -153,9 +194,40 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd
"no write-protect pin available!\n");
boarddata->wp_gpio = err;
}
+
+ err = gpio_request_one(boarddata->cd_gpio, GPIOF_IN, "ESDHC_CD");
+ if (err) {
+ dev_warn(mmc_dev(host->mmc),
+ "no card-detect pin available!\n");
+ goto no_card_detect_pin;
+ }
+
+ /* i.MX5x has issues to be researched */
+ if (!cpu_is_mx25() && !cpu_is_mx35())
+ goto not_supported;
+
+ err = request_irq(gpio_to_irq(boarddata->cd_gpio), cd_irq,
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+ mmc_hostname(host->mmc), host);
+ if (err) {
+ dev_warn(mmc_dev(host->mmc), "request irq error\n");
+ goto no_card_detect_irq;
+ }
+
+ sdhci_esdhc_ops.write_l = esdhc_writel_le;
+ sdhci_esdhc_ops.read_l = esdhc_readl_le;
+ /* Now we have a working card_detect again */
+ host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
}
return 0;
+
+ no_card_detect_irq:
+ gpio_free(boarddata->cd_gpio);
+ no_card_detect_pin:
+ boarddata->cd_gpio = err;
+ not_supported:
+ return 0;
}
static void esdhc_pltfm_exit(struct sdhci_host *host)
@@ -166,6 +238,13 @@ static void esdhc_pltfm_exit(struct sdhci_host *host)
if (boarddata && gpio_is_valid(boarddata->wp_gpio))
gpio_free(boarddata->wp_gpio);
+ if (boarddata && gpio_is_valid(boarddata->cd_gpio)) {
+ gpio_free(boarddata->cd_gpio);
+
+ if (!(host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION))
+ free_irq(gpio_to_irq(boarddata->cd_gpio), host);
+ }
+
clk_disable(pltfm_host->clk);
clk_put(pltfm_host->clk);
}
--
1.7.2.3
^ permalink raw reply related
* [PATCH 2/3] mmc: sdhci-esdhc: broken card detection is not a default quirk
From: Wolfram Sang @ 2011-02-26 13:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1298727881-12141-1-git-send-email-w.sang@pengutronix.de>
It can be worked around using a GPIO which will be done for i.MX later.
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
Acked-by: Anton Vorontsov <cbouatmailru@gmail.com>
Tested-by: Marc Reilly <marc@cpdesign.com.au>
Tested-by: Eric Benard <eric@eukrea.com>
---
change since last version:
* none
drivers/mmc/host/sdhci-esdhc-imx.c | 3 ++-
drivers/mmc/host/sdhci-esdhc.h | 1 -
drivers/mmc/host/sdhci-of-esdhc.c | 3 ++-
3 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 65df00b..49c9801 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -171,7 +171,8 @@ static void esdhc_pltfm_exit(struct sdhci_host *host)
}
struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
- .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA,
+ .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA
+ | SDHCI_QUIRK_BROKEN_CARD_DETECTION,
/* ADMA has issues. Might be fixable */
.ops = &sdhci_esdhc_ops,
.init = esdhc_pltfm_init,
diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h
index afaf1bc..c55aae8 100644
--- a/drivers/mmc/host/sdhci-esdhc.h
+++ b/drivers/mmc/host/sdhci-esdhc.h
@@ -19,7 +19,6 @@
*/
#define ESDHC_DEFAULT_QUIRKS (SDHCI_QUIRK_FORCE_BLK_SZ_2048 | \
- SDHCI_QUIRK_BROKEN_CARD_DETECTION | \
SDHCI_QUIRK_NO_BUSY_IRQ | \
SDHCI_QUIRK_NONSTANDARD_CLOCK | \
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | \
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index fcd0e1f..08161f6 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -73,7 +73,8 @@ static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host)
}
struct sdhci_of_data sdhci_esdhc = {
- .quirks = ESDHC_DEFAULT_QUIRKS,
+ /* card detection could be handled via GPIO */
+ .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_CARD_DETECTION,
.ops = {
.read_l = sdhci_be32bs_readl,
.read_w = esdhc_readw,
--
1.7.2.3
^ permalink raw reply related
* [PATCH 1/3] mmc: sdhci-esdhc-imx: add support for write protect on custom GPIO on mx25/35
From: Wolfram Sang @ 2011-02-26 13:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1298727881-12141-1-git-send-email-w.sang@pengutronix.de>
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
Tested-by: Marc Reilly <marc@cpdesign.com.au>
Tested-by: Eric Benard <eric@eukrea.com>
---
change since last version:
* none
arch/arm/plat-mxc/include/mach/esdhc.h | 10 +++++-
drivers/mmc/host/sdhci-esdhc-imx.c | 52 +++++++++++++++++++++++++-------
2 files changed, 50 insertions(+), 12 deletions(-)
diff --git a/arch/arm/plat-mxc/include/mach/esdhc.h b/arch/arm/plat-mxc/include/mach/esdhc.h
index a48a9aa..47da109 100644
--- a/arch/arm/plat-mxc/include/mach/esdhc.h
+++ b/arch/arm/plat-mxc/include/mach/esdhc.h
@@ -10,7 +10,15 @@
#ifndef __ASM_ARCH_IMX_ESDHC_H
#define __ASM_ARCH_IMX_ESDHC_H
+/**
+ * struct esdhc_platform_data - optional platform data for esdhc on i.MX
+ *
+ * strongly recommended for i.MX25/35, not needed for other variants
+ *
+ * @wp_gpio: gpio for write_protect (-EINVAL if unused)
+ */
+
struct esdhc_platform_data {
- unsigned int wp_gpio; /* write protect pin */
+ unsigned int wp_gpio;
};
#endif /* __ASM_ARCH_IMX_ESDHC_H */
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 9b82910..65df00b 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -15,9 +15,11 @@
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/clk.h>
+#include <linux/gpio.h>
#include <linux/mmc/host.h>
#include <linux/mmc/sdhci-pltfm.h>
#include <mach/hardware.h>
+#include <mach/esdhc.h>
#include "sdhci.h"
#include "sdhci-pltfm.h"
#include "sdhci-esdhc.h"
@@ -100,10 +102,31 @@ static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host)
return clk_get_rate(pltfm_host->clk) / 256 / 16;
}
+static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
+{
+ struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data;
+
+ if (boarddata && gpio_is_valid(boarddata->wp_gpio))
+ return gpio_get_value(boarddata->wp_gpio);
+ else
+ return -ENOSYS;
+}
+
+static struct sdhci_ops sdhci_esdhc_ops = {
+ .read_w = esdhc_readw_le,
+ .write_w = esdhc_writew_le,
+ .write_b = esdhc_writeb_le,
+ .set_clock = esdhc_set_clock,
+ .get_max_clock = esdhc_pltfm_get_max_clock,
+ .get_min_clock = esdhc_pltfm_get_min_clock,
+};
+
static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pdata)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data;
struct clk *clk;
+ int err;
clk = clk_get(mmc_dev(host->mmc), NULL);
if (IS_ERR(clk)) {
@@ -116,9 +139,21 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd
if (cpu_is_mx35() || cpu_is_mx51())
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
- /* Fix errata ENGcm07207 which is present on i.MX25 and i.MX35 */
- if (cpu_is_mx25() || cpu_is_mx35())
+ if (cpu_is_mx25() || cpu_is_mx35()) {
+ /* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */
host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK;
+ /* write_protect can't be routed to controller, use gpio */
+ sdhci_esdhc_ops.get_ro = esdhc_pltfm_get_ro;
+ }
+
+ if (boarddata) {
+ err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP");
+ if (err) {
+ dev_warn(mmc_dev(host->mmc),
+ "no write-protect pin available!\n");
+ boarddata->wp_gpio = err;
+ }
+ }
return 0;
}
@@ -126,20 +161,15 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd
static void esdhc_pltfm_exit(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data;
+
+ if (boarddata && gpio_is_valid(boarddata->wp_gpio))
+ gpio_free(boarddata->wp_gpio);
clk_disable(pltfm_host->clk);
clk_put(pltfm_host->clk);
}
-static struct sdhci_ops sdhci_esdhc_ops = {
- .read_w = esdhc_readw_le,
- .write_w = esdhc_writew_le,
- .write_b = esdhc_writeb_le,
- .set_clock = esdhc_set_clock,
- .get_max_clock = esdhc_pltfm_get_max_clock,
- .get_min_clock = esdhc_pltfm_get_min_clock,
-};
-
struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
.quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA,
/* ADMA has issues. Might be fixable */
--
1.7.2.3
^ permalink raw reply related
* [PATCH V4 0/3] adding write_protect and card_detect for mx25/35
From: Wolfram Sang @ 2011-02-26 13:44 UTC (permalink / raw)
To: linux-arm-kernel
Last tests showed some problems with MX51, especially with card_detect. While
the approach in general will suffice for i.MX5x, it seems there are a few
details missing right now. Because I do not have the resources (both time and
hardware) to deal with these issues, I propose a step by step approach. Let's
add the functionality for mx25/35 first and make sure there is no difference in
behaviour for mx5x. (Note that the i.MX5x can route the pins directly to the
controller, so a properly designed board should not need these gpio-additions.)
That is what this patch series does: The main change is that mx5x won't notice
any difference. For mx25/35, it is the same as it has been tested by Eric and
Marc.
Thanks to all involved in providing feedback, I hope it can go in now. If you
want to add support for it to your board, please CC me.
Have a nice weekend,
Wolfram
Wolfram Sang (3):
mmc: sdhci-esdhc-imx: add support for write protect on custom GPIO on
mx25/35
mmc: sdhci-esdhc: broken card detection is not a default quirk
mmc: sdhci-esdhc-imx: add card detect on custom GPIO for mx25/35
arch/arm/plat-mxc/include/mach/esdhc.h | 12 +++-
drivers/mmc/host/sdhci-esdhc-imx.c | 134 +++++++++++++++++++++++++++++---
drivers/mmc/host/sdhci-esdhc.h | 1 -
drivers/mmc/host/sdhci-of-esdhc.c | 3 +-
4 files changed, 135 insertions(+), 15 deletions(-)
--
1.7.2.3
^ permalink raw reply
* [PATCH 1/1] davinci: changed SRAM allocator to shared ram.
From: Subhasish Ghosh @ 2011-02-26 12:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <B85A65D85D7EB246BE421B3FB0FBB593024BE49711@dbde02.ent.ti.com>
Hi Sekhar,
I tried this using MMC and Kelvin's suggestions, but it never came back.
Here is a log:
root at arago:~# rtcwake -d /dev/rtc0 -s 20 -m mem
wakeup from "mem" at Tue Apr 21 14:31:13 2009
PM: Syncing filesystems ... done.
Freezing user space processes ... (elapsed 0.01 seconds) done.
Freezing remaining freezable tasks ... (elapsed 0.01 seconds) done.
Suspending console(s) (use no_console_suspend to debug)
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox