Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2] dma: imx-sdma: clarify firmare not found warning
From: Sascha Hauer @ 2014-01-20 10:07 UTC (permalink / raw)
  To: linux-arm-kernel

When a firmware cannot be found for the SDMA engine then we can
continue with the inernal ROM firmware.

The meaning of this message is frequently asked for, so make clear
that the driver still works with the internal ROM firmware and reduce
the loglevel from err to info.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Cc: Vinod Koul <vinod.koul@intel.com>
Cc: linux-arm-kernel at lists.infradead.org
Cc: Shawn Guo <shawn.guo@linaro.org>
---

changes since v1:
- instead of removing the message make it more clear

 drivers/dma/imx-sdma.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index c75679d..d79eaad 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -1259,7 +1259,10 @@ static void sdma_load_firmware(const struct firmware *fw, void *context)
 	unsigned short *ram_code;
 
 	if (!fw) {
-		dev_err(sdma->dev, "firmware not found\n");
+		dev_info(sdma->dev, "external firmware not found, using ROM firmware\n");
+		/*
+		 * In this case we just use the ROM firmware.
+		 */
 		return;
 	}
 
-- 
1.8.5.2

^ permalink raw reply related

* [PATCH] dma: imx-sdma: remove firmare not found warning
From: Sascha Hauer @ 2014-01-20 10:07 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140120074205.GG26823@intel.com>

On Mon, Jan 20, 2014 at 01:12:05PM +0530, Vinod Koul wrote:
> On Thu, Jan 16, 2014 at 04:46:26PM +0100, Sascha Hauer wrote:
> > When a firmware cannot be found for the SDMA engine then we can
> > continue with the inernal ROM firmware.
> typo		    ^^^^^^^
> 
> > The meaning of this message is frequently asked for and the usual
> > answer is that this message is of no relevance, so just make it
> > dev_dbg() and do not alienate the users anymore.
> > 
> > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> > Cc: Vinod Koul <vinod.koul@intel.com>
> > ---
> >  drivers/dma/imx-sdma.c | 5 ++++-
> >  1 file changed, 4 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
> > index c75679d..fe57a42 100644
> > --- a/drivers/dma/imx-sdma.c
> > +++ b/drivers/dma/imx-sdma.c
> > @@ -1259,7 +1259,10 @@ static void sdma_load_firmware(const struct firmware *fw, void *context)
> >  	unsigned short *ram_code;
> >  
> >  	if (!fw) {
> > -		dev_err(sdma->dev, "firmware not found\n");
> > +		dev_dbg(sdma->dev, "firmware not found\n");
> Shouldn't this be dev_info and would amke sense, external firmware not found
> using internal one??

Yeah, sounds better. See v2.

Sascha

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

^ permalink raw reply

* [PATCH v2] dma: fix vchan_cookie_complete() debug print
From: Vinod Koul @ 2014-01-20 10:00 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1386581123-4706-1-git-send-email-jonas.jensen@gmail.com>

On Mon, Dec 09, 2013 at 10:25:23AM +0100, Jonas Jensen wrote:
> vchan_cookie_complete() is supposed to print the cookie value
> but it's always zero because:
> 
> dma_cookie_complete() is called prior to dev_vdbg()
> 
> Move the call, place it after dev_vdbg().
> 
> Signed-off-by: Jonas Jensen <jonas.jensen@gmail.com>
Applied, thanks

--
~Vinod
> ---
> 
> Notes:
>     Changes since v1:
>     
>     1. remove local dma_cookie_t
>     2. call dma_cookie_complete() after dev_vdbg()
>     
>     Applies to next-20131209
> 
>  drivers/dma/virt-dma.h | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/dma/virt-dma.h b/drivers/dma/virt-dma.h
> index 85c19d6..7d6f611 100644
> --- a/drivers/dma/virt-dma.h
> +++ b/drivers/dma/virt-dma.h
> @@ -85,9 +85,9 @@ static inline void vchan_cookie_complete(struct virt_dma_desc *vd)
>  {
>  	struct virt_dma_chan *vc = to_virt_chan(vd->tx.chan);
>  
> -	dma_cookie_complete(&vd->tx);
>  	dev_vdbg(vc->chan.device->dev, "txd %p[%x]: marked complete\n",
>  		vd, vd->tx.cookie);
> +	dma_cookie_complete(&vd->tx);
>  	list_add_tail(&vd->node, &vc->desc_completed);
>  
>  	tasklet_schedule(&vc->task);
> -- 
> 1.8.2.1
> 

-- 

^ permalink raw reply

* [PATCH] dma: fix vchan_cookie_complete() debug print
From: Vinod Koul @ 2014-01-20  9:59 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1386344529-25617-1-git-send-email-jonas.jensen@gmail.com>

On Fri, Dec 06, 2013 at 04:42:09PM +0100, Jonas Jensen wrote:
> vd->tx.cookie is set zero on dma_cookie_complete(),
> save to local before printing it.
> 
> Signed-off-by: Jonas Jensen <jonas.jensen@gmail.com>
> ---
> 
> Notes:
>     dev_vdbg() could also be moved to happen earlier, what do you prefer?
This would be preferred IMHO. Also pls cc dmaengine at vger on this

--
~Vinod
>     
>     Applies to next-20131206
> 
>  drivers/dma/virt-dma.h | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/dma/virt-dma.h b/drivers/dma/virt-dma.h
> index 85c19d6..181b9526 100644
> --- a/drivers/dma/virt-dma.h
> +++ b/drivers/dma/virt-dma.h
> @@ -84,10 +84,12 @@ static inline bool vchan_issue_pending(struct virt_dma_chan *vc)
>  static inline void vchan_cookie_complete(struct virt_dma_desc *vd)
>  {
>  	struct virt_dma_chan *vc = to_virt_chan(vd->tx.chan);
> +	dma_cookie_t cookie;
>  
> +	cookie = vd->tx.cookie;
>  	dma_cookie_complete(&vd->tx);
>  	dev_vdbg(vc->chan.device->dev, "txd %p[%x]: marked complete\n",
> -		vd, vd->tx.cookie);
> +		 vd, cookie);
>  	list_add_tail(&vd->node, &vc->desc_completed);
>  
>  	tasklet_schedule(&vc->task);
> -- 
> 1.8.2.1
> 

-- 

^ permalink raw reply

* [RFC v3 08/13] ahci-platform: Allow specifying platform_data through of_device_id
From: Sascha Hauer @ 2014-01-20  9:57 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <52DCE9A4.50901@redhat.com>

On Mon, Jan 20, 2014 at 10:17:24AM +0100, Hans de Goede wrote:
> Hi,
> 
> I'm currently working on a slightly different implementation of a more
> generic ahci_platform.c where ahci_platform.c exports some standard platform
> related functionality as library functions.
> 
> Drivers which need to override some of ahci_platform.c's behavior because of
> non standard hw, will then export their own struct platform_driver and can
> call into the exported functions for standard stuff to avoid code duplication
> where appropriate, while still having 100% freedom to do things in a custom
> way where necessary.

Nice, thanks.

> 
> I hope to post a PATCH RFC v4 with these changes later today, which you will
> hopefully like better. Input on v4, even just a "yep better" remark would be
> much appreciated.

Yes, I will give feedback on v4.

Sascha

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

^ permalink raw reply

* [PATCH 0/2] DT updates for Hummingboard and new Cubox-i
From: Russell King - ARM Linux @ 2014-01-20  9:55 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAOesGMiych-jeo_eKGgL1qxsYQ=rkb4UQwgGBsG-7+GMbLJWhg@mail.gmail.com>

On Sun, Jan 19, 2014 at 07:34:22PM -0800, Olof Johansson wrote:
> I'm guessing this is going to mess up Shawn's cleanup patches, but
> time has ran out for 3.14 for those so they will need to be respun
> anyway, most likely.
> 
> We can apply them to arm-soc's dt branch. I think it's better if we
> merge them since dts files tend to be one of the conflict-ridden areas
> (even if this particular instance isn't). Send the series our way if
> you want, or send a branch pull request, your choice.

There's no conflict, and they build fine according to my autobuilder
which includes arm-soc for-next.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

^ permalink raw reply

* [PATCH v3 16/24] drm/i2c: tda998x: add DT documentation
From: Jean-Francois Moine @ 2014-01-20  9:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAOesGMi96wkHM8jfHNVnM7RJyW2vVoP6FT4YyYzKp-kfc0jTuQ@mail.gmail.com>

On Sun, 19 Jan 2014 20:06:09 -0800
Olof Johansson <olof@lixom.net> wrote:

> Hi,
> 
> On Sun, Jan 19, 2014 at 10:58 AM, Jean-Francois Moine <moinejf@free.fr> wrote:
> > Signed-off-by: Jean-Francois Moine <moinejf@free.fr>
> > ---
> >  .../devicetree/bindings/drm/i2c/tda998x.txt        | 24 ++++++++++++++++++++++
> >  1 file changed, 24 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/drm/i2c/tda998x.txt
> 
> Please cc bindings for review to devicetree at vger.kernel.org (cc:d here now)
> 
> > diff --git a/Documentation/devicetree/bindings/drm/i2c/tda998x.txt b/Documentation/devicetree/bindings/drm/i2c/tda998x.txt
> > new file mode 100644
> > index 0000000..72da71d
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/drm/i2c/tda998x.txt
> > @@ -0,0 +1,24 @@
> > +Device-Tree bindings for the NXP TDA998x HDMI transmitter
> > +
> > +Required properties;
> > +  - compatible: must be "nxp,tda998x"
> > +
> > +Optional properties:
> > +  - interrupts: interrupt number for HDMI exchanges - default: by polling
> 
> What are HDMI exchanges, and how do they differ from other interrupts?

The used HDMI interrupt events are screen plug/unplug and EDID read.
There are also CEC read/write which are not yet implemented in the
tda998x driver.

There is no difference from normal interrupts, except that the events
may be get by polling, so, the interrupt number is optional.

> > +
> > +  - pinctrl-0: pin control group to be used for this controller (IRQ).
> > +
> > +  - pinctrl-names: must contain a "default" entry.
> > +
> > +  - video-ports: 24 bits value - default: <0x230145>
> 
> What is this?

The video-ports value defines how the video controller is connected to
the tda998x chip. Each 4 bits value tells from which input pins comes
the video data and if there is any bit inversion. Each byte of this
video-ports is used to load the VIP_CNTRL_{0,1,2} registers. These ones
are described in the TDA9983B documentation which is the closer
available document about the TDA998x family.

The default value is the one defined for TI boards.
A known other value is <0x234501> which is used for Russell's Armada
DRM driver in the Cubox (Marvell A510), but this driver has no DT
support.

-- 
Ken ar c'henta?	|	      ** Breizh ha Linux atav! **
Jef		|		http://moinejf.free.fr/

^ permalink raw reply

* [PATCHv10 2/2] dma: Add Freescale eDMA engine driver support
From: Vinod Koul @ 2014-01-20  9:35 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <43d79ce905e24e9bb58ef49ac19db7d7@BL2PR03MB467.namprd03.prod.outlook.com>

On Mon, Jan 20, 2014 at 09:06:43AM +0000, Jingchang Lu wrote:
> 
> 
> > -----Original Message-----
> > From: Vinod Koul [mailto:vinod.koul at intel.com]
> > Sent: Monday, January 20, 2014 3:40 PM
> > To: Lu Jingchang-B35083
> > Cc: dan.j.williams at intel.com; arnd at arndb.de; shawn.guo at linaro.org;
> > pawel.moll at arm.com; mark.rutland at arm.com; swarren at wwwdotorg.org; linux-
> > kernel at vger.kernel.org; linux-arm-kernel at lists.infradead.org;
> > devicetree at vger.kernel.org; Wang Huan-B18965
> > Subject: Re: [PATCHv10 2/2] dma: Add Freescale eDMA engine driver support
> > 
> > On Fri, Jan 17, 2014 at 02:04:44PM +0800, Jingchang Lu wrote:
> > > Add Freescale enhanced direct memory(eDMA) controller support.
> > > This module can be found on Vybrid and LS-1 SoCs.
> > >
> > > Signed-off-by: Alison Wang <b18965@freescale.com>
> > > Signed-off-by: Jingchang Lu <b35083@freescale.com>
> > > Acked-by: Arnd Bergmann <arnd@arndb.de>
> > > ---
> > 
> > > +static int fsl_edma_control(struct dma_chan *chan, enum dma_ctrl_cmd
> > cmd,
> > > +		unsigned long arg)
> > > +{
> > > +	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
> > > +	struct dma_slave_config *cfg = (void *)arg;
> > > +	unsigned long flags;
> > > +	LIST_HEAD(head);
> > > +
> > > +	switch (cmd) {
> > > +	case DMA_TERMINATE_ALL:
> > > +		spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
> > > +		fsl_edma_disable_request(fsl_chan);
> > > +		fsl_chan->edesc = NULL;
> > > +		vchan_get_all_descriptors(&fsl_chan->vchan, &head);
> > > +		spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
> > > +		vchan_dma_desc_free_list(&fsl_chan->vchan, &head);
> > > +		return 0;
> > well what happens to the current ongoing transactions, i don't see those
> > getting
> > terminated?
> The fsl_edma_disable_request(fsl_chan) would end the channel's ongoing transaction, then
> the eDMA would not response to device dma request, and the vchan_dma_desc_free_list()
> will release all associate memory. Thanks.
Can you explain a bit more how terminate will happen, given taht you are using
same thing for pause?

> > 
> > > +
> > > +	case DMA_SLAVE_CONFIG:
> > > +		fsl_chan->fsc.dir = cfg->direction;
> > > +		if (cfg->direction == DMA_DEV_TO_MEM) {
> > > +			fsl_chan->fsc.dev_addr = cfg->src_addr;
> > > +			fsl_chan->fsc.addr_width = cfg->src_addr_width;
> > > +			fsl_chan->fsc.burst = cfg->src_maxburst;
> > > +			fsl_chan->fsc.attr = fsl_edma_get_tcd_attr(cfg-
> > >src_addr_width);
> > > +		} else if (cfg->direction == DMA_MEM_TO_DEV) {
> > > +			fsl_chan->fsc.dev_addr = cfg->dst_addr;
> > > +			fsl_chan->fsc.addr_width = cfg->dst_addr_width;
> > > +			fsl_chan->fsc.burst = cfg->dst_maxburst;
> > > +			fsl_chan->fsc.attr = fsl_edma_get_tcd_attr(cfg-
> > >dst_addr_width);
> > okay atrr is address width, why not save this standard struct instead?
> The value saved in fsc.attr is transferred by fsl_edma_get_tcd_attr(), it can
> be set into the channel control register later directly. the edma driver doesn't
> need to save all dma_slave_config parameters, so it only gets the necessaries.
Okay then this apprach looks okay

> > > +		} else {
> > > +			return -EINVAL;
> > > +		}
> > > +		return 0;
> > > +
> > > +	case DMA_PAUSE:
> > > +		spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
> > > +		if (fsl_chan->edesc) {
> > > +			fsl_edma_disable_request(fsl_chan);
> > > +			fsl_chan->status = DMA_PAUSED;
> > > +		}
> > > +		spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
> > > +		return 0;
> > > +
> > > +	case DMA_RESUME:
> > > +		spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
> > > +		if (fsl_chan->edesc) {
> > > +			fsl_edma_enable_request(fsl_chan);
> > > +			fsl_chan->status = DMA_IN_PROGRESS;
> > > +		}
> > > +		spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
> > > +		return 0;
> > > +
> > > +	default:
> > > +		return -ENXIO;
> > > +	}
> > > +}
> > > +
> > 
> > > +static struct fsl_edma_desc *fsl_edma_alloc_desc(struct fsl_edma_chan
> > *fsl_chan,
> > > +		int sg_len)
> > > +{
> > > +	struct fsl_edma_desc *fsl_desc;
> > > +	int i;
> > > +
> > > +	fsl_desc = kzalloc(sizeof(*fsl_desc) + sizeof(struct
> > fsl_edma_sw_tcd) * sg_len,
> > > +				GFP_NOWAIT);
> > > +	if (!fsl_desc)
> > > +		return NULL;
> > > +
> > > +	fsl_desc->echan = fsl_chan;
> > > +	fsl_desc->n_tcds = sg_len;
> > > +	for (i = 0; i < sg_len; i++) {
> > > +		fsl_desc->tcd[i].vtcd = dma_pool_alloc(fsl_chan->tcd_pool,
> > > +					GFP_NOWAIT, &fsl_desc->tcd[i].ptcd);
> > > +		if (!fsl_desc->tcd[i].vtcd)
> > > +			goto err;
> > > +	}
> > > +	return fsl_desc;
> > > +
> > > +err:
> > > +	while (--i >= 0)
> > > +		dma_pool_free(fsl_chan->tcd_pool, fsl_desc->tcd[i].vtcd,
> > > +				fsl_desc->tcd[i].ptcd);
> > > +	kfree(fsl_desc);
> > > +	return NULL;
> > > +}
> > > +
> > > +static struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic(
> > > +		struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
> > > +		size_t period_len, enum dma_transfer_direction direction,
> > > +		unsigned long flags, void *context)
> > > +{
> > you may want to implement the capablities api subsequently for audio
> > usage.
> Do you mean the device_slave_caps function? If it is, I will add it.
Yes, that can be incrementally added..

-- 

^ permalink raw reply

* [PATCH v4] dmaengine: sirf: enable generic dt binding for dma channels
From: Barry Song @ 2014-01-20  9:35 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140120074857.GJ26823@intel.com>

2014/1/20 Vinod Koul <vinod.koul@intel.com>:
> On Wed, Jan 08, 2014 at 10:12:49PM +0800, Barry Song wrote:
>> From: Barry Song <Baohua.Song@csr.com>
>>
>> move to support of_dma_request_slave_channel() and dma_request_slave_channel.
>> we add a xlate() to let dma clients be able to find right dma_chan by generic
>> "dmas" properties in dts.
>>
>> Cc: Mark Rutland <mark.rutland@arm.com>
>> Cc: Lars-Peter Clausen <lars@metafoo.de>
>> Signed-off-by: Barry Song <Baohua.Song@csr.com>
> Look okay, need an ACk from DT maintainers before I can apply...

Vinod, will i send v5 with your ack to
devicetree-discuss at lists.ozlabs.org, and CC Grant & Rob?

Hi Rob, will you Ack this one if you have noticed this thread?

>
> --
> ~Vinod
>> ---
>>  -v4: clear dt-binding document according to Mark's feedback

-barry

^ permalink raw reply

* [PATCH 01/20] ARM64 / ACPI: Make PCI optional for ACPI on ARM64
From: Hanjun Guo @ 2014-01-20  9:33 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAErSpo6tsZtqFfgBp9mwU9Ln7yDmKLWJFKK8eW9_m4Sgb=E3eg@mail.gmail.com>

On 2014-1-18 0:00, Bjorn Helgaas wrote:
> [+cc Jens, James, Ben, Fujita (authors of PCI_DMA_BUS_IS_PHYS usage)]
> 
> On Fri, Jan 17, 2014 at 5:24 AM, Hanjun Guo <hanjun.guo@linaro.org> wrote:
>> Not all the ARM64 targets that are using ACPI have PCI, so introduce
>> some stub functions to make PCI optional for ACPI, and make ACPI core
>> run without CONFIG_PCI on ARM64.
>>
>> pcibios_penalize_isa_irq() is arch dependent, introduce asm/pci.h to
>> include it.
>>
>> Since ACPI on X86 and IA64 depends on PCI, it will not break X86 and
>> IA64 with this patch.
>>
>> Signed-off-by: Graeme Gregory <graeme.gregory@linaro.org>
>> Signed-off-by: Al Stone <al.stone@linaro.org>
>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>> ---
>>  arch/arm64/include/asm/pci.h |   20 ++++++++++++++++++++
>>  drivers/acpi/Makefile        |    2 +-
>>  drivers/acpi/internal.h      |    7 +++++++
>>  drivers/acpi/osl.c           |    3 ++-
>>  include/linux/pci.h          |   33 ++++++++++++++++++++++++---------
>>  5 files changed, 54 insertions(+), 11 deletions(-)
>>  create mode 100644 arch/arm64/include/asm/pci.h
>>
>> diff --git a/arch/arm64/include/asm/pci.h b/arch/arm64/include/asm/pci.h
>> new file mode 100644
>> index 0000000..455909d
>> --- /dev/null
>> +++ b/arch/arm64/include/asm/pci.h
>> @@ -0,0 +1,20 @@
>> +#ifndef __ASMARM64_PCI_H
>> +#define __ASMARM64_PCI_H
>> +
>> +#ifdef __KERNEL__
>> +
>> +static inline void pcibios_penalize_isa_irq(int irq, int active)
>> +{
>> +       /* We don't do dynamic PCI IRQ allocation */
>> +}
>> +
>> +/*
>> + * The PCI address space does equal the physical memory address space.
>> + * The networking and block device layers use this boolean for bounce
>> + * buffer decisions.
>> + */
>> +#define PCI_DMA_BUS_IS_PHYS     (1)
> 
> I'm not sure this is accurate.  The arm code uses
> pci_add_resource_offset() with non-zero offsets, which means a
> physical memory address is not the same as a PCI bus address.  I don't
> know what arm64 does for PCI, but I suspect it is similar.

I'm not sure either. I copied this code from arm/asm/pci.h and I
thought it will be the same for ARM64.

> 
> I think PCI_DMA_BUS_IS_PHYS is due for some overhaul.  I'm dubious
> that it is working as intended anymore.  At the very least, it seems
> like something that is dependent on the device in question.
> 
>> diff --git a/include/linux/pci.h b/include/linux/pci.h
>> index a13d682..726cf2a 100644
>> --- a/include/linux/pci.h
>> +++ b/include/linux/pci.h
>> ...
>> +static inline int raw_pci_read(unsigned int domain, unsigned int bus,
>> +               unsigned int devfn, int reg, int len, u32 *val)
>> +{ return -EINVAL; }
>> +
>> +static inline int raw_pci_write(unsigned int domain, unsigned int bus,
>> +               unsigned int devfn, int reg, int len, u32 val)
>> +{return -EINVAL; }
> 
> Fix the spacing here (missing a space before "return").
> 
> With that, this include/linux/pci.h change is:
> 
> Acked-by: Bjorn Helgaas <bhelgaas@google.com>

Thanks!

Hanjun

^ permalink raw reply

* [PATCH 07/20] ARM64 / ACPI: Enable ARM64 in Kconfig
From: Hanjun Guo @ 2014-01-20  9:30 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <52D93F88.8090801@arm.com>

On 2014-1-17 22:34, Sudeep Holla wrote:
> On 17/01/14 12:25, Hanjun Guo wrote:
>> Add Kconfigs to build ACPI on ARM64, and make ACPI runable on ARM64.
>>
>> acpi_idle driver is x86/IA64 dependent now, so make CONFIG_ACPI_PROCESSOR
>> depends on X86 || IA64, and implement it on ARM/ARM64 in the furture.
>>
>> In order to make arm-core.c can both run on ARM and ARM64, introduce
>> CONFIG_ACPI_ARM to support it.
>>
>> Signed-off-by: Graeme Gregory <graeme.gregory@linaro.org>
>> Signed-off-by: Al Stone <al.stone@linaro.org>
>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>> ---
>>  arch/arm64/Kconfig         |    2 ++
>>  drivers/acpi/Kconfig       |   11 ++++++++---
>>  drivers/acpi/plat/Makefile |    2 +-
>>  3 files changed, 11 insertions(+), 4 deletions(-)
>>
>> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
>> index 6d4dd22..2b1fb1d 100644
>> --- a/arch/arm64/Kconfig
>> +++ b/arch/arm64/Kconfig
>> @@ -279,6 +279,8 @@ source "net/Kconfig"
>>  
>>  source "drivers/Kconfig"
>>  
>> +source "drivers/acpi/Kconfig"
>> +
>>  source "fs/Kconfig"
>>  
>>  source "arch/arm64/kvm/Kconfig"
>> diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
>> index 4770de5..cae5dc9 100644
>> --- a/drivers/acpi/Kconfig
>> +++ b/drivers/acpi/Kconfig
>> @@ -2,13 +2,16 @@
>>  # ACPI Configuration
>>  #
>>  
>> +config ACPI_ARM
>> +	bool
>> +
>>  menuconfig ACPI
>>  	bool "ACPI (Advanced Configuration and Power Interface) Support"
>>  	depends on !IA64_HP_SIM
>> -	depends on IA64 || X86
>> -	depends on PCI
>> +	depends on ((IA64 || X86) && PCI) || ARM64
>>  	select PNP
>> -	default y
>> +	select ACPI_ARM if ARM64
>> +	default y if !ARM64
>>  	help
>>  	  Advanced Configuration and Power Interface (ACPI) support for 
>>  	  Linux requires an ACPI-compliant platform (hardware/firmware),
>> @@ -149,6 +152,7 @@ config ACPI_PROCESSOR
>>  	tristate "Processor"
>>  	select THERMAL
>>  	select CPU_IDLE
>> +	depends on X86 || IA64
> 
> This doesn't look correct to me. You are disabling Perf/Idle/Thermal/Throttling
> support for ARM64. Any particular reason ?

As I said in the change log, acpi_idle driver is x86/IA64 dependent now,
we should revisit it later for these drivers on ARM64.

Since this is the ARM ACPI core patches, I think we can implement it later.

> 
> Also this is conflicting with other change where you are adding/exporting
> boot_option_idle_override which is mainly used in processor_idle and that's
> disabled for ARM64 here.

boot_option_idle_override is used in processor_core.c and it is the common
file used by every processor drivers including the processor_idle driver,
if I didn't introduce boot_option_idle_override there will be compile errors.

Thanks
Hanjun

^ permalink raw reply

* Note.
From: Patrick Seddigh @ 2014-01-20  9:28 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

   If you know you can engage yourself in this humanitarian task then I will advise that you contact me via email to discuss what it entails.

Have a great day ahead.

Regards,
Patrick Seddigh.

^ permalink raw reply

* [PATCHv11 2/2] dma: Add Freescale eDMA engine driver support
From: Jingchang Lu @ 2014-01-20  9:23 UTC (permalink / raw)
  To: linux-arm-kernel

Add Freescale enhanced direct memory(eDMA) controller support.
This module can be found on Vybrid and LS-1 SoCs.

Signed-off-by: Alison Wang <b18965@freescale.com>
Signed-off-by: Jingchang Lu <b35083@freescale.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
---
changes in v11:
 Add dma device_slave_caps definition.

changes in v10:
 define fsl_edma_mutex in fsl_edma_engine instead of global.
 minor changes of binding description.

changes in v9:
 define endian's operating functions instead of macro definition.
 remove the filter function, using dma_get_slave_channel instead.

changes in v8:
 change the edma driver according eDMA dts change.
 add big-endian and little-endian handling.

 no changes in v4 ~ v7.

 changes in v3:
  add vf610 edma dt-bindings namespace with prefix VF610_*.

 changes in v2:
  using generic dma-channels property instead of fsl,dma-channels.

 Documentation/devicetree/bindings/dma/fsl-edma.txt |  76 ++
 drivers/dma/Kconfig                                |  10 +
 drivers/dma/Makefile                               |   1 +
 drivers/dma/fsl-edma.c                             | 975 +++++++++++++++++++++
 4 files changed, 1062 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/dma/fsl-edma.txt
 create mode 100644 drivers/dma/fsl-edma.c

diff --git a/Documentation/devicetree/bindings/dma/fsl-edma.txt b/Documentation/devicetree/bindings/dma/fsl-edma.txt
new file mode 100644
index 0000000..191d7bd
--- /dev/null
+++ b/Documentation/devicetree/bindings/dma/fsl-edma.txt
@@ -0,0 +1,76 @@
+* Freescale enhanced Direct Memory Access(eDMA) Controller
+
+  The eDMA channels have multiplex capability by programmble memory-mapped
+registers. channels are split into two groups, called DMAMUX0 and DMAMUX1,
+specific DMA request source can only be multiplexed by any channel of certain
+group, DMAMUX0 or DMAMUX1, but not both.
+
+* eDMA Controller
+Required properties:
+- compatible :
+	- "fsl,vf610-edma" for eDMA used similar to that on Vybrid vf610 SoC
+- reg : Specifies base physical address(s) and size of the eDMA registers.
+	The 1st region is eDMA control register's address and size.
+	The 2nd and the 3rd regions are programmable channel multiplexing
+	control register's address and size.
+- interrupts : A list of interrupt-specifiers, one for each entry in
+	interrupt-names.
+- interrupt-names : Should contain:
+	"edma-tx" - the transmission interrupt
+	"edma-err" - the error interrupt
+- #dma-cells : Must be <2>.
+	The 1st cell specifies the DMAMUX(0 for DMAMUX0 and 1 for DMAMUX1).
+	Specific request source can only be multiplexed by specific channels
+	group called DMAMUX.
+	The 2nd cell specifies the request source(slot) ID.
+	See the SoC's reference manual for all the supported request sources.
+- dma-channels : Number of channels supported by the controller
+- clock-names : A list of channel group clock names. Should contain:
+	"dmamux0" - clock name of mux0 group
+	"dmamux1" - clock name of mux1 group
+- clocks : A list of phandle and clock-specifier pairs, one for each entry in
+	clock-names.
+
+Optional properties:
+- big-endian: If present registers and hardware scatter/gather descriptors
+	of the eDMA are implemented in big endian mode, otherwise in little
+	mode.
+
+
+Examples:
+
+edma0: dma-controller at 40018000 {
+	#dma-cells = <2>;
+	compatible = "fsl,vf610-edma";
+	reg = <0x40018000 0x2000>,
+		<0x40024000 0x1000>,
+		<0x40025000 0x1000>;
+	interrupts = <0 8 IRQ_TYPE_LEVEL_HIGH>,
+		<0 9 IRQ_TYPE_LEVEL_HIGH>;
+	interrupt-names = "edma-tx", "edma-err";
+	dma-channels = <32>;
+	clock-names = "dmamux0", "dmamux1";
+	clocks = <&clks VF610_CLK_DMAMUX0>,
+		<&clks VF610_CLK_DMAMUX1>;
+};
+
+
+* DMA clients
+DMA client drivers that uses the DMA function must use the format described
+in the dma.txt file, using a two-cell specifier for each channel: the 1st
+specifies the channel group(DMAMUX) in which this request can be multiplexed,
+and the 2nd specifies the request source.
+
+Examples:
+
+sai2: sai at 40031000 {
+	compatible = "fsl,vf610-sai";
+	reg = <0x40031000 0x1000>;
+	interrupts = <0 86 IRQ_TYPE_LEVEL_HIGH>;
+	clock-names = "sai";
+	clocks = <&clks VF610_CLK_SAI2>;
+	dma-names = "tx", "rx";
+	dmas = <&edma0 0 21>,
+		<&edma0 0 20>;
+	status = "disabled";
+};
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 9ae6f54..3d8a522 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -342,6 +342,16 @@ config K3_DMA
 	  Support the DMA engine for Hisilicon K3 platform
 	  devices.
 
+config FSL_EDMA
+	tristate "Freescale eDMA engine support"
+	depends on OF
+	select DMA_ENGINE
+	select DMA_VIRTUAL_CHANNELS
+	help
+	  Support the Freescale eDMA engine with programmable channel
+	  multiplexing capability for DMA request sources(slot).
+	  This module can be found on Freescale Vybrid and LS-1 SoCs.
+
 config DMA_ENGINE
 	bool
 
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 0a6f08e..e39c56b 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -43,3 +43,4 @@ obj-$(CONFIG_MMP_PDMA) += mmp_pdma.o
 obj-$(CONFIG_DMA_JZ4740) += dma-jz4740.o
 obj-$(CONFIG_TI_CPPI41) += cppi41.o
 obj-$(CONFIG_K3_DMA) += k3dma.o
+obj-$(CONFIG_FSL_EDMA) += fsl-edma.o
diff --git a/drivers/dma/fsl-edma.c b/drivers/dma/fsl-edma.c
new file mode 100644
index 0000000..9025300
--- /dev/null
+++ b/drivers/dma/fsl-edma.c
@@ -0,0 +1,975 @@
+/*
+ * drivers/dma/fsl-edma.c
+ *
+ * Copyright 2013-2014 Freescale Semiconductor, Inc.
+ *
+ * Driver for the Freescale eDMA engine with flexible channel multiplexing
+ * capability for DMA request sources. The eDMA block can be found on some
+ * Vybrid and Layerscape SoCs.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_dma.h>
+
+#include "virt-dma.h"
+
+#define EDMA_CR			0x00
+#define EDMA_ES			0x04
+#define EDMA_ERQ		0x0C
+#define EDMA_EEI		0x14
+#define EDMA_SERQ		0x1B
+#define EDMA_CERQ		0x1A
+#define EDMA_SEEI		0x19
+#define EDMA_CEEI		0x18
+#define EDMA_CINT		0x1F
+#define EDMA_CERR		0x1E
+#define EDMA_SSRT		0x1D
+#define EDMA_CDNE		0x1C
+#define EDMA_INTR		0x24
+#define EDMA_ERR		0x2C
+
+#define EDMA_TCD_SADDR(x)	(0x1000 + 32 * (x))
+#define EDMA_TCD_SOFF(x)	(0x1004 + 32 * (x))
+#define EDMA_TCD_ATTR(x)	(0x1006 + 32 * (x))
+#define EDMA_TCD_NBYTES(x)	(0x1008 + 32 * (x))
+#define EDMA_TCD_SLAST(x)	(0x100C + 32 * (x))
+#define EDMA_TCD_DADDR(x)	(0x1010 + 32 * (x))
+#define EDMA_TCD_DOFF(x)	(0x1014 + 32 * (x))
+#define EDMA_TCD_CITER_ELINK(x)	(0x1016 + 32 * (x))
+#define EDMA_TCD_CITER(x)	(0x1016 + 32 * (x))
+#define EDMA_TCD_DLAST_SGA(x)	(0x1018 + 32 * (x))
+#define EDMA_TCD_CSR(x)		(0x101C + 32 * (x))
+#define EDMA_TCD_BITER_ELINK(x)	(0x101E + 32 * (x))
+#define EDMA_TCD_BITER(x)	(0x101E + 32 * (x))
+
+#define EDMA_CR_EDBG		BIT(1)
+#define EDMA_CR_ERCA		BIT(2)
+#define EDMA_CR_ERGA		BIT(3)
+#define EDMA_CR_HOE		BIT(4)
+#define EDMA_CR_HALT		BIT(5)
+#define EDMA_CR_CLM		BIT(6)
+#define EDMA_CR_EMLM		BIT(7)
+#define EDMA_CR_ECX		BIT(16)
+#define EDMA_CR_CX		BIT(17)
+
+#define EDMA_SEEI_SEEI(x)	((x) & 0x1F)
+#define EDMA_CEEI_CEEI(x)	((x) & 0x1F)
+#define EDMA_CINT_CINT(x)	((x) & 0x1F)
+#define EDMA_CERR_CERR(x)	((x) & 0x1F)
+
+#define EDMA_TCD_ATTR_DSIZE(x)		(((x) & 0x0007))
+#define EDMA_TCD_ATTR_DMOD(x)		(((x) & 0x001F) << 3)
+#define EDMA_TCD_ATTR_SSIZE(x)		(((x) & 0x0007) << 8)
+#define EDMA_TCD_ATTR_SMOD(x)		(((x) & 0x001F) << 11)
+#define EDMA_TCD_ATTR_SSIZE_8BIT	(0x0000)
+#define EDMA_TCD_ATTR_SSIZE_16BIT	(0x0100)
+#define EDMA_TCD_ATTR_SSIZE_32BIT	(0x0200)
+#define EDMA_TCD_ATTR_SSIZE_64BIT	(0x0300)
+#define EDMA_TCD_ATTR_SSIZE_32BYTE	(0x0500)
+#define EDMA_TCD_ATTR_DSIZE_8BIT	(0x0000)
+#define EDMA_TCD_ATTR_DSIZE_16BIT	(0x0001)
+#define EDMA_TCD_ATTR_DSIZE_32BIT	(0x0002)
+#define EDMA_TCD_ATTR_DSIZE_64BIT	(0x0003)
+#define EDMA_TCD_ATTR_DSIZE_32BYTE	(0x0005)
+
+#define EDMA_TCD_SOFF_SOFF(x)		(x)
+#define EDMA_TCD_NBYTES_NBYTES(x)	(x)
+#define EDMA_TCD_SLAST_SLAST(x)		(x)
+#define EDMA_TCD_DADDR_DADDR(x)		(x)
+#define EDMA_TCD_CITER_CITER(x)		((x) & 0x7FFF)
+#define EDMA_TCD_DOFF_DOFF(x)		(x)
+#define EDMA_TCD_DLAST_SGA_DLAST_SGA(x)	(x)
+#define EDMA_TCD_BITER_BITER(x)		((x) & 0x7FFF)
+
+#define EDMA_TCD_CSR_START		BIT(0)
+#define EDMA_TCD_CSR_INT_MAJOR		BIT(1)
+#define EDMA_TCD_CSR_INT_HALF		BIT(2)
+#define EDMA_TCD_CSR_D_REQ		BIT(3)
+#define EDMA_TCD_CSR_E_SG		BIT(4)
+#define EDMA_TCD_CSR_E_LINK		BIT(5)
+#define EDMA_TCD_CSR_ACTIVE		BIT(6)
+#define EDMA_TCD_CSR_DONE		BIT(7)
+
+#define EDMAMUX_CHCFG_DIS		0x0
+#define EDMAMUX_CHCFG_ENBL		0x80
+#define EDMAMUX_CHCFG_SOURCE(n)		((n) & 0x3F)
+
+#define DMAMUX_NR	2
+
+#define FSL_EDMA_BUSWIDTHS	BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
+				BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
+				BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \
+				BIT(DMA_SLAVE_BUSWIDTH_8_BYTES)
+
+struct fsl_edma_hw_tcd {
+	u32	saddr;
+	u16	soff;
+	u16	attr;
+	u32	nbytes;
+	u32	slast;
+	u32	daddr;
+	u16	doff;
+	u16	citer;
+	u32	dlast_sga;
+	u16	csr;
+	u16	biter;
+};
+
+struct fsl_edma_sw_tcd {
+	dma_addr_t			ptcd;
+	struct fsl_edma_hw_tcd		*vtcd;
+};
+
+struct fsl_edma_slave_config {
+	enum dma_transfer_direction	dir;
+	enum dma_slave_buswidth		addr_width;
+	u32				dev_addr;
+	u32				burst;
+	u32				attr;
+};
+
+struct fsl_edma_chan {
+	struct virt_dma_chan		vchan;
+	enum dma_status			status;
+	struct fsl_edma_engine		*edma;
+	struct fsl_edma_desc		*edesc;
+	struct fsl_edma_slave_config	fsc;
+	struct dma_pool			*tcd_pool;
+};
+
+struct fsl_edma_desc {
+	struct virt_dma_desc		vdesc;
+	struct fsl_edma_chan		*echan;
+	bool				iscyclic;
+	unsigned int			n_tcds;
+	struct fsl_edma_sw_tcd		tcd[];
+};
+
+struct fsl_edma_engine {
+	struct dma_device	dma_dev;
+	void __iomem		*membase;
+	void __iomem		*muxbase[DMAMUX_NR];
+	struct clk		*muxclk[DMAMUX_NR];
+	struct mutex		fsl_edma_mutex;
+	u32			n_chans;
+	int			txirq;
+	int			errirq;
+	bool			big_endian;
+	struct fsl_edma_chan	chans[];
+};
+
+/*
+ * R/W functions for big- or little-endian registers
+ * the eDMA controller's endian is independent of the CPU core's endian.
+ */
+
+static u16 edma_readw(struct fsl_edma_engine *edma, void __iomem *addr)
+{
+	if (edma->big_endian)
+		return ioread16be(addr);
+	else
+		return ioread16(addr);
+}
+
+static u32 edma_readl(struct fsl_edma_engine *edma, void __iomem *addr)
+{
+	if (edma->big_endian)
+		return ioread32be(addr);
+	else
+		return ioread32(addr);
+}
+
+static void edma_writeb(struct fsl_edma_engine *edma, u8 val, void __iomem *addr)
+{
+	iowrite8(val, addr);
+}
+
+static void edma_writew(struct fsl_edma_engine *edma, u16 val, void __iomem *addr)
+{
+	if (edma->big_endian)
+		iowrite16be(val, addr);
+	else
+		iowrite16(val, addr);
+}
+
+static void edma_writel(struct fsl_edma_engine *edma, u32 val, void __iomem *addr)
+{
+	if (edma->big_endian)
+		iowrite32be(val, addr);
+	else
+		iowrite32(val, addr);
+}
+
+static struct fsl_edma_chan *to_fsl_edma_chan(struct dma_chan *chan)
+{
+	return container_of(chan, struct fsl_edma_chan, vchan.chan);
+}
+
+static struct fsl_edma_desc *to_fsl_edma_desc(struct virt_dma_desc *vd)
+{
+	return container_of(vd, struct fsl_edma_desc, vdesc);
+}
+
+static void fsl_edma_enable_request(struct fsl_edma_chan *fsl_chan)
+{
+	void __iomem *addr = fsl_chan->edma->membase;
+	u32 ch = fsl_chan->vchan.chan.chan_id;
+
+	edma_writeb(fsl_chan->edma, EDMA_SEEI_SEEI(ch), addr + EDMA_SEEI);
+	edma_writeb(fsl_chan->edma, ch, addr + EDMA_SERQ);
+}
+
+static void fsl_edma_disable_request(struct fsl_edma_chan *fsl_chan)
+{
+	void __iomem *addr = fsl_chan->edma->membase;
+	u32 ch = fsl_chan->vchan.chan.chan_id;
+
+	edma_writeb(fsl_chan->edma, ch, addr + EDMA_CERQ);
+	edma_writeb(fsl_chan->edma, EDMA_CEEI_CEEI(ch), addr + EDMA_CEEI);
+}
+
+static void fsl_edma_chan_mux(struct fsl_edma_chan *fsl_chan,
+			unsigned int slot, bool enable)
+{
+	u32 ch = fsl_chan->vchan.chan.chan_id;
+	void __iomem *muxaddr = fsl_chan->edma->muxbase[ch / DMAMUX_NR];
+	unsigned chans_per_mux, ch_off;
+
+	chans_per_mux = fsl_chan->edma->n_chans / DMAMUX_NR;
+	ch_off = fsl_chan->vchan.chan.chan_id % chans_per_mux;
+
+	if (enable)
+		edma_writeb(fsl_chan->edma,
+				EDMAMUX_CHCFG_ENBL | EDMAMUX_CHCFG_SOURCE(slot),
+				muxaddr + ch_off);
+	else
+		edma_writeb(fsl_chan->edma, EDMAMUX_CHCFG_DIS, muxaddr + ch_off);
+}
+
+static unsigned int fsl_edma_get_tcd_attr(enum dma_slave_buswidth addr_width)
+{
+	switch (addr_width) {
+	case 1:
+		return EDMA_TCD_ATTR_SSIZE_8BIT | EDMA_TCD_ATTR_DSIZE_8BIT;
+	case 2:
+		return EDMA_TCD_ATTR_SSIZE_16BIT | EDMA_TCD_ATTR_DSIZE_16BIT;
+	case 4:
+		return EDMA_TCD_ATTR_SSIZE_32BIT | EDMA_TCD_ATTR_DSIZE_32BIT;
+	case 8:
+		return EDMA_TCD_ATTR_SSIZE_64BIT | EDMA_TCD_ATTR_DSIZE_64BIT;
+	default:
+		return EDMA_TCD_ATTR_SSIZE_32BIT | EDMA_TCD_ATTR_DSIZE_32BIT;
+	}
+}
+
+static void fsl_edma_free_desc(struct virt_dma_desc *vdesc)
+{
+	struct fsl_edma_desc *fsl_desc;
+	int i;
+
+	fsl_desc = to_fsl_edma_desc(vdesc);
+	for (i = 0; i < fsl_desc->n_tcds; i++)
+			dma_pool_free(fsl_desc->echan->tcd_pool,
+					fsl_desc->tcd[i].vtcd,
+					fsl_desc->tcd[i].ptcd);
+	kfree(fsl_desc);
+}
+
+static int fsl_edma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+		unsigned long arg)
+{
+	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+	struct dma_slave_config *cfg = (void *)arg;
+	unsigned long flags;
+	LIST_HEAD(head);
+
+	switch (cmd) {
+	case DMA_TERMINATE_ALL:
+		spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+		fsl_edma_disable_request(fsl_chan);
+		fsl_chan->edesc = NULL;
+		vchan_get_all_descriptors(&fsl_chan->vchan, &head);
+		spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+		vchan_dma_desc_free_list(&fsl_chan->vchan, &head);
+		return 0;
+
+	case DMA_SLAVE_CONFIG:
+		fsl_chan->fsc.dir = cfg->direction;
+		if (cfg->direction == DMA_DEV_TO_MEM) {
+			fsl_chan->fsc.dev_addr = cfg->src_addr;
+			fsl_chan->fsc.addr_width = cfg->src_addr_width;
+			fsl_chan->fsc.burst = cfg->src_maxburst;
+			fsl_chan->fsc.attr = fsl_edma_get_tcd_attr(cfg->src_addr_width);
+		} else if (cfg->direction == DMA_MEM_TO_DEV) {
+			fsl_chan->fsc.dev_addr = cfg->dst_addr;
+			fsl_chan->fsc.addr_width = cfg->dst_addr_width;
+			fsl_chan->fsc.burst = cfg->dst_maxburst;
+			fsl_chan->fsc.attr = fsl_edma_get_tcd_attr(cfg->dst_addr_width);
+		} else {
+			return -EINVAL;
+		}
+		return 0;
+
+	case DMA_PAUSE:
+		spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+		if (fsl_chan->edesc) {
+			fsl_edma_disable_request(fsl_chan);
+			fsl_chan->status = DMA_PAUSED;
+		}
+		spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+		return 0;
+
+	case DMA_RESUME:
+		spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+		if (fsl_chan->edesc) {
+			fsl_edma_enable_request(fsl_chan);
+			fsl_chan->status = DMA_IN_PROGRESS;
+		}
+		spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+		return 0;
+
+	default:
+		return -ENXIO;
+	}
+}
+
+static size_t fsl_edma_desc_residue(struct fsl_edma_chan *fsl_chan,
+		struct virt_dma_desc *vdesc, bool in_progress)
+{
+	struct fsl_edma_desc *edesc = fsl_chan->edesc;
+	void __iomem *addr = fsl_chan->edma->membase;
+	u32 ch = fsl_chan->vchan.chan.chan_id;
+	enum dma_transfer_direction dir = fsl_chan->fsc.dir;
+	dma_addr_t cur_addr, dma_addr;
+	size_t len, size;
+	int i;
+
+	/* calculate the total size in this desc */
+	for (len = i = 0; i < fsl_chan->edesc->n_tcds; i++)
+		len += edma_readl(fsl_chan->edma, &(edesc->tcd[i].vtcd->nbytes))
+			* edma_readw(fsl_chan->edma, &(edesc->tcd[i].vtcd->biter));
+
+	if (!in_progress)
+		return len;
+
+	if (dir == DMA_MEM_TO_DEV)
+		cur_addr = edma_readl(fsl_chan->edma, addr + EDMA_TCD_SADDR(ch));
+	else
+		cur_addr = edma_readl(fsl_chan->edma, addr + EDMA_TCD_DADDR(ch));
+
+	/* figure out the finished and calculate the residue */
+	for (i = 0; i < fsl_chan->edesc->n_tcds; i++) {
+		size = edma_readl(fsl_chan->edma, &(edesc->tcd[i].vtcd->nbytes))
+			* edma_readw(fsl_chan->edma, &(edesc->tcd[i].vtcd->biter));
+		if (dir == DMA_MEM_TO_DEV)
+			dma_addr = edma_readl(fsl_chan->edma,
+					&(edesc->tcd[i].vtcd->saddr));
+		else
+			dma_addr = edma_readl(fsl_chan->edma,
+					&(edesc->tcd[i].vtcd->daddr));
+
+		len -= size;
+		if (cur_addr > dma_addr && cur_addr < dma_addr + size) {
+			len += dma_addr + size - cur_addr;
+			break;
+		}
+	}
+
+	return len;
+}
+
+static enum dma_status fsl_edma_tx_status(struct dma_chan *chan,
+		dma_cookie_t cookie, struct dma_tx_state *txstate)
+{
+	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+	struct virt_dma_desc *vdesc;
+	enum dma_status status;
+	unsigned long flags;
+
+	status = dma_cookie_status(chan, cookie, txstate);
+	if (status == DMA_COMPLETE)
+		return status;
+
+	if (!txstate)
+		return fsl_chan->status;
+
+	spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+	vdesc = vchan_find_desc(&fsl_chan->vchan, cookie);
+	if (fsl_chan->edesc && cookie == fsl_chan->edesc->vdesc.tx.cookie)
+		txstate->residue = fsl_edma_desc_residue(fsl_chan, vdesc, true);
+	else if (vdesc)
+		txstate->residue = fsl_edma_desc_residue(fsl_chan, vdesc, false);
+	else
+		txstate->residue = 0;
+
+	spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+
+	return fsl_chan->status;
+}
+
+static void fsl_edma_set_tcd_params(struct fsl_edma_chan *fsl_chan,
+		u32 src, u32 dst, u16 attr, u16 soff, u32 nbytes,
+		u32 slast, u16 citer, u16 biter, u32 doff, u32 dlast_sga,
+		u16 csr)
+{
+	void __iomem *addr = fsl_chan->edma->membase;
+	u32 ch = fsl_chan->vchan.chan.chan_id;
+
+	/*
+	 * TCD parameters have been swapped in fill_tcd_params(),
+	 * so just write them to registers in the cpu endian here
+	 */
+	writew(0, addr + EDMA_TCD_CSR(ch));
+	writel(src, addr + EDMA_TCD_SADDR(ch));
+	writel(dst, addr + EDMA_TCD_DADDR(ch));
+	writew(attr, addr + EDMA_TCD_ATTR(ch));
+	writew(soff, addr + EDMA_TCD_SOFF(ch));
+	writel(nbytes, addr + EDMA_TCD_NBYTES(ch));
+	writel(slast, addr + EDMA_TCD_SLAST(ch));
+	writew(citer, addr + EDMA_TCD_CITER(ch));
+	writew(biter, addr + EDMA_TCD_BITER(ch));
+	writew(doff, addr + EDMA_TCD_DOFF(ch));
+	writel(dlast_sga, addr + EDMA_TCD_DLAST_SGA(ch));
+	writew(csr, addr + EDMA_TCD_CSR(ch));
+}
+
+static void fill_tcd_params(struct fsl_edma_engine *edma,
+		struct fsl_edma_hw_tcd *tcd, u32 src, u32 dst,
+		u16 attr, u16 soff, u32 nbytes, u32 slast, u16 citer,
+		u16 biter, u16 doff, u32 dlast_sga, bool major_int,
+		bool disable_req, bool enable_sg)
+{
+	u16 csr = 0;
+
+	/*
+	 * eDMA hardware SGs require the TCD parameters stored in memory
+	 * the same endian as the eDMA module so that they can be loaded
+	 * automatically by the engine
+	 */
+	edma_writel(edma, src, &(tcd->saddr));
+	edma_writel(edma, dst, &(tcd->daddr));
+	edma_writew(edma, attr, &(tcd->attr));
+	edma_writew(edma, EDMA_TCD_SOFF_SOFF(soff), &(tcd->soff));
+	edma_writel(edma, EDMA_TCD_NBYTES_NBYTES(nbytes), &(tcd->nbytes));
+	edma_writel(edma, EDMA_TCD_SLAST_SLAST(slast), &(tcd->slast));
+	edma_writew(edma, EDMA_TCD_CITER_CITER(citer), &(tcd->citer));
+	edma_writew(edma, EDMA_TCD_DOFF_DOFF(doff), &(tcd->doff));
+	edma_writel(edma, EDMA_TCD_DLAST_SGA_DLAST_SGA(dlast_sga), &(tcd->dlast_sga));
+	edma_writew(edma, EDMA_TCD_BITER_BITER(biter), &(tcd->biter));
+	if (major_int)
+		csr |= EDMA_TCD_CSR_INT_MAJOR;
+
+	if (disable_req)
+		csr |= EDMA_TCD_CSR_D_REQ;
+
+	if (enable_sg)
+		csr |= EDMA_TCD_CSR_E_SG;
+
+	edma_writew(edma, csr, &(tcd->csr));
+}
+
+static struct fsl_edma_desc *fsl_edma_alloc_desc(struct fsl_edma_chan *fsl_chan,
+		int sg_len)
+{
+	struct fsl_edma_desc *fsl_desc;
+	int i;
+
+	fsl_desc = kzalloc(sizeof(*fsl_desc) + sizeof(struct fsl_edma_sw_tcd) * sg_len,
+				GFP_NOWAIT);
+	if (!fsl_desc)
+		return NULL;
+
+	fsl_desc->echan = fsl_chan;
+	fsl_desc->n_tcds = sg_len;
+	for (i = 0; i < sg_len; i++) {
+		fsl_desc->tcd[i].vtcd = dma_pool_alloc(fsl_chan->tcd_pool,
+					GFP_NOWAIT, &fsl_desc->tcd[i].ptcd);
+		if (!fsl_desc->tcd[i].vtcd)
+			goto err;
+	}
+	return fsl_desc;
+
+err:
+	while (--i >= 0)
+		dma_pool_free(fsl_chan->tcd_pool, fsl_desc->tcd[i].vtcd,
+				fsl_desc->tcd[i].ptcd);
+	kfree(fsl_desc);
+	return NULL;
+}
+
+static struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic(
+		struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
+		size_t period_len, enum dma_transfer_direction direction,
+		unsigned long flags, void *context)
+{
+	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+	struct fsl_edma_desc *fsl_desc;
+	dma_addr_t dma_buf_next;
+	int sg_len, i;
+	u32 src_addr, dst_addr, last_sg, nbytes;
+	u16 soff, doff, iter;
+
+	if (!is_slave_direction(fsl_chan->fsc.dir))
+		return NULL;
+
+	sg_len = buf_len / period_len;
+	fsl_desc = fsl_edma_alloc_desc(fsl_chan, sg_len);
+	if (!fsl_desc)
+		return NULL;
+	fsl_desc->iscyclic = true;
+
+	dma_buf_next = dma_addr;
+	nbytes = fsl_chan->fsc.addr_width * fsl_chan->fsc.burst;
+	iter = period_len / nbytes;
+
+	for (i = 0; i < sg_len; i++) {
+		if (dma_buf_next >= dma_addr + buf_len)
+			dma_buf_next = dma_addr;
+
+		/* get next sg's physical address */
+		last_sg = fsl_desc->tcd[(i + 1) % sg_len].ptcd;
+
+		if (fsl_chan->fsc.dir == DMA_MEM_TO_DEV) {
+			src_addr = dma_buf_next;
+			dst_addr = fsl_chan->fsc.dev_addr;
+			soff = fsl_chan->fsc.addr_width;
+			doff = 0;
+		} else {
+			src_addr = fsl_chan->fsc.dev_addr;
+			dst_addr = dma_buf_next;
+			soff = 0;
+			doff = fsl_chan->fsc.addr_width;
+		}
+
+		fill_tcd_params(fsl_chan->edma, fsl_desc->tcd[i].vtcd, src_addr,
+				dst_addr, fsl_chan->fsc.attr, soff, nbytes, 0,
+				iter, iter, doff, last_sg, true, false, true);
+		dma_buf_next += period_len;
+	}
+
+	return vchan_tx_prep(&fsl_chan->vchan, &fsl_desc->vdesc, flags);
+}
+
+static struct dma_async_tx_descriptor *fsl_edma_prep_slave_sg(
+		struct dma_chan *chan, struct scatterlist *sgl,
+		unsigned int sg_len, enum dma_transfer_direction direction,
+		unsigned long flags, void *context)
+{
+	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+	struct fsl_edma_desc *fsl_desc;
+	struct scatterlist *sg;
+	u32 src_addr, dst_addr, last_sg, nbytes;
+	u16 soff, doff, iter;
+	int i;
+
+	if (!is_slave_direction(fsl_chan->fsc.dir))
+		return NULL;
+
+	fsl_desc = fsl_edma_alloc_desc(fsl_chan, sg_len);
+	if (!fsl_desc)
+		return NULL;
+	fsl_desc->iscyclic = false;
+
+	nbytes = fsl_chan->fsc.addr_width * fsl_chan->fsc.burst;
+	for_each_sg(sgl, sg, sg_len, i) {
+		/* get next sg's physical address */
+		last_sg = fsl_desc->tcd[(i + 1) % sg_len].ptcd;
+
+		if (fsl_chan->fsc.dir == DMA_MEM_TO_DEV) {
+			src_addr = sg_dma_address(sg);
+			dst_addr = fsl_chan->fsc.dev_addr;
+			soff = fsl_chan->fsc.addr_width;
+			doff = 0;
+		} else {
+			src_addr = fsl_chan->fsc.dev_addr;
+			dst_addr = sg_dma_address(sg);
+			soff = 0;
+			doff = fsl_chan->fsc.addr_width;
+		}
+
+		iter = sg_dma_len(sg) / nbytes;
+		if (i < sg_len - 1) {
+			last_sg = fsl_desc->tcd[(i + 1)].ptcd;
+			fill_tcd_params(fsl_chan->edma, fsl_desc->tcd[i].vtcd,
+					src_addr, dst_addr, fsl_chan->fsc.attr,
+					soff, nbytes, 0, iter, iter, doff, last_sg,
+					false, false, true);
+		} else {
+			last_sg = 0;
+			fill_tcd_params(fsl_chan->edma, fsl_desc->tcd[i].vtcd,
+					src_addr, dst_addr, fsl_chan->fsc.attr,
+					soff, nbytes, 0, iter, iter, doff, last_sg,
+					true, true, false);
+		}
+	}
+
+	return vchan_tx_prep(&fsl_chan->vchan, &fsl_desc->vdesc, flags);
+}
+
+static void fsl_edma_xfer_desc(struct fsl_edma_chan *fsl_chan)
+{
+	struct fsl_edma_hw_tcd *tcd;
+	struct virt_dma_desc *vdesc;
+
+	vdesc = vchan_next_desc(&fsl_chan->vchan);
+	if (!vdesc)
+		return;
+	fsl_chan->edesc = to_fsl_edma_desc(vdesc);
+	tcd = fsl_chan->edesc->tcd[0].vtcd;
+	fsl_edma_set_tcd_params(fsl_chan, tcd->saddr, tcd->daddr, tcd->attr,
+			tcd->soff, tcd->nbytes, tcd->slast, tcd->citer,
+			tcd->biter, tcd->doff, tcd->dlast_sga, tcd->csr);
+	fsl_edma_enable_request(fsl_chan);
+	fsl_chan->status = DMA_IN_PROGRESS;
+}
+
+static irqreturn_t fsl_edma_tx_handler(int irq, void *dev_id)
+{
+	struct fsl_edma_engine *fsl_edma = dev_id;
+	unsigned int intr, ch;
+	void __iomem *base_addr;
+	struct fsl_edma_chan *fsl_chan;
+
+	base_addr = fsl_edma->membase;
+
+	intr = edma_readl(fsl_edma, base_addr + EDMA_INTR);
+	if (!intr)
+		return IRQ_NONE;
+
+	for (ch = 0; ch < fsl_edma->n_chans; ch++) {
+		if (intr & (0x1 << ch)) {
+			edma_writeb(fsl_edma, EDMA_CINT_CINT(ch),
+				base_addr + EDMA_CINT);
+
+			fsl_chan = &fsl_edma->chans[ch];
+
+			spin_lock(&fsl_chan->vchan.lock);
+			if (!fsl_chan->edesc->iscyclic) {
+				list_del(&fsl_chan->edesc->vdesc.node);
+				vchan_cookie_complete(&fsl_chan->edesc->vdesc);
+				fsl_chan->edesc = NULL;
+				fsl_chan->status = DMA_COMPLETE;
+			} else {
+				vchan_cyclic_callback(&fsl_chan->edesc->vdesc);
+			}
+
+			if (!fsl_chan->edesc)
+				fsl_edma_xfer_desc(fsl_chan);
+
+			spin_unlock(&fsl_chan->vchan.lock);
+		}
+	}
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t fsl_edma_err_handler(int irq, void *dev_id)
+{
+	struct fsl_edma_engine *fsl_edma = dev_id;
+	unsigned int err, ch;
+
+	err = edma_readl(fsl_edma, fsl_edma->membase + EDMA_ERR);
+	if (!err)
+		return IRQ_NONE;
+
+	for (ch = 0; ch < fsl_edma->n_chans; ch++) {
+		if (err & (0x1 << ch)) {
+			fsl_edma_disable_request(&fsl_edma->chans[ch]);
+			edma_writeb(fsl_edma, EDMA_CERR_CERR(ch),
+				fsl_edma->membase + EDMA_CERR);
+			fsl_edma->chans[ch].status = DMA_ERROR;
+		}
+	}
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t fsl_edma_irq_handler(int irq, void *dev_id)
+{
+	if (fsl_edma_tx_handler(irq, dev_id) == IRQ_HANDLED)
+		return IRQ_HANDLED;
+
+	return fsl_edma_err_handler(irq, dev_id);
+}
+
+static void fsl_edma_issue_pending(struct dma_chan *chan)
+{
+	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+	unsigned long flags;
+
+	spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+
+	if (vchan_issue_pending(&fsl_chan->vchan) && !fsl_chan->edesc)
+		fsl_edma_xfer_desc(fsl_chan);
+
+	spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+}
+
+static struct dma_chan *fsl_edma_xlate(struct of_phandle_args *dma_spec,
+		struct of_dma *ofdma)
+{
+	struct fsl_edma_engine *fsl_edma = ofdma->of_dma_data;
+	struct dma_chan *chan;
+
+	if (dma_spec->args_count != 2)
+		return NULL;
+
+	mutex_lock(&fsl_edma->fsl_edma_mutex);
+	list_for_each_entry(chan, &fsl_edma->dma_dev.channels, device_node) {
+		if (chan->client_count)
+			continue;
+		if ((chan->chan_id / DMAMUX_NR) == dma_spec->args[0]) {
+			chan = dma_get_slave_channel(chan);
+			if (chan) {
+				chan->device->privatecnt++;
+				fsl_edma_chan_mux(to_fsl_edma_chan(chan),
+					dma_spec->args[1], true);
+				mutex_unlock(&fsl_edma->fsl_edma_mutex);
+				return chan;
+			}
+		}
+	}
+	mutex_unlock(&fsl_edma->fsl_edma_mutex);
+	return NULL;
+}
+
+static int fsl_edma_alloc_chan_resources(struct dma_chan *chan)
+{
+	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+
+	fsl_chan->tcd_pool = dma_pool_create("tcd_pool", chan->device->dev,
+				sizeof(struct fsl_edma_hw_tcd),
+				32, 0);
+	return 0;
+}
+
+static void fsl_edma_free_chan_resources(struct dma_chan *chan)
+{
+	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+	unsigned long flags;
+	LIST_HEAD(head);
+
+	spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+	fsl_edma_disable_request(fsl_chan);
+	fsl_edma_chan_mux(fsl_chan, 0, false);
+	fsl_chan->edesc = NULL;
+	vchan_get_all_descriptors(&fsl_chan->vchan, &head);
+	spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+
+	vchan_dma_desc_free_list(&fsl_chan->vchan, &head);
+	dma_pool_destroy(fsl_chan->tcd_pool);
+	fsl_chan->tcd_pool = NULL;
+}
+
+static int fsl_dma_device_slave_caps(struct dma_chan *dchan,
+		struct dma_slave_caps *caps)
+{
+	caps->src_addr_widths = FSL_EDMA_BUSWIDTHS;
+	caps->dstn_addr_widths = FSL_EDMA_BUSWIDTHS;
+	caps->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+	caps->cmd_pause = true;
+	caps->cmd_terminate = true;
+
+	return 0;
+}
+
+static int
+fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma)
+{
+	int ret;
+
+	fsl_edma->txirq = platform_get_irq_byname(pdev, "edma-tx");
+	if (fsl_edma->txirq < 0) {
+		dev_err(&pdev->dev, "Can't get edma-tx irq.\n");
+		return fsl_edma->txirq;
+	}
+
+	fsl_edma->errirq = platform_get_irq_byname(pdev, "edma-err");
+	if (fsl_edma->errirq < 0) {
+		dev_err(&pdev->dev, "Can't get edma-err irq.\n");
+		return fsl_edma->errirq;
+	}
+
+	if (fsl_edma->txirq == fsl_edma->errirq) {
+		ret = devm_request_irq(&pdev->dev, fsl_edma->txirq,
+				fsl_edma_irq_handler, 0, "eDMA", fsl_edma);
+		if (ret) {
+			dev_err(&pdev->dev, "Can't register eDMA IRQ.\n");
+			 return  ret;
+		}
+	} else {
+		ret = devm_request_irq(&pdev->dev, fsl_edma->txirq,
+				fsl_edma_tx_handler, 0, "eDMA tx", fsl_edma);
+		if (ret) {
+			dev_err(&pdev->dev, "Can't register eDMA tx IRQ.\n");
+			return  ret;
+		}
+
+		ret = devm_request_irq(&pdev->dev, fsl_edma->errirq,
+				fsl_edma_err_handler, 0, "eDMA err", fsl_edma);
+		if (ret) {
+			dev_err(&pdev->dev, "Can't register eDMA err IRQ.\n");
+			return  ret;
+		}
+	}
+
+	return 0;
+}
+
+static int fsl_edma_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct fsl_edma_engine *fsl_edma;
+	struct fsl_edma_chan *fsl_chan;
+	struct resource *res;
+	int len, chans;
+	int ret, i;
+
+	ret = of_property_read_u32(np, "dma-channels", &chans);
+	if (ret) {
+		dev_err(&pdev->dev, "Can't get dma-channels.\n");
+		return ret;
+	}
+
+	len = sizeof(*fsl_edma) + sizeof(*fsl_chan) * chans;
+	fsl_edma = devm_kzalloc(&pdev->dev, len, GFP_KERNEL);
+	if (!fsl_edma)
+		return -ENOMEM;
+
+	fsl_edma->n_chans = chans;
+	mutex_init(&fsl_edma->fsl_edma_mutex);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	fsl_edma->membase = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(fsl_edma->membase))
+		return PTR_ERR(fsl_edma->membase);
+
+	for (i = 0; i < DMAMUX_NR; i++) {
+		char clkname[32];
+
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 1 + i);
+		fsl_edma->muxbase[i] = devm_ioremap_resource(&pdev->dev, res);
+		if (IS_ERR(fsl_edma->muxbase[i]))
+			return PTR_ERR(fsl_edma->muxbase[i]);
+
+		sprintf(clkname, "dmamux%d", i);
+		fsl_edma->muxclk[i] = devm_clk_get(&pdev->dev, clkname);
+		if (IS_ERR(fsl_edma->muxclk[i])) {
+			dev_err(&pdev->dev, "Missing DMAMUX block clock.\n");
+			return PTR_ERR(fsl_edma->muxclk[i]);
+		}
+
+		ret = clk_prepare_enable(fsl_edma->muxclk[i]);
+		if (ret) {
+			dev_err(&pdev->dev, "DMAMUX clk block failed.\n");
+			return ret;
+		}
+
+	}
+
+	ret = fsl_edma_irq_init(pdev, fsl_edma);
+	if (ret)
+		return ret;
+
+	fsl_edma->big_endian = of_property_read_bool(np, "big-endian");
+
+	INIT_LIST_HEAD(&fsl_edma->dma_dev.channels);
+	for (i = 0; i < fsl_edma->n_chans; i++) {
+		struct fsl_edma_chan *fsl_chan = &fsl_edma->chans[i];
+
+		fsl_chan->edma = fsl_edma;
+
+		fsl_chan->vchan.desc_free = fsl_edma_free_desc;
+		vchan_init(&fsl_chan->vchan, &fsl_edma->dma_dev);
+
+		edma_writew(fsl_edma, 0x0, fsl_edma->membase + EDMA_TCD_CSR(i));
+		fsl_edma_chan_mux(fsl_chan, 0, false);
+	}
+
+	dma_cap_set(DMA_PRIVATE, fsl_edma->dma_dev.cap_mask);
+	dma_cap_set(DMA_SLAVE, fsl_edma->dma_dev.cap_mask);
+	dma_cap_set(DMA_CYCLIC, fsl_edma->dma_dev.cap_mask);
+
+	fsl_edma->dma_dev.dev = &pdev->dev;
+	fsl_edma->dma_dev.device_alloc_chan_resources
+		= fsl_edma_alloc_chan_resources;
+	fsl_edma->dma_dev.device_free_chan_resources
+		= fsl_edma_free_chan_resources;
+	fsl_edma->dma_dev.device_tx_status = fsl_edma_tx_status;
+	fsl_edma->dma_dev.device_prep_slave_sg = fsl_edma_prep_slave_sg;
+	fsl_edma->dma_dev.device_prep_dma_cyclic = fsl_edma_prep_dma_cyclic;
+	fsl_edma->dma_dev.device_control = fsl_edma_control;
+	fsl_edma->dma_dev.device_issue_pending = fsl_edma_issue_pending;
+	fsl_edma->dma_dev.device_slave_caps = fsl_dma_device_slave_caps;
+
+	platform_set_drvdata(pdev, fsl_edma);
+
+	ret = dma_async_device_register(&fsl_edma->dma_dev);
+	if (ret) {
+		dev_err(&pdev->dev, "Can't register Freescale eDMA engine.\n");
+		return ret;
+	}
+
+	ret = of_dma_controller_register(np, fsl_edma_xlate, fsl_edma);
+	if (ret) {
+		dev_err(&pdev->dev, "Can't register Freescale eDMA of_dma.\n");
+		dma_async_device_unregister(&fsl_edma->dma_dev);
+		return ret;
+	}
+
+	/* enable round robin arbitration */
+	edma_writel(fsl_edma, EDMA_CR_ERGA | EDMA_CR_ERCA, fsl_edma->membase + EDMA_CR);
+
+	return 0;
+}
+
+static int fsl_edma_remove(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct fsl_edma_engine *fsl_edma = platform_get_drvdata(pdev);
+	int i;
+
+	of_dma_controller_free(np);
+	dma_async_device_unregister(&fsl_edma->dma_dev);
+
+	for (i = 0; i < DMAMUX_NR; i++)
+		clk_disable_unprepare(fsl_edma->muxclk[i]);
+
+	return 0;
+}
+
+static const struct of_device_id fsl_edma_dt_ids[] = {
+	{ .compatible = "fsl,vf610-edma", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, fsl_edma_dt_ids);
+
+static struct platform_driver fsl_edma_driver = {
+	.driver		= {
+		.name	= "fsl-edma",
+		.owner  = THIS_MODULE,
+		.of_match_table = fsl_edma_dt_ids,
+	},
+	.probe          = fsl_edma_probe,
+	.remove		= fsl_edma_remove,
+};
+
+module_platform_driver(fsl_edma_driver);
+
+MODULE_ALIAS("platform:fsl-edma");
+MODULE_DESCRIPTION("Freescale eDMA engine driver");
+MODULE_LICENSE("GPL v2");
-- 
1.8.0

^ permalink raw reply related

* [PATCH 03/20] ARM64 / ACPI: Introduce the skeleton of _PDC related for ARM64
From: Hanjun Guo @ 2014-01-20  9:20 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <52D93D4E.5020605@arm.com>

On 2014-1-17 22:25, Sudeep Holla wrote:
> On 17/01/14 12:24, Hanjun Guo wrote:
>> The _PDC (Processor Driver Capabilities) object provides OSPM a
>> mechanism to convey to the platform the capabilities supported
>> by OSPM for processor power management.
>>
>> OSPM evaluates _PDC prior to evaluating any other processor
>> power management objects returning configuration information.
>>
>> This patch introduces the skeleton of _PDC related file to make
>> ACPI core can be compiled on ARM64.
>>
>> Signed-off-by: Al Stone <al.stone@linaro.org>
>> Signed-off-by: Graeme Gregory <graeme.gregory@linaro.org>
>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>> ---
>>  arch/arm64/include/asm/acpi.h      |   32 ++++++++++++++++++++++++++++++++
>>  arch/arm64/include/asm/processor.h |    2 ++
>>  arch/arm64/kernel/process.c        |    3 +++
>>  3 files changed, 37 insertions(+)
>>  create mode 100644 arch/arm64/include/asm/acpi.h
>>
>> diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h
>> new file mode 100644
>> index 0000000..cf19dc6
>> --- /dev/null
>> +++ b/arch/arm64/include/asm/acpi.h
>> @@ -0,0 +1,32 @@
>> +/*
>> + *  Copyright (C) 2013, Al Stone <al.stone@linaro.org>
>> + *
>> + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> + *
>> + *  This program is free software; you can redistribute it and/or modify
>> + *  it under the terms of the GNU General Public License as published by
>> + *  the Free Software Foundation; either version 2 of the License, or
>> + *  (at your option) any later version.
>> + *
>> + *  This program is distributed in the hope that it will be useful,
>> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + *  GNU General Public License for more details.
>> + *
>> + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> + */
>> +
>> +#ifndef _ASM_ARM64_ACPI_H
>> +#define _ASM_ARM64_ACPI_H
>> +
>> +static inline bool arch_has_acpi_pdc(void)
>> +{
>> +	return false;	/* always false for now */
>> +}
>> +
>> +static inline void arch_acpi_set_pdc_bits(u32 *buf)
>> +{
>> +	return;
>> +}
>> +
>> +#endif /*_ASM_ARM64_ACPI_H*/
>> diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
>> index 45b20cd..50ce951 100644
>> --- a/arch/arm64/include/asm/processor.h
>> +++ b/arch/arm64/include/asm/processor.h
>> @@ -162,6 +162,8 @@ static inline void spin_lock_prefetch(const void *x)
>>  
>>  #define HAVE_ARCH_PICK_MMAP_LAYOUT
>>  
>> +extern unsigned long    boot_option_idle_override;
>> +
>>  #endif
>>  
>>  #endif /* __ASM_PROCESSOR_H */
>> diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
>> index de17c89..13d3d7f 100644
>> --- a/arch/arm64/kernel/process.c
>> +++ b/arch/arm64/kernel/process.c
>> @@ -89,6 +89,9 @@ void arch_cpu_idle_prepare(void)
>>  	local_fiq_enable();
>>  }
>>  
>> +unsigned long boot_option_idle_override = IDLE_NO_OVERRIDE;
>> +EXPORT_SYMBOL(boot_option_idle_override);
>> +
> 
> This is what I mentioned in other email. Do we really foresee use of this in
> ARM64 or it's just added to avoid build issues ?

Just avoid build issues, can not foresee use of this in ARM64 :)

Thanks
Hanjun

^ permalink raw reply

* [RFC v3 08/13] ahci-platform: Allow specifying platform_data through of_device_id
From: Hans de Goede @ 2014-01-20  9:17 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140120090950.GI16215@pengutronix.de>

Hi,

On 01/20/2014 10:09 AM, Sascha Hauer wrote:
> On Mon, Jan 20, 2014 at 09:35:06AM +0100, Hans de Goede wrote:
>> Hi,
>>
>> On 01/20/2014 09:24 AM, Sascha Hauer wrote:
>>>> +
>>>> +static const struct ahci_platform_data *ahci_get_pdata(struct device *dev)
>>>> +{
>>>> +	struct ahci_platform_data *pdata;
>>>> +	const struct of_device_id *of_id;
>>>> +
>>>> +	pdata = dev_get_platdata(dev);
>>>> +	if (pdata)
>>>> +		return pdata;
>>>> +
>>>> +	of_id = of_match_device(ahci_of_match, dev);
>>>> +	if (of_id)
>>>> +		return of_id->data;
>>>
>>> I don't think it's a good idea to force of_id->data to be of type struct
>>> struct ahci_platform_data *. With this we don't have a place to store
>>> SoC specific data anymore.
>>
>> ?? ahci_platform_data *is* soc specific data, it allows various soc
>> specific overrides.
>
> I know, but it might not be enough for encding the slight differences
> between i.MX53 and i.MX6. So you say then we would need to different
> instances of struct ahci_platform_data, one for i.MX53 and one for
> i.MX6. Ok, that works.
>
> Overall I must say that I'm not really happy with giving up control over
> the probe function and putting ahci_platform as a midlayer between the
> SoC and the ahci lib. Just my 2 cents, if I'm the only one feel free to
> ignore me, but maybe there are others that have the same feeling.

I'm currently working on a slightly different implementation of a more
generic ahci_platform.c where ahci_platform.c exports some standard platform
related functionality as library functions.

Drivers which need to override some of ahci_platform.c's behavior because of
non standard hw, will then export their own struct platform_driver and can
call into the exported functions for standard stuff to avoid code duplication
where appropriate, while still having 100% freedom to do things in a custom
way where necessary.

I hope to post a PATCH RFC v4 with these changes later today, which you will
hopefully like better. Input on v4, even just a "yep better" remark would be
much appreciated.

Regards,

Hans

^ permalink raw reply

* [PATCH v5 3/9] mfd: omap-usb-host: Update DT clock binding information
From: Roger Quadros @ 2014-01-20  9:14 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140110101107.GF28141@lee--X1>

On 01/10/2014 12:11 PM, Lee Jones wrote:
> On Thu, 09 Jan 2014, Roger Quadros wrote:
> 
>> The omap-usb-host driver expects certained named clocks.
>> Add this information to the DT binding document.
>>
>> Use clock names as per function for reference clocks.
>>
>> CC: Lee Jones <lee.jones@linaro.org>
>> CC: Samuel Ortiz <sameo@linux.intel.com>
>> Signed-off-by: Roger Quadros <rogerq@ti.com>
>> ---
>>  .../devicetree/bindings/mfd/omap-usb-host.txt      | 23 ++++++++++++++++++++++
>>  drivers/mfd/omap-usb-host.c                        |  6 +++---
>>  2 files changed, 26 insertions(+), 3 deletions(-)
> 
> Please don't mix up binding changes with code ones.
> 
> Separate patch please.
> 
OK.

cheers,
-roger

^ permalink raw reply

* [PATCH v5 2/9] mfd: omap-usb-host: Get clocks based on hardware revision
From: Roger Quadros @ 2014-01-20  9:14 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140110142640.GA32035@lee--X1>

On 01/10/2014 04:26 PM, Lee Jones wrote:
> On Fri, 10 Jan 2014, Arnd Bergmann wrote:
> 
>> On Friday 10 January 2014, Lee Jones wrote:
>>>>  
>>>> -     need_logic_fck = false;
>>>> +     /* Set all clocks as invalid to begin with */
>>>> +     omap->ehci_logic_fck = omap->init_60m_fclk = ERR_PTR(-EINVAL);
>>>> +     omap->utmi_p1_gfclk = omap->utmi_p2_gfclk = ERR_PTR(-EINVAL);
>>>> +     omap->xclk60mhsp1_ck = omap->xclk60mhsp2_ck = ERR_PTR(-EINVAL);
>>>
>>> I don't think this is the correct error code.
>>>
>>> -EINVAL means 'invalid parameter'.
>>>
>>> You probably want -ENODEV or -ENOSYS ('function not implemented'
>>> probably isn't ideal either tbh, but you get the idea). Perhaps you
>>> can set them as NULL and check for IS_ERR_OR_NULL() instead?
>>
>> I think ENODEV is ok here, I'd much prefer this over IS_ERR_OR_NULL().
> 
> Sounds good to me.
> 
OK. Will fix.

cheers,
-roger

^ permalink raw reply

* [PATCH V3 REPOST] dma: tegra: register as an OF DMA controller
From: Vinod Koul @ 2014-01-20  9:10 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1386699949-13595-1-git-send-email-swarren@wwwdotorg.org>

On Tue, Dec 10, 2013 at 11:25:49AM -0700, Stephen Warren wrote:
> From: Stephen Warren <swarren@nvidia.com>
> 
> Call of_dma_controller_register() so that DMA clients can look up the
> Tegra DMA controller using standard APIs. This requires the of_xlate()
> function to save off the DMA slave ID, and for tegra_dma_slave_config()
> not to over-write this information; once DMA client drivers are converted
> to dma_request_slave_channel() and DT-based lookups, they won't set this
> field of struct dma_slave_config anymore.
> 
> Cc: linux-tegra at vger.kernel.org
> Cc: linux-arm-kernel at lists.infradead.org
> Cc: Dan Williams <dan.j.williams@intel.com>
> Cc: Vinod Koul <vinod.koul@intel.com>
> Cc: dmaengine at vger.kernel.org
> Signed-off-by: Stephen Warren <swarren@nvidia.com>
> Acked-by: Arnd Bergmann <arnd@arndb.de>
> Reviewed-by: Thierry Reding <treding@nvidia.com>
Acked-by: Vinod Koul <vinod.koul@intel.com>

Sorry for delay in doing this

--
~Vinod
> ---
> (just reposting this in order to get an ack from one of the dmaengine
> maintainers)
> 
> v3:
> * Rework of_xlate() to use new dma_get_any_slave_channel().
> v2:
> * Use of_dma_slave_xlate() rather than of_dma_simple_xlate(), as
>   suggested by Arnd Bergmann.
> 
> This patch is part of a series with strong internal depdendencies. I'm
> looking for an ack so that I can take the entire series through the Tegra
> and arm-soc trees. The series will be part of a stable branch that can be
> merged into other subsystems if needed to avoid/resolve dependencies.
> ---
>  drivers/dma/tegra20-apb-dma.c | 39 ++++++++++++++++++++++++++++++++++++---
>  1 file changed, 36 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c
> index afa5844c9346..d11bb3620f27 100644
> --- a/drivers/dma/tegra20-apb-dma.c
> +++ b/drivers/dma/tegra20-apb-dma.c
> @@ -1,7 +1,7 @@
>  /*
>   * DMA driver for Nvidia's Tegra20 APB DMA controller.
>   *
> - * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
> + * Copyright (c) 2012-2013, NVIDIA CORPORATION.  All rights reserved.
>   *
>   * This program is free software; you can redistribute it and/or modify it
>   * under the terms and conditions of the GNU General Public License,
> @@ -29,6 +29,7 @@
>  #include <linux/module.h>
>  #include <linux/of.h>
>  #include <linux/of_device.h>
> +#include <linux/of_dma.h>
>  #include <linux/platform_device.h>
>  #include <linux/pm.h>
>  #include <linux/pm_runtime.h>
> @@ -199,6 +200,7 @@ struct tegra_dma_channel {
>  	void			*callback_param;
>  
>  	/* Channel-slave specific configuration */
> +	unsigned int slave_id;
>  	struct dma_slave_config dma_sconfig;
>  	struct tegra_dma_channel_regs	channel_reg;
>  };
> @@ -340,6 +342,8 @@ static int tegra_dma_slave_config(struct dma_chan *dc,
>  	}
>  
>  	memcpy(&tdc->dma_sconfig, sconfig, sizeof(*sconfig));
> +	if (!tdc->slave_id)
> +		tdc->slave_id = sconfig->slave_id;
>  	tdc->config_init = true;
>  	return 0;
>  }
> @@ -942,7 +946,7 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_slave_sg(
>  	ahb_seq |= TEGRA_APBDMA_AHBSEQ_BUS_WIDTH_32;
>  
>  	csr |= TEGRA_APBDMA_CSR_ONCE | TEGRA_APBDMA_CSR_FLOW;
> -	csr |= tdc->dma_sconfig.slave_id << TEGRA_APBDMA_CSR_REQ_SEL_SHIFT;
> +	csr |= tdc->slave_id << TEGRA_APBDMA_CSR_REQ_SEL_SHIFT;
>  	if (flags & DMA_PREP_INTERRUPT)
>  		csr |= TEGRA_APBDMA_CSR_IE_EOC;
>  
> @@ -1086,7 +1090,7 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_dma_cyclic(
>  	csr |= TEGRA_APBDMA_CSR_FLOW;
>  	if (flags & DMA_PREP_INTERRUPT)
>  		csr |= TEGRA_APBDMA_CSR_IE_EOC;
> -	csr |= tdc->dma_sconfig.slave_id << TEGRA_APBDMA_CSR_REQ_SEL_SHIFT;
> +	csr |= tdc->slave_id << TEGRA_APBDMA_CSR_REQ_SEL_SHIFT;
>  
>  	apb_seq |= TEGRA_APBDMA_APBSEQ_WRAP_WORD_1;
>  
> @@ -1206,6 +1210,25 @@ static void tegra_dma_free_chan_resources(struct dma_chan *dc)
>  		kfree(sg_req);
>  	}
>  	clk_disable_unprepare(tdma->dma_clk);
> +
> +	tdc->slave_id = 0;
> +}
> +
> +static struct dma_chan *tegra_dma_of_xlate(struct of_phandle_args *dma_spec,
> +					   struct of_dma *ofdma)
> +{
> +	struct tegra_dma *tdma = ofdma->of_dma_data;
> +	struct dma_chan *chan;
> +	struct tegra_dma_channel *tdc;
> +
> +	chan = dma_get_any_slave_channel(&tdma->dma_dev);
> +	if (!chan)
> +		return NULL;
> +
> +	tdc = to_tegra_dma_chan(chan);
> +	tdc->slave_id = dma_spec->args[0];
> +
> +	return chan;
>  }
>  
>  /* Tegra20 specific DMA controller information */
> @@ -1383,10 +1406,20 @@ static int tegra_dma_probe(struct platform_device *pdev)
>  		goto err_irq;
>  	}
>  
> +	ret = of_dma_controller_register(pdev->dev.of_node,
> +					 tegra_dma_of_xlate, tdma);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev,
> +			"Tegra20 APB DMA OF registration failed %d\n", ret);
> +		goto err_unregister_dma_dev;
> +	}
> +
>  	dev_info(&pdev->dev, "Tegra20 APB DMA driver register %d channels\n",
>  			cdata->nr_channels);
>  	return 0;
>  
> +err_unregister_dma_dev:
> +	dma_async_device_unregister(&tdma->dma_dev);
>  err_irq:
>  	while (--i >= 0) {
>  		struct tegra_dma_channel *tdc = &tdma->channels[i];
> -- 
> 1.8.1.5
> 

-- 

^ permalink raw reply

* [RFC v3 08/13] ahci-platform: Allow specifying platform_data through of_device_id
From: Sascha Hauer @ 2014-01-20  9:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <52DCDFBA.2070903@redhat.com>

On Mon, Jan 20, 2014 at 09:35:06AM +0100, Hans de Goede wrote:
> Hi,
> 
> On 01/20/2014 09:24 AM, Sascha Hauer wrote:
> >>+
> >>+static const struct ahci_platform_data *ahci_get_pdata(struct device *dev)
> >>+{
> >>+	struct ahci_platform_data *pdata;
> >>+	const struct of_device_id *of_id;
> >>+
> >>+	pdata = dev_get_platdata(dev);
> >>+	if (pdata)
> >>+		return pdata;
> >>+
> >>+	of_id = of_match_device(ahci_of_match, dev);
> >>+	if (of_id)
> >>+		return of_id->data;
> >
> >I don't think it's a good idea to force of_id->data to be of type struct
> >struct ahci_platform_data *. With this we don't have a place to store
> >SoC specific data anymore.
> 
> ?? ahci_platform_data *is* soc specific data, it allows various soc
> specific overrides.

I know, but it might not be enough for encding the slight differences
between i.MX53 and i.MX6. So you say then we would need to different
instances of struct ahci_platform_data, one for i.MX53 and one for
i.MX6. Ok, that works.

Overall I must say that I'm not really happy with giving up control over
the probe function and putting ahci_platform as a midlayer between the
SoC and the ahci lib. Just my 2 cents, if I'm the only one feel free to
ignore me, but maybe there are others that have the same feeling.

Sascha

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

^ permalink raw reply

* [PATCH 18/20] clocksource / acpi: Add macro CLOCKSOURCE_ACPI_DECLARE
From: Hanjun Guo @ 2014-01-20  9:08 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <201401171521.35940.arnd@arndb.de>

On 2014-1-17 22:21, Arnd Bergmann wrote:
> On Friday 17 January 2014, Hanjun Guo wrote:
>>
>> From: Amit Daniel Kachhap <amit.daniel@samsung.com>
>>
>> This macro does the same job as CLOCKSOURCE_OF_DECLARE. The device
>> name from the ACPI timer table is matched with all the registered
>> timer controllers and matching initialisation routine is invoked.
> 
> I wouldn't anticipate this infrastructure to be required. Shouldn't all
> ARMv8 machines have an architected timer?

I not sure of this, could anyone can give some guidance? if only arch
timer is available for ARM64, this will make thing very simple.

Thanks
Hanjun

^ permalink raw reply

* [PATCHv10 2/2] dma: Add Freescale eDMA engine driver support
From: Jingchang Lu @ 2014-01-20  9:06 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140120074019.GF26823@intel.com>



> -----Original Message-----
> From: Vinod Koul [mailto:vinod.koul at intel.com]
> Sent: Monday, January 20, 2014 3:40 PM
> To: Lu Jingchang-B35083
> Cc: dan.j.williams at intel.com; arnd at arndb.de; shawn.guo at linaro.org;
> pawel.moll at arm.com; mark.rutland at arm.com; swarren at wwwdotorg.org; linux-
> kernel at vger.kernel.org; linux-arm-kernel at lists.infradead.org;
> devicetree at vger.kernel.org; Wang Huan-B18965
> Subject: Re: [PATCHv10 2/2] dma: Add Freescale eDMA engine driver support
> 
> On Fri, Jan 17, 2014 at 02:04:44PM +0800, Jingchang Lu wrote:
> > Add Freescale enhanced direct memory(eDMA) controller support.
> > This module can be found on Vybrid and LS-1 SoCs.
> >
> > Signed-off-by: Alison Wang <b18965@freescale.com>
> > Signed-off-by: Jingchang Lu <b35083@freescale.com>
> > Acked-by: Arnd Bergmann <arnd@arndb.de>
> > ---
> 
> > +static int fsl_edma_control(struct dma_chan *chan, enum dma_ctrl_cmd
> cmd,
> > +		unsigned long arg)
> > +{
> > +	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
> > +	struct dma_slave_config *cfg = (void *)arg;
> > +	unsigned long flags;
> > +	LIST_HEAD(head);
> > +
> > +	switch (cmd) {
> > +	case DMA_TERMINATE_ALL:
> > +		spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
> > +		fsl_edma_disable_request(fsl_chan);
> > +		fsl_chan->edesc = NULL;
> > +		vchan_get_all_descriptors(&fsl_chan->vchan, &head);
> > +		spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
> > +		vchan_dma_desc_free_list(&fsl_chan->vchan, &head);
> > +		return 0;
> well what happens to the current ongoing transactions, i don't see those
> getting
> terminated?
The fsl_edma_disable_request(fsl_chan) would end the channel's ongoing transaction, then
the eDMA would not response to device dma request, and the vchan_dma_desc_free_list()
will release all associate memory. Thanks.

> 
> > +
> > +	case DMA_SLAVE_CONFIG:
> > +		fsl_chan->fsc.dir = cfg->direction;
> > +		if (cfg->direction == DMA_DEV_TO_MEM) {
> > +			fsl_chan->fsc.dev_addr = cfg->src_addr;
> > +			fsl_chan->fsc.addr_width = cfg->src_addr_width;
> > +			fsl_chan->fsc.burst = cfg->src_maxburst;
> > +			fsl_chan->fsc.attr = fsl_edma_get_tcd_attr(cfg-
> >src_addr_width);
> > +		} else if (cfg->direction == DMA_MEM_TO_DEV) {
> > +			fsl_chan->fsc.dev_addr = cfg->dst_addr;
> > +			fsl_chan->fsc.addr_width = cfg->dst_addr_width;
> > +			fsl_chan->fsc.burst = cfg->dst_maxburst;
> > +			fsl_chan->fsc.attr = fsl_edma_get_tcd_attr(cfg-
> >dst_addr_width);
> okay atrr is address width, why not save this standard struct instead?
The value saved in fsc.attr is transferred by fsl_edma_get_tcd_attr(), it can
be set into the channel control register later directly. the edma driver doesn't
need to save all dma_slave_config parameters, so it only gets the necessaries.
Thanks.
 
> 
> > +		} else {
> > +			return -EINVAL;
> > +		}
> > +		return 0;
> > +
> > +	case DMA_PAUSE:
> > +		spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
> > +		if (fsl_chan->edesc) {
> > +			fsl_edma_disable_request(fsl_chan);
> > +			fsl_chan->status = DMA_PAUSED;
> > +		}
> > +		spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
> > +		return 0;
> > +
> > +	case DMA_RESUME:
> > +		spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
> > +		if (fsl_chan->edesc) {
> > +			fsl_edma_enable_request(fsl_chan);
> > +			fsl_chan->status = DMA_IN_PROGRESS;
> > +		}
> > +		spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
> > +		return 0;
> > +
> > +	default:
> > +		return -ENXIO;
> > +	}
> > +}
> > +
> 
> > +static struct fsl_edma_desc *fsl_edma_alloc_desc(struct fsl_edma_chan
> *fsl_chan,
> > +		int sg_len)
> > +{
> > +	struct fsl_edma_desc *fsl_desc;
> > +	int i;
> > +
> > +	fsl_desc = kzalloc(sizeof(*fsl_desc) + sizeof(struct
> fsl_edma_sw_tcd) * sg_len,
> > +				GFP_NOWAIT);
> > +	if (!fsl_desc)
> > +		return NULL;
> > +
> > +	fsl_desc->echan = fsl_chan;
> > +	fsl_desc->n_tcds = sg_len;
> > +	for (i = 0; i < sg_len; i++) {
> > +		fsl_desc->tcd[i].vtcd = dma_pool_alloc(fsl_chan->tcd_pool,
> > +					GFP_NOWAIT, &fsl_desc->tcd[i].ptcd);
> > +		if (!fsl_desc->tcd[i].vtcd)
> > +			goto err;
> > +	}
> > +	return fsl_desc;
> > +
> > +err:
> > +	while (--i >= 0)
> > +		dma_pool_free(fsl_chan->tcd_pool, fsl_desc->tcd[i].vtcd,
> > +				fsl_desc->tcd[i].ptcd);
> > +	kfree(fsl_desc);
> > +	return NULL;
> > +}
> > +
> > +static struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic(
> > +		struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
> > +		size_t period_len, enum dma_transfer_direction direction,
> > +		unsigned long flags, void *context)
> > +{
> you may want to implement the capablities api subsequently for audio
> usage.
Do you mean the device_slave_caps function? If it is, I will add it.
Thanks.

> 
> > +	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
> > +	struct fsl_edma_desc *fsl_desc;
> > +	dma_addr_t dma_buf_next;
> > +	int sg_len, i;
> > +	u32 src_addr, dst_addr, last_sg, nbytes;
> > +	u16 soff, doff, iter;
> > +
> > +	if (!is_slave_direction(fsl_chan->fsc.dir))
> > +		return NULL;
> > +
> > +	sg_len = buf_len / period_len;
> > +	fsl_desc = fsl_edma_alloc_desc(fsl_chan, sg_len);
> > +	if (!fsl_desc)
> > +		return NULL;
> > +	fsl_desc->iscyclic = true;
> > +
> > +	dma_buf_next = dma_addr;
> > +	nbytes = fsl_chan->fsc.addr_width * fsl_chan->fsc.burst;
> > +	iter = period_len / nbytes;
> empty line here pls
Ok, thanks.


Best Regards,
Jingchang

^ permalink raw reply

* [PATCH] ARM: imx: add cpuidle support for i.mx6sl
From: Anson.Huang at freescale.com @ 2014-01-20  9:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <30BEA0EF-C7F3-48FB-9B07-2C244788DD38@freescale.com>

Hi, Tobias and Shawn
	I debug into this issue today, the root cause is that we have a usleep_range(50, 500); in arch/arm/mach-imx/clk-pllv3.c's clk_pllv3_wait_lock function, which will cause kernel schedule during cpufreq change, and the idle thread has another clk operation which will cause mutex nest, and it will try to wake up previous mutex hold by cpufreq change's pll1 clk_set_rate.
	So, to fix this issue, we should not use any usleep in the wait function of pllv3's code, or we should not call any clk API in the imx6sl_set_wait_clk function. What do you think?

	BTW, I found another issue, if EVK board boot up with 396MHz, then the initialized clock parent status is wrong, as ARM is from PFD 396MHz, I will generate another patch to fix that once I have bandwidth.

Best Regards.
Anson huang ???
?
Freescale Semiconductor Shanghai
?????????192?A?2?
201203
Tel:021-28937058


>-----Original Message-----
>From: Huang Yongcai-B20788
>Sent: Saturday, January 18, 2014 7:53 AM
>To: John Tobias
>Cc: <linux-arm-kernel@lists.infradead.org>; Shawn Guo
>Subject: Re: [PATCH] ARM: imx: add cpuidle support for i.mx6sl
>
>Hi, Tobias
>        I will debug it next week and feedback to you. Thanks.
>
>Sent from Anson's iPhone
>
>> ? 2014?1?18??7:42?"John Tobias" <john.tobias.ph@gmail.com> ???
>>
>> Hi Anson,
>>
>> My kernel for iMX6SL has a imx6q-cpufreq and I used your patch.
>> Unfortunately, the kernel crashes if the imx6sl_set_wait_clk being
>> called in imx6sl_enter_wait.
>>
>> [  288.166905] [<80044b80>] (dequeue_task+0x0/0xc8) from [<80045650>]
>> (deactivate_task+0x30/0x34)
>> [  288.176403] [<80045620>] (deactivate_task+0x0/0x34) from
>> [<8050ac88>] (__schedule+0x318/0x58c) [  288.185848] [<8050a970>]
>> (__schedule+0x0/0x58c) from [<8050af34>]
>> (schedule+0x38/0x88)
>> [  288.194758] [<8050aefc>] (schedule+0x0/0x88) from [<8050b1c8>]
>> (schedule_preempt_disabled+0x10/0x14)
>> [  288.204858] [<8050b1b8>] (schedule_preempt_disabled+0x0/0x14) from
>> [<8050bcd4>] (mutex_lock_nested+0x16c/0x334) [  288.215850]
>> [<8050bb68>] (mutex_lock_nested+0x0/0x334) from [<8034763c>]
>> (clk_prepare_lock+0x90/0x104) [  288.226041] [<803475ac>]
>> (clk_prepare_lock+0x0/0x104) from [<80349254>]
>> (clk_set_rate+0x1c/0xbc) [  288.235535]  r6:806fd360 r5:00000000
>> r4:bf817f80 r3:80713d80 [  288.242679] [<80349238>]
>> (clk_set_rate+0x0/0xbc) from [<8001e574>]
>> (imx6sl_set_wait_clk+0x28/0x70)
>> [  288.252354]  r5:00000043 r4:00000001 [  288.256585] [<8001e54c>]
>> (imx6sl_set_wait_clk+0x0/0x70) from [<8001def4>]
>> (imx6sl_enter_wait+0x24/0x2c) [  288.266684]  r5:00000043 r4:00000001
>> [  288.270949] [<8001ded0>] (imx6sl_enter_wait+0x0/0x2c) from
>> [<80317608>] (cpuidle_enter_state+0x44/0xfc) [  288.281051]
>> r4:13bf2645 r3:8001ded0 [  288.285682] [<803175c4>]
>> (cpuidle_enter_state+0x0/0xfc) from [<803177bc>]
>> (cpuidle_idle_call+0xfc/0x150) [  288.295871]  r8:806e00d8 r7:00000001
>> r6:00000000 r5:80c58034 r4:806fd360 [  288.304428] [<803176c0>]
>> (cpuidle_idle_call+0x0/0x150) from [<8000fa68>]
>> (arch_cpu_idle+0x10/0x44) [  288.314108]  r9:8070970a r8:8070970a
>> r7:806d2000 r6:806da0dc r5:806d2000
>> r4:806d2000
>> [  288.323611] [<8000fa58>] (arch_cpu_idle+0x0/0x44) from [<800590f4>]
>> (cpu_startup_entry+0xe0/0x120)
>> [  288.333460] [<80059014>] (cpu_startup_entry+0x0/0x120) from
>> [<80503c8c>] (rest_init+0xcc/0xdc) [  288.342810]  r7:ffffffff
>> r3:00000000 [  288.347115] [<80503bc0>] (rest_init+0x0/0xdc) from
>> [<806a2b00>]
>> (start_kernel+0x348/0x354)
>> [  288.356099]  r6:806da040 r5:806da040 r4:806da150 [  288.361972]
>> [<806a27b8>] (start_kernel+0x0/0x354) from [<80008070>]
>> (0x80008070)
>>
>>
>> Regards,
>>
>> john
>>
>>

^ permalink raw reply

* [PATCH 02/20] ARM64 : Add dummy asm/cpu.h
From: Hanjun Guo @ 2014-01-20  8:58 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <52D93CAA.1080604@arm.com>

On 2014-1-17 22:22, Sudeep Holla wrote:
> On 17/01/14 12:24, Hanjun Guo wrote:
>> ACPI requires a cpu.h, add a dummy one copied from arm. This will need
>> updated or replaced as ACPI based cpu hotplug or cpu topology for armv8
>> is worked out.
>>
>> Signed-off-by: Graeme Gregory <graeme.gregory@linaro.org>
>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>> ---
>>  arch/arm64/include/asm/cpu.h |   25 +++++++++++++++++++++++++
>>  1 file changed, 25 insertions(+)
>>  create mode 100644 arch/arm64/include/asm/cpu.h
>>
>> diff --git a/arch/arm64/include/asm/cpu.h b/arch/arm64/include/asm/cpu.h
>> new file mode 100644
>> index 0000000..8625eb1
>> --- /dev/null
>> +++ b/arch/arm64/include/asm/cpu.h
>> @@ -0,0 +1,25 @@
>> +/*
>> + *  Copyright (C) 2004-2005 ARM Ltd.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +#ifndef __ASM_ARM_CPU_H
>> +#define __ASM_ARM_CPU_H
>> +
>> +#include <linux/percpu.h>
>> +#include <linux/cpu.h>
>> +#include <linux/topology.h>
>> +
>> +struct cpuinfo_arm {
>> +	struct cpu	cpu;
>> +	u64		cpuid;
>> +#ifdef CONFIG_SMP
>> +	unsigned int	loops_per_jiffy;
> 
> IIUC we don't have loop-based delay support in ARM64.
> It's always timer based and in which case we don't need loops_per_jiffy

Ok, will remove it.

Thanks
Hanjun

^ permalink raw reply

* [PATCH 09/20] ARM64 / ACPI: Implement core functions for parsing MADT table
From: Hanjun Guo @ 2014-01-20  8:49 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <201401171512.42850.arnd@arndb.de>

On 2014-1-17 22:12, Arnd Bergmann wrote:
> On Friday 17 January 2014, Hanjun Guo wrote:
>>  
>> +/*
>> + * Local interrupt controller address,
>> + * GIC cpu interface base address on ARM/ARM64
>> + */
>> +static u64 acpi_lapic_addr __initdata;
> 
> If it's cpu local, don't you need more than one address to support SMP?

Good point, thanks for pointing this out. I have a question, do we really
have some SoCs without banked registers?

I ask this question because we can do something for GIC cpu interface
with per cpu offset, but ACPI do NOT support per cpu offset for GIC
distributor.

> Also, the variable appears to be write-only.

Actually not, it will be used for GIC initialization.

> 
>> +#define BAD_MADT_ENTRY(entry, end) (					\
>> +	(!entry) || (unsigned long)entry + sizeof(*entry) > end ||	\
>> +	((struct acpi_subtable_header *)entry)->length < sizeof(*entry))
>> +
> 
> Better make this an inline function.
> 
>> +static int __init
>> +acpi_parse_gic(struct acpi_subtable_header *header, const unsigned long end)
>> +{
>> +	struct acpi_madt_generic_interrupt *processor = NULL;
>> +
>> +	processor = (struct acpi_madt_generic_interrupt *)header;
> 
> You don't need the initialization in the first line when you write to the
> variable before reading it. Same in the other functions.

Ok, I will update them all in next version.

Thanks
hanjun

^ permalink raw reply

* [PATCH v4] dmaengine: sirf: enable generic dt binding for dma channels
From: Vinod Koul @ 2014-01-20  8:47 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAGsJ_4zcwCx0RNMNx8YaDBFtGE=02-B79+WKDGeky80X5agcuw@mail.gmail.com>

On Mon, Jan 20, 2014 at 05:35:07PM +0800, Barry Song wrote:
> 2014/1/20 Vinod Koul <vinod.koul@intel.com>:
> > On Wed, Jan 08, 2014 at 10:12:49PM +0800, Barry Song wrote:
> >> From: Barry Song <Baohua.Song@csr.com>
> >>
> >> move to support of_dma_request_slave_channel() and dma_request_slave_channel.
> >> we add a xlate() to let dma clients be able to find right dma_chan by generic
> >> "dmas" properties in dts.
> >>
> >> Cc: Mark Rutland <mark.rutland@arm.com>
> >> Cc: Lars-Peter Clausen <lars@metafoo.de>
> >> Signed-off-by: Barry Song <Baohua.Song@csr.com>
> > Look okay, need an ACk from DT maintainers before I can apply...
> 
> Vinod, will i send v5 with your ack to
> devicetree-discuss at lists.ozlabs.org, and CC Grant & Rob?
Which tree are you tragetting this, if dmaengine then my ack make no sense :)

> 
> Hi Rob, will you Ack this one if you have noticed this thread?
I dont think Robs email is avlid anymore, I think he moved to Linaro, if I am
not mistaken.

~Vinod
> > ~Vinod
> >> ---
> >>  -v4: clear dt-binding document according to Mark's feedback
> 
> -barry
> --
> To unsubscribe from this list: send the line "unsubscribe dmaengine" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

-- 

^ permalink raw reply


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