Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] OMAP2+: TWL: make conversion routines static
From: Nishanth Menon @ 2011-01-03 18:58 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1294081110-23695-1-git-send-email-nm@ti.com>

The uv_to_vsel, vsel_to_uv functions don't need to be exposed to the
world as they are used as function pointers. make them static.

Fixes sparse warnings:
arch/arm/mach-omap2/omap_twl.c:63:15: warning: symbol 'twl4030_vsel_to_uv' was not declared. Should it be static?
arch/arm/mach-omap2/omap_twl.c:68:4: warning: symbol 'twl4030_uv_to_vsel' was not declared. Should it be static?
arch/arm/mach-omap2/omap_twl.c:73:15: warning: symbol 'twl6030_vsel_to_uv' was not declared. Should it be static?
arch/arm/mach-omap2/omap_twl.c:105:4: warning: symbol 'twl6030_uv_to_vsel' was not declared. Should it be static?

Signed-off-by: Nishanth Menon <nm@ti.com>
---
 arch/arm/mach-omap2/omap_twl.c |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-omap2/omap_twl.c b/arch/arm/mach-omap2/omap_twl.c
index 15f8c6c..65ab4e3 100644
--- a/arch/arm/mach-omap2/omap_twl.c
+++ b/arch/arm/mach-omap2/omap_twl.c
@@ -60,17 +60,17 @@ static u8 smps_offset;
 
 #define REG_SMPS_OFFSET         0xE0
 
-unsigned long twl4030_vsel_to_uv(const u8 vsel)
+static unsigned long twl4030_vsel_to_uv(const u8 vsel)
 {
 	return (((vsel * 125) + 6000)) * 100;
 }
 
-u8 twl4030_uv_to_vsel(unsigned long uv)
+static u8 twl4030_uv_to_vsel(unsigned long uv)
 {
 	return DIV_ROUND_UP(uv - 600000, 12500);
 }
 
-unsigned long twl6030_vsel_to_uv(const u8 vsel)
+static unsigned long twl6030_vsel_to_uv(const u8 vsel)
 {
 	/*
 	 * In TWL6030 depending on the value of SMPS_OFFSET
@@ -102,7 +102,7 @@ unsigned long twl6030_vsel_to_uv(const u8 vsel)
 		return ((((vsel - 1) * 125) + 6000)) * 100;
 }
 
-u8 twl6030_uv_to_vsel(unsigned long uv)
+static u8 twl6030_uv_to_vsel(unsigned long uv)
 {
 	/*
 	 * In TWL6030 depending on the value of SMPS_OFFSET
-- 
1.6.3.3

^ permalink raw reply related

* [PATCH 0/2] OMAP: TWL: sparse fixes
From: Nishanth Menon @ 2011-01-03 18:58 UTC (permalink / raw)
  To: linux-arm-kernel

Source:
git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap-2.6.git
branch: omap-for-linus

Doing a rm arch/arm/mach-omap2/*.o;make C=1 arch/arm/mach-omap2/
resulted in the following sparse warnings:
http://pastebin.mozilla.org/907954

This series fixes the twl warnings
Nishanth Menon (2):
  OMAP2+: TWL: make conversion routines static
  OMAP2+: TWL: include pm header for init protos

 arch/arm/mach-omap2/omap_twl.c |   10 ++++++----
 1 files changed, 6 insertions(+), 4 deletions(-)

Regards,
Nishanth Menon

^ permalink raw reply

* [RFC PATCH] Avoid aliasing mappings in DMA coherent allocator
From: Janusz Krzysztofik @ 2011-01-03 18:28 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20110103095751.GA26785@n2100.arm.linux.org.uk>

Monday 03 January 2011 10:57:52 Russell King - ARM Linux wrote:
> On Tue, Dec 28, 2010 at 09:29:58PM +0000, Janusz Krzysztofik wrote:
> > Works fine on OMAP1 based Amstrad Delta, both default 2MB/2MB and
> > shrinked to 1MB/1MB configurations. No need to preallocate dma
> > coherent memory for camera video buffers on boot.
>
> That's good news.
>
> > However, in 1MB/1MB configuration it failed to allocate 600kB of
> > writecombined omapfb vram, required for double-buffering, and
> > reserving up to 4MB of machine's total 32MB seems too expensive.
>
> Do you have other users of the writecombined memory?  If so, what
> size are they?

Apparently ASoC omap-pcm, 2 x 128kB.

> As the 600k allocation can only be satisfied at the beginning of the
> region, we could do top-down rather than bottom-up allocation
> (untested):

Yes, this solves the issue for me. Both omap-pcm and omapfb/lcdc are now 
able to get their requested DMA writecombined buffers (2 x 128kB + 
600kB) from the reserved 1MB area.

Tested-by: Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>

I'll try to prepare for review a followup patch that updates those 
<{mach,plat}/memory.h> and similiar include files which provided their 
own non-default CONSISTENT_DMA_SIZE values. Since I'm not familiar with 
machines other that OMAP1, I'll take a 50/50 approach as a starting 
point if no other indications can be found.

Thanks,
Janusz

> diff --git a/arch/arm/mm/vmregion.c b/arch/arm/mm/vmregion.c
> index 935993e..036fdbf 100644
> --- a/arch/arm/mm/vmregion.c
> +++ b/arch/arm/mm/vmregion.c
> @@ -38,7 +38,7 @@ struct arm_vmregion *
>  arm_vmregion_alloc(struct arm_vmregion_head *head, size_t align,
>  		   size_t size, gfp_t gfp)
>  {
> -	unsigned long addr = head->vm_start, end = head->vm_end - size;
> +	unsigned long start = head->vm_start, addr = head->vm_end;
>  	unsigned long flags;
>  	struct arm_vmregion *c, *new;
>
> @@ -54,21 +54,20 @@ arm_vmregion_alloc(struct arm_vmregion_head
> *head, size_t align,
>
>  	spin_lock_irqsave(&head->vm_lock, flags);
>
> -	list_for_each_entry(c, &head->vm_list, vm_list) {
> -		if ((addr + size) < addr)
> -			goto nospc;
> -		if ((addr + size) <= c->vm_start)
> +	addr = rounddown(addr - size, align);
> +	list_for_each_entry_reverse(c, &head->vm_list, vm_list) {
> +		if (addr >= c->vm_end)
>  			goto found;
> -		addr = ALIGN(c->vm_end, align);
> -		if (addr > end)
> +		addr = rounddown(c->vm_start - size, align);
> +		if (addr < start)
>  			goto nospc;
>  	}
>
>   found:
>  	/*
> -	 * Insert this entry _before_ the one we found.
> +	 * Insert this entry after the one we found.
>  	 */
> -	list_add_tail(&new->vm_list, &c->vm_list);
> +	list_add(&new->vm_list, &c->vm_list);
>  	new->vm_start = addr;
>  	new->vm_end = addr + size;
>  	new->vm_active = 1;

^ permalink raw reply

* [RFC] Fixing CPU Hotplug for RealView Platforms
From: Russell King - ARM Linux @ 2011-01-03 18:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <AANLkTikZgWgwsWpxbuXGLRzPnwtrZyiSU7k2dXGfuc69@mail.gmail.com>

On Mon, Jan 03, 2011 at 06:39:56PM +0100, Vincent Guittot wrote:
> On 3 January 2011 11:46, Russell King - ARM Linux
> <linux@arm.linux.org.uk> wrote:
> > On Mon, Dec 20, 2010 at 09:16:15AM +0100, Vincent Guittot wrote:
> >> I'm also interested in hotplug latency measurement and have done some
> >> on my CA9 platform u8500. I have the same kind of result for plugging
> >> a secondary cpu:
> >> ? total duration = 295ms
> >> ? 166 us for the low level cpu wake up
> >> ? 228ms between the return from platform_cpu_die and the cpu becomes online
> >>
> >> I have added some trace events for doing these measurements and I'd
> >> like to add some generic traces point in the cpu hotplug code like we
> >> already have in power management code (cpuidle, suspend, cpufreq ...)
> >> These traces could be used with power events for studying the impact
> >> of cpu hotplug in the complete power management scheme.
> >
> > Note that if you pass lpj=<number> to the kernel, you'll bypass the
> > calibration and have a faster response to CPU onlining.
> >
> 
> yes, the total duration decreases down to 40ms

I'm not sure that I believe it takes 40ms, as it's only taking about
104us to get to the calibration for me.  The calibration when disabled
is virtually a do-nothing, so shouldn't be taking 40ms.

The trace code may be hitting locks which are interfering with the
timing - this below is entirely lockless with a proper (and working)
sched_clock() implementation.

See mach-vexpress/platsmp.c for the things to add.  Also note that it
requires the SMP changes (and for good measure, the clksrc stuff too.)
Might be easier to apply on top of linux-next.

diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 11d6a94..0b3a15a 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -40,6 +40,7 @@
 #include <asm/ptrace.h>
 #include <asm/localtimer.h>
 
+#include <asm/smp-debug.h>
 /*
  * as from 2.5, kernels no longer have an init_tasks structure
  * so we need some other way of telling a new secondary core
@@ -47,6 +48,8 @@
  */
 struct secondary_data secondary_data;
 
+struct smp_debug smp_debug;
+
 enum ipi_msg_type {
 	IPI_TIMER = 2,
 	IPI_RESCHEDULE,
@@ -55,6 +58,24 @@ enum ipi_msg_type {
 	IPI_CPU_STOP,
 };
 
+static const char *debug_names[] = {
+	[D_START]		= "Start",
+	[D_BOOT_SECONDARY_CALL]	= "Booting",
+	[D_CROSS_CALL]		= "Cross call",
+	[D_PEN_RELEASED]	= "Pen released",
+	[D_UNLOCK]		= "Unlock",
+	[D_BOOT_SECONDARY_RET]	= "Boot returned",
+	[D_BOOT_DONE]		= "Boot complete",
+	[D_SEC_RESTART]		= "Sec: restart",
+	[D_SEC_UP]		= "Sec: up",
+	[D_SEC_PLAT_ENTER]	= "Sec: enter",
+	[D_SEC_PLAT_PEN_WRITE]	= "Sec: pen write",
+	[D_SEC_PLAT_PEN_DONE]	= "Sec: pen done",
+	[D_SEC_PLAT_EXIT]	= "Sec: exit",
+	[D_SEC_CALIBRATE]	= "Sec: calibrate",
+	[D_SEC_ONLINE]		= "Sec: online",
+};
+
 int __cpuinit __cpu_up(unsigned int cpu)
 {
 	struct cpuinfo_arm *ci = &per_cpu(cpu_data, cpu);
@@ -111,7 +132,10 @@ int __cpuinit __cpu_up(unsigned int cpu)
 	/*
 	 * Now bring the CPU into our world.
 	 */
+	smp_debug_mark(D_START);
+	smp_debug_mark(D_BOOT_SECONDARY_CALL);
 	ret = boot_secondary(cpu, idle);
+	smp_debug_mark(D_BOOT_SECONDARY_RET);
 	if (ret == 0) {
 		unsigned long timeout;
 
@@ -135,6 +159,7 @@ int __cpuinit __cpu_up(unsigned int cpu)
 	} else {
 		pr_err("CPU%u: failed to boot: %d\n", cpu, ret);
 	}
+	smp_debug_mark(D_BOOT_DONE);
 
 	secondary_data.stack = NULL;
 	secondary_data.pgdir = 0;
@@ -148,6 +173,14 @@ int __cpuinit __cpu_up(unsigned int cpu)
 	}
 
 	pgd_free(&init_mm, pgd);
+{
+	int i;
+	for (i = 0; i < D_NUM; i++) {
+		if (debug_names[i] && smp_debug.entry[i])
+			pr_info("SMP: %s: %llu\n", debug_names[i],
+				smp_debug.entry[i] - smp_debug.entry[0]);
+	}
+}
 
 	return ret;
 }
@@ -245,6 +278,8 @@ void __ref cpu_die(void)
 	 */
 	platform_cpu_die(cpu);
 
+	smp_debug_mark(D_SEC_RESTART);
+
 	/*
 	 * Do not return to the idle loop - jump back to the secondary
 	 * cpu initialisation.  There's some initialisation which needs
@@ -278,6 +313,7 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
 	struct mm_struct *mm = &init_mm;
 	unsigned int cpu = smp_processor_id();
 
+	smp_debug_mark(D_SEC_UP);
 	printk("CPU%u: Booted secondary processor\n", cpu);
 
 	/*
@@ -312,6 +348,8 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
 	 */
 	percpu_timer_setup();
 
+	smp_debug_mark(D_SEC_CALIBRATE);
+
 	calibrate_delay();
 
 	smp_store_cpu_info(cpu);
@@ -320,6 +358,7 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
 	 * OK, now it's safe to let the boot CPU continue
 	 */
 	set_cpu_online(cpu, true);
+	smp_debug_mark(D_SEC_ONLINE);
 
 	/*
 	 * OK, it's off to the idle thread for us
diff --git a/arch/arm/mach-vexpress/platsmp.c b/arch/arm/mach-vexpress/platsmp.c
index b1687b6..0a77a6b 100644
--- a/arch/arm/mach-vexpress/platsmp.c
+++ b/arch/arm/mach-vexpress/platsmp.c
@@ -27,7 +27,7 @@
 #include "core.h"
 
 extern void vexpress_secondary_startup(void);
-
+#include <asm/smp-debug.h>
 /*
  * control for which core is the next to come out of the secondary
  * boot "holding pen"
@@ -56,6 +56,7 @@ static DEFINE_SPINLOCK(boot_lock);
 
 void __cpuinit platform_secondary_init(unsigned int cpu)
 {
+	smp_debug_mark(D_SEC_PLAT_ENTER);
 	/*
 	 * if any interrupts are already enabled for the primary
 	 * core (e.g. timer irq), then they will not have been enabled
@@ -67,13 +68,16 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
 	 * let the primary processor know we're out of the
 	 * pen, then head off into the C entry point
 	 */
+	smp_debug_mark(D_SEC_PLAT_PEN_WRITE);
 	write_pen_release(-1);
+	smp_debug_mark(D_SEC_PLAT_PEN_DONE);
 
 	/*
 	 * Synchronise with the boot thread.
 	 */
 	spin_lock(&boot_lock);
 	spin_unlock(&boot_lock);
+	smp_debug_mark(D_SEC_PLAT_EXIT);
 }
 
 int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
@@ -99,6 +103,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
 	 * the boot monitor to read the system wide flags register,
 	 * and branch to the address found there.
 	 */
+	smp_debug_mark(D_CROSS_CALL);
 	smp_cross_call(cpumask_of(cpu), 1);
 
 	timeout = jiffies + (1 * HZ);
@@ -109,12 +114,14 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
 
 		udelay(10);
 	}
+	smp_debug_mark(D_PEN_RELEASED);
 
 	/*
 	 * now the secondary core is starting up let it run its
 	 * calibrations, then wait for it to finish
 	 */
 	spin_unlock(&boot_lock);
+	smp_debug_mark(D_UNLOCK);
 
 	return pen_release != -1 ? -ENOSYS : 0;
 }
--- /dev/null	2010-08-07 18:16:05.574112050 +0100
+++ arch/arm/include/asm/smp-debug.h	2010-12-18 22:03:23.622580304 +0000
@@ -0,0 +1,39 @@
+#include <linux/sched.h>
+
+enum {
+	D_START,
+	D_INIT_IDLE,
+	D_PGD_ALLOC,
+	D_IDMAP_ADD,
+	D_BOOT_SECONDARY_CALL,
+	D_CROSS_CALL,
+	D_PEN_RELEASED,
+	D_UNLOCK,
+	D_BOOT_SECONDARY_RET,
+	D_BOOT_DONE,
+	D_IDMAP_DEL,
+	D_PGD_FREE,
+
+	D_SEC = 16,
+	D_SEC_RESTART = D_SEC,
+	D_SEC_UP,
+	D_SEC_PLAT_ENTER,
+	D_SEC_PLAT_PEN_WRITE,
+	D_SEC_PLAT_PEN_DONE,
+	D_SEC_PLAT_EXIT,
+	D_SEC_CALIBRATE,
+	D_SEC_ONLINE,
+	
+	D_NUM,
+};
+
+struct smp_debug {
+	unsigned long long	entry[D_NUM];
+};
+
+extern struct smp_debug smp_debug;
+
+static inline void smp_debug_mark(int ent)
+{
+	smp_debug.entry[ent] = sched_clock();
+}

^ permalink raw reply related

* [RFC] Fixing CPU Hotplug for RealView Platforms
From: Vincent Guittot @ 2011-01-03 17:39 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20110103104621.GF26785@n2100.arm.linux.org.uk>

On 3 January 2011 11:46, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:
> On Mon, Dec 20, 2010 at 09:16:15AM +0100, Vincent Guittot wrote:
>> I'm also interested in hotplug latency measurement and have done some
>> on my CA9 platform u8500. I have the same kind of result for plugging
>> a secondary cpu:
>> ? total duration = 295ms
>> ? 166 us for the low level cpu wake up
>> ? 228ms between the return from platform_cpu_die and the cpu becomes online
>>
>> I have added some trace events for doing these measurements and I'd
>> like to add some generic traces point in the cpu hotplug code like we
>> already have in power management code (cpuidle, suspend, cpufreq ...)
>> These traces could be used with power events for studying the impact
>> of cpu hotplug in the complete power management scheme.
>
> Note that if you pass lpj=<number> to the kernel, you'll bypass the
> calibration and have a faster response to CPU onlining.
>

yes, the total duration decreases down to 40ms

^ permalink raw reply

* [PATCH v5 1/3] ARM: add CPPI 4.1 DMA support
From: Russell King - ARM Linux @ 2011-01-03 17:19 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <4D220246.5020303@mvista.com>

On Mon, Jan 03, 2011 at 08:07:18PM +0300, Sergei Shtylyov wrote:
> Hello.
>
> On 03-01-2011 20:01, Gupta, Ajay Kumar wrote:
>
>>>>> Add support for Texas Instuments Communication Port Programming Interface 4.1
>>>>> (CPPI 4.1) used on OMAP-L1x/DA8xx and AM35x.
>
>>>>> At this moment, only the DMA controller and queue manager are supported.
>>>>> Support for the buffer manager is lacking but these chips don't have it anyway.
>
>>>>> Signed-off-by: Sergei Shtylyov<sshtylyov@ru.mvista.com>
>>>>> Signed-off-by: Sekhar Nori<nsekhar@ti.com>
>
>>>>     Russell, you have recently discarded this patch from your patch
>>>> system. Can we know the reason?
>
>>> It was recently discussed with TI, and various people raised concerns
>>> about it.  I don't remember the exact details, and I wish they'd raise
>>> them with the patch author directly.  It may have been that it's
>>> inventing its own API rather than using something like the DMA engine
>>> API.
>
>>> Adding linux-omap to try to get a response there.
>
>> Sergei,
>> This issue was discussed recently at TI and proposal was to place it to
>> drivers/dma folder.
>
>    Note that I have neither time nor inclination to do this work (not do 
> I think it's even feasible), so it will have to fall on TI's shoulders...
>
>> Moreover, even Felipe also seems to move other musb
>> DMAs (Inventra, CPPI3.0, TUSB) to drivers/dma.
>
>    Frankly speaking, I doubt that drivers/dma/ will have place for the 
> purely MUSB specific DMA engines such as the named ones (there's no TUSB 
> DMA BTW -- it uses OMAP DMA).

Long term, we need to kill off all these platform private DMA interfaces.
There's a growing amount of IP that's being shared not only between ARM
silicon vendors, but also across architectures, and having to re-implement
drivers because the underlying DMA engine is different is not feasible.

For example, we're seeing ARMs primecells being used with various
different DMA controllers in various different ARM SoCs.  I've heard
rumours of them appearing in MIPS or PPC stuff as well.  We're seeing
PXA peripheral IP appearing in x86 stuff too.

We can't have drivers tied to their SoC DMA engines, and we can't continue
having SoC DMA engines implementing their own unique APIs.  We do need to
get on top of this before it becomes a major problem (if it hasn't
already).

The DMA engine API is still evolving, and should not be taken as concrete
- I've recently been bringing up a number of points with Dan on various
aspects of the API, some of which ultimately will lead to changes to the
async-tx API, and others which hopefully will mean that the DMA slave
API is better documented.

^ permalink raw reply

* [PATCH v5 1/3] ARM: add CPPI 4.1 DMA support
From: Gupta, Ajay Kumar @ 2011-01-03 17:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <4D220246.5020303@mvista.com>

Hi,
> >>>> Add support for Texas Instuments Communication Port Programming
> Interface 4.1
> >>>> (CPPI 4.1) used on OMAP-L1x/DA8xx and AM35x.
> 
> >>>> At this moment, only the DMA controller and queue manager are
> supported.
> >>>> Support for the buffer manager is lacking but these chips don't have
> it anyway.
> 
> >>>> Signed-off-by: Sergei Shtylyov<sshtylyov@ru.mvista.com>
> >>>> Signed-off-by: Sekhar Nori<nsekhar@ti.com>
> 
> >>>     Russell, you have recently discarded this patch from your patch
> >>> system. Can we know the reason?
> 
> >> It was recently discussed with TI, and various people raised concerns
> >> about it.  I don't remember the exact details, and I wish they'd raise
> >> them with the patch author directly.  It may have been that it's
> >> inventing its own API rather than using something like the DMA engine
> >> API.
> 
> >> Adding linux-omap to try to get a response there.
> 
> > Sergei,
> > This issue was discussed recently at TI and proposal was to place it to
> > drivers/dma folder.
> 
>     Note that I have neither time nor inclination to do this work (not do
> I think it's even feasible), so it will have to fall on TI's shoulders...

This is fine. No issues. We will discuss this at length at linux-usb list.

> 
> > Moreover, even Felipe also seems to move other musb
> > DMAs (Inventra, CPPI3.0, TUSB) to drivers/dma.
> 
>     Frankly speaking, I doubt that drivers/dma/ will have place for the
> purely MUSB specific DMA engines such as the named ones (there's no TUSB
> DMA BTW it uses OMAP DMA).
I think we will get more clarity once we start on this activity.

Thanks,
Ajay
> 
> > Regards,
> > Ajay
> 
> WBR, Sergei

^ permalink raw reply

* [PATCH v5 1/3] ARM: add CPPI 4.1 DMA support
From: Sergei Shtylyov @ 2011-01-03 17:07 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <19F8576C6E063C45BE387C64729E739404BD3F2C4D@dbde02.ent.ti.com>

Hello.

On 03-01-2011 20:01, Gupta, Ajay Kumar wrote:

>>>> Add support for Texas Instuments Communication Port Programming Interface 4.1
>>>> (CPPI 4.1) used on OMAP-L1x/DA8xx and AM35x.

>>>> At this moment, only the DMA controller and queue manager are supported.
>>>> Support for the buffer manager is lacking but these chips don't have it anyway.

>>>> Signed-off-by: Sergei Shtylyov<sshtylyov@ru.mvista.com>
>>>> Signed-off-by: Sekhar Nori<nsekhar@ti.com>

>>>     Russell, you have recently discarded this patch from your patch
>>> system. Can we know the reason?

>> It was recently discussed with TI, and various people raised concerns
>> about it.  I don't remember the exact details, and I wish they'd raise
>> them with the patch author directly.  It may have been that it's
>> inventing its own API rather than using something like the DMA engine
>> API.

>> Adding linux-omap to try to get a response there.

> Sergei,
> This issue was discussed recently at TI and proposal was to place it to
> drivers/dma folder.

    Note that I have neither time nor inclination to do this work (not do I 
think it's even feasible), so it will have to fall on TI's shoulders...

> Moreover, even Felipe also seems to move other musb
> DMAs (Inventra, CPPI3.0, TUSB) to drivers/dma.

    Frankly speaking, I doubt that drivers/dma/ will have place for the purely 
MUSB specific DMA engines such as the named ones (there's no TUSB DMA BTW -- 
it uses OMAP DMA).

> Regards,
> Ajay

WBR, Sergei

^ permalink raw reply

* [PATCH v5 1/3] ARM: add CPPI 4.1 DMA support
From: Gupta, Ajay Kumar @ 2011-01-03 17:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20110103163447.GB2911@n2100.arm.linux.org.uk>

Hi,
> >> Add support for Texas Instuments Communication Port Programming
> Interface 4.1
> >> (CPPI 4.1) used on OMAP-L1x/DA8xx and AM35x.
> >
> >> At this moment, only the DMA controller and queue manager are supported.
> >> Support for the buffer manager is lacking but these chips don't have it
> anyway.
> >
> >> Signed-off-by: Sergei Shtylyov<sshtylyov@ru.mvista.com>
> >> Signed-off-by: Sekhar Nori<nsekhar@ti.com>
> >
> >    Russell, you have recently discarded this patch from your patch
> > system. Can we know the reason?
> 
> It was recently discussed with TI, and various people raised concerns
> about it.  I don't remember the exact details, and I wish they'd raise
> them with the patch author directly.  It may have been that it's
> inventing its own API rather than using something like the DMA engine
> API.
> 
> Adding linux-omap to try to get a response there.

Sergei,
This issue was discussed recently at TI and proposal was to place it to
drivers/dma folder. Moreover, even Felipe also seems to move other musb
DMAs (Inventra, CPPI3.0, TUSB) to drivers/dma.

Regards,
Ajay
> _______________________________________________
> Davinci-linux-open-source mailing list
> Davinci-linux-open-source at linux.davincidsp.com
> http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source

^ permalink raw reply

* dmaengine: fix dma_unmap (was: Re: [PATCH 06/13] DMAENGINE: driver for the ARM PL080/PL081 PrimeCells)
From: Russell King - ARM Linux @ 2011-01-03 16:52 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <AANLkTinJAULeb1EsWk=S=b32h69X1x-noRw73Ok0uyfx@mail.gmail.com>

On Mon, Jan 03, 2011 at 08:36:00AM -0800, Dan Williams wrote:
> For raid this will have implications for architectures that split
> operation types on to different physical channels.  Preparing the
> entire operation chain ahead of time is not possible on such
> configuration because we need to remap the buffers for each channel
> transition.

That's not entirely true.  You will only need to remap buffers if
old_chan->device != new_chan->device, as the underlying struct device
will be the different and could possibly have a different IOMMU or
DMA-able memory parameters.

So, when changing channels, the optimization is not engine specific,
but can be effected when the chan->device points to the same dma_device
structure.  That means it should still be possible to chain several
operations together, even if it means that they occur on different
channels on the same device.

One passing idea is the async_* operations need to chain buffers in
terms of <virtual page+offset, len, dma_addr_t, struct dma_device *>, or
maybe <struct dma_device *, scatterlist>.  If the dma_device pointer is
initialized, the scatterlist is already mapped.  If this differs from
the dma_device for the next selected operation, the previous operations
need to be run, then unmap and remap for the new device.

Does that sound possible?

> > I'd also like to see DMA_COMPL_SKIP_*_UNMAP always set by prep_slave_sg()
> > in tx->flags so we don't have to end up with "is this a slave operation"
> > tests in the completion handler.
> 
> Longer term I do not see these flags surviving, but yes a 2.6.38
> change along these lines makes sense.

Well, if the idea is to kill those flags, then it would be a good idea
not to introduce new uses of them as that'll only complicate matters.

I do have an untested patch which adds the unmap to pl08x, but I'm
wondering if it's worth it, or whether to disable the memcpy support
for the time being.

^ permalink raw reply

* dmaengine: fix dma_unmap (was: Re: [PATCH 06/13] DMAENGINE: driver for the ARM PL080/PL081 PrimeCells)
From: Dan Williams @ 2011-01-03 16:36 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jan 3, 2011 at 3:14 AM, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:
> On Sun, Jan 02, 2011 at 09:33:34PM +0100, Linus Walleij wrote:
>> As for the in-tree PL08x driver I'd say it's doing pretty well for
>> memcpy() so we could add platform data for that on supported
>> platforms, then for device transfers we need more elaborative
>> work.
>
> It has the issue that it's not unmapping the buffers after the memcpy()
> operation has completed, so on ARMv6+ we have the possibility for
> speculative prefetches to corrupt the destination buffer.
>
> Neither are a number of the other DMA engine drivers. ?This is why I'd
> like to see some common infrastructure in the DMA engine core for saying
> "this tx descriptor is now complete" so that DMA engine driver authors
> don't have to even think about whether they should be unmapping buffers.

This requires that a copy of the mapped addresses be maintained
outside the driver's physical descriptor.  This needs support from the
client to set up storage for this information (probably a
scatterlist).  The dmaengine core could use this to implement a common
unmap routine.  However,  this still has the problem of how to prevent
unmapping too early in the multi-operation raid case and how to
communicate the full set of addresses to unmap to the final descriptor
in such a chain.  I think the only way to fully solve this is to make
the client solely responsible for both mapping and unmapping.

For raid this will have implications for architectures that split
operation types on to different physical channels.  Preparing the
entire operation chain ahead of time is not possible on such
configuration because we need to remap the buffers for each channel
transition.  So, raid will have an optimized path for engines like
mv_xor, ioatdma, and iop-adma (iop13xx) where all buffers can be
mapped upfront (against a single physical channel) and then unmapped
when all stripe operations complete.  For the others iop-adma (iop3xx)
and ppc44x we need to wait for each leg to finish before mapping and
issuing the next leg.  There will most likely be negative performance
implications of waiting and reissuing, but as far as I can see this is
unavoidable.

> I'd also like to see DMA_COMPL_SKIP_*_UNMAP always set by prep_slave_sg()
> in tx->flags so we don't have to end up with "is this a slave operation"
> tests in the completion handler.

Longer term I do not see these flags surviving, but yes a 2.6.38
change along these lines makes sense.

--
Dan

^ permalink raw reply

* [PATCH v5 1/3] ARM: add CPPI 4.1 DMA support
From: Russell King - ARM Linux @ 2011-01-03 16:34 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <4D21F3F2.6090302@mvista.com>

On Mon, Jan 03, 2011 at 07:06:10PM +0300, Sergei Shtylyov wrote:
> Hello.
>
> On 15-05-2010 22:14, Sergei Shtylyov wrote:
>
>> Add support for Texas Instuments Communication Port Programming Interface 4.1
>> (CPPI 4.1) used on OMAP-L1x/DA8xx and AM35x.
>
>> At this moment, only the DMA controller and queue manager are supported.
>> Support for the buffer manager is lacking but these chips don't have it anyway.
>
>> Signed-off-by: Sergei Shtylyov<sshtylyov@ru.mvista.com>
>> Signed-off-by: Sekhar Nori<nsekhar@ti.com>
>
>    Russell, you have recently discarded this patch from your patch 
> system. Can we know the reason?

It was recently discussed with TI, and various people raised concerns
about it.  I don't remember the exact details, and I wish they'd raise
them with the patch author directly.  It may have been that it's
inventing its own API rather than using something like the DMA engine
API.

Adding linux-omap to try to get a response there.

^ permalink raw reply

* [PATCH 6/7] ARM: PL011: Add support for transmit DMA
From: Russell King - ARM Linux @ 2011-01-03 16:30 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <AANLkTi=kRbUTtBFmaS6X8ybfsnN1Br8MGysx8dTFcvsw@mail.gmail.com>

On Mon, Jan 03, 2011 at 04:42:18PM +0530, Rabin Vincent wrote:
> On Mon, Jan 3, 2011 at 15:40, Russell King - ARM Linux
> <linux@arm.linux.org.uk> wrote:
> > + ? ? ? if (dma_map_sg(dma_dev->dev, &dmatx->sg, 1, DMA_TO_DEVICE) != 1) {
> > + ? ? ? ? ? ? ? uap->dmatx.queued = false;
> > + ? ? ? ? ? ? ? dev_dbg(uap->port.dev, "unable to map TX DMA\n");
> > + ? ? ? ? ? ? ? return -EBUSY;
> > + ? ? ? }
> > +
> > + ? ? ? desc = dma_dev->device_prep_slave_sg(chan, &dmatx->sg, 1, DMA_TO_DEVICE,
> > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
> > + ? ? ? if (!desc) {
> > + ? ? ? ? ? ? ? uap->dmatx.queued = false;
> 
> Doesn't dma_unmap_sg need to be called here?

Yup.  Here's the updated patch.  Also killed the no longer required
dma_cookie_t.

 drivers/serial/amba-pl011.c |  508 ++++++++++++++++++++++++++++++++++++++++++-
 include/linux/amba/serial.h |    7 +
 2 files changed, 513 insertions(+), 2 deletions(-)

diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c
index f741a8b..ab025dc 100644
--- a/drivers/serial/amba-pl011.c
+++ b/drivers/serial/amba-pl011.c
@@ -7,6 +7,7 @@
  *
  *  Copyright 1999 ARM Limited
  *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *  Copyright (C) 2010 ST-Ericsson SA
  *
  * 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
@@ -48,6 +49,9 @@
 #include <linux/amba/serial.h>
 #include <linux/clk.h>
 #include <linux/slab.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
 
 #include <asm/io.h>
 #include <asm/sizes.h>
@@ -88,6 +92,14 @@ static struct vendor_data vendor_st = {
 	.oversampling		= true,
 };
 
+/* Deals with DMA transactions */
+struct pl011_dmatx_data {
+	struct dma_chan		*chan;
+	struct scatterlist	sg;
+	char			*buf;
+	bool			queued;
+};
+
 /*
  * We wrap our port structure around the generic uart_port.
  */
@@ -95,6 +107,7 @@ struct uart_amba_port {
 	struct uart_port	port;
 	struct clk		*clk;
 	const struct vendor_data *vendor;
+	unsigned int		dmacr;		/* dma control reg */
 	unsigned int		im;		/* interrupt mask */
 	unsigned int		old_status;
 	unsigned int		fifosize;	/* vendor-specific */
@@ -102,22 +115,500 @@ struct uart_amba_port {
 	unsigned int		lcrh_rx;	/* vendor-specific */
 	bool			autorts;
 	char			type[12];
+#ifdef CONFIG_DMA_ENGINE
+	/* DMA stuff */
+	bool			using_dma;
+	struct pl011_dmatx_data	dmatx;
+#endif
+};
+
+/*
+ * All the DMA operation mode stuff goes inside this ifdef.
+ * This assumes that you have a generic DMA device interface,
+ * no custom DMA interfaces are supported.
+ */
+#ifdef CONFIG_DMA_ENGINE
+
+#define PL011_DMA_BUFFER_SIZE PAGE_SIZE
+
+static void pl011_dma_probe_initcall(struct uart_amba_port *uap)
+{
+	/* DMA is the sole user of the platform data right now */
+	struct amba_pl011_data *plat = uap->port.dev->platform_data;
+	struct dma_slave_config tx_conf = {
+		.dst_addr = uap->port.mapbase + UART01x_DR,
+		.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
+		.direction = DMA_TO_DEVICE,
+		.dst_maxburst = uap->fifosize >> 1,
+	};
+	struct dma_chan *chan;
+	dma_cap_mask_t mask;
+
+	/* We need platform data */
+	if (!plat || !plat->dma_filter) {
+		dev_info(uap->port.dev, "no DMA platform data\n");
+		return;
+	}
+
+	/* Try to acquire a generic DMA engine slave channel */
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_SLAVE, mask);
+
+	chan = dma_request_channel(mask, plat->dma_filter, plat->dma_tx_param);
+	if (!chan) {
+		dev_err(uap->port.dev, "no TX DMA channel!\n");
+		return;
+	}
+
+	dmaengine_slave_config(chan, &tx_conf);
+	uap->dmatx.chan = chan;
+
+	dev_info(uap->port.dev, "DMA channel TX %s\n",
+		 dma_chan_name(uap->dmatx.chan));
+}
+
+#ifndef MODULE
+/*
+ * Stack up the UARTs and let the above initcall be done at device
+ * initcall time, because the serial driver is called as an arch
+ * initcall, and at this time the DMA subsystem is not yet registered.
+ * At this point the driver will switch over to using DMA where desired.
+ */
+struct dma_uap {
+	struct list_head node;
+	struct uart_amba_port *uap;
 };
 
+static LIST_HEAD(pl011_dma_uarts);
+
+static int __init pl011_dma_initcall(void)
+{
+	struct list_head *node, *tmp;
+
+	list_for_each_safe(node, tmp, &pl011_dma_uarts) {
+		struct dma_uap *dmau = list_entry(node, struct dma_uap, node);
+		pl011_dma_probe_initcall(dmau->uap);
+		list_del(node);
+		kfree(dmau);
+	}
+	return 0;
+}
+
+device_initcall(pl011_dma_initcall);
+
+static void pl011_dma_probe(struct uart_amba_port *uap)
+{
+	struct dma_uap *dmau = kzalloc(sizeof(struct dma_uap), GFP_KERNEL);
+	if (dmau) {
+		dmau->uap = uap;
+		list_add_tail(&dmau->node, &pl011_dma_uarts);
+	}
+}
+#else
+static void pl011_dma_probe(struct uart_amba_port *uap)
+{
+	pl011_dma_probe_initcall(uap);
+}
+#endif
+
+static void pl011_dma_remove(struct uart_amba_port *uap)
+{
+	/* TODO: remove the initcall if it has not yet executed */
+	if (uap->dmatx.chan)
+		dma_release_channel(uap->dmatx.chan);
+}
+
+
+/* Forward declare this for the refill routine */
+static int pl011_dma_tx_refill(struct uart_amba_port *uap);
+
+/*
+ * The current DMA TX buffer has been sent.
+ * Try to queue up another DMA buffer.
+ */
+static void pl011_dma_tx_callback(void *data)
+{
+	struct uart_amba_port *uap = data;
+	struct pl011_dmatx_data *dmatx = &uap->dmatx;
+	unsigned long flags;
+	u16 dmacr;
+
+	spin_lock_irqsave(&uap->port.lock, flags);
+	if (uap->dmatx.queued)
+		dma_unmap_sg(dmatx->chan->device->dev, &dmatx->sg, 1,
+			     DMA_TO_DEVICE);
+
+	dmacr = uap->dmacr;
+	uap->dmacr = dmacr & ~UART011_TXDMAE;
+	writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+
+	/*
+	 * If TX DMA was disabled, it means that we've stopped the DMA for
+	 * some reason (eg, XOFF received, or we want to send an X-char.)
+	 *
+	 * Note: we need to be careful here of a potential race between DMA
+	 * and the rest of the driver - if the driver disables TX DMA while
+	 * a TX buffer completing, we must update the tx queued status to
+	 * get further refills (hence we check dmacr).
+	 */
+	if (!(dmacr & UART011_TXDMAE) || uart_tx_stopped(&uap->port) ||
+	    uart_circ_empty(&uap->port.state->xmit)) {
+		uap->dmatx.queued = false;
+		spin_unlock_irqrestore(&uap->port.lock, flags);
+		return;
+	}
+
+	if (pl011_dma_tx_refill(uap) <= 0) {
+		/*
+		 * We didn't queue a DMA buffer for some reason, but we
+		 * have data pending to be sent.  Re-enable the TX IRQ.
+		 */
+		uap->im |= UART011_TXIM;
+		writew(uap->im, uap->port.membase + UART011_IMSC);
+	}
+	spin_unlock_irqrestore(&uap->port.lock, flags);
+}
+
+/*
+ * Try to refill the TX DMA buffer.
+ * Locking: called with port lock held and IRQs disabled.
+ * Returns:
+ *   1 if we queued up a TX DMA buffer.
+ *   0 if we didn't want to handle this by DMA
+ *  <0 on error
+ */
+static int pl011_dma_tx_refill(struct uart_amba_port *uap)
+{
+	struct pl011_dmatx_data *dmatx = &uap->dmatx;
+	struct dma_chan *chan = dmatx->chan;
+	struct dma_device *dma_dev = chan->device;
+	struct dma_async_tx_descriptor *desc;
+	struct circ_buf *xmit = &uap->port.state->xmit;
+	unsigned int count;
+
+	/*
+	 * Try to avoid the overhead involved in using DMA if the
+	 * transaction fits in the first half of the FIFO, by using
+	 * the standard interrupt handling.  This ensures that we
+	 * issue a uart_write_wakeup() at the appropriate time.
+	 */
+	count = uart_circ_chars_pending(xmit);
+	if (count < (uap->fifosize >> 1)) {
+		uap->dmatx.queued = false;
+		return 0;
+	}
+
+	/*
+	 * Bodge: don't send the last character by DMA, as this
+	 * will prevent XON from notifying us to restart DMA.
+	 */
+	count -= 1;
+
+	/* Else proceed to copy the TX chars to the DMA buffer and fire DMA */
+	if (count > PL011_DMA_BUFFER_SIZE)
+		count = PL011_DMA_BUFFER_SIZE;
+
+	if (xmit->tail < xmit->head)
+		memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], count);
+	else {
+		size_t first = UART_XMIT_SIZE - xmit->tail;
+		size_t second = xmit->head;
+
+		memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], first);
+		if (second)
+			memcpy(&dmatx->buf[first], &xmit->buf[0], second);
+	}
+
+	dmatx->sg.length = count;
+
+	if (dma_map_sg(dma_dev->dev, &dmatx->sg, 1, DMA_TO_DEVICE) != 1) {
+		uap->dmatx.queued = false;
+		dev_dbg(uap->port.dev, "unable to map TX DMA\n");
+		return -EBUSY;
+	}
+
+	desc = dma_dev->device_prep_slave_sg(chan, &dmatx->sg, 1, DMA_TO_DEVICE,
+					     DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+	if (!desc) {
+		dma_unmap_sg(dma_dev->dev, &dmatx->sg, 1, DMA_TO_DEVICE);
+		uap->dmatx.queued = false;
+		/*
+		 * If DMA cannot be used right now, we complete this
+		 * transaction via IRQ and let the TTY layer retry.
+		 */
+		dev_dbg(uap->port.dev, "TX DMA busy\n");
+		return -EBUSY;
+	}
+
+	/* Some data to go along to the callback */
+	desc->callback = pl011_dma_tx_callback;
+	desc->callback_param = uap;
+
+	/* All errors should happen at prepare time */
+	dmaengine_submit(desc);
+
+	/* Fire the DMA transaction */
+	dma_dev->device_issue_pending(chan);
+
+	uap->dmacr |= UART011_TXDMAE;
+	writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+	uap->dmatx.queued = true;
+
+	/*
+	 * Now we know that DMA will fire, so advance the ring buffer
+	 * with the stuff we just dispatched.
+	 */
+	xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
+	uap->port.icount.tx += count;
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(&uap->port);
+
+	return 1;
+}
+
+/*
+ * We received a transmit interrupt without a pending X-char but with
+ * pending characters.
+ * Locking: called with port lock held and IRQs disabled.
+ * Returns:
+ *   false if we want to use PIO to transmit
+ *   true if we queued a DMA buffer
+ */
+static bool pl011_dma_tx_irq(struct uart_amba_port *uap)
+{
+	if (!uap->using_dma)
+		return false;
+
+	/*
+	 * If we already have a TX buffer queued, but received a
+	 * TX interrupt, it will be because we've just sent an X-char.
+	 * Ensure the TX DMA is enabled and the TX IRQ is disabled.
+	 */
+	if (uap->dmatx.queued) {
+		uap->dmacr |= UART011_TXDMAE;
+		writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+		uap->im &= ~UART011_TXIM;
+		writew(uap->im, uap->port.membase + UART011_IMSC);
+		return true;
+	}
+
+	/*
+	 * We don't have a TX buffer queued, so try to queue one.
+	 * If we succesfully queued a buffer, mask the TX IRQ.
+	 */
+	if (pl011_dma_tx_refill(uap) > 0) {
+		uap->im &= ~UART011_TXIM;
+		writew(uap->im, uap->port.membase + UART011_IMSC);
+		return true;
+	}
+	return false;
+}
+
+/*
+ * Stop the DMA transmit (eg, due to received XOFF).
+ * Locking: called with port lock held and IRQs disabled.
+ */
+static inline void pl011_dma_tx_stop(struct uart_amba_port *uap)
+{
+	if (uap->dmatx.queued) {
+		uap->dmacr &= ~UART011_TXDMAE;
+		writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+	}
+}
+
+/*
+ * Try to start a DMA transmit, or in the case of an XON/OFF
+ * character queued for send, try to get that character out ASAP.
+ * Locking: called with port lock held and IRQs disabled.
+ * Returns:
+ *   false if we want the TX IRQ to be enabled
+ *   true if we have a buffer queued
+ */
+static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
+{
+	u16 dmacr;
+
+	if (!uap->using_dma)
+		return false;
+
+	if (!uap->port.x_char) {
+		/* no X-char, try to push chars out in DMA mode */
+		bool ret = true;
+
+		if (!uap->dmatx.queued) {
+			if (pl011_dma_tx_refill(uap) > 0) {
+				uap->im &= ~UART011_TXIM;
+				ret = true;
+			} else {
+				uap->im |= UART011_TXIM;
+				ret = false;
+			}
+			writew(uap->im, uap->port.membase + UART011_IMSC);
+		} else if (!(uap->dmacr & UART011_TXDMAE)) {
+			uap->dmacr |= UART011_TXDMAE;
+			writew(uap->dmacr,
+				       uap->port.membase + UART011_DMACR);
+		}
+		return ret;
+	}
+
+	/*
+	 * We have an X-char to send.  Disable DMA to prevent it loading
+	 * the TX fifo, and then see if we can stuff it into the FIFO.
+	 */
+	dmacr = uap->dmacr;
+	uap->dmacr &= ~UART011_TXDMAE;
+	writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+
+	if (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) {
+		/*
+		 * No space in the FIFO, so enable the transmit interrupt
+		 * so we know when there is space.  Note that once we've
+		 * loaded the character, we should just re-enable DMA.
+		 */
+		return false;
+	}
+
+	writew(uap->port.x_char, uap->port.membase + UART01x_DR);
+	uap->port.icount.tx++;
+	uap->port.x_char = 0;
+
+	/* Success - restore the DMA state */
+	uap->dmacr = dmacr;
+	writew(dmacr, uap->port.membase + UART011_DMACR);
+
+	return true;
+}
+
+/*
+ * Flush the transmit buffer.
+ * Locking: called with port lock held and IRQs disabled.
+ */
+static void pl011_dma_flush_buffer(struct uart_port *port)
+{
+	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+
+	if (!uap->using_dma)
+		return;
+
+	/* Avoid deadlock with the DMA engine callback */
+	spin_unlock(&uap->port.lock);
+	dmaengine_terminate_all(uap->dmatx.chan);
+	spin_lock(&uap->port.lock);
+	if (uap->dmatx.queued) {
+		dma_unmap_sg(uap->dmatx.chan->device->dev, &uap->dmatx.sg, 1,
+			     DMA_TO_DEVICE);
+		uap->dmatx.queued = false;
+		uap->dmacr &= ~UART011_TXDMAE;
+		writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+	}
+}
+
+
+static void pl011_dma_startup(struct uart_amba_port *uap)
+{
+	if (!uap->dmatx.chan)
+		return;
+
+	uap->dmatx.buf = kmalloc(PL011_DMA_BUFFER_SIZE, GFP_KERNEL);
+	if (!uap->dmatx.buf) {
+		dev_err(uap->port.dev, "no memory for DMA TX buffer\n");
+		uap->port.fifosize = uap->fifosize;
+		return;
+	}
+
+	sg_init_one(&uap->dmatx.sg, uap->dmatx.buf, PL011_DMA_BUFFER_SIZE);
+
+	/* The DMA buffer is now the FIFO the TTY subsystem can use */
+	uap->port.fifosize = PL011_DMA_BUFFER_SIZE;
+	uap->using_dma = true;
+
+	/* Turn on DMA error (RX/TX will be enabled on demand) */
+	uap->dmacr |= UART011_DMAONERR;
+	writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+}
+
+static void pl011_dma_shutdown(struct uart_amba_port *uap)
+{
+	if (!uap->using_dma)
+		return;
+
+	/* Disable RX and TX DMA */
+	while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY)
+		barrier();
+
+	spin_lock_irq(&uap->port.lock);
+	uap->dmacr &= ~(UART011_DMAONERR | UART011_RXDMAE | UART011_TXDMAE);
+	writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+	spin_unlock_irq(&uap->port.lock);
+
+	/* In theory, this should already be done by pl011_dma_flush_buffer */
+	dmaengine_terminate_all(uap->dmatx.chan);
+	if (uap->dmatx.queued) {
+		dma_unmap_sg(uap->dmatx.chan->device->dev, &uap->dmatx.sg, 1,
+			     DMA_TO_DEVICE);
+		uap->dmatx.queued = false;
+	}
+
+	kfree(uap->dmatx.buf);
+
+	uap->using_dma = false;
+}
+
+#else
+/* Blank functions if the DMA engine is not available */
+static inline void pl011_dma_probe(struct uart_amba_port *uap)
+{
+}
+
+static inline void pl011_dma_remove(struct uart_amba_port *uap)
+{
+}
+
+static inline void pl011_dma_startup(struct uart_amba_port *uap)
+{
+}
+
+static inline void pl011_dma_shutdown(struct uart_amba_port *uap)
+{
+}
+
+static inline bool pl011_dma_tx_irq(struct uart_amba_port *uap)
+{
+	return false;
+}
+
+static inline void pl011_dma_tx_stop(struct uart_amba_port *uap)
+{
+}
+
+static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
+{
+	return false;
+}
+
+#define pl011_dma_flush_buffer	NULL
+#endif
+
+
 static void pl011_stop_tx(struct uart_port *port)
 {
 	struct uart_amba_port *uap = (struct uart_amba_port *)port;
 
 	uap->im &= ~UART011_TXIM;
 	writew(uap->im, uap->port.membase + UART011_IMSC);
+	pl011_dma_tx_stop(uap);
 }
 
 static void pl011_start_tx(struct uart_port *port)
 {
 	struct uart_amba_port *uap = (struct uart_amba_port *)port;
 
-	uap->im |= UART011_TXIM;
-	writew(uap->im, uap->port.membase + UART011_IMSC);
+	if (!pl011_dma_tx_start(uap)) {
+		uap->im |= UART011_TXIM;
+		writew(uap->im, uap->port.membase + UART011_IMSC);
+	}
 }
 
 static void pl011_stop_rx(struct uart_port *port)
@@ -204,6 +695,10 @@ static void pl011_tx_chars(struct uart_amba_port *uap)
 		return;
 	}
 
+	/* If we are using DMA mode, try to send some characters. */
+	if (pl011_dma_tx_irq(uap))
+		return;
+
 	count = uap->fifosize >> 1;
 	do {
 		writew(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR);
@@ -434,6 +929,9 @@ static int pl011_startup(struct uart_port *port)
 	 */
 	uap->old_status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
 
+	/* Startup DMA */
+	pl011_dma_startup(uap);
+
 	/*
 	 * Finally, enable interrupts
 	 */
@@ -473,6 +971,8 @@ static void pl011_shutdown(struct uart_port *port)
 	writew(0xffff, uap->port.membase + UART011_ICR);
 	spin_unlock_irq(&uap->port.lock);
 
+	pl011_dma_shutdown(uap);
+
 	/*
 	 * Free the interrupt
 	 */
@@ -691,6 +1191,7 @@ static struct uart_ops amba_pl011_pops = {
 	.break_ctl	= pl011_break_ctl,
 	.startup	= pl011_startup,
 	.shutdown	= pl011_shutdown,
+	.flush_buffer	= pl011_dma_flush_buffer,
 	.set_termios	= pl011_set_termios,
 	.type		= pl011_type,
 	.release_port	= pl010_release_port,
@@ -883,6 +1384,7 @@ static int pl011_probe(struct amba_device *dev, struct amba_id *id)
 	uap->port.ops = &amba_pl011_pops;
 	uap->port.flags = UPF_BOOT_AUTOCONF;
 	uap->port.line = i;
+	pl011_dma_probe(uap);
 
 	snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev));
 
@@ -893,6 +1395,7 @@ static int pl011_probe(struct amba_device *dev, struct amba_id *id)
 	if (ret) {
 		amba_set_drvdata(dev, NULL);
 		amba_ports[i] = NULL;
+		pl011_dma_remove(uap);
 		clk_put(uap->clk);
  unmap:
 		iounmap(base);
@@ -916,6 +1419,7 @@ static int pl011_remove(struct amba_device *dev)
 		if (amba_ports[i] == uap)
 			amba_ports[i] = NULL;
 
+	pl011_dma_remove(uap);
 	iounmap(uap->port.membase);
 	clk_put(uap->clk);
 	kfree(uap);
diff --git a/include/linux/amba/serial.h b/include/linux/amba/serial.h
index 6021588..577f22e 100644
--- a/include/linux/amba/serial.h
+++ b/include/linux/amba/serial.h
@@ -180,6 +180,13 @@ struct amba_device; /* in uncompress this is included but amba/bus.h is not */
 struct amba_pl010_data {
 	void (*set_mctrl)(struct amba_device *dev, void __iomem *base, unsigned int mctrl);
 };
+
+struct dma_chan;
+struct amba_pl011_data {
+	bool (*dma_filter)(struct dma_chan *chan, void *filter_param);
+	void *dma_rx_param;
+	void *dma_tx_param;
+};
 #endif
 
 #endif

^ permalink raw reply related

* [PATCH v5 1/3] ARM: add CPPI 4.1 DMA support
From: Sergei Shtylyov @ 2011-01-03 16:06 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <201005152214.53993.sshtylyov@ru.mvista.com>

Hello.

On 15-05-2010 22:14, Sergei Shtylyov wrote:

> Add support for Texas Instuments Communication Port Programming Interface 4.1
> (CPPI 4.1) used on OMAP-L1x/DA8xx and AM35x.

> At this moment, only the DMA controller and queue manager are supported.
> Support for the buffer manager is lacking but these chips don't have it anyway.

> Signed-off-by: Sergei Shtylyov<sshtylyov@ru.mvista.com>
> Signed-off-by: Sekhar Nori<nsekhar@ti.com>

    Russell, you have recently discarded this patch from your patch system. 
Can we know the reason?

WBR, Sergei

^ permalink raw reply

* [PATCH 2/2] arm/pxa: buildfix for pam27x without fb
From: Eric Miao @ 2011-01-03 15:57 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1293654828-24661-2-git-send-email-bigeasy@linutronix.de>

On Thu, Dec 30, 2010 at 4:33 AM, Sebastian Andrzej Siewior
<bigeasy@linutronix.de> wrote:
> |arch/arm/mach-pxa/palmld.c: In function ?palmld_init?:
> |arch/arm/mach-pxa/palmld.c:330: error: ?palm_320x480_lcd_mode? undeclared (first use in this function)
> |arch/arm/mach-pxa/palmld.c:330: error: (Each undeclared identifier is reported only once
> |arch/arm/mach-pxa/palmld.c:330: error: for each function it appears in.)
>
> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>

Marek,

I need your ack please.

> ---
> ?arch/arm/mach-pxa/include/mach/palm27x.h | ? ?2 +-
> ?1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/arch/arm/mach-pxa/include/mach/palm27x.h b/arch/arm/mach-pxa/include/mach/palm27x.h
> index 0a5e5ea..7b7927c 100644
> --- a/arch/arm/mach-pxa/include/mach/palm27x.h
> +++ b/arch/arm/mach-pxa/include/mach/palm27x.h
> @@ -34,7 +34,7 @@ extern struct pxafb_mode_info palm_320x320_new_lcd_mode;
> ?extern void __init palm27x_lcd_init(int power,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?struct pxafb_mode_info *mode);
> ?#else
> -static inline void palm27x_lcd_init(int power, struct pxafb_mode_info *mode) {}
> +#define palm27x_lcd_init(power, mode) ?do { } while (0)
> ?#endif
>
> ?#if ? ?defined(CONFIG_USB_GADGET_PXA27X) || \
> --
> 1.7.3.2
>
>

^ permalink raw reply

* [GIT PULL] pxa: 3 fixes for 2.6.37-rc8
From: Eric Miao @ 2011-01-03 15:48 UTC (permalink / raw)
  To: linux-arm-kernel

The following changes since commit 387c31c7e5c9805b0aef8833d1731a5fe7bdea14:

  Linux 2.6.37-rc8 (2010-12-28 17:05:48 -0800)

are available in the git repository at:
  git://git.kernel.org/pub/scm/linux/kernel/git/ycmiao/pxa-linux-2.6.git fix

Aric D. Blumer (1):
      ARM: pxa: fix page table corruption on resume

Lennert Buytenhek (1):
      ARM: pxa: PXA_ESERIES depends on FB_W100.

Mike Rapoport (1):
      ARM: it8152: add IT8152_LAST_IRQ definition to fix build error

 arch/arm/include/asm/hardware/it8152.h |    1 +
 arch/arm/mach-pxa/Kconfig              |    1 +
 arch/arm/mach-pxa/sleep.S              |    4 ++--
 3 files changed, 4 insertions(+), 2 deletions(-)

^ permalink raw reply

* [PATCH] [ARM] pxa: fix page table corruption on resume
From: Eric Miao @ 2011-01-03 15:47 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1293639509-9373-1-git-send-email-mreimer@sdgsystems.com>

On Thu, Dec 30, 2010 at 12:18 AM, Matt Reimer <mreimer@sdgsystems.com> wrote:
> From: Aric D. Blumer <aric@sdgsystems.com>
>
> Before this patch, the following error would sometimes occur after a
> resume on pxa3xx:
>
> ? ?/path/to/mm/memory.c:144: bad pmd 8040542e.
>
> The problem was that a temporary page table mapping was being improperly
> restored.
>
> The PXA3xx resume code creates a temporary mapping of resume_turn_on_mmu
> to avoid a prefetch abort. ?The pxa3xx_resume_after_mmu code requires
> that the r1 register holding the address of this mapping not be
> modified, however, resume_turn_on_mmu does modify it. It is mostly
> correct in that r1 receives the base table address, but it may also
> get other bits in 13:0. ?This results in pxa3xx_resume_after_mmu
> restoring the original mapping to the wrong place, corrupting memory
> and leaving the temporary mapping in place.
>
> Signed-off-by: Matt Reimer <mreimer@sdgsystems.com>

Applied.

> ---
> ?arch/arm/mach-pxa/sleep.S | ? ?4 ++--
> ?1 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm/mach-pxa/sleep.S b/arch/arm/mach-pxa/sleep.S
> index 52c30b0..ae00811 100644
> --- a/arch/arm/mach-pxa/sleep.S
> +++ b/arch/arm/mach-pxa/sleep.S
> @@ -353,8 +353,8 @@ resume_turn_on_mmu:
>
> ? ? ? ?@ Let us ensure we jump to resume_after_mmu only when the mcr above
> ? ? ? ?@ actually took effect. ?They call it the "cpwait" operation.
> - ? ? ? mrc ? ? p15, 0, r1, c2, c0, 0 ? ? ? ? ? @ queue a dependency on CP15
> - ? ? ? sub ? ? pc, r2, r1, lsr #32 ? ? ? ? ? ? @ jump to virtual addr
> + ? ? ? mrc ? ? p15, 0, r0, c2, c0, 0 ? ? ? ? ? @ queue a dependency on CP15
> + ? ? ? sub ? ? pc, r2, r0, lsr #32 ? ? ? ? ? ? @ jump to virtual addr
> ? ? ? ?nop
> ? ? ? ?nop
> ? ? ? ?nop
> --
> 1.7.0.4
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>

^ permalink raw reply

* [PATCH] [ARM] it8152: add IT8152_LAST_IRQ definition to fix build error
From: Eric Miao @ 2011-01-03 15:43 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1293606386-17388-1-git-send-email-mike@compulab.co.il>

On Wed, Dec 29, 2010 at 3:06 PM, Mike Rapoport <mike@compulab.co.il> wrote:
> The commit 6ac6b817f3f4c23c5febd960d8deb343e13af5f3 (ARM: pxa: encode
> IRQ number into .nr_irqs) removed definition of ITE_LAST_IRQ which
> caused the following build error:
>
> CC ? ? ?arch/arm/common/it8152.o
> arch/arm/common/it8152.c: In function 'it8152_init_irq':
> arch/arm/common/it8152.c:86: error: 'IT8152_LAST_IRQ' undeclared (first use in this function)
> arch/arm/common/it8152.c:86: error: (Each undeclared identifier is reported only once
> arch/arm/common/it8152.c:86: error: for each function it appears in.)
> make[2]: *** [arch/arm/common/it8152.o] Error 1
>
> Defining the IT8152_LAST_IRQ in the arch/arm/include/hardware/it8152.c
> fixes the build.
>
> Signed-off-by: Mike Rapoport <mike@compulab.co.il>

Applied.

> ---
> ?arch/arm/include/asm/hardware/it8152.h | ? ?1 +
> ?1 files changed, 1 insertions(+), 0 deletions(-)
>
> diff --git a/arch/arm/include/asm/hardware/it8152.h b/arch/arm/include/asm/hardware/it8152.h
> index 21fa272..b2f95c7 100644
> --- a/arch/arm/include/asm/hardware/it8152.h
> +++ b/arch/arm/include/asm/hardware/it8152.h
> @@ -76,6 +76,7 @@ extern unsigned long it8152_base_address;
> ? IT8152_PD_IRQ(0) ?Audio controller (ACR)
> ?*/
> ?#define IT8152_IRQ(x) ? (IRQ_BOARD_START + (x))
> +#define IT8152_LAST_IRQ ? ? ? ?(IRQ_BOARD_START + 40)
>
> ?/* IRQ-sources in 3 groups - local devices, LPC (serial), and external PCI */
> ?#define IT8152_LD_IRQ_COUNT ? ? 9
> --
> 1.6.4.4
>
>

^ permalink raw reply

* [PATCH 3/9] Add a mfd IPUv3 driver
From: Sascha Hauer @ 2011-01-03 15:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1292842127-21406-4-git-send-email-s.hauer@pengutronix.de>

On Mon, Dec 20, 2010 at 11:48:41AM +0100, Sascha Hauer wrote:
> The IPU is the Image Processing Unit found on i.MX50/51/53 SoCs. It
> features several units for image processing, this patch adds support
> for the units needed for Framebuffer support, namely:
>
> - Display Controller (dc)
> - Display Interface (di)
> - Display Multi Fifo Controller (dmfc)
> - Display Processor (dp)
> - Image DMA Controller (idmac)
>
> This patch is based on the Freescale driver, but follows a different
> approach. The Freescale code implements logical idmac channels and
> the handling of the subunits is hidden in common idmac code pathes
> in big switch/case statements. This patch instead just provides code
> and resource management for the different subunits. The user, in this
> case the framebuffer driver, decides how the different units play
> together.
>
> The IPU has other units missing in this patch:
>
> - CMOS Sensor Interface (csi)
> - Video Deinterlacer (vdi)
> - Sensor Multi FIFO Controler (smfc)
> - Image Converter (ic)
> - Image Rotator (irt)
>
> So expect more files to come in this directory.
>
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>

Hello Samuel,

I see no further comments on this series. Does this mean you are ok with
the patch or didn't you find the time looking at it?

This patch can go via the mfd tree or I can push this via my i.MX tree.
Going via the i.MX tree makes life a bit easier for me because we do not
run into merge order dependencies. Please let me know what you prefer.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply

* [PATCH 02/04] ARM i.MX25 Add SIM driver
From: Wolfram Sang @ 2011-01-03 15:29 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <4D21E53E.2050809@fqingenieria.es>

Hi,

> Regarding if this driver can fit into mainline, I agree that the
> kernel is not the right place to contain a smartcard API. There are
> other projects doing that quite well (muscle, opensc, ...). But in
> fact, the idea of this driver is not to give a smartcard API but
> support the I.MX25 SIM core, which is explicitly hardware dependant.

Juergen Beisert also wrote a driver for it and you can read the
discussions about mainlining strategies here:

https://lkml.org/lkml/2010/5/7/214
http://www.opensc-project.org/pipermail/opensc-devel/2010-May/014225.html

Patches for opensc:

http://www.opensc-project.org/pipermail/opensc-devel/2010-May/014271.html

IIRC the direction was okay, just some obstacles left.

Kind regards,

   Wolfram

-- 
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: 198 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20110103/5756d247/attachment.sig>

^ permalink raw reply

* [PATCH 02/04] ARM i.MX25 Add SIM driver
From: Russell King - ARM Linux @ 2011-01-03 15:27 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <4D21E53E.2050809@fqingenieria.es>

On Mon, Jan 03, 2011 at 04:03:26PM +0100, Jaume Ribot wrote:
> IMHO, there is  
> no conceptual difference between this driver and any of the others  
> contained into plat-mxc/ directory. That's also why this driver has not  
> been placed into drivers/ directory.

I repeat, drivers for user interfaces should be in the drivers/ subtree
and not the arch/ subtree.  It's something that Linus Torvalds has
complained about, and it's a practice that needs to stop right now if we
want to continue being part of mainline.

I don't see anything in plat-mxc registering itself as user visible driver.
The only things I see are low level such as cpufreq drivers, clocksource/
clockevent code, gpio and pwm services.  So, there's no precident in
plat-mxc for user visible device drivers.

The problem is that no one expects user visible device drivers in the
arch/ tree, and so they will get missed when updates to their kernel APIs
happen.

^ permalink raw reply

* [PATCH 06/13] DMAENGINE: driver for the ARM PL080/PL081 PrimeCells
From: Russell King - ARM Linux @ 2011-01-03 15:19 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <AANLkTikpyAggDCPef1pS=_QHnu9-FyLcpddGyVHnGwWx@mail.gmail.com>

Another issue to think about in terms of API guarantees...

Pausing an on-going transfer (which from what I read is a recent addition
to the API) can be problematical - having tripped over one such problem
on my Realview EB (PL081 rev1) platform.

With the PL08x, when you program a channel up for a M->P transfer and
enable it, the DMAC will immediately fetch data from memory and mark
itself busy before the first DMA request from the peripheral.

When the first DMA request occurs from the peripheral, the DMAC starts
feeding this data to the peripheral, and fetches new data into its FIFO
as required.

The problem comes when the peripheral stops requesting data from the
DMAC, and then you want to pause it.  Current code sets the HALT bit,
and then spins indefinitely for the BUSY bit to clear - which it will
only ever do if the peripheral drains the FIFO.  As a result of botched
DMA signal selection code for the Realview EB, the DMA signals never
went active, and on terminate_all() the CPU locked up solid (no
interrupts) spinning on the DMAC to clear the busy bit.

It may be worth specifying that a pause followed by a resume is
expected to never lose data - and that drivers must check the result
of a request to pause the channel.  If DMA engine drivers are unable
to pause the channel within a reasonable amount of time, they should
return -ETIMEOUT, so they know that there may still be data that
could still be transferred to the peripheral.

One important note about this condition is that with the DMA channel
marked BUSY+HALT and the channel being configured for M->P, the
peripheral can still transfer data from the DMAC to itself, and this
causes the transfer size value in the CNTL register to decrement (since
reading the CNTL register returns the number of transfers _to_ the
destination, not the number of transfers from the source.)

I've changed the comment against pl08x_pause_phy_chan() to this:

 * Pause the channel by setting the HALT bit.
 *
 * For M->P transfers, pause the DMAC first and then stop the peripheral -
 * the FIFO can only drain if the peripheral is still requesting data.
 * (note: this can still timeout if the DMAC FIFO never drains of data.)
 *
 * For P->M transfers, disable the peripheral first to stop it filling
 * the DMAC FIFO, and then pause the DMAC.

I've not decided whether it should be possible to resume an ETIMEOUT'd
pause request (in theory with pl08x, that's just a matter of clearing
the HALT bit) or whether an ETIMEOUT'd pause request should restore
the previous HALT bit setting (possibly re-enabling transfers on the
channel.)  Allowing it to be re-enabled in some way would be the safest
thing in terms of data integrity for the reason mentioned in the
"important note" above.

Dan, Linus, any thoughts?

^ permalink raw reply

* [PATCH 02/04] ARM i.MX25 Add SIM driver
From: Jaume Ribot @ 2011-01-03 15:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20110103130551.GA24408@pengutronix.de>


Hi Sascha,


On 03/01/2011 14:05, Sascha Hauer wrote:
> Hello Iban,
>
> On Mon, Jan 03, 2011 at 10:07:19AM +0100, FQ | Iban Cerro wrote:
>> This driver is slightly based on the Freescale original one, with several
>> code simplifications. We made specially emphasis in avoiding any ISO7816
>> code into the driver, which is not the right place to be. Driver mainly
>> works via ioctl to configure and then using read/write functions to
>> read/write smart cards.
>>
>> One important consideration (not clear in the User Manual from our point
>> of view) is that there exist two SIM modules into the MX25 core, both of
>> them in different memory position. This causes all accesses to SIM modules
>> must be done via SIM0. This differs from the way the User Manual explains
>> how to access the two different SIM modules, which seems is inherited from
>> the MX51 core.
> The following comments are mostly coding style related, running Lindent
> and checkpatch.pl on this patch seems to be a good start for improving
> this driver.
Thanks for comments and reviews. We will apply all recommendations and 
we will resubmit patches, also with all identation issues solved.
> The main problem for pushing this driver to mainline is that you invent
> a i.MX specific smartcard API. This is not a good idea and probably not
> acceptable in mainline.
Regarding if this driver can fit into mainline, I agree that the kernel 
is not the right place to contain a smartcard API. There are other 
projects doing that quite well (muscle, opensc, ...). But in fact, the 
idea of this driver is not to give a smartcard API but support the 
I.MX25 SIM core, which is explicitly hardware dependant. IMHO, there is 
no conceptual difference between this driver and any of the others 
contained into plat-mxc/ directory. That's also why this driver has not 
been placed into drivers/ directory. Maybe we can study to perform a 
higher simplification of the driver, in order to remove any reminiscence 
of smartcard API functions and only performing hardware (MX25) dependent 
jobs .
>> Signed-off-by: Iban Cerro Galvez<iban@fqingenieria.es>
>> ---
>>   arch/arm/plat-mxc/Kconfig                |    7 +
>>   arch/arm/plat-mxc/Makefile               |    1 +
>>   arch/arm/plat-mxc/include/mach/mxc_sim.h |  319 +++++++++++
>>   arch/arm/plat-mxc/sim.c                  |  874
>> ++++++++++++++++++++++++++++++
> Your mailer breaks lines which means that other people can't apply this
> patch.
>
>>   4 files changed, 1201 insertions(+), 0 deletions(-)
>>   create mode 100644 arch/arm/plat-mxc/include/mach/mxc_sim.h
>>   create mode 100644 arch/arm/plat-mxc/sim.c
>>
>> diff --git a/arch/arm/plat-mxc/Kconfig b/arch/arm/plat-mxc/Kconfig
>> index 389f217..7b16d0d 100644
>> --- a/arch/arm/plat-mxc/Kconfig
>> +++ b/arch/arm/plat-mxc/Kconfig
>> @@ -74,6 +74,13 @@ config MXC_PWM
>>   	help
>>   	  Enable support for the i.MX PWM controller(s).
>>
>> +config MXC_SIM
>> + 	tristate "Enable SIM driver"
>> + 	select HAVE_SIM
>> + 	help
>> + 	  Enable support for the i.MX SIM controller(s).
>> +
>> +
>>   config MXC_DEBUG_BOARD
>>   	bool "Enable MXC debug board(for 3-stack)"
>>   	help
>> diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile
>> index 5fd20e9..73073fb 100644
>> --- a/arch/arm/plat-mxc/Makefile
>> +++ b/arch/arm/plat-mxc/Makefile
>> @@ -12,6 +12,7 @@ obj-$(CONFIG_MXC_AVIC) += avic.o
>>   obj-$(CONFIG_IMX_HAVE_IOMUX_V1) += iomux-v1.o
>>   obj-$(CONFIG_ARCH_MXC_IOMUX_V3) += iomux-v3.o
>>   obj-$(CONFIG_IRAM_ALLOC) += iram_alloc.o
>> +obj-$(CONFIG_MXC_SIM) += sim.o
>>   obj-$(CONFIG_MXC_PWM)  += pwm.o
>>   obj-$(CONFIG_USB_EHCI_MXC) += ehci.o
>>   obj-$(CONFIG_MXC_ULPI) += ulpi.o
>> diff --git a/arch/arm/plat-mxc/include/mach/mxc_sim.h
>> b/arch/arm/plat-mxc/include/mach/mxc_sim.h
>> new file mode 100644
>> index 0000000..74ff008
>> --- /dev/null
>> +++ b/arch/arm/plat-mxc/include/mach/mxc_sim.h
>> @@ -0,0 +1,319 @@
>> +/*
>> + * Copyright 2010-2011 FQ Ingenieria Electronica S.A.
>> + *
>> + *  Adapted and simplify this driver to kernel mainline code style using
>> + *  other drivers from Freescale
>> + *  Jaume Ribot (jaume at fqingenieria.es)
>> + *  Iban Cerro Galvez (iban at fqingenieria.es)
>> + */
>> +
>> +/*
>> + * 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.
>> + */
>> +
>> +/*!
>> + * @file mxc_sim.h
>> + *
>> + * @brief Driver for Freescale IMX SIM interface
>> + *
>> + */
>> +
>> +#ifndef MXC_SIM_INTERFACE_H
>> +#define MXC_SIM_INTERFACE_H
>> +
>> +#define SIM_DRIVER_VERSION 0x01
>> +
>> +/* Transmit and receive buffer sizes */
>> +#define SIM_XMT_BUFFER_SIZE 256
>> +#define SIM_RCV_BUFFER_SIZE 256
>> +
>> +/*BAUD_DIVISOR */
>> +#define SIM_DEFAULT_BAUD_DIV 372
>> +
>> +#define WRITE_TIMEOUT 1000
>> +#define READ_TIMEOUT 1000
>> +
>> +
>> +struct mxc_sim_platform_data {
>> +	unsigned int clk_rate;
>> +	char *clock_sim;
> Please do not pass clock names to drivers. Use clk_get(dev, id) instead.
>
>> +	char *power_sim;
> This seems to be unused.
>
>> +	int (*init)(struct platform_device *pdev);
>> +	void (*exit)(void);
>> +	unsigned int detect; /* 1 have detect pin, 0 not */
>> +	unsigned int sim_number; /* 0 or 1 */
>> +};
>> +
>> +typedef struct {
>> +	unsigned long addr;
>> +	unsigned long data;
>> +} sim_reg;
> Do not typedef struct types, see Documentation/CodingStyle.
>
>> +
>> +/* Main SIM driver structure */
>> +typedef struct {
>> +	/*SIM number 0, 1 */
>> +	int sim_number;
>> +	/* card inserted = 1, ATR received = 2, card removed = 0 */
>> +	int present;
>> +	/* current ATR or OPS state */
>> +	int state;
>> +	/* current power state */
>> +	int power;
>> +	/* error code occured during transfer */
>> +	int errval;
>> +	/* Clock id */
>> +	struct clk *clk;
>> +	/* on off clk*/
>> +	uint8_t clk_flag;
>> +	/* frequency of clk sim */
>> +	uint32_t clk_sim;
>> +	/* value of clk divisor*/
>> +	int uart_div;
>> +	/* IO map memory */
>> +	struct resource *res;
>> +	/* Mapped address */
>> +	void __iomem *ioaddr;	/* Mapped address */
>> +	int ipb_irq;		/* sim ipb IRQ num */
>> +	int dat_irq;		/* sim dat IRQ num */
>> +	/* async notifier for card and ATR detection */
>> +	struct fasync_struct *fasync;
>> +	/* Platform specific data */
>> +	struct mxc_sim_platform_data *plat_data;
>> +} sim_t;
> ditto
>
>> +
>> +/* ISO7816-3 protocols */
>> +#define SIM_PROTOCOL_T0  0
>> +#define SIM_PROTOCOL_T1  1
>> +
>> +/* Transfer types for SIM_IOCTL_XFER */
>> +#define SIM_XFER_TYPE_TPDU 0
>> +#define SIM_XFER_TYPE_PTS  1
>> +
>> +/* Interface power states */
>> +#define SIM_POWER_OFF 0
>> +#define SIM_POWER_ON  1
>> +
>> +/* Return values for SIM_IOCTL_GET_PRESENSE */
>> +#define SIM_PRESENT_REMOVED     0
>> +#define SIM_PRESENT_DETECTED    1
>> +#define SIM_PRESENT_OPERATIONAL 2
>> +
>> +/* Return values for SIM_IOCTL_GET_ERROR */
>> +#define SIM_OK                         0
>> +#define SIM_E_ACCESS                   1
>> +#define SIM_E_TPDUSHORT                2
>> +#define SIM_E_PTSEMPTY                 3
>> +#define SIM_E_INVALIDXFERTYPE          4
>> +#define SIM_E_INVALIDXMTLENGTH         5
>> +#define SIM_E_INVALIDRCVLENGTH         6
>> +#define SIM_E_NACK                     7
>> +#define SIM_E_TIMEOUT                  8
>> +#define SIM_E_NOCARD                   9
>> +#define SIM_E_PARAM_FI_INVALID         10
>> +#define SIM_E_PARAM_DI_INVALID         11
>> +#define SIM_E_PARAM_FBYD_WITHFRACTION  12
>> +#define SIM_E_PARAM_FBYD_NOTDIVBY8OR12 13
>> +#define SIM_E_PARAM_DIVISOR_RANGE      14
>> +#define SIM_E_MALLOC                   15
>> +#define SIM_E_IRQ                      16
>> +#define SIM_E_POWERED_ON               17
>> +#define SIM_E_POWERED_OFF              18
>> +
>> +/* ioctl encodings */
>> +#define SIM_IOCTL_BASE 0xc0
>> +#define SIM_IOCTL_VERSION        _IOR(SIM_IOCTL_BASE, 1,unsigned char)
>> +#define SIM_IOCTL_POWER_ON       _IO(SIM_IOCTL_BASE,  2)
>> +#define SIM_IOCTL_POWER_OFF      _IO(SIM_IOCTL_BASE,  3)
>> +#define SIM_IOCTL_WARM_RESET     _IO(SIM_IOCTL_BASE,  4)
>> +#define SIM_IOCTL_COLD_RESET     _IO(SIM_IOCTL_BASE,  5)
>> +#define SIM_IOCTL_CLK_PORT			 _IOW(SIM_IOCTL_BASE, 6, int)
>> +#define SIM_IOCTL_RST_PORT			 _IOW(SIM_IOCTL_BASE, 7, int)
>> +#define SIM_IOCTL_VCC_PORT			 _IOW(SIM_IOCTL_BASE, 8, int)
>> +#define SIM_IOCTL_SET_CLK_SIM    _IOW(SIM_IOCTL_BASE, 9, unsigned long)
>> +#define SIM_IOCTL_SET_CLK_DIV		 _IOW(SIM_IOCTL_BASE, 10, int)
>> +#define SIM_IOCTL_GET_REG				 _IOW(SIM_IOCTL_BASE, 11, sim_reg)
>> +#define SIM_IOCTL_SET_REG				 _IOW(SIM_IOCTL_BASE, 12, sim_reg)
>> +
>> +/* Interface character references */
>> +#define SIM_IFC_TXI(letter, number) (letter + number * 4)
>> +#define SIM_IFC_TA1   SIM_IFC_TXI(0, 0)
>> +#define SIM_IFC_TB1   SIM_IFC_TXI(0, 1)
>> +#define SIM_IFC_TC1   SIM_IFC_TXI(0, 2)
>> +#define SIM_IFC_TD1   SIM_IFC_TXI(0, 3)
>> +#define SIM_IFC_TA2   SIM_IFC_TXI(1, 0)
>> +#define SIM_IFC_TB2   SIM_IFC_TXI(1, 1)
>> +#define SIM_IFC_TC2   SIM_IFC_TXI(1, 2)
>> +#define SIM_IFC_TD2   SIM_IFC_TXI(1, 3)
>> +#define SIM_IFC_TA3   SIM_IFC_TXI(2, 0)
>> +#define SIM_IFC_TB3   SIM_IFC_TXI(2, 1)
>> +#define SIM_IFC_TC3   SIM_IFC_TXI(2, 2)
>> +#define SIM_IFC_TD3   SIM_IFC_TXI(2, 3)
>> +#define SIM_IFC_TA4   SIM_IFC_TXI(3, 0)
>> +#define SIM_IFC_TB4   SIM_IFC_TXI(3, 1)
>> +#define SIM_IFC_TC4   SIM_IFC_TXI(3, 2)
>> +#define SIM_IFC_TD4   SIM_IFC_TXI(3, 3)
>> +
>> +/* ATR and OPS states */
>> +#define SIM_STATE_REMOVED              0
>> +#define SIM_STATE_OPERATIONAL_IDLE     1
>> +#define SIM_STATE_OPERATIONAL_COMMAND  2
>> +#define SIM_STATE_OPERATIONAL_RESPONSE 3
>> +#define SIM_STATE_OPERATIONAL_STATUS1  4
>> +#define SIM_STATE_OPERATIONAL_STATUS2  5
>> +#define SIM_STATE_OPERATIONAL_PTS      6
>> +#define SIM_STATE_DETECTED_ATR_T0       7
>> +#define SIM_STATE_DETECTED_ATR_TS       8
>> +#define SIM_STATE_DETECTED_ATR_TXI      9
>> +#define SIM_STATE_DETECTED_ATR_THB      10
>> +#define SIM_STATE_DETECTED_ATR_TCK      11
>> +
>> +/* Definitions of the offset of the SIM hardware registers */
>> +#define PORT1_CNTL 	0x00	/* 00 */
>> +#define SETUP 		0x04	/* 04 */
>> +#define PORT1_DETECT 	0x08	/* 08 */
>> +#define PORT1_XMT_BUF 	0x0C	/* 0c */
>> +#define PORT1_RCV_BUF 	0x10	/* 10 */
>> +#define PORT0_CNTL 	0x14	/* 14 */
>> +#define CNTL 		0x18	/* 18 */
>> +#define CLK_PRESCALER 	0x1C	/* 1c */
>> +#define RCV_THRESHOLD 	0x20	/* 20 */
>> +#define ENABLE 		0x24	/* 24 */
>> +#define XMT_STATUS 	0x28	/* 28 */
>> +#define RCV_STATUS 	0x2C	/* 2c */
>> +#define INT_MASK 	0x30	/* 30 */
>> +#define PORTO_XMT_BUF 	0x34	/* 34 */
>> +#define PORT0_RCV_BUF 	0x38	/* 38 */
>> +#define PORT0_DETECT 	0x3C	/* 3c */
>> +#define DATA_FORMAT 	0x40	/* 40 */
>> +#define XMT_THRESHOLD 	0x44	/* 44 */
>> +#define GUARD_CNTL 	0x48	/* 48 */
>> +#define OD_CONFIG 	0x4C	/* 4c */
>> +#define RESET_CNTL 	0x50	/* 50 */
>> +#define CHAR_WAIT 	0x54	/* 54 */
>> +#define GPCNT 		0x58	/* 58 */
>> +#define DIVISOR 	0x5C	/* 5c */
>> +#define BWT 		0x60	/* 60 */
>> +#define BGT 		0x64	/* 64 */
>> +#define BWT_H 		0x68	/* 68 */
>> +#define XMT_FIFO_STAT 	0x6C	/* 6c */
>> +#define RCV_FIFO_CNT 	0x70	/* 70 */
>> +#define RCV_FIFO_WPTR 	0x74	/* 74 */
>> +#define RCV_FIFO_RPTR 	0x78	/* 78 */
> so 0x78 means 78, who would have guessed that? Please remove the comments.
>
>> +
>> +/* SIM port[0|1]_cntl register bits */
>> +#define SIM_PORT_CNTL_SFPD   (1<<7)
>> +#define SIM_PORT_CNTL_3VOLT  (1<<6)
>> +#define SIM_PORT_CNTL_SCSP   (1<<5)
>> +#define SIM_PORT_CNTL_SCEN   (1<<4)
>> +#define SIM_PORT_CNTL_SRST   (1<<3)
>> +#define SIM_PORT_CNTL_STEN   (1<<2)
>> +#define SIM_PORT_CNTL_SVEN   (1<<1)
>> +#define SIM_PORT_CNTL_SAPD   (1<<0)
>> +
>> +#define MX25_SIM_SETUP_P1_EN 		(1<<1)		// Port 1 enabled
>> +#define MX25_SIM_SETUP_AMODE_EN (1<<0)		// Alternate port enabled
> Please do not use C99 style comments.
>
>> +
>> +/* SIM od_config register bits */
>> +#define SIM_OD_CONFIG_OD_P1  (1<<1)
>> +#define SIM_OD_CONFIG_OD_P0  (1<<0)
>> +
>> +/* SIM enable register bits */
>> +#define SIM_ENABLE_XMTEN     (1<<1)
>> +#define SIM_ENABLE_RCVEN     (1<<0)
>> +
>> +/* SIM int_mask register bits */
>> +#define SIM_INT_MASK_RFEM    (1<<13)
>> +#define SIM_INT_MASK_BGTM    (1<<12)
>> +#define SIM_INT_MASK_BWTM    (1<<11)
>> +#define SIM_INT_MASK_RTM     (1<<10)
>> +#define SIM_INT_MASK_CWTM    (1<<9)
>> +#define SIM_INT_MASK_GPCM    (1<<8)
>> +#define SIM_INT_MASK_TDTFM   (1<<7)
>> +#define SIM_INT_MASK_TFOM    (1<<6)
>> +#define SIM_INT_MASK_XTM     (1<<5)
>> +#define SIM_INT_MASK_TFEIM   (1<<4)
>> +#define SIM_INT_MASK_ETCIM   (1<<3)
>> +#define SIM_INT_MASK_OIM     (1<<2)
>> +#define SIM_INT_MASK_TCIM    (1<<1)
>> +#define SIM_INT_MASK_RIM     (1<<0)
>> +
>> +/* SIM xmt_status register bits */
>> +#define SIM_XMT_STATUS_GPCNT (1<<8)
>> +#define SIM_XMT_STATUS_TDTF  (1<<7)
>> +#define SIM_XMT_STATUS_TFO   (1<<6)
>> +#define SIM_XMT_STATUS_TC    (1<<5)
>> +#define SIM_XMT_STATUS_ETC   (1<<4)
>> +#define SIM_XMT_STATUS_TFE   (1<<3)
>> +#define SIM_XMT_STATUS_XTE   (1<<0)
>> +
>> +/* SIM rcv_status register bits */
>> +#define SIM_RCV_STATUS_BGT   (1<<11)
>> +#define SIM_RCV_STATUS_BWT   (1<<10)
>> +#define SIM_RCV_STATUS_RTE   (1<<9)
>> +#define SIM_RCV_STATUS_CWT   (1<<8)
>> +#define SIM_RCV_STATUS_CRCOK (1<<7)
>> +#define SIM_RCV_STATUS_LRCOK (1<<6)
>> +#define SIM_RCV_STATUS_RDRF  (1<<5)
>> +#define SIM_RCV_STATUS_RFD   (1<<4)
>> +#define SIM_RCV_STATUS_RFE   (1<<1)
>> +#define SIM_RCV_STATUS_OEF   (1<<0)
>> +
>> +/* SIM cntl register bits */
>> +#define SIM_CNTL_BWTEN       (1<<15)
>> +#define SIM_CNTL_XMT_CRC_LRC (1<<14)
>> +#define SIM_CNTL_CRCEN       (1<<13)
>> +#define SIM_CNTL_LRCEN       (1<<12)
>> +#define SIM_CNTL_CWTEN       (1<<11)
>> +#define SIM_CNTL_SAMPLE12    (1<<4)
>> +#define SIM_CNTL_ONACK       (1<<3)
>> +#define SIM_CNTL_ANACK       (1<<2)
>> +#define SIM_CNTL_ICM         (1<<1)
>> +#define SIM_CNTL_GPCNT_CLK_SEL(x)   ((x&0x03)<<9)
> Please add some spacing here, like this: ((x&  0x3)<<  9)
> See Documentation/CodingStyle for more information.
> Also, there are braces missing around x, it should be:
>
> (((x)&  0x3)<<  9)
>
>> +#define SIM_CNTL_GPCNT_CLK_SEL_MASK     (0x03<<9)
>> +#define SIM_CNTL_BAUD_SEL(x)        ((x&0x07)<<6)
>> +#define SIM_CNTL_BAUD_SEL_MASK          (0x07<<6)
>> +
>> +/* SIM rcv_threshold register bits */
>> +#define SIM_RCV_THRESHOLD_RTH(x)    ((x&0x0f)<<9)
>> +#define SIM_RCV_THRESHOLD_RTH_MASK      (0x0f<<9)
>> +#define SIM_RCV_THRESHOLD_RDT(x)   ((x&0x1ff)<<0)
>> +#define SIM_RCV_THRESHOLD_RDT_MASK     (0x1ff<<0)
>> +
>> +/* SIM xmt_threshold register bits */
>> +#define SIM_XMT_THRESHOLD_XTH(x)    ((x&0x0f)<<4)
>> +#define SIM_XMT_THRESHOLD_XTH_MASK      (0x0f<<4)
>> +#define SIM_XMT_THRESHOLD_TDT(x)    ((x&0x0f)<<0)
>> +#define SIM_XMT_THRESHOLD_TDT_MASK      (0x0f<<0)
>> +
>> +/* SIM guard_cntl register bits */
>> +#define SIM_GUARD_CNTL_RCVR11              (1<<8)
>> +#define SIM_GIARD_CNTL_GETU(x)           (x&0xff)
>> +#define SIM_GIARD_CNTL_GETU_MASK           (0xff)
>> +
>> +/* SIM port[0|]_detect register bits */
>> +#define SIM_PORT_DETECT_SPDS  (1<<3)
>> +#define SIM_PORT_DETECT_SPDP  (1<<2)
>> +#define SIM_PORT_DETECT_SDI   (1<<1)
>> +#define SIM_PORT_DETECT_SDIM  (1<<0)
>> +
>> +/* SIM XMT_FIFO_STAT*/
>> +#define SIM_XMT_FIFO_XMT_CNT_MASK  	(0x0f<<8)
>> +#define SIM_XMT_FIFO_XMT_WPTR_MASK  (0x0f<<4)
>> +#define SIM_XMT_FIFO_XMT_RPTR_MASK  (0x0f<<0)
>> +
>> +/* SIM PORT_RCV_BUF */
>> +#define PORT_RCV_BUF_PE			(1<<8)
>> +#define PORT_RCV_BUF_FE			(1<<9)
>> +#define PORT_RCV_BUF_CWT		(1<<10)
>> +/* SIM RESET_CNTL */
>> +#define SIM_RESET_CNTL_DBUG 			(1<<6)
>> +#define SIM_RESET_CNTL_STOP 			(1<<5)
>> +#define SIM_RESET_CNTL_DOZE 			(1<<4)
>> +#define SIM_RESET_CNTL_KILL_CLOCK (1<<3)
>> +#define SIM_RESET_CNTL_SOFT_RST		(1<<2)
>> +#define SIM_RESET_CNTL_FLUSH_XMT  (1<<1)
>> +#define SIM_RESET_CNTL_FLUSH_RCV  (1<<0)
>> +/* END of REGS definitions */
>> +#endif
>> diff --git a/arch/arm/plat-mxc/sim.c b/arch/arm/plat-mxc/sim.c
>> new file mode 100644
>> index 0000000..7af073c
>> --- /dev/null
>> +++ b/arch/arm/plat-mxc/sim.c
>> @@ -0,0 +1,874 @@
>> +/*
>> + * Copyright 2010-2011 FQ Ingenieria Electronica S.A.
>> + *
>> + *  Adapted and simplify this driver to kernel mainline code style using
>> + *  other drivers from Freescale
>> + *  Jaume Ribot (jaume at fqingenieria.es)
>> + *  Iban Cerro Galvez (iban at fqingenieria.es)
>> + */
>> +
>> +/*
>> + * 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.
>> + */
>> +
>> +/*!
>> + * @file mxc_sim.c
>> + *
>> + * @brief Driver for Freescale IMX SIM interface
>> + *
>> + */
>> +
>> +#include<linux/module.h>
>> +#include<linux/ioport.h>
>> +#include<linux/kernel.h>
>> +#include<linux/delay.h>
>> +
>> +#include<linux/sched.h>
>> +#include<linux/io.h>
>> +#include<linux/interrupt.h>
>> +#include<linux/poll.h>
>> +#include<linux/miscdevice.h>
>> +#include<linux/clk.h>
>> +#include<linux/types.h>
>> +#include<linux/platform_device.h>
>> +#include<linux/slab.h>
>> +
>> +#include<asm/io.h>
>> +#include<mach/hardware.h>
>> +#include<mach/mxc_sim.h>
>> +
>> +#define DRIVER_NAME "mxc_sim"
>> +#define SIM1_DEV_NAME "mxc_sim_0"
>> +#define SIM2_DEV_NAME "mxc_sim_1"
>> +
>> +static struct miscdevice sim_dev;
>> +
>> +#define sim_debug(fmt, ...) \
>> +		printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
> Please do not define your own debug functions. dev_dbg is the weapon of
> choice here.
>
>> +
>> +
>> +/* Function: sim_clear_ports
>> + *
>> + * Description: function to unset reset, Vcc_enable or Clk_enable
>> + *
>> + * Parameters:
>> + * sim_t* sim              pointer to SIM device handler
>> + * uint32_t value					 value to set port
>> + */
>> +static void sim_clear_ports(sim_t *sim, uint32_t value)
>> +{
>> +	uint32_t reg_data;
>> +	void __iomem *addr;
>> +
>> +#if defined(CONFIG_SOC_IMX25)
>> +			if (cpu_is_mx25()) {
>> +				addr = sim->ioaddr + PORT0_CNTL;
>> +			}
> broken indention.
>
>> +#else
>> +	if (sim->sim_number ==0)
>> +		addr = sim->ioaddr + PORT0_CNTL;
>> +	else
>> +		addr = sim->ioaddr + PORT1_CNTL;
>> +#endif
> This #ifdef looks wrong here. The idea is to make the driver independent
> of compile time options. Now with this ifdef, if i.MX25 is enabled, it
> won't be working on any other SoC.
>
>> +
>> +	reg_data = __raw_readl(addr);
>> +	reg_data&= ~value;
>> +	__raw_writel(reg_data, addr);
>> +}
>> +
>> +
>> +/* Function: sim_set_ports
>> + *
>> + * Description: function to set Reset, Vcc enable or Clk_enabble
>> + *
>> + * Parameters:
>> + * sim_t* sim              pointer to SIM device handler
>> + * uint32_t value					 value to set port
>> + */
>> +static void sim_set_ports(sim_t *sim, uint32_t value)
>> +{
>> +	uint32_t reg_data;
>> +	void __iomem *addr;
>> +
>> +#if defined(CONFIG_SOC_IMX25)
>> +	if (cpu_is_mx25()) {
>> +		addr = sim->ioaddr + PORT0_CNTL;
>> +	}
>> +#else
>> +	if (sim->sim_number ==0)
>> +		addr = sim->ioaddr + PORT0_CNTL;
>> +	else
>> +		addr = sim->ioaddr + PORT1_CNTL;
>> +#endif
>> +
>> +	reg_data = __raw_readl(addr);
>> +	reg_data |= value;
>> +	__raw_writel(reg_data, addr);
>> +
>> +}
>> +
>> +
>> +/* Function: sim_power_on
>> + *
>> + * Description: run the power on sequence. Follow sequence explained in
>> RM 39.5
>> + *
>> + * Parameters:
>> + * sim_t* sim              pointer to SIM device handler
>> + */
>> +
>> +static void sim_power_on(sim_t *sim)
>> +{
>> +	uint32_t reg_data;
>> +
>> +	// Power on sequence
> This comment is not very useful.
>
>> +	sim_debug("%s Powering on the sim port.\n", __func__);
>> +
>> +	// Enable Vcc enable port
>> +	sim_set_ports(sim, SIM_PORT_CNTL_SVEN);
>> +	msleep(10);//TODO: adjust this delay
>> +
>> +	// Enable CLK enable Port
>> +	sim_set_ports(sim, SIM_PORT_CNTL_SCEN);
>> +	msleep(10);//TODO: adjust this delay
>> +
>> +	// Configure RCV parameters
>> +	reg_data = SIM_RCV_THRESHOLD_RTH(0) | SIM_RCV_THRESHOLD_RDT(1);
>> +	__raw_writel(reg_data, sim->ioaddr + RCV_THRESHOLD);
>> +	__raw_writel(SIM_RCV_STATUS_RDRF, sim->ioaddr + RCV_STATUS);
>> +
>> +	//Configure int
>> +	reg_data = __raw_readl(sim->ioaddr + INT_MASK);
>> +	reg_data&= ~SIM_INT_MASK_RIM;
>> +	__raw_writel(reg_data, sim->ioaddr + INT_MASK);
>> +
>> +	//Duplicate in function sim_start
>> +	__raw_writel(31, sim->ioaddr + DIVISOR);
>> +	reg_data = __raw_readl(sim->ioaddr + CNTL);
>> +	reg_data |= SIM_CNTL_SAMPLE12;
>> +	__raw_writel(reg_data, sim->ioaddr + CNTL);
>> +
>> +	// Enable RCV
>> +	reg_data = __raw_readl(sim->ioaddr + ENABLE);
>> +	reg_data |= SIM_ENABLE_RCVEN;
>> +	__raw_writel(reg_data, sim->ioaddr + ENABLE);
>> +
>> +	// Enable RST
>> +	sim_set_ports(sim, SIM_PORT_CNTL_SRST);
>> +	msleep(10);//TODO: adjust this delay
>> +
>> +	sim->power = SIM_POWER_ON;
>> +
>> +};
>> +
>> +/* Function: sim_power_off
>> + *
>> + * Description: run the power off sequence
>> + *
>> + * Parameters:
>> + * sim_t* sim              pointer to SIM device handler
>> + */
>> +
>> +static void sim_power_off(sim_t *sim)
>> +{
>> +	uint32_t reg_data;
>> +
>> +	sim_debug("%s entering.\n", __func__);
>> +	/* sim_power_off sequence */
>> +
>> +	//disable clk
>> +	sim_clear_ports(sim, SIM_PORT_CNTL_SCEN);
>> +
>> +	reg_data = __raw_readl(sim->ioaddr + ENABLE);
>> +	reg_data&= ~SIM_ENABLE_RCVEN;
>> +	__raw_writel(reg_data, sim->ioaddr + ENABLE);
>> +
>> +	reg_data = __raw_readl(sim->ioaddr + INT_MASK);
>> +	reg_data |= SIM_INT_MASK_RIM;
>> +	__raw_writel(reg_data, sim->ioaddr + INT_MASK);
>> +
>> +	__raw_writel(0, sim->ioaddr + RCV_THRESHOLD);
>> +
>> +	//Disable RST
>> +	sim_clear_ports(sim, SIM_PORT_CNTL_SRST);
>> +	//Disable Vcc enable port
>> +	sim_clear_ports(sim, SIM_PORT_CNTL_SVEN);
>> +
>> +	sim->power = SIM_POWER_OFF;
>> +};
>> +
>> +/* Function: sim_set_clk_sim
>> + *
>> + * Description: Set CLK SIM frequency
>> + *
>> + * Parameters:
>> + * sim_t* sim              pointer to SIM device handler
>> + */
>> +uint32_t sim_set_clk_sim(sim_t *sim)
>> +{
>> +	uint32_t clk_rate, clk_div = 0;
>> +	// get ipg_clk
>> +	clk_rate = clk_get_rate(sim->clk);
>> +	// calcule divisor
>> +	clk_div = clk_rate / sim->clk_sim;
>> +	if (clk_rate % sim->clk_sim)
>> +		clk_div++;
>> +	//write divisor
>> +	__raw_writel(clk_div, sim->ioaddr + CLK_PRESCALER);
>> +	//calculate real Value
>> +	clk_rate =clk_rate/clk_div;
>> +
>> +	sim_debug("%s prescaler is 0x%x.\n", __func__, clk_div);
>> +	sim_debug("Clk = %d Hz\n", clk_rate);
>> +
>> +	return clk_rate;
>> +}
>> +
>> +/* Function: sim_set_clk_uart_divisor
>> + *
>> + * Description: Set SIM Uart divisor frequency
>> + *
>> + * Parameters:
>> + * sim_t* sim              pointer to SIM device handler
>> + */
>> +int sim_set_clk_uart_divisor(sim_t *sim)
>> +{
>> +	uint32_t reg, divisor;
>> +
>> +	//ajust baud_sel ->  divisor register
> s/ajust/adjust/
>
>> +	reg = __raw_readl(sim->ioaddr + CNTL);
>> +	//ajust sample 12
>> +	if ((sim->uart_div % 12) == 0)
>> +	{
> See Documentaion/CodingStyle for placing braces.
>
>> +		reg |= SIM_CNTL_SAMPLE12;
>> +		divisor=sim->uart_div/12;
>> +	}
>> +	else if ((sim->uart_div % 8) == 0)
>> +	{
>> +		reg&= ~SIM_CNTL_SAMPLE12;
>> +		divisor=sim->uart_div/8;
>> +	}
>> +	else
>> +	{
>> +		sim_debug("%s no valid divisor \n", __func__);
>> +		return -1;
>> +	}
>> +	// put 111 in baud_sel for use Divisor register
>> +	reg |=  SIM_CNTL_BAUD_SEL(7);
>> +	__raw_writel(reg, sim->ioaddr + CNTL);
>> +	//ajust Divisor register
>> +	__raw_writel(divisor, sim->ioaddr + DIVISOR );
>> +	sim_debug("%s divisor is %d.\n", __func__, sim->uart_div);
>> +
>> +	return 0;
>> +}
>> +
>> +
>> +
>> +/* Function: sim_start
>> + *
>> + * Description: ramp up the SIM interface.
>> + *
>> + * Parameters:
>> + * sim_t* sim              pointer to SIM device handler
>> + */
>> +static void sim_start(sim_t *sim)
>> +{
>> +	uint32_t reg_data = 0;
>> +
>> +	sim_debug("%s entering.\n", __func__);
>> +	// Configuring SIM for Operation
>> +	// Adjust XMT thresholds (no NACK and 4 bytes or less to activate TDTF bit
>> +	reg_data = SIM_XMT_THRESHOLD_XTH(0) | SIM_XMT_THRESHOLD_TDT(4);
>> +	__raw_writel(reg_data, sim->ioaddr + XMT_THRESHOLD);
>> +	// Enable SIM port N and alternate port disabled ->  Only applies to MX51
>> +	// Always eanble port 0,
>> +
>> +	// Always enable port 0 ->  Duplicated SIM core
>> +	__raw_writel(0x00, sim->ioaddr + SETUP);
>> +
>> +	// Adjust clock divider in function of platform definitions
>> +	// 66.5 / 5 ->  13.5 ->  14 (4.75MHZ initial frequency)
>> +	sim->clk_sim = sim->plat_data->clk_rate;
>> +	sim_set_clk_sim(sim);
>> +
>> +	// Adjust Control register
>> +	reg_data = __raw_readl(sim->ioaddr + CNTL);
>> +	reg_data |=  SIM_CNTL_ANACK | SIM_CNTL_ICM;
>> +	__raw_writel(reg_data, sim->ioaddr + CNTL);
>> +
>> +	// Adjust BAUD divider
>> +	sim->uart_div=SIM_DEFAULT_BAUD_DIV;
>> +	sim_set_clk_uart_divisor(sim);
>> +
>> +	// Adjust Open Drain in Port 0 XMT configuration register
>> +	reg_data = __raw_readl(sim->ioaddr + OD_CONFIG);
>> +	reg_data |= SIM_OD_CONFIG_OD_P0 | SIM_OD_CONFIG_OD_P1;
>> +	__raw_writel(reg_data, sim->ioaddr + OD_CONFIG);
>> +
>> +	// Adjust Port 0
>> +	reg_data = __raw_readl(sim->ioaddr + PORT0_CNTL);
>> +	reg_data |= SIM_PORT_CNTL_3VOLT | SIM_PORT_CNTL_STEN;
>> +	__raw_writel(reg_data, sim->ioaddr + PORT0_CNTL);
>> +
>> +	// Since there is no PD0 layout on MX51, assume that there is a SIM card
>> in slot defaulty.
>> +	if (0 == (sim->plat_data->detect)) {
>> +		reg_data = __raw_readl(sim->ioaddr + PORT0_DETECT);
>> +		reg_data |= SIM_PORT_DETECT_SPDS;
>> +		__raw_writel(reg_data, sim->ioaddr + PORT0_DETECT);
>> +		sim->present = SIM_PRESENT_DETECTED;
>> +	}
>> +
>> +	// FQ enable SIM present on the future
>> +	if (sim->present == SIM_PRESENT_DETECTED)
>> +		sim_power_on(sim);
>> +
>> +};
>> +
>> +/* Function: sim_stop
>> + *
>> + * Description: shut down the SIM interface
>> + *
>> + * Parameters:
>> + * sim_t* sim              pointer to SIM device handler
>> + */
>> +
>> +static void sim_stop(sim_t *sim)
>> +{
>> +	sim_debug("%s entering.\n", __func__);
>> +	__raw_writel(0, sim->ioaddr + SETUP);
>> +	__raw_writel(0, sim->ioaddr + ENABLE);
>> +	__raw_writel(0, sim->ioaddr + PORT0_CNTL);
>> +	__raw_writel(SIM_CNTL_ANACK | SIM_CNTL_ICM, sim->ioaddr + CNTL);
>> +	__raw_writel(0, sim->ioaddr + CLK_PRESCALER);
>> +	__raw_writel(0, sim->ioaddr + SETUP);
>> +	__raw_writel(0, sim->ioaddr + OD_CONFIG);
>> +	__raw_writel(0, sim->ioaddr + XMT_THRESHOLD);
>> +	//Clear XMT_STATUS
>> +	__raw_writel( SIM_XMT_STATUS_TDTF | SIM_XMT_STATUS_TC   |
>> +								SIM_XMT_STATUS_ETC  |	SIM_XMT_STATUS_TFE   , sim->ioaddr +
>> XMT_STATUS);
>> +	//Enable SOFT_RESET
>> +	__raw_writel(SIM_RESET_CNTL_SOFT_RST , sim->ioaddr + RESET_CNTL);
>> +	mdelay(1);//TODO: adjust this delay
>> +};
>> +
>> +/* Function: sim_data_reset
>> + *
>> + * Description: reset a SIM structure to default values
>> + *
>> + * Parameters:
>> + * sim_t* sim              pointer to SIM device handler
>> + */
>> +
>> +static void sim_data_reset(sim_t *sim)
>> +{
>> +	sim->present = SIM_PRESENT_REMOVED;
>> +	sim->state = SIM_STATE_REMOVED;
>> +	sim->power = SIM_POWER_OFF;
>> +	sim->errval = SIM_OK;
>> +};
>> +
>> +/* Function: sim_cold_reset
>> + *
>> + * Description: cold reset the SIM interface, including card
>> + * power down and interface hardware reset.
>> + *
>> + * Parameters:
>> + * sim_t* sim              pointer to SIM device handler
>> + */
>> +
>> +static void sim_cold_reset(sim_t *sim)
>> +{
>> +	sim_debug("%s entering.\n", __func__);
>> +	if (sim->present != SIM_PRESENT_REMOVED) {
>> +		sim_power_off(sim);
>> +		sim_stop(sim);
>> +		sim_data_reset(sim);
>> +		sim->state = SIM_STATE_DETECTED_ATR_T0;
>> +		sim->present = SIM_PRESENT_DETECTED;
>> +		msleep(50);//TODO: adjust this delay
>> +		sim_start(sim);
>> +		sim_power_on(sim);
>> +	};
>> +};
>> +
>> +/* Function: sim_warm_reset
>> + *
>> + * Description: warm reset the SIM interface: just invoke the
>> + * reset signal and reset the SIM structure for the interface.
>> + *
>> + * Parameters:
>> + * sim_t* sim              pointer to SIM device handler
>> + */
>> +
>> +static void sim_warm_reset(sim_t *sim)
>> +{
>> +	sim_debug("%s entering.\n", __func__);
>> +	if (sim->present != SIM_PRESENT_REMOVED) {
>> +		sim_set_ports(sim,SIM_PORT_CNTL_SRST);
>> +		sim_data_reset(sim);
>> +		msleep(50);//TODO: adjust this delay
>> +		sim_clear_ports(sim,SIM_PORT_CNTL_SRST);
>> +
>> +	};
>> +};
>> +
>> +/* Function: sim_ioctl
>> + *
>> + * Description: handle ioctl calls
>> + *
>> + * Parameters: OS specific
>> + */
>> +
>> +static long sim_ioctl(struct file *file, unsigned int cmd, unsigned long
>> arg)
>> +{
>> +	int ret=0, value=-1;
>> +	unsigned long real_freq;
>> +	unsigned char version = SIM_DRIVER_VERSION;
>> +	sim_t *sim = (sim_t *) file->private_data;
>> +	sim_reg s_reg = {0,0};
>> +
>> +	sim_debug("%s cmd %d \n", __func__, cmd);
>> +	switch (cmd) {
>> +		sim_debug("ioctl cmd %d is issued...\n", cmd);
>> +
>> +		case SIM_IOCTL_VERSION:
>> +			sim_debug("ioctl cmd SIM_IOCTL_VERSION\n");
>> +			ret = copy_to_user((unsigned char *) arg,&version,
>> +						 sizeof(unsigned char));
>> +			break;
>> +
>> +		case SIM_IOCTL_POWER_ON:
>> +			sim_debug("ioctl cmd SIM_IOCTL_POWER_ON\n");
>> +			if (sim->power == SIM_POWER_ON) {
>> +				ret = -SIM_E_POWERED_ON;
>> +				break;
>> +			};
>> +			sim_power_on(sim);
>> +			break;
>> +
>> +		case SIM_IOCTL_POWER_OFF:
>> +			sim_debug("ioctl cmd SIM_IOCTL_POWER_OFF\n");
>> +			if (sim->power == SIM_POWER_OFF) {
>> +				ret = -SIM_E_POWERED_OFF;
>> +				break;
>> +			};
>> +			sim_power_off(sim);
>> +			break;
>> +
>> +		case SIM_IOCTL_COLD_RESET:
>> +			sim_debug("ioctl cmd SIM_IOCTL_COLD_RESET\n");
>> +			if (sim->power == SIM_POWER_OFF) {
>> +				ret = -SIM_E_POWERED_OFF;
>> +				break;
>> +			};
>> +			sim_cold_reset(sim);
>> +			break;
>> +
>> +		case SIM_IOCTL_WARM_RESET:
>> +			sim_debug("ioctl cmd SIM_IOCTL_WARM_RESET\n");
>> +			sim_warm_reset(sim);
>> +			if (sim->power == SIM_POWER_OFF) {
>> +				ret = -SIM_E_POWERED_OFF;
>> +				break;
>> +			};
>> +			break;
>> +
>> +		case SIM_IOCTL_CLK_PORT:
>> +			sim_debug("ioctl cmd SIM_IOCTL_CLK_PORT\n");
>> +			ret = copy_from_user(&value, (int *) arg,
>> +								 sizeof(int));
>> +			if (value == 0)
>> +				sim_set_ports(sim, SIM_PORT_CNTL_SCEN);
>> +			else
>> +				sim_clear_ports(sim, SIM_PORT_CNTL_SCEN);
>> +			break;
>> +
>> +		case SIM_IOCTL_RST_PORT:
>> +			sim_debug("ioctl cmd SIM_IOCTL_RST_PORT\n");
>> +			ret = copy_from_user(&value, (int *) arg,
>> +								 sizeof(int));
>> +			if (value == 0)
>> +				sim_set_ports(sim, SIM_PORT_CNTL_SRST);
>> +			else
>> +				sim_clear_ports(sim, SIM_PORT_CNTL_SRST);
>> +			break;
>> +
>> +		case SIM_IOCTL_VCC_PORT:
>> +			sim_debug("ioctl cmd SIM_IOCTL_VCC_PORT\n");
>> +			ret = copy_from_user(&value, (int *) arg,
>> +								 sizeof(int));
>> +			if (value == 0)
>> +				sim_set_ports(sim, SIM_PORT_CNTL_SVEN);
>> +			else
>> +				sim_clear_ports(sim, SIM_PORT_CNTL_SVEN);
>> +			break;
>> +
>> +		case SIM_IOCTL_SET_CLK_SIM:
>> +			sim_debug("ioctl cmd SIM_IOCTL_SET_CLK_SIM\n");
>> +			ret = copy_from_user(&real_freq, (unsigned long *) arg,
>> +									 sizeof(unsigned long));
>> +			if (sim->clk_sim>  0)
>> +			{
>> +				sim->clk_sim = real_freq;
>> +				real_freq = sim_set_clk_sim(sim);
>> +			}
>> +			else
>> +			{
>> +				sim_debug("Invalid Freq. %lu Hz\n",real_freq );
>> +				real_freq = -1;
>> +			}
>> +			ret = copy_to_user((unsigned long *) arg,&real_freq,
>> +						sizeof(unsigned long));
>> +			break;
>> +
>> +		case SIM_IOCTL_SET_CLK_DIV:
>> +			sim_debug("ioctl cmd SIM_IOCTL_SET_CLK_DIV\n");
>> +			ret = copy_from_user(&value, (int *) arg,
>> +									 sizeof(int));
>> +			if (sim->uart_div>  0)
>> +					{
>> +						sim->uart_div = value;
>> +						ret = sim_set_clk_uart_divisor(sim);
>> +					}
>> +					else
>> +					{
>> +						sim_debug("Invalid DIV. %d\n",value);
>> +					}
>> +			break;
>> +
>> +	/*debug register*/
>> +		case SIM_IOCTL_GET_REG:
>> +			sim_debug("ioctl cmd SIM_IOCTL_GET_REG\n");
>> +			ret = copy_from_user(&s_reg, (sim_reg *) arg, sizeof(sim_reg));
>> +			s_reg.data =(unsigned long) __raw_readl(s_reg.addr);
>> +			ret = copy_to_user((sim_reg *) arg,&s_reg, sizeof(sim_reg));
>> +			break;
>> +
>> +		case SIM_IOCTL_SET_REG:
>> +			sim_debug("ioctl cmd SIM_IOCTL_SET_REG\n");
>> +			ret = copy_from_user(&s_reg, (sim_reg *) arg, sizeof(sim_reg));
>> +			__raw_writel( (uint32_t) s_reg.data,  sim->ioaddr + s_reg.addr);
>> +			break;
>> +	};
>> +
>> +	return ret;
>> +};
>> +
>> +/* Function: sim_write
>> + *
>> + * Description: handle write calls
>> + *
>> + * Parameters: OS specific
>> + */
>> +static ssize_t sim_write(struct file *file, const char *user_buf,
>> +		size_t count, loff_t *ppos)
>> +{
>> +	int ret=0, i;
>> +	uint32_t reg_data=0;
>> +	sim_t *sim = (sim_t *) file->private_data;
>> +	char write_buffer[SIM_XMT_BUFFER_SIZE];
>> +	int timeout;
>> +
>> +	sim_debug("%s entering.\n", __func__);
>> +
>> +		ret = copy_from_user(write_buffer, user_buf,count);
> broken indention.
>
>> +		if (ret)
>> +			return  -EFAULT;
>> +
>> +		//start XMT
>> +		reg_data = __raw_readl(sim->ioaddr + ENABLE);
>> +		reg_data |= SIM_ENABLE_XMTEN;
>> +		__raw_writel(reg_data, sim->ioaddr + ENABLE);
>> +
>> +		for (i=0; i<  count; i++)
>> +		{
>> +			//transmit 1 Byte
>> +			__raw_writel( write_buffer[i],sim->ioaddr + PORT1_XMT_BUF );
>> +			sim_debug( "TX = %02x\n", write_buffer[i] );
>> +
>> +			// wait write 1 Byte TODO: interupts
>> +			timeout= WRITE_TIMEOUT;
>> +			do {
>> +			reg_data = __raw_readl( sim->ioaddr + XMT_FIFO_STAT );
>> +			reg_data = ( reg_data&&  SIM_XMT_FIFO_XMT_CNT_MASK )>>  8;
>> +			sim_debug("wait write, timeout = %d", timeout );
>> +			timeout--;
>> +			}while  ( reg_data>  0&&  timeout != 0 );
> broken indention.
>
>> +		}
>> +
>> +		//disable write
>> +		reg_data = __raw_readl( sim->ioaddr + ENABLE );
>> +		reg_data&= ~SIM_ENABLE_XMTEN;
>> +		__raw_writel( reg_data, sim->ioaddr + ENABLE );
>> +
>> +		return i;
>> +};
>> +
>> +/* Function: sim_read
>> + *
>> + * Description: handle read calls
>> + *
>> + * Parameters: OS specific
>> + */
>> +static ssize_t sim_read(struct file *file, char *user_buf,
>> +		size_t count, loff_t *ppos)
>> +{
>> +	int ret=0;
>> +	char read_buffer[SIM_RCV_BUFFER_SIZE];
>> +	sim_t *sim = (sim_t *) file->private_data;
>> +	int i=0;
>> +	int timeout = READ_TIMEOUT;
>> +
>> +	sim_debug("%s entering.\n", __func__);
>> +
>> +	while (__raw_readl(sim->ioaddr + RCV_FIFO_CNT) != 0&&  i<  count&&
>> timeout>  0 ) {
>> +		uint32_t data;
>> +		data = __raw_readl(sim->ioaddr + PORT1_RCV_BUF);
>> +		sim_debug("RX = %02x\n", data);
>> +		//detect parity ERROR or FRAME ERROR or CWT ERROR
>> +		if ( data&  (PORT_RCV_BUF_PE | PORT_RCV_BUF_FE | PORT_RCV_BUF_CWT ) )
>> +		{
>> +			printk(KERN_ERR "ERROR READ !\n");
>> +			return IRQ_HANDLED;
>> +		}
>> +		else{
>> +			read_buffer[i] = (char) data;
>> +			i++;
>> +		}
>> +		timeout--;
>> +	};
>> +	ret = copy_to_user(user_buf, read_buffer,i);
>> +	if (ret)
>> +		return -EFAULT;
>> +
>> +	return i;
>> +}
>> +
>> +
>> +/* Function: sim_open
>> + *
>> + * Description: ramp up interface when being opened
>> + *
>> + * Parameters: OS specific
>> + */
>> +
>> +static int sim_open(struct inode *inode, struct file *file)
>> +{
>> +	int errval = SIM_OK;
>> +
>> +	sim_t *sim = dev_get_drvdata(sim_dev.parent);
>> +	file->private_data = sim;
>> +
>> +	sim_debug("%s entering.\n", __func__);
>> +	if (!sim->ioaddr) {
>> +		errval = -ENOMEM;
>> +		return errval;
>> +	}
>> +
>> +	if (!(sim->clk_flag)) {
>> +		sim_debug("\n%s enable the clock ret = %d\n", __func__,
>> clk_enable(sim->clk) );
>> +		sim->clk_flag = 1;
>> +	}
>> +
>> +	sim_start(sim);
>> +
>> +	return errval;
>> +};
>> +/* Function: sim_fasync
>> + *
>> + * Description: async handler
>> + *
>> + * Parameters: OS specific
>> + */
>> +
>> +static int sim_fasync(int fd, struct file *file, int mode)
>> +{
>> +	sim_t *sim = (sim_t *) file->private_data;
>> +	pr_debug("%s entering.\n", __func__);
>> +	return fasync_helper(fd, file, mode,&sim->fasync);
>> +}
>> +/* Function: sim_release
>> + *
>> + * Description: shut down interface when being closed
>> + *
>> + * Parameters: OS specific
>> + */
>> +
>> +static int sim_release(struct inode *inode, struct file *file)
>> +{
>> +	uint32_t reg_data;
>> +
>> +	sim_t *sim = (sim_t *) file->private_data;
>> +
>> +	sim_debug("%s entering.\n", __func__);
>> +	if (sim->clk_flag) {
>> +		sim_debug("\n%s disable the clock\n", __func__);
>> +		clk_disable(sim->clk);
>> +		sim->clk_flag = 0;
>> +	}
>> +
>> +	/* disable presense detection */
>> +	reg_data = __raw_readl(sim->ioaddr + PORT0_DETECT);
>> +	__raw_writel(reg_data | SIM_PORT_DETECT_SDIM, sim->ioaddr + PORT0_DETECT);
>> +
>> +	if (sim->present != SIM_PRESENT_REMOVED) {
>> +		sim_power_off(sim);
>> +		if (sim->fasync)
>> +			kill_fasync(&sim->fasync, SIGIO, POLL_IN);
>> +	};
>> +
>> +	sim_stop(sim);
>> +
>> +	sim_fasync(-1, file, 0);
>> +
>> +	sim_debug("exit\n");
>> +	return 0;
>> +};
>> +
>> +static const struct file_operations sim_fops = {
>> +	.owner 	=	THIS_MODULE,
>> +	.read = sim_read,
>> +	.write = sim_write,
>> +	.open = sim_open,
>> +	.unlocked_ioctl = sim_ioctl,
>> +	.fasync = sim_fasync,		// FQ commented
>> +	.release = sim_release
>> +};
>> +
>> +// TODO ->  Dev name must be dynamic or include all SIM ports
>> +/*
>> +static struct miscdevice sim_dev = {
>> +		MISC_DYNAMIC_MINOR,
>> +		NULL,
>> +		&sim_fops,
>> +};
>> +*/
>> +
>> +/*****************************************************************************\
>> + *
>>     *
>> + * Driver init/exit
>>     *
>> + *
>>     *
>> +\*****************************************************************************/
> Trailing whitespaces here.
>
>> +
>> +static int sim_probe(struct platform_device *pdev)
>> +{
>> +	int ret = 0;
>> +	struct mxc_sim_platform_data *sim_plat = pdev->dev.platform_data;
>> +
>> +	sim_t *sim = kzalloc(sizeof(sim_t), GFP_KERNEL);
>> +
>> +	if (sim == 0) {
>> +		ret = -ENOMEM;
>> +		printk(KERN_ERR "Can't get the MEMORY\n");
>> +		return ret;
>> +	};
>> +
>> +	BUG_ON(pdev == NULL);
>> +
>> +	sim->plat_data = sim_plat;
>> +	sim->clk_flag = 0;
>> +	sim->sim_number = sim->plat_data->sim_number;
>> +
>> +	printk(KERN_INFO "Trying initialize port %d...\n", sim->sim_number);
>> +
>> +	sim->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +	if (!sim->res) {
>> +		ret = -ENOMEM;
>> +		printk(KERN_ERR "Can't get the MEMORY\n");
> Use dev_err here. Also it is useful to print the error value here.
>
>> +		goto out;
>> +	}
>> +
>> +	// request the sim clk and sim_serial_clk
>> +	sim_debug("CLK rate:%d\n", sim->plat_data->clk_rate);
>> +	sim->clk = clk_get_sys(sim->plat_data->clock_sim, NULL);
>> +	if (IS_ERR(sim->clk)) {
>> +		ret = PTR_ERR(sim->clk);
>> +		printk(KERN_ERR "Get CLK ERROR !\n");
>> +		goto out;
>> +	}
>> +	sim_debug("sim clock:%lu\n", clk_get_rate(sim->clk));
>> +
>> +	if (!request_mem_region(sim->res->start,
>> +				sim->res->end -
>> +				sim->res->start + 1, pdev->name)) {
>> +		printk(KERN_ERR "request_mem_region failed\n");
>> +		ret = -ENOMEM;
>> +		goto out1;
>> +	}
>> +
>> +	sim->ioaddr = (void *)ioremap(sim->res->start, sim->res->end -
>> +				      sim->res->start + 1);
> ioremap can fail.
>
>> +
>> +	platform_set_drvdata(pdev, sim);
>> +	sim_dev.minor = MISC_DYNAMIC_MINOR;
>> +	if 				(sim->sim_number == 0)
>> +		sim_dev.name = SIM1_DEV_NAME;
>> +	else if 	(sim->sim_number == 1)
>> +		sim_dev.name = SIM2_DEV_NAME;
>> +	sim_dev.fops =&sim_fops,
>> +	sim_dev.parent =&(pdev->dev);
>> +
>> +	misc_register(&sim_dev);
> I suppose this function can fail?
>
>> +
>> +	return ret;
>> +
>> +out1:
>> +	clk_put(sim->clk);
>> +out:
>> +	kfree(sim);
>> +	return ret;
>> +}
>> +
>> +static int sim_remove(struct platform_device *pdev)
>> +{
>> +	sim_t *sim = platform_get_drvdata(pdev);
>> +
>> +	clk_put(sim->clk);
>> +
>> +	if (sim->ipb_irq)
>> +		free_irq(sim->ipb_irq, sim);
>> +	if (sim->dat_irq)
>> +		free_irq(sim->dat_irq, sim);
> I see no request_irq anywhere in this patch.
>
>> +
>> +	iounmap(sim->ioaddr);
>> +
>> +	kfree(sim);
>> +	release_mem_region(sim->res->start,
>> +			   sim->res->end - sim->res->start + 1);
>> +
>> +
>> +	misc_deregister(&sim_dev);
>> +	return 0;
>> +}
>> +
>> +static struct platform_driver sim_driver = {
>> +	.driver = {
>> +		   .name = DRIVER_NAME,
>> +		   .owner	= THIS_MODULE,
>> +		   },
>> +	.probe = sim_probe,
>> +	.remove = sim_remove,
>> +	.suspend = NULL,
>> +	.resume = NULL,
>> +};
>> +
>> +static int __init sim_drv_init(void)
>> +{
>> +	printk(KERN_INFO "IMX : SIM driver\n");
>> +
>> +	return platform_driver_register(&sim_driver);
>> +}
>> +
>> +static void __exit sim_drv_exit(void)
>> +{
>> +	platform_driver_unregister(&sim_driver);
>> +}
>> +
>> +module_init(sim_drv_init);
>> +module_exit(sim_drv_exit);
>> +
>> +MODULE_AUTHOR("FQ Ingenieria Electronica S.A.");
>> +MODULE_DESCRIPTION("MXC SIM Driver");
>> +MODULE_LICENSE("GPL");
>> -- 
>> 1.5.4.3
>>
>>
>>

^ permalink raw reply

* [patch 1/5] ehci-mxc: Enable vbus later
From: Sascha Hauer @ 2011-01-03 14:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20101220155810.708379512@rtp-net.org>

On Mon, Dec 20, 2010 at 04:48:54PM +0100, Arnaud Patard wrote:
> vbus should be enabled after usb_add_hcd() otherwise USB is not working
> on my efikamx.

I have tested this on different i.MX27/31/35 based boards, the USB is
still functional, so

Tested-by: Sascha Hauer <s.hauer@pengutronix.de>

> 
> Signed-off-by: Arnaud Patard <arnaud.patard@rtp-net.org>
> Index: tst-usb/drivers/usb/host/ehci-mxc.c
> ===================================================================
> --- tst-usb.orig/drivers/usb/host/ehci-mxc.c	2010-12-20 15:38:41.000000000 +0100
> +++ tst-usb/drivers/usb/host/ehci-mxc.c	2010-12-20 15:38:43.000000000 +0100
> @@ -210,11 +210,6 @@
>  			ret = -ENODEV;
>  			goto err_add;
>  		}
> -		ret = otg_set_vbus(pdata->otg, 1);
> -		if (ret) {
> -			dev_err(dev, "unable to enable vbus on transceiver\n");
> -			goto err_add;
> -		}
>  	}
>  
>  	priv->hcd = hcd;
> @@ -224,6 +219,14 @@
>  	if (ret)
>  		goto err_add;
>  
> +	if (pdata->otg) {
> +		ret = otg_set_vbus(pdata->otg, 1);
> +		if (ret) {
> +			dev_err(dev, "unable to enable vbus on transceiver\n");
> +			goto err_add;
> +		}
> +	}
> +
>  	return 0;
>  
>  err_add:
> 
> 
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply

* zaurus bluetooth regression
From: Pavel Machek @ 2011-01-03 14:17 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <AANLkTika7HAEc+BbqSnbo8viUt4nOqoeB69qWZs85-9s@mail.gmail.com>

Hi!

> >> It seems this commit
> >>
> >> commit 7a56aa45982bb87bfca98a2832b5ae782c03364a
> > ...
> >> ...is responsible for my bluetooth problems on zaurus -- at least
> >> bisect pointed to it, ?as I use 16C950-based bluetooth card, it seems
> >> very logical. I'll try 2.6.37-rc8 with that patch reverted...
> >>
> >
> > And yes, 37-rc8 with that reverted results in working bluetooth, so
> > yrs, that patch is responsible.
> 
> could you tell, what kind of problem you're encountering and if you
> could tell, which flag UART_CAP_EFR or UART_CAP_SLEEP causes the
> problem?

Bluetooth will not work with 'tx command timeout', details should be
in bugzilla.

CAP_EFR seems to cause the problem.
								Pavel

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox