Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] arm/tegra: Harmony: Configure PMC for low-level interrupts
From: Olof Johansson @ 2011-10-12 22:51 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1316643040-7998-1-git-send-email-swarren@nvidia.com>

On Wed, Sep 21, 2011 at 04:10:40PM -0600, Stephen Warren wrote:
> Without this, the PMC continually detects an interrupt when the PMU_IRQ
> line is high, causing the tps6686x IRQ handler thread to hog an entire
> CPU.
> 
> This change was originally written by Wei Ni <wni@nvidia.com> for Seaboard
> in the ChromeOS kernel.
> 
> Long-term, this should probably be moved into some kind of PMU driver,
> or perhaps integrated into the GPIO/IRQ/pinmux system?
> 
> Signed-off-by: Stephen Warren <swarren@nvidia.com>

Thanks, applied to for-3.2/features.


-Olof

^ permalink raw reply

* [PATCH v4 3/4] gpio/tegra: Convert to a platform device
From: Grant Likely @ 2011-10-12 23:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20111012224131.GD25128@quad.lixom.net>

On Wed, Oct 12, 2011 at 4:41 PM, Olof Johansson <olof@lixom.net> wrote:
> On Tue, Oct 11, 2011 at 04:16:14PM -0600, Stephen Warren wrote:
>> v3: Make regs variable static. Remove empty init of tegra_gpio_banks.
>>
>> v2: Retrieve IRQ and memory addresses from resources instead of hard-
>> coding them. Add back initialization of tegra_gpio_chip.of_node.
>
> In the future, please move the revision log to below the ---, and just have
> the main patch description above, since that is what goes into the git repo.

No!  Keep it above the line so it shows up in the Linux commit log.
It makes it easier to know which version of a patch actually got
committed.  :-)

>> Signed-off-by: Stephen Warren <swarren@nvidia.com>
>
> Otherwise, patch looks good. Due to dependencies between this, the rest
> of this patch series and the pinmux changes, I'll hold off on it until
> the dependencies land (i.e. target it for 3.3). We're cutting it very close
> to the merge window as it is, I'll start for-3.3 branches shortly.

Actually, see if you can get it in via the same tree as the pinmux
changes.  Dependencies is not a reason to hold off from getting it
into linux-next.

g.

^ permalink raw reply

* [PATCH v4 3/4] gpio/tegra: Convert to a platform device
From: Grant Likely @ 2011-10-12 23:08 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1318371375-4083-3-git-send-email-swarren@nvidia.com>

On Tue, Oct 11, 2011 at 4:16 PM, Stephen Warren <swarren@nvidia.com> wrote:
> v3: Make regs variable static. Remove empty init of tegra_gpio_banks.
>
> v2: Retrieve IRQ and memory addresses from resources instead of hard-
> coding them. Add back initialization of tegra_gpio_chip.of_node.
>
> Signed-off-by: Stephen Warren <swarren@nvidia.com>

Acked-by: Grant Likely <grant.likely@secretlab.ca>

One comment below however.

> @@ -333,28 +335,55 @@ static struct irq_chip tegra_gpio_irq_chip = {
> ?*/
> ?static struct lock_class_key gpio_lock_class;
>
> -static int __init tegra_gpio_init(void)
> +static int __init tegra_gpio_probe(struct platform_device *pdev)

__devinit because this is put in the .probe hook of the driver.

g.

^ permalink raw reply

* [PATCH v4 3/4] gpio/tegra: Convert to a platform device
From: Olof Johansson @ 2011-10-12 23:19 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CACxGe6tf0Ly8AC-6xUeoMrVj3y0KHkrcgj87SerAaCAnNhfNqA@mail.gmail.com>

On Wed, Oct 12, 2011 at 05:03:24PM -0600, Grant Likely wrote:
> On Wed, Oct 12, 2011 at 4:41 PM, Olof Johansson <olof@lixom.net> wrote:
> > On Tue, Oct 11, 2011 at 04:16:14PM -0600, Stephen Warren wrote:
> >> v3: Make regs variable static. Remove empty init of tegra_gpio_banks.
> >>
> >> v2: Retrieve IRQ and memory addresses from resources instead of hard-
> >> coding them. Add back initialization of tegra_gpio_chip.of_node.
> >
> > In the future, please move the revision log to below the ---, and just have
> > the main patch description above, since that is what goes into the git repo.
> 
> No!  Keep it above the line so it shows up in the Linux commit log.
> It makes it easier to know which version of a patch actually got
> committed.  :-)

Alright, I'm convinced.

Maybe it was the fact that the patch description was 100% revision log that
made me notice it this time. :)

> >> Signed-off-by: Stephen Warren <swarren@nvidia.com>
> >
> > Otherwise, patch looks good. Due to dependencies between this, the rest
> > of this patch series and the pinmux changes, I'll hold off on it until
> > the dependencies land (i.e. target it for 3.3). We're cutting it very close
> > to the merge window as it is, I'll start for-3.3 branches shortly.
> 
> Actually, see if you can get it in via the same tree as the pinmux
> changes.  Dependencies is not a reason to hold off from getting it
> into linux-next.

Ok, the fixup is minimal, should be trivial to spot at git merge time.

Stephen, do you want to respin yourself or should I do the __devinit
change when I apply?


-Olof

^ permalink raw reply

* [GIT PULL] Please pull tegra cleanups for 3.2
From: Olof Johansson @ 2011-10-12 23:34 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Arnd,

Please pull the below branch of cleanups for the 3.2 merge window.
They have been included in linux-next for a couple of days already.

Thanks!


-Olof

The following changes since commit 976d167615b64e14bc1491ca51d424e2ba9a5e84:

  Linux 3.1-rc9 (2011-10-04 18:11:50 -0700)

are available in the git repository at:
  git://git.kernel.org/pub/scm/linux/kernel/git/olof/tegra.git for-3.2/cleanup

Olof Johansson (14):
      ARM: tegra: annotate IO_*_VIRT pointers
      ARM: tegra: timer: don't cast __iomem pointers
      ARM: tegra: tegra2_clocks: don't cast __iomem pointers
      ARM: tegra: tegra2_clocks: 0 -> NULL changes
      ARM: tegra: pcie: don't cast __iomem pointers
      ARM: tegra: pcie: include board.h
      ARM: tegra: pcie: 0 -> NULL changes
      ARM: tegra: tegra_init_cache should be static
      ARM: tegra: tegra_rtc_read_ms should be static
      ARM: tegra: tegra_powergate_is_powered should be static
      ARM: tegra: tegra2_clocks: don't export some tables
      ARM: tegra: dma: staticify some tables and functions
      ARM: tegra: cpu-tegra: sparse type fix
      ARM: tegra: cpu-tegra: unexport two functions

 arch/arm/mach-tegra/common.c                 |    2 +-
 arch/arm/mach-tegra/cpu-tegra.c              |    6 ++--
 arch/arm/mach-tegra/dma.c                    |   14 +++++---
 arch/arm/mach-tegra/include/mach/io.h        |   18 ++++++---
 arch/arm/mach-tegra/include/mach/powergate.h |    1 -
 arch/arm/mach-tegra/io.c                     |    8 ++--
 arch/arm/mach-tegra/pcie.c                   |    8 +++--
 arch/arm/mach-tegra/powergate.c              |    5 +--
 arch/arm/mach-tegra/tegra2_clocks.c          |   50 +++++++++++++-------------
 arch/arm/mach-tegra/timer.c                  |    6 ++--
 10 files changed, 64 insertions(+), 54 deletions(-)

^ permalink raw reply

* [PATCH v6 14/16] OMAP2+: UART: Take console_lock in suspend path if not taken
From: Kevin Hilman @ 2011-10-12 23:47 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAAL8m4zrveqqS3vq=dqMkS2gT24_=1UO+ukbxnQVf+AX4TBaVQ@mail.gmail.com>

Govindraj <govindraj.ti@gmail.com> writes:

> On Wed, Oct 12, 2011 at 12:31 AM, Kevin Hilman <khilman@ti.com> wrote:
>> "Govindraj.R" <govindraj.raja@ti.com> writes:
>>
>>> In suspend path the console_lock is taken by uart_port_suspend
>>> however when no_console_suspend is used console_lock is not taken.
>>>
>>> During system wide suspend omap_pwr_domain hooks cut all
>>> clocks that are left enabled. So its unsafe to proceed printing after
>>> clocks are cut by pwr_domain hooks.
>>
>> As I've mentioned in previous reviews, when no_console_suspend is
>> enabled, the user has explicitly requested console output during
>> suspend. ?In order to support that, we should not be cutting clocks at
>> all in that mode.
>>
>> One way to address this would be to just disable runtime PM in the
>> ->prepare method of the driver if no_console_suspend is enabled.
>>
>
> Okay fine exploring this option, right API's would be to use
> pm_runtime_forbid/allow.

Yes.

> <<SNIP>>
>
> +static int serial_omap_runtime_prepare(struct device *dev)
> +{
> +       if (!console_suspend_enabled)
> +               pm_runtime_forbid(dev);
> +
> +       return 0;
> +}
> +
> +static void serial_omap_runtime_complete(struct device *dev)
> +{
> +       if (!console_suspend_enabled)
> +               pm_runtime_allow(dev);
> +}
> +
>  static const struct dev_pm_ops serial_omap_dev_pm_ops = {
>         SET_SYSTEM_SLEEP_PM_OPS(serial_omap_suspend, serial_omap_resume)
>         SET_RUNTIME_PM_OPS(serial_omap_runtime_suspend,
>                                 serial_omap_runtime_resume, NULL)
> +       .prepare = serial_omap_runtime_prepare,
> +       .complete =  serial_omap_runtime_complete,
>  };

OK, but please add comments to these functions about exactly why they
are needed.

>
> But to either use runtime forbid or disable we have ensure that
> power_domain hooks don't go ahead and disable
> the clocks with omap_device_idle as *runtime forbid or disable will
> not set runtime_status to RPM_SUSPENDED*
> and will stay in RPM_ACTIVE if we call runtime disable or forbid from
> active state.

Correct.

> in power_domain hooks we just check the pm_runtime_status_suspended
> this will be false even if
> we do runtime disable/forbid and it will cut uart clocks always.
>
> So we may need below check also:
>
> diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c
> index 26aee5c..286a534 100644
> --- a/arch/arm/plat-omap/omap_device.c
> +++ b/arch/arm/plat-omap/omap_device.c
> @@ -592,7 +592,8 @@ static int _od_suspend_noirq(struct device *dev)
>
>         ret = pm_generic_suspend_noirq(dev);
>
> -       if (!ret && !pm_runtime_status_suspended(dev)) {
> +       if (!ret && pm_runtime_enabled(dev) &&
> +                       !pm_runtime_status_suspended(dev)) {
>                 if (pm_generic_runtime_suspend(dev) == 0) {
>                         omap_device_idle(pdev);
>                         od->flags |= OMAP_DEVICE_SUSPENDED;

This isn't right either because devices that may not yet be initialized
(or loaded) may not have runtime PM enabled, so those devices may not
be properly idled.

We have an omap_device API to disable this feature at the PM domain level:
omap_device_disable_idle_on_suspend().  All you should have to do is to
use this API in the device init code on the console UART if
no_console_suspend has been enabled.

Kevin

^ permalink raw reply

* [PATCH v6 15/16] OMAP2+: UART: Enable back uart clocks with runtime API for early console
From: Kevin Hilman @ 2011-10-13  0:00 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAAL8m4xmGQaQZm5Oz8B5e6Mt7VP7c_VwQ=AnfpKotZRci32JiQ@mail.gmail.com>

Govindraj <govindraj.ti@gmail.com> writes:

> On Wed, Oct 12, 2011 at 2:36 AM, Kevin Hilman <khilman@ti.com> wrote:
>> "Govindraj.R" <govindraj.raja@ti.com> writes:
>>
>>> For the early console probing we had avoided hwmod reset and idling
>>> and uart was idled using hwmod API and enabled back using omap_device API
>>> after omap_device registration.
>>>
>>> Now since we are using runtime API's to enable back uart, move hwmod
>>> idling and use runtime API to enable back UART.
>>>
>>> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
>>
>> Now that the driver is using runtime PM. ?Why do we still need
>> HWMOD_INIT_NO_IDLE and HWMOD_INIT_NO_RESET?
>>
>> The comment in the code says:
>>
>> ? ? ? ? ? ? ? ?/*
>> ? ? ? ? ? ? ? ? * During UART early init, device need to be probed
>> ? ? ? ? ? ? ? ? * to determine SoC specific init before omap_device
>> ? ? ? ? ? ? ? ? * is ready. ?Therefore, don't allow idle here
>> ? ? ? ? ? ? ? ? */
>>
>> This was true when using the 8250 driver because it was not using
>> runtime PM so could not know how to (re)enable the device.
>>
>> However, since the driver is now runtime PM adapted, any device access
>> should be contained within a runtime PM get/put block, so there should
>> no longer be a reason not allow the IP blocks to be reset during boot.
>>
>
> Forgot to add, this is still needed for
> earlyprintk(CONFIG_EARLY_PRINTK) use case,

Ah, right.  I forgot about that.  Please update the changelog (and
comment in the code) to reflect that.

> The initial boot prints until a console driver is available is from
> "arch/arm/kernel/early_printk.c" which does a tx on uart console
> and relies on configuration from bootloader.
>
> during bootup earlyprink does a tx on uart console and if  uart driver
> is not available yet
> uart reset or idle done by hwmod layer can cause boot failures.
>
> --> put_char from earlyprintk.c
>      --> reset/idle from hwmod layer
>           --> put_char from earlyprintk.c
>
>
> So console_uart reset or clock gating must be done only after uart
> driver is available or be prevented using these available hwmod_flags.

So why not leave the driver out of it and solve it like the current code
does?

The current codes use the hwmod flags, then waits until the UART driver
is available (after omap_device_build) and uses omap_hwmod_idle() to do
an clean idle of the device. 

Notably this is inside a console_lock/console_unlock block so that
prints are buffered.

The current code then does an omap_device_enable() to re-enable the
device, but you shouldn't need that after the driver is converted to
runtime PM.

Kevin

^ permalink raw reply

* [PATCH v6 09/16] OMAP2+: UART: Add runtime pm support for omap-serial driver
From: Kevin Hilman @ 2011-10-13  0:06 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1317380495-584-9-git-send-email-govindraj.raja@ti.com>

"Govindraj.R" <govindraj.raja@ti.com> writes:

[...] 

> Use device_may_wakeup to check whether uart has wakeup capabilities
> and then enable uart runtime usage for the uart.

Curious about what happens when device_may_wakeup() is not set during
device init.

[...]

> @@ -1305,6 +1363,16 @@ static int serial_omap_probe(struct platform_device *pdev)
>  		up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE;
>  	}
>  
> +	pm_runtime_use_autosuspend(&pdev->dev);
> +	pm_runtime_set_autosuspend_delay(&pdev->dev,
> +			OMAP_UART_AUTOSUSPEND_DELAY);
> +
> +	pm_runtime_irq_safe(&pdev->dev);
> +	if (device_may_wakeup(&pdev->dev)) {
> +		pm_runtime_enable(&pdev->dev);

So if device_may_wakeup() is false, runtime PM is not enabled, then...

> +		pm_runtime_get_sync(&pdev->dev);

...this get doesn't happen, and the first register access causes a crash.

So either this get isn't needed, because there is no device access in
this path, or this path is broken and needs validation.

> +	}
> +
>  	ui[pdev->id] = up;
>  	serial_omap_add_console_port(up);
>  
> @@ -1312,6 +1380,7 @@ static int serial_omap_probe(struct platform_device *pdev)
>  	if (ret != 0)
>  		goto do_release_region;
>  
> +	pm_runtime_put(&pdev->dev);

...also, this put is not balanced with a corresponding get.

Kevin

^ permalink raw reply

* [Linaro-mm-sig] [PATCH 1/2] ARM: initial proof-of-concept IOMMU mapper for DMA-mapping
From: Krishna Reddy @ 2011-10-13  0:18 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <401E54CE964CD94BAE1EB4A729C7087E3722519C65@HQMAIL04.nvidia.com>

Here a patch v2 that has updates/fixes to DMA IOMMU code. With these changes, the nvidia device is able to boot with all its platform drivers as DMA IOMMU clients.

Here is the overview of changes.

1. Converted the mutex to spinlock to handle atomic context calls and used spinlock in necessary places.
2. Implemented arm_iommu_map_page and arm_iommu_unmap_page, which are used by MMC host stack.
3. Separated creation of dma_iommu_mapping from arm_iommu_attach_device in order to share mapping.
4. Fixed various bugs identified in DMA IOMMU code during testing.




[PATCH] ARM: dma-mapping: Add iommu map_page/unmap_page and fix issues.

Signed-off-by: Krishna Reddy <vdumpa@nvidia.com>
---
 arch/arm/include/asm/dma-iommu.h |   14 ++-
 arch/arm/mm/dma-mapping.c        |  229 +++++++++++++++++++++++++-------------
 2 files changed, 161 insertions(+), 82 deletions(-)

diff --git a/arch/arm/include/asm/dma-iommu.h b/arch/arm/include/asm/dma-iommu.h
index 0b2677e..5f4e37f 100644
--- a/arch/arm/include/asm/dma-iommu.h
+++ b/arch/arm/include/asm/dma-iommu.h
@@ -7,6 +7,8 @@
 #include <linux/scatterlist.h>
 #include <linux/dma-debug.h>
 #include <linux/kmemcheck.h>
+#include <linux/spinlock_types.h>
+#include <linux/kref.h>

 #include <asm/memory.h>

@@ -19,11 +21,17 @@ struct dma_iommu_mapping {
        unsigned int            order;
        dma_addr_t              base;

-       struct mutex            lock;
+       spinlock_t              lock;
+       struct kref             kref;
 };

-int arm_iommu_attach_device(struct device *dev, dma_addr_t base,
-                           dma_addr_t size, int order);
+struct dma_iommu_mapping *arm_iommu_create_mapping(dma_addr_t base,
+                                                   size_t size, int order);
+
+void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping);
+
+int arm_iommu_attach_device(struct device *dev,
+                           struct dma_iommu_mapping *mapping);

 #endif /* __KERNEL__ */
 #endif
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 020bde1..721b7c0 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -739,32 +739,42 @@ fs_initcall(dma_debug_do_init);

 /* IOMMU */

-static inline dma_addr_t __alloc_iova(struct dma_iommu_mapping *mapping, size_t size)
+static inline dma_addr_t __alloc_iova(struct dma_iommu_mapping *mapping,
+                                       size_t size)
 {
-       unsigned int order = get_order(size);
        unsigned int align = 0;
        unsigned int count, start;
+       unsigned long flags;

-       if (order > mapping->order)
-               align = (1 << (order - mapping->order)) - 1;
+       count = ((PAGE_ALIGN(size) >> PAGE_SHIFT) +
+                (1 << mapping->order) - 1) >> mapping->order;

-       count = ((size >> PAGE_SHIFT) + (1 << mapping->order) - 1) >> mapping->order;
-
-       start = bitmap_find_next_zero_area(mapping->bitmap, mapping->bits, 0, count, align);
-       if (start > mapping->bits)
+       spin_lock_irqsave(&mapping->lock, flags);
+       start = bitmap_find_next_zero_area(mapping->bitmap, mapping->bits,
+                                           0, count, align);
+       if (start > mapping->bits) {
+               spin_unlock_irqrestore(&mapping->lock, flags);
                return ~0;
+       }

        bitmap_set(mapping->bitmap, start, count);
+       spin_unlock_irqrestore(&mapping->lock, flags);

        return mapping->base + (start << (mapping->order + PAGE_SHIFT));
 }

-static inline void __free_iova(struct dma_iommu_mapping *mapping, dma_addr_t addr, size_t size)
+static inline void __free_iova(struct dma_iommu_mapping *mapping,
+                               dma_addr_t addr, size_t size)
 {
-       unsigned int start = (addr - mapping->base) >> (mapping->order + PAGE_SHIFT);
-       unsigned int count = ((size >> PAGE_SHIFT) + (1 << mapping->order) - 1) >> mapping->order;
+       unsigned int start = (addr - mapping->base) >>
+                            (mapping->order + PAGE_SHIFT);
+       unsigned int count = ((PAGE_ALIGN(size) >> PAGE_SHIFT) +
+                             (1 << mapping->order) - 1) >> mapping->order;
+       unsigned long flags;

+       spin_lock_irqsave(&mapping->lock, flags);
        bitmap_clear(mapping->bitmap, start, count);
+       spin_unlock_irqrestore(&mapping->lock, flags);
 }

 static struct page **__iommu_alloc_buffer(struct device *dev, size_t size, gfp_t gfp)
@@ -867,7 +877,7 @@ __iommu_alloc_remap(struct page **pages, size_t size, gfp_t gfp, pgprot_t prot)
 static dma_addr_t __iommu_create_mapping(struct device *dev, struct page **pages, size_t size)
 {
        struct dma_iommu_mapping *mapping = dev->archdata.mapping;
-       unsigned int count = size >> PAGE_SHIFT;
+       unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
        dma_addr_t dma_addr, iova;
        int i, ret = ~0;

@@ -892,13 +902,12 @@ fail:
 static int __iommu_remove_mapping(struct device *dev, dma_addr_t iova, size_t size)
 {
        struct dma_iommu_mapping *mapping = dev->archdata.mapping;
-       unsigned int count = size >> PAGE_SHIFT;
+       unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
        int i;

-       for (i=0; i<count; i++) {
-               iommu_unmap(mapping->domain, iova, 0);
-               iova += PAGE_SIZE;
-       }
+       iova = iova & PAGE_MASK;
+       for (i = 0; i < count; i++)
+               iommu_unmap(mapping->domain, iova + (i << PAGE_SHIFT), 0);
        __free_iova(mapping, iova, size);
        return 0;
 }
@@ -906,7 +915,6 @@ static int __iommu_remove_mapping(struct device *dev, dma_addr_t iova, size_t si
 static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
            dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs)
 {
-       struct dma_iommu_mapping *mapping = dev->archdata.mapping;
        pgprot_t prot = __get_dma_pgprot(attrs, pgprot_kernel);
        struct page **pages;
        void *addr = NULL;
@@ -914,11 +922,9 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
        *handle = ~0;
        size = PAGE_ALIGN(size);

-       mutex_lock(&mapping->lock);
-
        pages = __iommu_alloc_buffer(dev, size, gfp);
        if (!pages)
-               goto err_unlock;
+               goto exit;

        *handle = __iommu_create_mapping(dev, pages, size);
        if (*handle == ~0)
@@ -928,15 +934,13 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
        if (!addr)
                goto err_mapping;

-       mutex_unlock(&mapping->lock);
        return addr;

 err_mapping:
        __iommu_remove_mapping(dev, *handle, size);
 err_buffer:
        __iommu_free_buffer(dev, pages, size);
-err_unlock:
-       mutex_unlock(&mapping->lock);
+exit:
        return NULL;
 }

@@ -944,11 +948,9 @@ static int arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
                    void *cpu_addr, dma_addr_t dma_addr, size_t size,
                    struct dma_attrs *attrs)
 {
-       unsigned long user_size;
        struct arm_vmregion *c;

        vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot);
-       user_size = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;

        c = arm_vmregion_find(&consistent_head, (unsigned long)cpu_addr);
        if (c) {
@@ -981,11 +983,9 @@ static int arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
 void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
                          dma_addr_t handle, struct dma_attrs *attrs)
 {
-       struct dma_iommu_mapping *mapping = dev->archdata.mapping;
        struct arm_vmregion *c;
        size = PAGE_ALIGN(size);

-       mutex_lock(&mapping->lock);
        c = arm_vmregion_find(&consistent_head, (unsigned long)cpu_addr);
        if (c) {
                struct page **pages = c->priv;
@@ -993,7 +993,6 @@ void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
                __iommu_remove_mapping(dev, handle, size);
                __iommu_free_buffer(dev, pages, size);
        }
-       mutex_unlock(&mapping->lock);
 }

 static int __map_sg_chunk(struct device *dev, struct scatterlist *sg,
@@ -1001,80 +1000,118 @@ static int __map_sg_chunk(struct device *dev, struct scatterlist *sg,
                          enum dma_data_direction dir)
 {
        struct dma_iommu_mapping *mapping = dev->archdata.mapping;
-       dma_addr_t dma_addr, iova;
+       dma_addr_t iova;
        int ret = 0;
+       unsigned int count, i;
+       struct scatterlist *s;

+       size = PAGE_ALIGN(size);
        *handle = ~0;
-       mutex_lock(&mapping->lock);

-       iova = dma_addr = __alloc_iova(mapping, size);
-       if (dma_addr == 0)
-               goto fail;
+       iova = __alloc_iova(mapping, size);
+       if (iova == 0)
+               return -ENOMEM;

-       while (size) {
-               unsigned int phys = page_to_phys(sg_page(sg));
-               unsigned int len = sg->offset + sg->length;
+       for (count = 0, s = sg; count < (size >> PAGE_SHIFT); s = sg_next(s)) {
+               phys_addr_t phys = page_to_phys(sg_page(s));
+               unsigned int len = PAGE_ALIGN(s->offset + s->length);

                if (!arch_is_coherent())
-                       __dma_page_cpu_to_dev(sg_page(sg), sg->offset, sg->length, dir);
+                       __dma_page_cpu_to_dev(sg_page(s), s->offset,
+                                               s->length, dir);

-               while (len) {
-                       ret = iommu_map(mapping->domain, iova, phys, 0, 0);
+               for (i = 0; i < (len >> PAGE_SHIFT); i++) {
+                       ret = iommu_map(mapping->domain,
+                               iova + (count << PAGE_SHIFT),
+                               phys + (i << PAGE_SHIFT), 0, 0);
                        if (ret < 0)
                                goto fail;
-                       iova += PAGE_SIZE;
-                       len -= PAGE_SIZE;
-                       size -= PAGE_SIZE;
+                       count++;
                }
-               sg = sg_next(sg);
        }
-
-       *handle = dma_addr;
-       mutex_unlock(&mapping->lock);
+       *handle = iova;

        return 0;
 fail:
+       while (count--)
+               iommu_unmap(mapping->domain, iova + count * PAGE_SIZE, 0);
        __iommu_remove_mapping(dev, iova, size);
-       mutex_unlock(&mapping->lock);
        return ret;
 }

+static dma_addr_t arm_iommu_map_page(struct device *dev, struct page *page,
+            unsigned long offset, size_t size, enum dma_data_direction dir,
+            struct dma_attrs *attrs)
+{
+       dma_addr_t dma_addr;
+
+       if (!arch_is_coherent())
+               __dma_page_cpu_to_dev(page, offset, size, dir);
+
+       BUG_ON((offset+size) > PAGE_SIZE);
+       dma_addr = __iommu_create_mapping(dev, &page, PAGE_SIZE);
+       return dma_addr + offset;
+}
+
+static void arm_iommu_unmap_page(struct device *dev, dma_addr_t handle,
+               size_t size, enum dma_data_direction dir,
+               struct dma_attrs *attrs)
+{
+       struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+       phys_addr_t phys;
+
+       phys = iommu_iova_to_phys(mapping->domain, handle);
+       __iommu_remove_mapping(dev, handle, size);
+       if (!arch_is_coherent())
+               __dma_page_dev_to_cpu(pfn_to_page(__phys_to_pfn(phys)),
+                                     phys & ~PAGE_MASK, size, dir);
+}
+
 int arm_iommu_map_sg(struct device *dev, struct scatterlist *sg, int nents,
                     enum dma_data_direction dir, struct dma_attrs *attrs)
 {
        struct scatterlist *s = sg, *dma = sg, *start = sg;
-       int i, count = 1;
+       int i, count = 0;
        unsigned int offset = s->offset;
        unsigned int size = s->offset + s->length;

+       s->dma_address = ~0;
+       s->dma_length = 0;
+
        for (i = 1; i < nents; i++) {
+               s = sg_next(s);
                s->dma_address = ~0;
                s->dma_length = 0;

-               s = sg_next(s);
-
-               if (s->offset || (size & (PAGE_SIZE - 1))) {
-                       if (__map_sg_chunk(dev, start, size, &dma->dma_address, dir) < 0)
+               if (s->offset || size & ~PAGE_MASK ||
+                   size + s->length > dma_get_max_seg_size(dev)) {
+                       if (__map_sg_chunk(dev, start, size,
+                                           &dma->dma_address, dir) < 0)
                                goto bad_mapping;

                        dma->dma_address += offset;
-                       dma->dma_length = size;
+                       dma->dma_length = size - offset;

                        size = offset = s->offset;
                        start = s;
                        dma = sg_next(dma);
-                       count += 1;
+                       count++;
                }
-               size += sg->length;
+               size += s->length;
        }
-       __map_sg_chunk(dev, start, size, &dma->dma_address, dir);
-       d->dma_address += offset;

-       return count;
+       if (__map_sg_chunk(dev, start, size, &dma->dma_address, dir) < 0)
+               goto bad_mapping;
+       dma->dma_address += offset;
+       dma->dma_length = size - offset;
+
+       return ++count;

 bad_mapping:
-       for_each_sg(sg, s, count-1, i)
-               __iommu_remove_mapping(dev, sg_dma_address(s), sg_dma_len(s));
+       for_each_sg(sg, s, count, i) {
+               __iommu_remove_mapping(dev, sg_dma_address(s),
+                                       PAGE_ALIGN(sg_dma_len(s)));
+       }
        return 0;
 }

@@ -1086,9 +1123,11 @@ void arm_iommu_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,

        for_each_sg(sg, s, nents, i) {
                if (sg_dma_len(s))
-                       __iommu_remove_mapping(dev, sg_dma_address(s), sg_dma_len(s));
+                       __iommu_remove_mapping(dev, sg_dma_address(s),
+                                               sg_dma_len(s));
                if (!arch_is_coherent())
-                       __dma_page_dev_to_cpu(sg_page(sg), sg->offset, sg->length, dir);
+                       __dma_page_dev_to_cpu(sg_page(s), s->offset,
+                                               s->length, dir);
        }
 }

@@ -1108,7 +1147,8 @@ void arm_iommu_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,

        for_each_sg(sg, s, nents, i)
                if (!arch_is_coherent())
-                       __dma_page_dev_to_cpu(sg_page(sg), sg->offset, sg->length, dir);
+                       __dma_page_dev_to_cpu(sg_page(s), s->offset,
+                                               s->length, dir);
 }

 /**
@@ -1126,20 +1166,24 @@ void arm_iommu_sync_sg_for_device(struct device *dev, struct scatterlist *sg,

        for_each_sg(sg, s, nents, i)
                if (!arch_is_coherent())
-                       __dma_page_cpu_to_dev(sg_page(sg), sg->offset, sg->length, dir);
+                       __dma_page_cpu_to_dev(sg_page(s), s->offset,
+                                               s->length, dir);
 }

 struct dma_map_ops iommu_ops = {
        .alloc          = arm_iommu_alloc_attrs,
        .free           = arm_iommu_free_attrs,
        .mmap           = arm_iommu_mmap_attrs,
+       .map_page       = arm_iommu_map_page,
+       .unmap_page     = arm_iommu_unmap_page,
        .map_sg                 = arm_iommu_map_sg,
        .unmap_sg               = arm_iommu_unmap_sg,
        .sync_sg_for_cpu        = arm_iommu_sync_sg_for_cpu,
        .sync_sg_for_device     = arm_iommu_sync_sg_for_device,
 };

-int arm_iommu_attach_device(struct device *dev, dma_addr_t base, size_t size, int order)
+struct dma_iommu_mapping *arm_iommu_create_mapping(dma_addr_t base,
+                                                   size_t size, int order)
 {
        unsigned int count = (size >> PAGE_SHIFT) - order;
        unsigned int bitmap_size = BITS_TO_LONGS(count) * sizeof(long);
@@ -1157,30 +1201,57 @@ int arm_iommu_attach_device(struct device *dev, dma_addr_t base, size_t size, in
        mapping->base = base;
        mapping->bits = bitmap_size;
        mapping->order = order;
-       mutex_init(&mapping->lock);
+       spin_lock_init(&mapping->lock);

        mapping->domain = iommu_domain_alloc();
        if (!mapping->domain)
                goto err3;

-       err = iommu_attach_device(mapping->domain, dev);
-       if (err != 0)
-               goto err4;
-
-       dev->archdata.mapping = mapping;
-       set_dma_ops(dev, &iommu_ops);
-
-       printk(KERN_INFO "Attached IOMMU controller to %s device.\n", dev_name(dev));
-       return 0;
+       kref_init(&mapping->kref);
+       return mapping;

-err4:
-       iommu_domain_free(mapping->domain);
 err3:
        kfree(mapping->bitmap);
 err2:
        kfree(mapping);
 err:
-       return -ENOMEM;
+       return ERR_PTR(err);
+}
+EXPORT_SYMBOL(arm_iommu_create_mapping);
+
+static void release_iommu_mapping(struct kref *kref)
+{
+       struct dma_iommu_mapping *mapping =
+               container_of(kref, struct dma_iommu_mapping, kref);
+
+       iommu_domain_free(mapping->domain);
+       kfree(mapping->bitmap);
+       kfree(mapping);
+}
+
+void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping)
+{
+       if (mapping)
+               kref_put(&mapping->kref, release_iommu_mapping);
+}
+EXPORT_SYMBOL(arm_iommu_release_mapping);
+
+int arm_iommu_attach_device(struct device *dev,
+                           struct dma_iommu_mapping *mapping)
+{
+       int err;
+
+       err = iommu_attach_device(mapping->domain, dev);
+       if (err)
+               return err;
+
+       kref_get(&mapping->kref);
+       dev->archdata.mapping = mapping;
+       set_dma_ops(dev, &iommu_ops);
+
+       printk(KERN_INFO "*****Attached IOMMU controller to %s device.\n",
+               dev_name(dev));
+       return 0;
 }
 EXPORT_SYMBOL(arm_iommu_attach_device);

--
1.7.0.4

--
nvpublic

^ permalink raw reply related

* [PATCH v3 1/4] dmaengine: at_hdmac: platform data move to use .id_table
From: Grant Likely @ 2011-10-13  0:32 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <f91f267b82ac0f0459c11a7bdf3ab0ea8758656a.1318438197.git.nicolas.ferre@atmel.com>

On Wed, Oct 12, 2011 at 06:57:11PM +0200, Nicolas Ferre wrote:
> We remove the use of platform data from DMA controller driver.
> We now use of .id_table to distinguish between compatible
> types. The two implementations allow to determine the
> number of channels and the capabilities of the controller.
> 
> Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>

Acked-by: Grant Likely <grant.likely@secretlab.ca>

> ---
>  drivers/dma/at_hdmac.c      |   48 ++++++++++++++++++++++++++++++++++---------
>  drivers/dma/at_hdmac_regs.h |    8 +++++++
>  2 files changed, 46 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
> index fcfa0a8..d1869c5 100644
> --- a/drivers/dma/at_hdmac.c
> +++ b/drivers/dma/at_hdmac.c
> @@ -1175,6 +1175,18 @@ static void atc_free_chan_resources(struct dma_chan *chan)
>  
>  /*--  Module Management  -----------------------------------------------*/
>  
> +static struct platform_device_id atdma_devtypes[] = {
> +	{
> +		.name = "at91sam9rl_dma",
> +		.driver_data = ATDMA_DEVTYPE_SAM9RL,
> +	}, {
> +		.name = "at91sam9g45_dma",
> +		.driver_data = ATDMA_DEVTYPE_SAM9G45,
> +	}, {
> +		/* sentinel */
> +	}
> +};
> +
>  /**
>   * at_dma_off - disable DMA controller
>   * @atdma: the Atmel HDAMC device
> @@ -1193,18 +1205,32 @@ static void at_dma_off(struct at_dma *atdma)
>  
>  static int __init at_dma_probe(struct platform_device *pdev)
>  {
> -	struct at_dma_platform_data *pdata;
>  	struct resource		*io;
>  	struct at_dma		*atdma;
>  	size_t			size;
>  	int			irq;
>  	int			err;
>  	int			i;
> +	u32                     nr_channels;
> +	dma_cap_mask_t          cap_mask = {};
> +	enum atdma_devtype	atdmatype;
> +
> +	dma_cap_set(DMA_MEMCPY, cap_mask);
> +
> +	/* get DMA parameters from controller type */
> +	atdmatype = platform_get_device_id(pdev)->driver_data;
>  
> -	/* get DMA Controller parameters from platform */
> -	pdata = pdev->dev.platform_data;
> -	if (!pdata || pdata->nr_channels > AT_DMA_MAX_NR_CHANNELS)
> +	switch (atdmatype) {
> +	case ATDMA_DEVTYPE_SAM9RL:
> +		nr_channels = 2;
> +		break;
> +	case ATDMA_DEVTYPE_SAM9G45:
> +		nr_channels = 8;
> +		dma_cap_set(DMA_SLAVE, cap_mask);
> +		break;
> +	default:
>  		return -EINVAL;
> +	}
>  
>  	io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>  	if (!io)
> @@ -1215,14 +1241,15 @@ static int __init at_dma_probe(struct platform_device *pdev)
>  		return irq;
>  
>  	size = sizeof(struct at_dma);
> -	size += pdata->nr_channels * sizeof(struct at_dma_chan);
> +	size += nr_channels * sizeof(struct at_dma_chan);
>  	atdma = kzalloc(size, GFP_KERNEL);
>  	if (!atdma)
>  		return -ENOMEM;
>  
> -	/* discover transaction capabilites from the platform data */
> -	atdma->dma_common.cap_mask = pdata->cap_mask;
> -	atdma->all_chan_mask = (1 << pdata->nr_channels) - 1;
> +	/* discover transaction capabilities */
> +	atdma->dma_common.cap_mask = cap_mask;
> +	atdma->all_chan_mask = (1 << nr_channels) - 1;
> +	atdma->devtype = atdmatype;
>  
>  	size = resource_size(io);
>  	if (!request_mem_region(io->start, size, pdev->dev.driver->name)) {
> @@ -1268,7 +1295,7 @@ static int __init at_dma_probe(struct platform_device *pdev)
>  
>  	/* initialize channels related values */
>  	INIT_LIST_HEAD(&atdma->dma_common.channels);
> -	for (i = 0; i < pdata->nr_channels; i++) {
> +	for (i = 0; i < nr_channels; i++) {
>  		struct at_dma_chan	*atchan = &atdma->chan[i];
>  
>  		atchan->chan_common.device = &atdma->dma_common;
> @@ -1313,7 +1340,7 @@ static int __init at_dma_probe(struct platform_device *pdev)
>  	dev_info(&pdev->dev, "Atmel AHB DMA Controller ( %s%s), %d channels\n",
>  	  dma_has_cap(DMA_MEMCPY, atdma->dma_common.cap_mask) ? "cpy " : "",
>  	  dma_has_cap(DMA_SLAVE, atdma->dma_common.cap_mask)  ? "slave " : "",
> -	  pdata->nr_channels);
> +	  nr_channels);
>  
>  	dma_async_device_register(&atdma->dma_common);
>  
> @@ -1495,6 +1522,7 @@ static const struct dev_pm_ops at_dma_dev_pm_ops = {
>  static struct platform_driver at_dma_driver = {
>  	.remove		= __exit_p(at_dma_remove),
>  	.shutdown	= at_dma_shutdown,
> +	.id_table	= atdma_devtypes,
>  	.driver = {
>  		.name	= "at_hdmac",
>  		.pm	= &at_dma_dev_pm_ops,
> diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h
> index aa4c9ae..d7d6737 100644
> --- a/drivers/dma/at_hdmac_regs.h
> +++ b/drivers/dma/at_hdmac_regs.h
> @@ -248,9 +248,16 @@ static inline struct at_dma_chan *to_at_dma_chan(struct dma_chan *dchan)
>  
>  /*--  Controller  ------------------------------------------------------*/
>  
> +enum atdma_devtype {
> +	ATDMA_DEVTYPE_UNDEFINED = 0,
> +	ATDMA_DEVTYPE_SAM9RL,	/* compatible with SAM9RL DMA controller */
> +	ATDMA_DEVTYPE_SAM9G45,	/* compatible with SAM9G45 DMA controller */
> +};
> +
>  /**
>   * struct at_dma - internal representation of an Atmel HDMA Controller
>   * @chan_common: common dmaengine dma_device object members
> + * @atdma_devtype: identifier of DMA controller compatibility
>   * @ch_regs: memory mapped register base
>   * @clk: dma controller clock
>   * @save_imr: interrupt mask register that is saved on suspend/resume cycle
> @@ -260,6 +267,7 @@ static inline struct at_dma_chan *to_at_dma_chan(struct dma_chan *dchan)
>   */
>  struct at_dma {
>  	struct dma_device	dma_common;
> +	enum atdma_devtype	devtype;
>  	void __iomem		*regs;
>  	struct clk		*clk;
>  	u32			save_imr;
> -- 
> 1.7.5.4
> 

^ permalink raw reply

* [PATCH v3 2/4] dmaengine: at_hdmac: add device tree support
From: Grant Likely @ 2011-10-13  0:34 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <6a7ec87c53609bbb517b199a9b48a5322a625aa1.1318438197.git.nicolas.ferre@atmel.com>

On Wed, Oct 12, 2011 at 06:57:12PM +0200, Nicolas Ferre wrote:
> Add device tree probe support for atmel at_hdmac DMA driver.
> Bindings are added to specify DMA controller configuration.
> 
> Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
> ---
>  .../devicetree/bindings/dma/atmel-dma.txt          |   14 +++++++++
>  drivers/dma/at_hdmac.c                             |   30 +++++++++++++++++++-
>  2 files changed, 43 insertions(+), 1 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/dma/atmel-dma.txt
> 
> diff --git a/Documentation/devicetree/bindings/dma/atmel-dma.txt b/Documentation/devicetree/bindings/dma/atmel-dma.txt
> new file mode 100644
> index 0000000..3c046ee
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/dma/atmel-dma.txt
> @@ -0,0 +1,14 @@
> +* Atmel Direct Memory Access Controller (DMA)
> +
> +Required properties:
> +- compatible: Should be "atmel,<chip>-dma"
> +- reg: Should contain DMA registers location and length
> +- interrupts: Should contain DMA interrupt
> +
> +Examples:
> +
> +dma at ffffec00 {
> +	compatible = "atmel,at91sam9g45-dma";
> +	reg = <0xffffec00 0x200>;
> +	interrupts = <21>;
> +};
> diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
> index d1869c5..42bd64c 100644
> --- a/drivers/dma/at_hdmac.c
> +++ b/drivers/dma/at_hdmac.c
> @@ -23,6 +23,8 @@
>  #include <linux/module.h>
>  #include <linux/platform_device.h>
>  #include <linux/slab.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
>  
>  #include "at_hdmac_regs.h"
>  
> @@ -1175,6 +1177,20 @@ static void atc_free_chan_resources(struct dma_chan *chan)
>  
>  /*--  Module Management  -----------------------------------------------*/
>  
> +#if defined(CONFIG_OF)
> +static const struct of_device_id atmel_dma_dt_ids[] = {
> +	{
> +		.compatible = "atmel,at91sam9rl-dma",
> +		.data = (void *)ATDMA_DEVTYPE_SAM9RL
> +	}, {
> +		.compatible = "atmel,at91sam9g45-dma",
> +		.data = (void *)ATDMA_DEVTYPE_SAM9G45
> +	}, { /* sentinel */ }
> +};
> +
> +MODULE_DEVICE_TABLE(of, atmel_dma_dt_ids);
> +#endif
> +
>  static struct platform_device_id atdma_devtypes[] = {
>  	{
>  		.name = "at91sam9rl_dma",
> @@ -1187,6 +1203,17 @@ static struct platform_device_id atdma_devtypes[] = {
>  	}
>  };
>  
> +static inline enum atdma_devtype __init at_dma_get_driver_data(
> +					struct platform_device *pdev)
> +{
> +	if (pdev->dev.of_node) {
> +		const struct of_device_id *match;
> +		match = of_match_node(atmel_dma_dt_ids, pdev->dev.of_node);

You'll need to check the return value.  It is possible (though
unlikely) to have a device with an of_node but still happens to get
bound via the platform_driver id_table.  In which case match would be
NULL here.

Otherwise, you can add my a-b after fixing that bug.

Acked-by: Grant Likely <grant.likely@secretlab.ca>

g.


> +		return (enum atdma_devtype)match->data;
> +	}
> +	return platform_get_device_id(pdev)->driver_data;
> +}
> +
>  /**
>   * at_dma_off - disable DMA controller
>   * @atdma: the Atmel HDAMC device
> @@ -1218,7 +1245,7 @@ static int __init at_dma_probe(struct platform_device *pdev)
>  	dma_cap_set(DMA_MEMCPY, cap_mask);
>  
>  	/* get DMA parameters from controller type */
> -	atdmatype = platform_get_device_id(pdev)->driver_data;
> +	atdmatype = at_dma_get_driver_data(pdev);
>  
>  	switch (atdmatype) {
>  	case ATDMA_DEVTYPE_SAM9RL:
> @@ -1526,6 +1553,7 @@ static struct platform_driver at_dma_driver = {
>  	.driver = {
>  		.name	= "at_hdmac",
>  		.pm	= &at_dma_dev_pm_ops,
> +		.of_match_table	= of_match_ptr(atmel_dma_dt_ids),
>  	},
>  };
>  
> -- 
> 1.7.5.4
> 

^ permalink raw reply

* [PATCH v3 3/4] ARM: at91/dma: remove platform data from DMA controller
From: Grant Likely @ 2011-10-13  0:34 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <bcf2b73ecc158bf20f94b00d3b8a6d140eff2026.1318438197.git.nicolas.ferre@atmel.com>

On Wed, Oct 12, 2011 at 06:57:13PM +0200, Nicolas Ferre wrote:
> DMA controller can deduce its configuration data from
> the platform. Remove the platform data and match device
> types with the compatible ones.
> 
> Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>

Acked-by: Grant Likely <grant.likely@secretlab.ca>

> ---
>  arch/arm/mach-at91/at91sam9g45_devices.c   |    9 +--------
>  arch/arm/mach-at91/at91sam9rl_devices.c    |    8 +-------
>  arch/arm/mach-at91/include/mach/at_hdmac.h |   10 ----------
>  3 files changed, 2 insertions(+), 25 deletions(-)
> 
> diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
> index 600bffb..c9b897f 100644
> --- a/arch/arm/mach-at91/at91sam9g45_devices.c
> +++ b/arch/arm/mach-at91/at91sam9g45_devices.c
> @@ -38,10 +38,6 @@
>  #if defined(CONFIG_AT_HDMAC) || defined(CONFIG_AT_HDMAC_MODULE)
>  static u64 hdmac_dmamask = DMA_BIT_MASK(32);
>  
> -static struct at_dma_platform_data atdma_pdata = {
> -	.nr_channels	= 8,
> -};
> -
>  static struct resource hdmac_resources[] = {
>  	[0] = {
>  		.start	= AT91_BASE_SYS + AT91_DMA,
> @@ -56,12 +52,11 @@ static struct resource hdmac_resources[] = {
>  };
>  
>  static struct platform_device at_hdmac_device = {
> -	.name		= "at_hdmac",
> +	.name		= "at91sam9g45_dma",
>  	.id		= -1,
>  	.dev		= {
>  				.dma_mask		= &hdmac_dmamask,
>  				.coherent_dma_mask	= DMA_BIT_MASK(32),
> -				.platform_data		= &atdma_pdata,
>  	},
>  	.resource	= hdmac_resources,
>  	.num_resources	= ARRAY_SIZE(hdmac_resources),
> @@ -69,8 +64,6 @@ static struct platform_device at_hdmac_device = {
>  
>  void __init at91_add_device_hdmac(void)
>  {
> -	dma_cap_set(DMA_MEMCPY, atdma_pdata.cap_mask);
> -	dma_cap_set(DMA_SLAVE, atdma_pdata.cap_mask);
>  	platform_device_register(&at_hdmac_device);
>  }
>  #else
> diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
> index aacb19d..81954f7 100644
> --- a/arch/arm/mach-at91/at91sam9rl_devices.c
> +++ b/arch/arm/mach-at91/at91sam9rl_devices.c
> @@ -33,10 +33,6 @@
>  #if defined(CONFIG_AT_HDMAC) || defined(CONFIG_AT_HDMAC_MODULE)
>  static u64 hdmac_dmamask = DMA_BIT_MASK(32);
>  
> -static struct at_dma_platform_data atdma_pdata = {
> -	.nr_channels	= 2,
> -};
> -
>  static struct resource hdmac_resources[] = {
>  	[0] = {
>  		.start	= AT91_BASE_SYS + AT91_DMA,
> @@ -51,12 +47,11 @@ static struct resource hdmac_resources[] = {
>  };
>  
>  static struct platform_device at_hdmac_device = {
> -	.name		= "at_hdmac",
> +	.name		= "at91sam9rl_dma",
>  	.id		= -1,
>  	.dev		= {
>  				.dma_mask		= &hdmac_dmamask,
>  				.coherent_dma_mask	= DMA_BIT_MASK(32),
> -				.platform_data		= &atdma_pdata,
>  	},
>  	.resource	= hdmac_resources,
>  	.num_resources	= ARRAY_SIZE(hdmac_resources),
> @@ -64,7 +59,6 @@ static struct platform_device at_hdmac_device = {
>  
>  void __init at91_add_device_hdmac(void)
>  {
> -	dma_cap_set(DMA_MEMCPY, atdma_pdata.cap_mask);
>  	platform_device_register(&at_hdmac_device);
>  }
>  #else
> diff --git a/arch/arm/mach-at91/include/mach/at_hdmac.h b/arch/arm/mach-at91/include/mach/at_hdmac.h
> index 187cb58..652c1a1 100644
> --- a/arch/arm/mach-at91/include/mach/at_hdmac.h
> +++ b/arch/arm/mach-at91/include/mach/at_hdmac.h
> @@ -14,16 +14,6 @@
>  #include <linux/dmaengine.h>
>  
>  /**
> - * struct at_dma_platform_data - Controller configuration parameters
> - * @nr_channels: Number of channels supported by hardware (max 8)
> - * @cap_mask: dma_capability flags supported by the platform
> - */
> -struct at_dma_platform_data {
> -	unsigned int	nr_channels;
> -	dma_cap_mask_t  cap_mask;
> -};
> -
> -/**
>   * enum at_dma_slave_width - DMA slave register access width.
>   * @AT_DMA_SLAVE_WIDTH_8BIT: Do 8-bit slave register accesses
>   * @AT_DMA_SLAVE_WIDTH_16BIT: Do 16-bit slave register accesses
> -- 
> 1.7.5.4
> 

^ permalink raw reply

* [PATCH v3 4/4] ARM: at91/dma: DMA controller registering with DT support
From: Grant Likely @ 2011-10-13  0:35 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <8d71a02275bc252b3841bf9f0e2e17a16df6deda.1318438197.git.nicolas.ferre@atmel.com>

On Wed, Oct 12, 2011 at 06:57:14PM +0200, Nicolas Ferre wrote:
> Device tree support on at91sam9g45 family SoC. Only call
> platform_device_register() if no dma-controller node is
> found in device tree.
> 
> Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>

Acked-by: Grant Likely <grant.likely@secretlab.ca>

> ---
>  arch/arm/mach-at91/at91sam9g45_devices.c |    8 +++++++-
>  1 files changed, 7 insertions(+), 1 deletions(-)
> 
> diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
> index c9b897f..b9888c5 100644
> --- a/arch/arm/mach-at91/at91sam9g45_devices.c
> +++ b/arch/arm/mach-at91/at91sam9g45_devices.c
> @@ -64,7 +64,13 @@ static struct platform_device at_hdmac_device = {
>  
>  void __init at91_add_device_hdmac(void)
>  {
> -	platform_device_register(&at_hdmac_device);
> +	struct device_node *of_node =
> +		of_find_node_by_name(NULL, "dma-controller");
> +
> +	if (of_node)
> +		of_node_put(of_node);
> +	else
> +		platform_device_register(&at_hdmac_device);
>  }
>  #else
>  void __init at91_add_device_hdmac(void) {}
> -- 
> 1.7.5.4
> 

^ permalink raw reply

* [PATCH 1/3] ARM: Samsung: Move timer irq numbers to end of linux irq space
From: Grant Likely @ 2011-10-13  0:41 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <4E95BC01.8090805@gmail.com>

On Wed, Oct 12, 2011 at 11:10:41AM -0500, Rob Herring wrote:
> On 10/10/2011 03:11 AM, Thomas Abraham wrote:
> > All of Samsung's s5p platforms have timer irqs statically mapped from linux
> > irq numbers 11 to 15. These timer irqs are moved to end of the statically
> > mapped linux irq space and the hardware irqs, which were statically mapped
> > starting from 32 is moved to start from 0. The NR_IRQS macro is consolidated
> > for all the s5p platforms in this process.
> > 
> > Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
> > ---
> >  arch/arm/mach-exynos4/include/mach/entry-macro.S |    1 -
> >  arch/arm/mach-exynos4/include/mach/irqs.h        |    3 +--
> >  arch/arm/mach-s5p64x0/include/mach/irqs.h        |    4 +---
> >  arch/arm/mach-s5pc100/include/mach/irqs.h        |    3 +--
> >  arch/arm/mach-s5pv210/include/mach/irqs.h        |    3 +--
> >  arch/arm/plat-samsung/include/plat/irqs.h        |    7 +++++--
> >  6 files changed, 9 insertions(+), 12 deletions(-)
> > 
> > diff --git a/arch/arm/mach-exynos4/include/mach/entry-macro.S b/arch/arm/mach-exynos4/include/mach/entry-macro.S
> > index 4c9adbd..5c4fbcc 100644
> > --- a/arch/arm/mach-exynos4/include/mach/entry-macro.S
> > +++ b/arch/arm/mach-exynos4/include/mach/entry-macro.S
> > @@ -72,7 +72,6 @@
> >  		cmpcc	\irqnr, \irqnr
> >  		cmpne	\irqnr, \tmp
> >  		cmpcs	\irqnr, \irqnr
> > -		addne	\irqnr, \irqnr, #32
> 
> 
> With this change, can't you now use the common entry-macro-gic.S?
> 
> 
> >  		.endm
> >  
> > diff --git a/arch/arm/mach-exynos4/include/mach/irqs.h b/arch/arm/mach-exynos4/include/mach/irqs.h
> > index dfd4b7e..43087c3 100644
> > --- a/arch/arm/mach-exynos4/include/mach/irqs.h
> > +++ b/arch/arm/mach-exynos4/include/mach/irqs.h
> > @@ -163,7 +163,6 @@
> >  #define IRQ_GPIO2_NR_GROUPS	9
> >  #define IRQ_GPIO_END		(S5P_GPIOINT_BASE + S5P_GPIOINT_COUNT)
> >  
> > -/* Set the default NR_IRQS */
> > -#define NR_IRQS			(IRQ_GPIO_END + 64)
> > +#define IRQ_TIMER_BASE		(IRQ_GPIO_END + 64)
> >  
> >  #endif /* __ASM_ARCH_IRQS_H */
> > diff --git a/arch/arm/mach-s5p64x0/include/mach/irqs.h b/arch/arm/mach-s5p64x0/include/mach/irqs.h
> > index 53982db..bea73cc 100644
> > --- a/arch/arm/mach-s5p64x0/include/mach/irqs.h
> > +++ b/arch/arm/mach-s5p64x0/include/mach/irqs.h
> > @@ -141,8 +141,6 @@
> >  
> >  #define IRQ_EINT_GROUP(grp, x)	(IRQ_EINT_GROUP##grp##_BASE + (x))
> >  
> > -/* Set the default NR_IRQS */
> > -
> > -#define NR_IRQS			(IRQ_EINT_GROUP8_BASE + IRQ_EINT_GROUP8_NR + 1)
> > +#define IRQ_TIMER_BASE		(IRQ_EINT_GROUP8_BASE + IRQ_EINT_GROUP8_NR + 1)
> >  
> >  #endif /* __ASM_ARCH_IRQS_H */
> > diff --git a/arch/arm/mach-s5pc100/include/mach/irqs.h b/arch/arm/mach-s5pc100/include/mach/irqs.h
> > index d2eb475..3a9d300 100644
> > --- a/arch/arm/mach-s5pc100/include/mach/irqs.h
> > +++ b/arch/arm/mach-s5pc100/include/mach/irqs.h
> > @@ -104,8 +104,7 @@
> >  #define S5P_GPIOINT_BASE	(IRQ_EINT(31) + 1)
> >  #define S5P_GPIOINT_GROUP_MAXNR	21
> >  
> > -/* Set the default NR_IRQS */
> > -#define NR_IRQS			(IRQ_EINT(31) + S5P_GPIOINT_COUNT + 1)
> > +#define IRQ_TIMER_BASE		(IRQ_EINT(31) + S5P_GPIOINT_COUNT + 1)
> >  
> >  /* Compatibility */
> >  #define IRQ_LCD_FIFO		IRQ_LCD0
> > diff --git a/arch/arm/mach-s5pv210/include/mach/irqs.h b/arch/arm/mach-s5pv210/include/mach/irqs.h
> > index 5e0de3a..df3173a 100644
> > --- a/arch/arm/mach-s5pv210/include/mach/irqs.h
> > +++ b/arch/arm/mach-s5pv210/include/mach/irqs.h
> > @@ -125,8 +125,7 @@
> >  #define S5P_GPIOINT_BASE	(IRQ_EINT(31) + 1)
> >  #define S5P_GPIOINT_GROUP_MAXNR	22
> >  
> > -/* Set the default NR_IRQS */
> > -#define NR_IRQS			(IRQ_EINT(31) + S5P_GPIOINT_COUNT + 1)
> > +#define IRQ_TIMER_BASE		(IRQ_EINT(31) + S5P_GPIOINT_COUNT + 1)
> >  
> >  /* Compatibility */
> >  #define IRQ_LCD_FIFO		IRQ_LCD0
> > diff --git a/arch/arm/plat-samsung/include/plat/irqs.h b/arch/arm/plat-samsung/include/plat/irqs.h
> > index 08d1a7e..b8918b3 100644
> > --- a/arch/arm/plat-samsung/include/plat/irqs.h
> > +++ b/arch/arm/plat-samsung/include/plat/irqs.h
> > @@ -22,7 +22,7 @@
> >   * mulitple of 32 to allow the common code to work
> >   */
> >  
> > -#define S5P_IRQ_OFFSET		(32)
> > +#define S5P_IRQ_OFFSET		(0)
> 
> Just remove this.

One comment on this; Make sure irqs mapping does *not* start at 0. 0 is not supposed to be used.

g.

^ permalink raw reply

* [PATCH 3/3] ARM: Exynos4: Add support for dt irq specifier to linux virq conversion
From: Grant Likely @ 2011-10-13  0:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1318234289-22041-4-git-send-email-thomas.abraham@linaro.org>

On Mon, Oct 10, 2011 at 01:41:29PM +0530, Thomas Abraham wrote:
> Add support for conversion of device tree interrupt specifier to linux
> virq domain for GIC and Interrupt combiner controllers.
> 
> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
> ---
>  .../devicetree/bindings/irq/samsung-combiner.txt   |   24 ++++++++++
>  arch/arm/mach-exynos4/cpu.c                        |   20 ++++++++-
>  arch/arm/mach-exynos4/irq-combiner.c               |   45 ++++++++++++++++++++
>  3 files changed, 88 insertions(+), 1 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/irq/samsung-combiner.txt
> 
> diff --git a/Documentation/devicetree/bindings/irq/samsung-combiner.txt b/Documentation/devicetree/bindings/irq/samsung-combiner.txt
> new file mode 100644
> index 0000000..b7d5c30
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/irq/samsung-combiner.txt
> @@ -0,0 +1,24 @@
> +* Exynos4 Interrupt Combiner Controller
> +
> +Samsung's Exynos4 architecture includes a interrupt combiner which
> +can combine interrupt sources as a group and provide a single
> +interrupt request for the group. The interrupt request from each
> +group are connected to a parent interrupt controller, which is GIC
> +in case of Exynos4.
> +
> +Required properties:
> +- compatible: should be "samsung,exynos4-combiner".
> +- interrupt-cells: should be <2>. The meaning of the cells are
> +    * First Cell: Combiner Group Number.
> +    * Second Cell: Interrupt within the group.
> +- reg: Base address and size of interrupt combiner registers.
> +- interrupt-controller: Identifies the node as an interrupt controller.
> +
> +Example:
> +
> +	combiner: interrupt-controller at 10440000 {
> +		compatible = "samsung,exynos4-combiner";
> +		#interrupt-cells = <2>;
> +		interrupt-controller;
> +		reg = <0x10440000 0x200>;
> +	};
> diff --git a/arch/arm/mach-exynos4/cpu.c b/arch/arm/mach-exynos4/cpu.c
> index 358624d..776e8d4 100644
> --- a/arch/arm/mach-exynos4/cpu.c
> +++ b/arch/arm/mach-exynos4/cpu.c
> @@ -10,6 +10,8 @@
>  
>  #include <linux/sched.h>
>  #include <linux/sysdev.h>
> +#include <linux/of.h>
> +#include <linux/of_irq.h>
>  
>  #include <asm/mach/map.h>
>  #include <asm/mach/irq.h>
> @@ -38,6 +40,8 @@ unsigned int gic_bank_offset __read_mostly;
>  extern int combiner_init(unsigned int combiner_nr, void __iomem *base,
>  			 unsigned int irq_start);
>  extern void combiner_cascade_irq(unsigned int combiner_nr, unsigned int irq);
> +extern void combiner_init_dt(struct device_node *node,
> +				struct device_node *parent);
>  
>  /* Initial IO mappings */
>  static struct map_desc exynos4_iodesc[] __initdata = {
> @@ -229,13 +233,27 @@ static void exynos4_gic_irq_fix_base(struct irq_data *d)
>  			    (gic_bank_offset * smp_processor_id());
>  }
>  
> +#ifdef CONFIG_OF
> +static const struct of_device_id exynos4_dt_irq_match[] = {
> +	{ .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
> +	{ .compatible = "samsung,exynos4-combiner", .data = combiner_init_dt, },
> +	{},
> +};
> +#endif
> +
>  void __init exynos4_init_irq(void)
>  {
>  	int irq;
>  
>  	gic_bank_offset = soc_is_exynos4412() ? 0x4000 : 0x8000;
>  
> -	gic_init(0, IRQ_PPI(0), S5P_VA_GIC_DIST, S5P_VA_GIC_CPU);
> +#ifdef CONFIG_OF
> +	if (of_have_populated_dt())
> +		of_irq_init(exynos4_dt_irq_match);
> +	else
> +#endif

With the proper empty implementations of of_have_populated_dt() and
of_irq_init(), the #ifdef block here should probably be removed.

> +		gic_init(0, IRQ_PPI(0), S5P_VA_GIC_DIST, S5P_VA_GIC_CPU);
> +
>  	gic_arch_extn.irq_eoi = exynos4_gic_irq_fix_base;
>  	gic_arch_extn.irq_unmask = exynos4_gic_irq_fix_base;
>  	gic_arch_extn.irq_mask = exynos4_gic_irq_fix_base;
> diff --git a/arch/arm/mach-exynos4/irq-combiner.c b/arch/arm/mach-exynos4/irq-combiner.c
> index 5a2758a..198bd0d 100644
> --- a/arch/arm/mach-exynos4/irq-combiner.c
> +++ b/arch/arm/mach-exynos4/irq-combiner.c
> @@ -12,7 +12,12 @@
>   * published by the Free Software Foundation.
>  */
>  
> +#include <linux/errno.h>
>  #include <linux/io.h>
> +#include <linux/of.h>
> +#include <linux/of_irq.h>
> +#include <linux/irqdomain.h>
> +#include <linux/slab.h>
>  
>  #include <asm/mach/irq.h>
>  
> @@ -122,3 +127,43 @@ void __init combiner_init(unsigned int combiner_nr, void __iomem *base,
>  		set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
>  	}
>  }
> +
> +#ifdef CONFIG_OF
> +/* Translate dt irq specifier to linux virq for interrupt combiner controller */
> +static int exynos4_irq_domain_combiner_dt_translate(struct irq_domain *d,
> +			struct device_node *controller,
> +			const u32 *intspec, unsigned int intsize,
> +			unsigned long *out_hwirq, unsigned int *out_type)
> +{
> +	if (d->of_node != controller)
> +		return -EINVAL;
> +	if (intsize < 2)
> +		return -EINVAL;
> +
> +	*out_hwirq = COMBINER_IRQ(intspec[0], intspec[1]);
> +	*out_type = IRQ_TYPE_NONE;
> +	return 0;
> +}
> +
> +static struct irq_domain_ops exynos4_irq_domain_combiner_ops = {
> +	.dt_translate = exynos4_irq_domain_combiner_dt_translate,
> +};
> +
> +void __init combiner_init_dt(struct device_node *node,
> +					struct device_node *parent)
> +{
> +	struct irq_domain *domain;
> +
> +	if (WARN(!node, "combiner_init_dt: invalid node in parameter\n"))
> +		return;
> +
> +	domain = kzalloc(sizeof(*domain), GFP_KERNEL);
> +	if (domain) {
> +		domain->of_node = node;
> +		domain->ops = &exynos4_irq_domain_combiner_ops;
> +		irq_domain_add(domain);
> +	} else {
> +		WARN_ON(1);
> +	}

I would normally expect this order for error handling :

	domain = kzalloc(sizeof(*domain), GFP_KERNEL);
	if (!domain) {
		WARN_ON(1);
		return;
	}

	domain->of_node = node;
	domain->ops = &exynos4_irq_domain_combiner_ops;
	irq_domain_add(domain);

But having said that, I don't think this is the right approach.
combiner_init_dt I would expect to call combiner_init(), and the
irq_domain should become part of the combiner_chip_data structure so
that it can be used for mapping back and forth from linux and hqirq
numbers.  (irq_data->hwirq and the mapping function).  Rolling the
irq_domain into the irq controller private data structure is what was
done for the GIC too.

g.

^ permalink raw reply

* [PATCH 1/2] drivers: create a pin control subsystem v9
From: Chanho Park @ 2011-10-13  0:55 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1317629862-13549-1-git-send-email-linus.walleij@stericsson.com>

> +Interaction with the GPIO subsystem
> +===================================
> +
> +The GPIO drivers may want to perform operations of various types on the same
> +physical pins that are also registered as GPIO pins.
> +
> +Since the pin controller subsystem have its pinspace local to the pin
> +controller we need a mapping so that the pin control subsystem can figure out
> +which pin controller handles control of a certain GPIO pin. Since a single
> +pin controller may be muxing several GPIO ranges (typically SoCs that have
> +one set of pins but internally several GPIO silicon blocks, each modeled as
> +a struct gpio_chip) any number of GPIO ranges can be added to a pin controller
> +instance like this:
> +
> +struct gpio_chip chip_a;
> +struct gpio_chip chip_b;
> +
> +static struct pinctrl_gpio_range gpio_range_a = {
> + ? ? ? .name = "chip a",
> + ? ? ? .id = 0,
> + ? ? ? .base = 32,
> + ? ? ? .npins = 16,
> + ? ? ? .gc = &chip_a;
> +};
> +
> +static struct pinctrl_gpio_range gpio_range_a = {
> + ? ? ? .name = "chip b",
> + ? ? ? .id = 0,
> + ? ? ? .base = 48,
> + ? ? ? .npins = 8,
> + ? ? ? .gc = &chip_b;
> +};
> +
> +
> +{
> + ? ? ? struct pinctrl_dev *pctl;
> + ? ? ? ...
> + ? ? ? pinctrl_add_gpio_range(pctl, &gpio_range_a);
> + ? ? ? pinctrl_add_gpio_range(pctl, &gpio_range_b);
> +}
> +
> +So this complex system has one pin controller handling two different
> +GPIO chips. Chip a has 16 pins and chip b has 8 pins. They are mapped in
> +the global GPIO pin space at:
> +
> +chip a: [32 .. 47]
> +chip b: [48 .. 55]
> +
> +When GPIO-specific functions in the pin control subsystem are called, these
> +ranges will be used to look up the apropriate pin controller by inspecting
> +and matching the pin to the pin ranges across all controllers. When a
> +pin controller handling the matching range is found, GPIO-specific functions
> +will be called on that specific pin controller.
> +
> +For all functionalities dealing with pin biasing, pin muxing etc, the pin
> +controller subsystem will subtract the range's .base offset from the passed
> +in gpio pin number, and pass that on to the pin control driver, so the driver
> +will get an offset into its handled number range. Further it is also passed
> +the range ID value, so that the pin controller knows which range it should
> +deal with.
> +
> +For example: if a user issues pinctrl_gpio_set_foo(50), the pin control
> +subsystem will find that the second range on this pin controller matches,
> +subtract the base 48 and call the
> +pinctrl_driver_gpio_set_foo(pinctrl, range, 2) where the latter function has
> +this signature:
> +
> +int pinctrl_driver_gpio_set_foo(struct pinctrl_dev *pctldev,
> + ? ?struct pinctrl_gpio_range *rangeid,
> + ? ?unsigned offset);
> +
> +Now the driver knows that we want to do some GPIO-specific operation on the
> +second GPIO range handled by "chip b", at offset 2 in that specific range.
> +
> +(If the GPIO subsystem is ever refactored to use a local per-GPIO controller
> +pin space, this mapping will need to be augmented accordingly.)
> +

Hello,
Some gpio-ranges doesn't match with pin numbers.
For example, gpio_range_b starts gpio 48.
However, a pin base number of gpio_range_b is 96. It isn't same with gpio base.
A pinctrl driver must know this pin_space-gpio_range mappings.

static struct pinctrl_gpio_range gpio_range_a = {
 ? ? ? .name = "chip b",
 ? ? ? .id = 0,
 ? ? ? .base = 48,
       .pin_base = 96,
 ? ? ? .npins = 8,
 ? ? ? .gc = &chip_b;
};

To solve this sparse gpio-range issue, you will implement
above pinctrl_driver_gpio_xxx which not yet implemented.
How about below simple patch just added pin_base instead
using pinctrl_driver_gpio_xxx function?

diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c
index a0a90a2..7d7f7c0 100644
--- a/drivers/pinctrl/pinmux.c
+++ b/drivers/pinctrl/pinmux.c
@@ -223,7 +223,7 @@ int pinmux_request_gpio(unsigned gpio)
 		return -EINVAL;

 	/* Convert to the pin controllers number space */
-	pin = gpio - range->base;
+	pin = gpio - range->base + range->pin_base;

 	/* Conjure some name stating what chip and pin this is taken by */
 	snprintf(gpiostr, 15, "%s:%d", range->name, gpio);
@@ -248,7 +248,7 @@ void pinmux_free_gpio(unsigned gpio)
                return;

        /* Convert to the pin controllers number space */
-       pin = gpio - range->base;
+       pin = gpio - range->base + range->pin_base;

        pin_free(pctldev, pin);
 }
diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h
index 1e6f67e..6041fd4 100644
--- a/include/linux/pinctrl/pinctrl.h
+++ b/include/linux/pinctrl/pinctrl.h
@@ -53,6 +53,7 @@ struct pinctrl_gpio_range {
 	const char *name;
 	unsigned int id;
 	unsigned int base;
+	unsigned int pin_base;
 	unsigned int npins;
 	struct gpio_chip *gc;
 };


...snip...

+/**
+ * pinctrl_get_device_gpio_range() - find device for GPIO range
+ * @gpio: the pin to locate the pin controller for
+ * @outdev: the pin control device if found
+ * @outrange: the GPIO range if found
+ *
+ * Find the pin controller handling a certain GPIO pin from the pinspace of
+ * the GPIO subsystem, return the device and the matching GPIO range. Returns
+ * negative if the GPIO range could not be found in any device.
+ */
+int pinctrl_get_device_gpio_range(unsigned gpio,
+                               struct pinctrl_dev **outdev,
+                               struct pinctrl_gpio_range **outrange)
+{
+       struct pinctrl_dev *pctldev = NULL;
+
+       /* Loop over the pin controllers */
+       mutex_lock(&pinctrldev_list_mutex);
+       list_for_each_entry(pctldev, &pinctrldev_list, node) {
+               struct pinctrl_gpio_range *range;
+
+               range = pinctrl_match_gpio_range(pctldev, gpio);
+               if (range != NULL) {
+                       *outdev = pctldev;
+                       *outrange = range;

missing mutex_unlock

+                       return 0;
+               }
+       }
+       mutex_unlock(&pinctrldev_list_mutex);
+
+       return -EINVAL;
+}

-- 
Best Regards,
Chanho Park

^ permalink raw reply related

* [PATCH] gpio: exynos4: Add device tree support
From: Grant Likely @ 2011-10-13  0:58 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <069c01cc88e3$92f86d90$b8e948b0$%kim@samsung.com>

On Wed, Oct 12, 2011 at 10:33:48PM +0900, Kukjin Kim wrote:
> Thomas Abraham wrote:
> > 
> > As gpio chips get registered, a device tree node which represents the
> > gpio chip is searched and attached to it. A translate function is also
> > provided to convert the gpio specifier into actual platform settings
> > for pin function selection, pull up/down and driver strength settings.
> > 
> > Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
> 
> Hi Thomas,
> 
> You got some comments from Rob, so could you please address from him?
> Others, looks ok to me.
> 
> And I need to get the ack from Grant to upstream via Samsung tree for
> upcoming merge window.
> Grant, is this ok for you?

Yes, go ahead and merge it with my:

Acked-by: Grant Likely <grant.likely@secretlab.ca>

g.

^ permalink raw reply

* [PATCH] gpio: exynos4: Add device tree support
From: Grant Likely @ 2011-10-13  1:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAJuYYwRsM_aGkeG9v97jdsJgSQeokViuLGdF5TvqEkNZCAgFVA@mail.gmail.com>

On Wed, Oct 12, 2011 at 09:45:25PM +0530, Thomas Abraham wrote:
> On 12 October 2011 20:41, Rob Herring <robherring2@gmail.com> wrote:
> > On 10/11/2011 11:06 AM, Thomas Abraham wrote:
> >> On 11 October 2011 21:00, Rob Herring <robherring2@gmail.com> wrote:
> >>> On 10/11/2011 10:19 AM, Thomas Abraham wrote:
> >>>> Hi Rob,
> >>>>
> >>>> On 11 October 2011 20:41, Rob Herring <robherring2@gmail.com> wrote:
> >>>>> Thomas,
> >>>>>
> >>>>> On 10/11/2011 03:16 AM, Thomas Abraham wrote:
> >>>>>> As gpio chips get registered, a device tree node which represents the
> >>>>>> gpio chip is searched and attached to it. A translate function is also
> >>>>>> provided to convert the gpio specifier into actual platform settings
> >>>>>> for pin function selection, pull up/down and driver strength settings.
> >>>>>>
> >>>>>> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
> >>>>>> ---
> >>>>>> This patch is based on the latest consolidated Samsung GPIO driver available
> >>>>>> in the following tree:
> >>>>>> ? https://github.com/kgene/linux-samsung.git ?branch: for-next
> >>>>>>
> >>>>>> ?.../devicetree/bindings/gpio/gpio-samsung.txt ? ? ?| ? 30 +++++++++++
> >>>>>> ?drivers/gpio/gpio-samsung.c ? ? ? ? ? ? ? ? ? ? ? ?| ? 53 ++++++++++++++++++++
> >>>>>> ?2 files changed, 83 insertions(+), 0 deletions(-)
> >>>>>> ?create mode 100644 Documentation/devicetree/bindings/gpio/gpio-samsung.txt
> >>>>>>
> >>>>>> diff --git a/Documentation/devicetree/bindings/gpio/gpio-samsung.txt b/Documentation/devicetree/bindings/gpio/gpio-samsung.txt
> >>>>>> new file mode 100644
> >>>>>> index 0000000..883faeb
> >>>>>> --- /dev/null
> >>>>>> +++ b/Documentation/devicetree/bindings/gpio/gpio-samsung.txt
> >>>>>> @@ -0,0 +1,30 @@
> >>>>>> +Samsung Exynos4 GPIO Controller
> >>>>>> +
> >>>>>> +Required properties:
> >>>>>> +- compatible: Format of compatible property value should be
> >>>>>> + ?"samsung,exynos4-gpio-<controller_name>". Example: For GPA0 controller, the
> >>>>>> + ?compatible property value should be "samsung,exynos4-gpio-gpa0".
> >>>>>
> >>>>> Isn't gpa0 an instance of the h/w, not a version?
> >>>>
> >>>> GPA0 is a instance of the gpio controller. There are several such
> >>>> instances and there could be differences in those instances such as
> >>>> the number of GPIO lines managed by that gpio controller instance.
> >>>>
> >>>
> >>> That doesn't seem like a reason to have different compatible strings.
> >>> Does that affect the programming model of the controller? Unused lines
> >>> whether at the board level or SOC level shouldn't really matter.
> >>
> >>
> >> No, that does not affect the programming of the controller. The reason
> >> for the instance name extension in compatible string is to match the
> >> gpio_chip with a gpio controller node. When matched, the of_node
> >> pointer of the gpio_chip is set to point to that controller node.
> >>
> >> This might not be the best possible implementation but the device tree
> >> support code in this patch is dictated by the structure of the
> >> existing gpio driver code. As you suggested previously, I will look at
> >> reworking the gpio driver a little later but for now, there was a need
> >> for working gpio dt solution to make progress on dt support for other
> >> controllers.
> >
> > Linux should provide clues about what's needed in a binding, but the
> > binding should not be defined based on current Linux code. Doing the
> > binding one way and changing it later is not a good plan.
> 
> Ok. When starting on this, two compatible values where used for the
> gpio controllers, one was "samsung,exynos4-gpio" and another was
> "samsung,exynos4-gpio-<ctrl_name>". And when the gpio dt support would
> mature, the second compatible value could be dropped. Non-linux
> platforms could always use the generic "samsung,exynos4-gpio"
> compatible value to match. I moved to using only
> "samsung,exynos4-gpio-<ctrl_name>" just before sending this patch
> because I was not sure of the right approach.
> 
> >
> > I think you need to convert all users of gpio over as well so you can
> > move to dynamic gpio_chip creation and gpio numbering. Or maybe you can
> > match based on base address? This is going to be a common problem as
> > gpio is converted over to DT. Perhaps Grant or others have suggestions
> > on the approach to use.
> 
> Yes, I agree with you about the dynamic gpio_chip creation and gpio
> numbering. Probably, I should have focussed more on this before moving
> to dt support for other controllers.
> 
> But matching based on base address is still an option if that is
> better than matching with compatible values as defined currently. The
> 'struct samsung_gpio_chip' which encapsulates 'struct gpio_chip' has
> information about the base address of the gpio controller. The match
> of gpio device node with 'struct gpio_chip' can be quickly moved over
> to base address matching. Would this be better than the current
> approach?

That's what I would do.

g.

^ permalink raw reply

* [PATCH v2 2/5] tty/serial: atmel_serial: change platform_data variable name
From: Grant Likely @ 2011-10-13  1:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <58d65421a85737b7a25b967da09c3f564fc49be7.1318433947.git.nicolas.ferre@atmel.com>

On Wed, Oct 12, 2011 at 06:06:57PM +0200, Nicolas Ferre wrote:
> Easier to follow if platform_data name is pdata.
> 
> Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>

Acked-by: Grant Likely <grant.likely@secretlab.ca>

> ---
>  drivers/tty/serial/atmel_serial.c |   14 +++++++-------
>  1 files changed, 7 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
> index c7232a9..a507daa 100644
> --- a/drivers/tty/serial/atmel_serial.c
> +++ b/drivers/tty/serial/atmel_serial.c
> @@ -1417,13 +1417,13 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
>  				      struct platform_device *pdev)
>  {
>  	struct uart_port *port = &atmel_port->uart;
> -	struct atmel_uart_data *data = pdev->dev.platform_data;
> +	struct atmel_uart_data *pdata = pdev->dev.platform_data;
>  
>  	port->iotype		= UPIO_MEM;
>  	port->flags		= UPF_BOOT_AUTOCONF;
>  	port->ops		= &atmel_pops;
>  	port->fifosize		= 1;
> -	port->line		= data->num;
> +	port->line		= pdata->num;
>  	port->dev		= &pdev->dev;
>  	port->mapbase	= pdev->resource[0].start;
>  	port->irq	= pdev->resource[1].start;
> @@ -1433,9 +1433,9 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
>  
>  	memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring));
>  
> -	if (data->regs)
> +	if (pdata->regs)
>  		/* Already mapped by setup code */
> -		port->membase = data->regs;
> +		port->membase = pdata->regs;
>  	else {
>  		port->flags	|= UPF_IOREMAP;
>  		port->membase	= NULL;
> @@ -1450,9 +1450,9 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
>  		/* only enable clock when USART is in use */
>  	}
>  
> -	atmel_port->use_dma_rx = data->use_dma_rx;
> -	atmel_port->use_dma_tx = data->use_dma_tx;
> -	atmel_port->rs485	= data->rs485;
> +	atmel_port->use_dma_rx = pdata->use_dma_rx;
> +	atmel_port->use_dma_tx = pdata->use_dma_tx;
> +	atmel_port->rs485	= pdata->rs485;
>  	/* Use TXEMPTY for interrupt when rs485 else TXRDY or ENDTX|TXBUFE */
>  	if (atmel_port->rs485.flags & SER_RS485_ENABLED)
>  		atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
> -- 
> 1.7.5.4
> 

^ permalink raw reply

* [PATCH v2 1/5] tty/serial: RS485 bindings for device tree
From: Grant Likely @ 2011-10-13  1:02 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <37a19e194d02144aecd24f284f5e43979643a3c3.1318433947.git.nicolas.ferre@atmel.com>

On Wed, Oct 12, 2011 at 06:06:56PM +0200, Nicolas Ferre wrote:
> Generic bindings for RS485 feature included in some UARTs.
> Those bindings have to be used withing an UART device tree node.
> Documentation updated to link to the bindings definition.
> 
> Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>

Acked-by: Grant Likely <grant.likely@secretlab.ca>

> ---
>  Documentation/devicetree/bindings/serial/rs485.txt |   31 ++++++++++++++++++++
>  .../devicetree/bindings/tty/serial/atmel-usart.txt |   27 +++++++++++++++++
>  Documentation/serial/serial-rs485.txt              |    5 +++
>  3 files changed, 63 insertions(+), 0 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/serial/rs485.txt
>  create mode 100644 Documentation/devicetree/bindings/tty/serial/atmel-usart.txt
> 
> diff --git a/Documentation/devicetree/bindings/serial/rs485.txt b/Documentation/devicetree/bindings/serial/rs485.txt
> new file mode 100644
> index 0000000..1e753c6
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/serial/rs485.txt
> @@ -0,0 +1,31 @@
> +* RS485 serial communications
> +
> +The RTS signal is capable of automatically controlling line direction for
> +the built-in half-duplex mode.
> +The properties described hereafter shall be given to a half-duplex capable
> +UART node.
> +
> +Required properties:
> +- rs485-rts-delay: prop-encoded-array <a b> where:
> +  * a is the delay beteween rts signal and beginning of data sent in milliseconds.
> +      it corresponds to the delay before sending data.
> +  * b is the delay between end of data sent and rts signal in milliseconds
> +      it corresponds to the delay after sending data and actual release of the line.
> +
> +Optional properties:
> +- linux,rs485-enabled-at-boot-time: empty property telling to enable the rs485
> +  feature at boot time. It can be disabled later with proper ioctl.
> +- rs485-rx-during-tx: empty property that enables the receiving of data even
> +  whilst sending data.
> +
> +RS485 example for Atmel USART:
> +	usart0: serial at fff8c000 {
> +		compatible = "atmel,at91sam9260-usart";
> +		reg = <0xfff8c000 0x4000>;
> +		interrupts = <7>;
> +		atmel,use-dma-rx;
> +		atmel,use-dma-tx;
> +		linux,rs485-enabled-at-boot-time;
> +		rs485-rts-delay = <0 200>;		// in milliseconds
> +	};
> +
> diff --git a/Documentation/devicetree/bindings/tty/serial/atmel-usart.txt b/Documentation/devicetree/bindings/tty/serial/atmel-usart.txt
> new file mode 100644
> index 0000000..a49d9a1
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/tty/serial/atmel-usart.txt
> @@ -0,0 +1,27 @@
> +* Atmel Universal Synchronous Asynchronous Receiver/Transmitter (USART)
> +
> +Required properties:
> +- compatible: Should be "atmel,<chip>-usart"
> +  The compatible <chip> indicated will be the first SoC to support an
> +  additional mode or an USART new feature.
> +- reg: Should contain registers location and length
> +- interrupts: Should contain interrupt
> +
> +Optional properties:
> +- atmel,use-dma-rx: use of PDC or DMA for receiving data
> +- atmel,use-dma-tx: use of PDC or DMA for transmitting data
> +
> +<chip> compatible description:
> +- at91rm9200:  legacy USART support
> +- at91sam9260: generic USART implementation for SAM9 SoCs
> +
> +Example:
> +
> +	usart0: serial at fff8c000 {
> +		compatible = "atmel,at91sam9260-usart";
> +		reg = <0xfff8c000 0x4000>;
> +		interrupts = <7>;
> +		atmel,use-dma-rx;
> +		atmel,use-dma-tx;
> +	};
> +
> diff --git a/Documentation/serial/serial-rs485.txt b/Documentation/serial/serial-rs485.txt
> index c8878f8..079cb3d 100644
> --- a/Documentation/serial/serial-rs485.txt
> +++ b/Documentation/serial/serial-rs485.txt
> @@ -28,6 +28,10 @@
>     RS485 communications. This data structure is used to set and configure RS485
>     parameters in the platform data and in ioctls.
>  
> +   The device tree can also provide RS485 boot time parameters (see [2]
> +   for bindings). The driver is in charge of filling this data structure from
> +   the values given by the device tree.
> +
>     Any driver for devices capable of working both as RS232 and RS485 should
>     provide at least the following ioctls:
>  
> @@ -121,3 +125,4 @@
>  5. REFERENCES
>  
>   [1]	include/linux/serial.h
> + [2]	Documentation/devicetree/bindings/serial/rs485.txt
> -- 
> 1.7.5.4
> 

^ permalink raw reply

* [PATCH v2 3/5] tty/serial: atmel_serial: whitespace and braces modifications
From: Grant Likely @ 2011-10-13  1:02 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <e4c59e6f5ee33c1be57085ac0840b53322526367.1318433947.git.nicolas.ferre@atmel.com>

On Wed, Oct 12, 2011 at 06:06:58PM +0200, Nicolas Ferre wrote:
> Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>

Acked-by: Grant Likely <grant.likely@secretlab.ca>

> ---
>  drivers/tty/serial/atmel_serial.c |    9 +++++----
>  1 files changed, 5 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
> index a507daa..bb72354 100644
> --- a/drivers/tty/serial/atmel_serial.c
> +++ b/drivers/tty/serial/atmel_serial.c
> @@ -1433,10 +1433,10 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
>  
>  	memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring));
>  
> -	if (pdata->regs)
> +	if (pdata->regs) {
>  		/* Already mapped by setup code */
>  		port->membase = pdata->regs;
> -	else {
> +	} else {
>  		port->flags	|= UPF_IOREMAP;
>  		port->membase	= NULL;
>  	}
> @@ -1450,9 +1450,10 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
>  		/* only enable clock when USART is in use */
>  	}
>  
> -	atmel_port->use_dma_rx = pdata->use_dma_rx;
> -	atmel_port->use_dma_tx = pdata->use_dma_tx;
> +	atmel_port->use_dma_rx	= pdata->use_dma_rx;
> +	atmel_port->use_dma_tx	= pdata->use_dma_tx;
>  	atmel_port->rs485	= pdata->rs485;
> +
>  	/* Use TXEMPTY for interrupt when rs485 else TXRDY or ENDTX|TXBUFE */
>  	if (atmel_port->rs485.flags & SER_RS485_ENABLED)
>  		atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
> -- 
> 1.7.5.4
> 

^ permalink raw reply

* [PATCH v2 4/5] tty/serial: atmel_serial: auto-enumerate ports
From: Grant Likely @ 2011-10-13  1:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <ecef50a9b874d08bb46c0a12d1e4ad01e641d3d5.1318433947.git.nicolas.ferre@atmel.com>

On Wed, Oct 12, 2011 at 06:06:59PM +0200, Nicolas Ferre wrote:
> If no platform data provided to enumerate ports, use a bit field
> to choose port number and check if port is already initialized.
> Use this mechanism for both console and plain serial ports.
> 
> Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>

Acked-by: Grant Likely <grant.likely@secretlab.ca>

> ---
>  drivers/tty/serial/atmel_serial.c |   44 ++++++++++++++++++++++++++++++------
>  1 files changed, 36 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
> index bb72354..1074329 100644
> --- a/drivers/tty/serial/atmel_serial.c
> +++ b/drivers/tty/serial/atmel_serial.c
> @@ -157,6 +157,7 @@ struct atmel_uart_port {
>  };
>  
>  static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART];
> +static unsigned long atmel_ports_in_use;
>  
>  #ifdef SUPPORT_SYSRQ
>  static struct console atmel_console;
> @@ -1423,7 +1424,6 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
>  	port->flags		= UPF_BOOT_AUTOCONF;
>  	port->ops		= &atmel_pops;
>  	port->fifosize		= 1;
> -	port->line		= pdata->num;
>  	port->dev		= &pdev->dev;
>  	port->mapbase	= pdev->resource[0].start;
>  	port->irq	= pdev->resource[1].start;
> @@ -1613,10 +1613,15 @@ static struct console atmel_console = {
>  static int __init atmel_console_init(void)
>  {
>  	if (atmel_default_console_device) {
> -		add_preferred_console(ATMEL_DEVICENAME,
> -				      atmel_default_console_device->id, NULL);
> -		atmel_init_port(&atmel_ports[atmel_default_console_device->id],
> -				atmel_default_console_device);
> +		int id = atmel_default_console_device->id;
> +		struct atmel_uart_port *port = &atmel_ports[id];
> +
> +		set_bit(id, &atmel_ports_in_use);
> +		port->backup_imr = 0;
> +		port->uart.line = id;
> +
> +		add_preferred_console(ATMEL_DEVICENAME, id, NULL);
> +		atmel_init_port(port, atmel_default_console_device);
>  		register_console(&atmel_console);
>  	}
>  
> @@ -1715,12 +1720,33 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev)
>  	struct atmel_uart_port *port;
>  	struct atmel_uart_data *pdata = pdev->dev.platform_data;
>  	void *data;
> -	int ret;
> +	int ret = -ENODEV;
>  
>  	BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1));
>  
> -	port = &atmel_ports[pdata->num];
> +	if (pdata)
> +		ret = pdata->num;
> +
> +	if (ret < 0)
> +		/* port id not found in platform data:
> +		 * auto-enumerate it */
> +		ret = find_first_zero_bit(&atmel_ports_in_use,
> +				sizeof(atmel_ports_in_use));
> +
> +	if (ret > ATMEL_MAX_UART) {
> +		ret = -ENODEV;
> +		goto err;
> +	}
> +
> +	if (test_and_set_bit(ret, &atmel_ports_in_use)) {
> +		/* port already in use */
> +		ret = -EBUSY;
> +		goto err;
> +	}
> +
> +	port = &atmel_ports[ret];
>  	port->backup_imr = 0;
> +	port->uart.line = ret;
>  
>  	atmel_init_port(port, pdev);
>  
> @@ -1766,7 +1792,7 @@ err_alloc_ring:
>  		clk_put(port->clk);
>  		port->clk = NULL;
>  	}
> -
> +err:
>  	return ret;
>  }
>  
> @@ -1786,6 +1812,8 @@ static int __devexit atmel_serial_remove(struct platform_device *pdev)
>  
>  	/* "port" is allocated statically, so we shouldn't free it */
>  
> +	clear_bit(port->line, &atmel_ports_in_use);
> +
>  	clk_put(atmel_port->clk);
>  
>  	return ret;
> -- 
> 1.7.5.4
> 

^ permalink raw reply

* [PATCH] [RESEND]  ARM: tegra: devices.c should include devices.h
From: Olof Johansson @ 2011-10-13  1:03 UTC (permalink / raw)
  To: linux-arm-kernel

Resolves lots of sparse warnings:

arch/arm/mach-tegra/devices.c:102:24: warning: symbol 'tegra_i2c_device1' was not declared. Should it be static?
arch/arm/mach-tegra/devices.c:112:24: warning: symbol 'tegra_i2c_device2' was not declared. Should it be static?
arch/arm/mach-tegra/devices.c:122:24: warning: symbol 'tegra_i2c_device3' was not declared. Should it be static?
arch/arm/mach-tegra/devices.c:132:24: warning: symbol 'tegra_i2c_device4' was not declared. Should it be static?
[...]

Signed-off-by: Olof Johansson <olof@lixom.net>
---

One of these days I will learn to not typo on the mailing list addresses
for git send-email. Sigh.

 arch/arm/mach-tegra/devices.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-tegra/devices.c b/arch/arm/mach-tegra/devices.c
index 240d5dc..7a2a02d 100644
--- a/arch/arm/mach-tegra/devices.c
+++ b/arch/arm/mach-tegra/devices.c
@@ -29,7 +29,9 @@
 #include <mach/iomap.h>
 #include <mach/dma.h>
 #include <mach/usb_phy.h>
+
 #include "gpio-names.h"
+#include "devices.h"
 
 static struct resource gpio_resource[] = {
 	[0] = {
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH v2 5/5] tty/serial: atmel_serial: add device tree support
From: Grant Likely @ 2011-10-13  1:04 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <46ce59e472d36715d8bed57570d2b7747323f4d4.1318433947.git.nicolas.ferre@atmel.com>

On Wed, Oct 12, 2011 at 06:07:00PM +0200, Nicolas Ferre wrote:
> Will use aliases to enumerate ports, if available.
> 
> Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>

Acked-by: Grant Likely <grant.likely@secretlab.ca>

> ---
>  drivers/tty/serial/atmel_serial.c |   79 +++++++++++++++++++++++++++++++++----
>  1 files changed, 71 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
> index 1074329..fc4081e 100644
> --- a/drivers/tty/serial/atmel_serial.c
> +++ b/drivers/tty/serial/atmel_serial.c
> @@ -33,6 +33,8 @@
>  #include <linux/sysrq.h>
>  #include <linux/tty_flip.h>
>  #include <linux/platform_device.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
>  #include <linux/dma-mapping.h>
>  #include <linux/atmel_pdc.h>
>  #include <linux/atmel_serial.h>
> @@ -163,6 +165,16 @@ static unsigned long atmel_ports_in_use;
>  static struct console atmel_console;
>  #endif
>  
> +#if defined(CONFIG_OF)
> +static const struct of_device_id atmel_serial_dt_ids[] = {
> +	{ .compatible = "atmel,at91rm9200-usart" },
> +	{ .compatible = "atmel,at91sam9260-usart" },
> +	{ /* sentinel */ }
> +};
> +
> +MODULE_DEVICE_TABLE(of, atmel_serial_dt_ids);
> +#endif
> +
>  static inline struct atmel_uart_port *
>  to_atmel_uart_port(struct uart_port *uart)
>  {
> @@ -1411,6 +1423,48 @@ static struct uart_ops atmel_pops = {
>  #endif
>  };
>  
> +static void __devinit atmel_of_init_port(struct atmel_uart_port *atmel_port,
> +					 struct device_node *np)
> +{
> +	u32 rs485_delay[2];
> +
> +	/* DMA/PDC usage specification */
> +	if (of_get_property(np, "atmel,use-dma-rx", NULL))
> +		atmel_port->use_dma_rx	= 1;
> +	else
> +		atmel_port->use_dma_rx	= 0;
> +	if (of_get_property(np, "atmel,use-dma-tx", NULL))
> +		atmel_port->use_dma_tx	= 1;
> +	else
> +		atmel_port->use_dma_tx	= 0;
> +
> +	/* rs485 properties */
> +	if (of_property_read_u32_array(np, "rs485-rts-delay",
> +					    rs485_delay, 2) == 0) {
> +		struct serial_rs485 *rs485conf = &atmel_port->rs485;
> +
> +		rs485conf->delay_rts_before_send = rs485_delay[0];
> +		rs485conf->delay_rts_after_send = rs485_delay[1];
> +		rs485conf->flags = 0;
> +
> +		if (rs485conf->delay_rts_before_send == 0 &&
> +		    rs485conf->delay_rts_after_send == 0) {
> +			rs485conf->flags |= SER_RS485_RTS_ON_SEND;
> +		} else {
> +			if (rs485conf->delay_rts_before_send)
> +				rs485conf->flags |= SER_RS485_RTS_BEFORE_SEND;
> +			if (rs485conf->delay_rts_after_send)
> +				rs485conf->flags |= SER_RS485_RTS_AFTER_SEND;
> +		}
> +
> +		if (of_get_property(np, "rs485-rx-during-tx", NULL))
> +			rs485conf->flags |= SER_RS485_RX_DURING_TX;
> +
> +		if (of_get_property(np, "linux,rs485-enabled-at-boot-time", NULL))
> +			rs485conf->flags |= SER_RS485_ENABLED;
> +	}
> +}
> +
>  /*
>   * Configure the port from the platform device resource info.
>   */
> @@ -1420,6 +1474,14 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
>  	struct uart_port *port = &atmel_port->uart;
>  	struct atmel_uart_data *pdata = pdev->dev.platform_data;
>  
> +	if (pdev->dev.of_node) {
> +		atmel_of_init_port(atmel_port, pdev->dev.of_node);
> +	} else {
> +		atmel_port->use_dma_rx	= pdata->use_dma_rx;
> +		atmel_port->use_dma_tx	= pdata->use_dma_tx;
> +		atmel_port->rs485	= pdata->rs485;
> +	}
> +
>  	port->iotype		= UPIO_MEM;
>  	port->flags		= UPF_BOOT_AUTOCONF;
>  	port->ops		= &atmel_pops;
> @@ -1433,7 +1495,7 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
>  
>  	memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring));
>  
> -	if (pdata->regs) {
> +	if (pdata && pdata->regs) {
>  		/* Already mapped by setup code */
>  		port->membase = pdata->regs;
>  	} else {
> @@ -1450,10 +1512,6 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
>  		/* only enable clock when USART is in use */
>  	}
>  
> -	atmel_port->use_dma_rx	= pdata->use_dma_rx;
> -	atmel_port->use_dma_tx	= pdata->use_dma_tx;
> -	atmel_port->rs485	= pdata->rs485;
> -
>  	/* Use TXEMPTY for interrupt when rs485 else TXRDY or ENDTX|TXBUFE */
>  	if (atmel_port->rs485.flags & SER_RS485_ENABLED)
>  		atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
> @@ -1718,17 +1776,21 @@ static int atmel_serial_resume(struct platform_device *pdev)
>  static int __devinit atmel_serial_probe(struct platform_device *pdev)
>  {
>  	struct atmel_uart_port *port;
> +	struct device_node *np = pdev->dev.of_node;
>  	struct atmel_uart_data *pdata = pdev->dev.platform_data;
>  	void *data;
>  	int ret = -ENODEV;
>  
>  	BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1));
>  
> -	if (pdata)
> -		ret = pdata->num;
> +	if (np)
> +		ret = of_alias_get_id(np, "serial");
> +	else
> +		if (pdata)
> +			ret = pdata->num;
>  
>  	if (ret < 0)
> -		/* port id not found in platform data:
> +		/* port id not found in platform data nor device-tree aliases:
>  		 * auto-enumerate it */
>  		ret = find_first_zero_bit(&atmel_ports_in_use,
>  				sizeof(atmel_ports_in_use));
> @@ -1827,6 +1889,7 @@ static struct platform_driver atmel_serial_driver = {
>  	.driver		= {
>  		.name	= "atmel_usart",
>  		.owner	= THIS_MODULE,
> +		.of_match_table	= of_match_ptr(atmel_serial_dt_ids),
>  	},
>  };
>  
> -- 
> 1.7.5.4
> 

^ permalink raw reply

* [PATCH v6 10/16] OMAP2+: UART: Modify omap_uart_can_sleep function
From: Govindraj @ 2011-10-13  1:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <87wrcangkq.fsf@ti.com>

On Thu, Oct 13, 2011 at 1:11 AM, Kevin Hilman <khilman@ti.com> wrote:
> Govindraj <govindraj.ti@gmail.com> writes:
>
>> On Tue, Oct 11, 2011 at 11:54 PM, Kevin Hilman <khilman@ti.com> wrote:
>>> "Govindraj.R" <govindraj.raja@ti.com> writes:
>>>
>>>> Modify the omap_uart_can_sleep function to check uart is active
>>>> or not to be used by pm code to enter low power states.
>>>
>>> Doesn't the driver now control when the UART clocks are gated (using
>>> runtime PM autosuspend)?
>>>
>>> IMO, this check should be completely removed and the driver should
>>> be managing this with the autosuspend timeout.
>>>
>>>> Removing this check can cause console response little sluggish.
>>>
>>> Sluggish in what way?
>>>
>>
>> response is slower like when we type something or cat debugfs/pm_count
>> see things little slower on console, there is no character loss.
>>
>> Happens even though we have not set the autosuspend timeout and uart
>> clocks are active, which basically means allowing mpu to enter
>> retention keeping uart active.
>
> OK, I see now.
>
>> this delay in response or sluggishness is not there on my 3430SDP or
>> 3630zoom board but I was able to see this behavior on a beagle
>> board(xm rev c).
>
> Here's why:
>
> The difference is the powerdomain that the console UART is on for these
> boards. ?UART1,2 are in CORE, UART2/3 are in PER. ? SDP uses UART1 (CORE),
> Zoom3 doesn't use OMAP UARTs at all, and Beagle uses UART3 (PER).
>
> Due to a HW sleepdep between MPU and CORE, MPU will not transition until
> CORE does, which means MPU will not transition until UART 1 & 2 are
> idle.
>
> On Beagle, the console is ttyO2 (UART3) which is in PER, and since the
> MPU is free to transition independently of PER, that is what is
> happening, resulting in slower response time on for any boards that have
> PER-UART consoles.
>
>> retaining this uart_can_sleep check in omap3_can_sleep ensures a better
>> console user experience. (not allowing mpu to enter retention
>> until uart clocks are cut)
>
> Yes, but obviously comes at the expense of power savings. ?IOW, This is
> a hard-coded power vs. performance trade off that we are trying to get
> away from.
>
> So, the root of the problem is that the MPU wakeup latency is causing a
> "sluggish" console. ?The solution? ?request an MPU wakeup latency
> constraint.
>

Okay, Will explore this.

> This is a classic use-case for such a constraint, and the serial driver
> should have the option of requesting a constraint to prevent the sluggish
> console. ?The constraint only needs to be held until the auto-suspend
> delay expires, so should be relased in the ->runtime_suspend() method of
> the driver.
>
> This constraint needs to be configurable, probably from the board file,
> so that it is optional, and so users who don't care about sluggish
> consoles (or non-console UART users who don't care about response time)
> have the option of preferring power savings over UART responsiveness.
>
> As a reference, the i2c driver is currently doing something similar
> in that it request an MPU constraint to prevent the MPU from going into
> retention/off while waiting for an i2c interrupt to arrive.
>

Thanks, will check and try to use the mpu constraints

--
Govindraj.R.

^ 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