SUPERH platform development
 help / color / mirror / Atom feed
* [PATCH][RESEND] ARM: mach-shmobile: AG5EVM/Kota2 external Ethernet fix
From: Magnus Damm @ 2011-08-26  4:49 UTC (permalink / raw)
  To: linux-sh

From: Magnus Damm <damm@opensource.se>

Keep the ZB clock enabled on sh73a0 to allow the BSC
to access external peripherals hooked up to CS signals.

This is needed to unbreak Ethernet support on sh73a0 boards
such as AG5EVM and Kota2 together with the following patch:

 794d78f drivers: sh: late disabling of clocks V2

Signed-off-by: Magnus Damm <damm@opensource.se>
---

 Rafael, since this patch is Runtime PM clock related, can you
 please merge this with your other 3.1-rc fixes?

 Without this patch sh73a0-based boards cannot use Ethernet.

 arch/arm/mach-shmobile/clock-sh73a0.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

--- 0001/arch/arm/mach-shmobile/clock-sh73a0.c
+++ work/arch/arm/mach-shmobile/clock-sh73a0.c	2011-08-22 14:31:42.000000000 +0900
@@ -243,7 +243,7 @@ static struct clk div6_clks[DIV6_NR] = {
 	[DIV6_VCK1] = SH_CLK_DIV6(&pll1_div2_clk, VCLKCR1, 0),
 	[DIV6_VCK2] = SH_CLK_DIV6(&pll1_div2_clk, VCLKCR2, 0),
 	[DIV6_VCK3] = SH_CLK_DIV6(&pll1_div2_clk, VCLKCR3, 0),
-	[DIV6_ZB1] = SH_CLK_DIV6(&pll1_div2_clk, ZBCKCR, 0),
+	[DIV6_ZB1] = SH_CLK_DIV6(&pll1_div2_clk, ZBCKCR, CLK_ENABLE_ON_INIT),
 	[DIV6_FLCTL] = SH_CLK_DIV6(&pll1_div2_clk, FLCKCR, 0),
 	[DIV6_SDHI0] = SH_CLK_DIV6(&pll1_div2_clk, SD0CKCR, 0),
 	[DIV6_SDHI1] = SH_CLK_DIV6(&pll1_div2_clk, SD1CKCR, 0),

^ permalink raw reply

* [PATCH] ARM: mach-shmobile: sh7372 LCDC1 suspend fix V2
From: Magnus Damm @ 2011-08-26  4:47 UTC (permalink / raw)
  To: linux-sh
In-Reply-To: <20110824093936.8230.53081.sendpatchset@rxone.opensource.se>

From: Magnus Damm <damm@opensource.se>

Associate the HDMI clock together with LCDC1 on sh7372 V2.

Without this patch Suspend-to-RAM hangs on the boards
AP4EVB and Mackerel. The code hangs in the LCDC driver
where the software is waiting forever for the hardware to
power down. By explicitly associating the HDMI clock with
LCDC1 we can make sure the HDMI clock is enabled using
Runtime PM whenever the driver is accessing the hardware.

This HDMI and LCDC1 dependency is documented in the sh7372
data sheet. Older kernels did work as expected but the
recently merged (3.1-rc)

 794d78f drivers: sh: late disabling of clocks V2

introduced code to turn off clocks lacking software reference
which happens to include the HDMI clock that is needed by
LCDC1 to operate as expected.

Signed-off-by: Magnus Damm <damm@opensource.se>
---

 Changes V1 -> V2:
 - Use lcdc1_device on AP4EVB to build properly.

 arch/arm/mach-shmobile/board-ap4evb.c   |    1 +
 arch/arm/mach-shmobile/board-mackerel.c |    1 +
 arch/arm/mach-shmobile/clock-sh7372.c   |    2 ++
 3 files changed, 4 insertions(+)

--- 0001/arch/arm/mach-shmobile/board-ap4evb.c
+++ work/arch/arm/mach-shmobile/board-ap4evb.c	2011-08-26 13:41:24.000000000 +0900
@@ -1412,6 +1412,7 @@ static void __init ap4evb_init(void)
 	fsi_init_pm_clock();
 	sh7372_pm_init();
 	pm_clk_add(&fsi_device.dev, "spu2");
+	pm_clk_add(&lcdc1_device.dev, "hdmi");
 }
 
 static void __init ap4evb_timer_init(void)
--- 0004/arch/arm/mach-shmobile/board-mackerel.c
+++ work/arch/arm/mach-shmobile/board-mackerel.c	2011-08-26 13:33:36.000000000 +0900
@@ -1592,6 +1592,7 @@ static void __init mackerel_init(void)
 	hdmi_init_pm_clock();
 	sh7372_pm_init();
 	pm_clk_add(&fsi_device.dev, "spu2");
+	pm_clk_add(&hdmi_lcdc_device.dev, "hdmi");
 }
 
 static void __init mackerel_timer_init(void)
--- 0005/arch/arm/mach-shmobile/clock-sh7372.c
+++ work/arch/arm/mach-shmobile/clock-sh7372.c	2011-08-26 13:33:36.000000000 +0900
@@ -659,6 +659,8 @@ static struct clk_lookup lookups[] = {
 	CLKDEV_DEV_ID("renesas_usbhs.1", &mstp_clks[MSTP406]), /* USB1 */
 	CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[MSTP403]), /* KEYSC */
 
+	CLKDEV_ICK_ID("hdmi", "sh_mobile_lcdc_fb.1",
+		      &div6_reparent_clks[DIV6_HDMI]),
 	CLKDEV_ICK_ID("ick", "sh-mobile-hdmi", &div6_reparent_clks[DIV6_HDMI]),
 	CLKDEV_ICK_ID("icka", "sh_fsi2", &div6_reparent_clks[DIV6_FSIA]),
 	CLKDEV_ICK_ID("ickb", "sh_fsi2", &div6_reparent_clks[DIV6_FSIB]),

^ permalink raw reply

* Re: Can not compile Ecovec board
From: Nobuhiro Iwamatsu @ 2011-08-26  4:30 UTC (permalink / raw)
  To: linux-sh
In-Reply-To: <87aaaxou97.wl%kuninori.morimoto.gx@renesas.com>

This was already revised in linux-next tree.

Best regards,
  Nobuhiro

2011/8/26 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>:
>
> Hi Paul, Magnus, SH-ML members
>
> I can not compile Ecovec board on latest linus/master branch
> it say
>
> -------------------------
>  GEN     /opt/usr/src/WORK/morimoto/gitlinux/binary/ecovec/Makefile
>  CHK     include/linux/version.h
>  Using /opt/usr/src/WORK/morimoto/gitlinux/linux-2.6 as source for kernel
>  CHK     include/generated/utsrelease.h
> make[3]: `include/generated/machtypes.h' is up to date.
>  CALL    /opt/usr/src/WORK/morimoto/gitlinux/linux-2.6/scripts/checksyscalls.sh
>  CHK     include/generated/compile.h
>  CC      arch/sh/kernel/idle.o
>  CC      arch/sh/kernel/ptrace_32.o
>  CC      arch/sh/kernel/return_address.o
> /opt/usr/src/WORK/morimoto/gitlinux/linux-2.6/arch/sh/kernel/idle.c:25:15: error: static declaration of 'pm_idle' follows non-static declaration
> /opt/usr/src/WORK/morimoto/gitlinux/linux-2.6/include/linux/pm.h:34:15: note: previous declaration of 'pm_idle' was here
> make[3]: *** [arch/sh/kernel/idle.o] Error 1
> make[3]: *** Waiting for unfinished jobs....
> /opt/usr/src/WORK/morimoto/gitlinux/linux-2.6/arch/sh/kernel/ptrace_32.c:66:6: error: conflicting types for 'ptrace_triggered'
> /opt/usr/src/WORK/morimoto/gitlinux/linux-2.6/arch/sh/include/asm/ptrace.h:126:13: note: previous declaration of 'ptrace_triggered' was here
> make[3]: *** [arch/sh/kernel/ptrace_32.o] Error 1
> make[2]: *** [arch/sh/kernel] Error 2
> make[2]: *** Waiting for unfinished jobs....
> make[2]: *** wait: No child processes.  Stop.
> make[1]: *** [sub-make] Error 2
> make: *** [all] Error 2
> -------------------------
>
> Best regards
> ---
> Kuninori Morimoto
> --
> To unsubscribe from this list: send the line "unsubscribe linux-sh" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>



-- 
Nobuhiro Iwamatsu
   iwamatsu at {nigauri.org / debian.org}
   GPG ID: 40AD1FA6

^ permalink raw reply

* Can not compile Ecovec board
From: Kuninori Morimoto @ 2011-08-26  1:07 UTC (permalink / raw)
  To: linux-sh


Hi Paul, Magnus, SH-ML members

I can not compile Ecovec board on latest linus/master branch
it say

-------------------------
  GEN     /opt/usr/src/WORK/morimoto/gitlinux/binary/ecovec/Makefile
  CHK     include/linux/version.h
  Using /opt/usr/src/WORK/morimoto/gitlinux/linux-2.6 as source for kernel
  CHK     include/generated/utsrelease.h
make[3]: `include/generated/machtypes.h' is up to date.
  CALL    /opt/usr/src/WORK/morimoto/gitlinux/linux-2.6/scripts/checksyscalls.sh
  CHK     include/generated/compile.h
  CC      arch/sh/kernel/idle.o
  CC      arch/sh/kernel/ptrace_32.o
  CC      arch/sh/kernel/return_address.o
/opt/usr/src/WORK/morimoto/gitlinux/linux-2.6/arch/sh/kernel/idle.c:25:15: error: static declaration of 'pm_idle' follows non-static declaration
/opt/usr/src/WORK/morimoto/gitlinux/linux-2.6/include/linux/pm.h:34:15: note: previous declaration of 'pm_idle' was here
make[3]: *** [arch/sh/kernel/idle.o] Error 1
make[3]: *** Waiting for unfinished jobs....
/opt/usr/src/WORK/morimoto/gitlinux/linux-2.6/arch/sh/kernel/ptrace_32.c:66:6: error: conflicting types for 'ptrace_triggered'
/opt/usr/src/WORK/morimoto/gitlinux/linux-2.6/arch/sh/include/asm/ptrace.h:126:13: note: previous declaration of 'ptrace_triggered' was here
make[3]: *** [arch/sh/kernel/ptrace_32.o] Error 1
make[2]: *** [arch/sh/kernel] Error 2
make[2]: *** Waiting for unfinished jobs....
make[2]: *** wait: No child processes.  Stop.
make[1]: *** [sub-make] Error 2
make: *** [all] Error 2
-------------------------

Best regards
---
Kuninori Morimoto

^ permalink raw reply

* Re: [PATCH] dma: shdma: transfer based runtime PM
From: Guennadi Liakhovetski @ 2011-08-25 23:11 UTC (permalink / raw)
  To: Koul, Vinod; +Cc: linux-kernel, linux-sh, Dan Williams, Paul Mundt
In-Reply-To: <1314292850.1606.88.camel@vkoul-udesk3>

On Thu, 25 Aug 2011, Koul, Vinod wrote:

> On Thu, 2011-08-25 at 16:55 +0200, Guennadi Liakhovetski wrote:
> > On Thu, 25 Aug 2011, Koul, Vinod wrote:
> > 
> > > On Thu, 2011-08-25 at 16:37 +0200, Guennadi Liakhovetski wrote:
> > > > On Thu, 25 Aug 2011, Koul, Vinod wrote:
> > > > 
> > > > > On Thu, 2011-08-18 at 16:55 +0200, Guennadi Liakhovetski wrote:
> > > > > > Currently the shdma dmaengine driver uses runtime PM to save power, when
> > > > > > no channel on the specific controller is requested by a user. This patch
> > > > > > switches the driver to count individual DMA transfers. That way the
> > > > > > controller can be powered down between transfers, even if some of its
> > > > > > channels are in use.
> > > > > No, I don't agree with the approach here, you don't need to count the
> > > > > transfers, the runtime_pm framework does that very well for you.
> > > > > 
> > > > > What you need to do is to call pm_runtime_get() in your .issue_pending
> > > > > callback (NOT in tx_submit anyway, this needs to be fixed in driver, see
> > > > > the Documentation/dmaengine.txt
> > > > > And once the transfer has completed you need to call pm_rumtime_put()
> > > > 
> > > > This has been discussed before:
> > > > 
> > > > http://marc.info/?l=linux-sh&m\x131004613801231&w=2
> > > uh, yes but at least the runtime_xxx needs to get fixed.
> > 
> > This isn't so easy either. In principle, yes, I know, that pm_runtime_* 
> > calls count depth. But I don't think the DMA case is simple enough for 
> > that. It's not necessarily one in - one out. Think about terminating 
> > transfers, timing out, closing the channel, etc. In those cases you'd have 
> > to count pending transfers and pm_runtime_put() for each of them. This is 
> > even less trivial on shdma, where DMA transfers get split into sg-lists, 
> > which are then all queued on a single queue. So, you'd have to scan that 
> > queue and check for transfer borders... That's why I decided that doing 
> > just one get() on the first descriptor and one put() on the last one would 
> > be easier and more robust.
> Wont it be easy to to do:
> - pm_runtime_get() in each submit
> - pm_runtime_put() in each callback
> Normal case above would work just fine
> - In terminate case, count the number of issued transactions, and call
> pm_runtime_put() for each canceled transaction
> (i am assuming that for each timeout error, the client will call
> terminate)

As I said, this won't be very easy to do this in a robust way. You'd have 
to scan your list of DMA blocks and see, which of them belong to one 
descriptor, and once you reach the end of that descriptor, issue a put(). 
Perhaps, this can be done, but my choice went to the currently presented 
solution.

Thanks
Guennadi

> Let me know if there is a case for you which doesn't fit in above
> 
> -- 
> ~Vinod

---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/

^ permalink raw reply

* Re: [PATCH] dma: shdma: transfer based runtime PM
From: Koul, Vinod @ 2011-08-25 17:32 UTC (permalink / raw)
  To: Guennadi Liakhovetski; +Cc: linux-kernel, linux-sh, Dan Williams, Paul Mundt
In-Reply-To: <Pine.LNX.4.64.1108251648100.17190@axis700.grange>

On Thu, 2011-08-25 at 16:55 +0200, Guennadi Liakhovetski wrote:
> On Thu, 25 Aug 2011, Koul, Vinod wrote:
> 
> > On Thu, 2011-08-25 at 16:37 +0200, Guennadi Liakhovetski wrote:
> > > On Thu, 25 Aug 2011, Koul, Vinod wrote:
> > > 
> > > > On Thu, 2011-08-18 at 16:55 +0200, Guennadi Liakhovetski wrote:
> > > > > Currently the shdma dmaengine driver uses runtime PM to save power, when
> > > > > no channel on the specific controller is requested by a user. This patch
> > > > > switches the driver to count individual DMA transfers. That way the
> > > > > controller can be powered down between transfers, even if some of its
> > > > > channels are in use.
> > > > No, I don't agree with the approach here, you don't need to count the
> > > > transfers, the runtime_pm framework does that very well for you.
> > > > 
> > > > What you need to do is to call pm_runtime_get() in your .issue_pending
> > > > callback (NOT in tx_submit anyway, this needs to be fixed in driver, see
> > > > the Documentation/dmaengine.txt
> > > > And once the transfer has completed you need to call pm_rumtime_put()
> > > 
> > > This has been discussed before:
> > > 
> > > http://marc.info/?l=linux-sh&m\x131004613801231&w=2
> > uh, yes but at least the runtime_xxx needs to get fixed.
> 
> This isn't so easy either. In principle, yes, I know, that pm_runtime_* 
> calls count depth. But I don't think the DMA case is simple enough for 
> that. It's not necessarily one in - one out. Think about terminating 
> transfers, timing out, closing the channel, etc. In those cases you'd have 
> to count pending transfers and pm_runtime_put() for each of them. This is 
> even less trivial on shdma, where DMA transfers get split into sg-lists, 
> which are then all queued on a single queue. So, you'd have to scan that 
> queue and check for transfer borders... That's why I decided that doing 
> just one get() on the first descriptor and one put() on the last one would 
> be easier and more robust.
Wont it be easy to to do:
- pm_runtime_get() in each submit
- pm_runtime_put() in each callback
Normal case above would work just fine
- In terminate case, count the number of issued transactions, and call
pm_runtime_put() for each canceled transaction
(i am assuming that for each timeout error, the client will call
terminate)

Let me know if there is a case for you which doesn't fit in above

-- 
~Vinod


^ permalink raw reply

* Re: [PATCH] dma: shdma: transfer based runtime PM
From: Guennadi Liakhovetski @ 2011-08-25 14:55 UTC (permalink / raw)
  To: Koul, Vinod; +Cc: linux-kernel, linux-sh, Dan Williams, Paul Mundt
In-Reply-To: <1314283286.1606.52.camel@vkoul-udesk3>

On Thu, 25 Aug 2011, Koul, Vinod wrote:

> On Thu, 2011-08-25 at 16:37 +0200, Guennadi Liakhovetski wrote:
> > On Thu, 25 Aug 2011, Koul, Vinod wrote:
> > 
> > > On Thu, 2011-08-18 at 16:55 +0200, Guennadi Liakhovetski wrote:
> > > > Currently the shdma dmaengine driver uses runtime PM to save power, when
> > > > no channel on the specific controller is requested by a user. This patch
> > > > switches the driver to count individual DMA transfers. That way the
> > > > controller can be powered down between transfers, even if some of its
> > > > channels are in use.
> > > No, I don't agree with the approach here, you don't need to count the
> > > transfers, the runtime_pm framework does that very well for you.
> > > 
> > > What you need to do is to call pm_runtime_get() in your .issue_pending
> > > callback (NOT in tx_submit anyway, this needs to be fixed in driver, see
> > > the Documentation/dmaengine.txt
> > > And once the transfer has completed you need to call pm_rumtime_put()
> > 
> > This has been discussed before:
> > 
> > http://marc.info/?l=linux-sh&m\x131004613801231&w=2
> uh, yes but at least the runtime_xxx needs to get fixed.

This isn't so easy either. In principle, yes, I know, that pm_runtime_* 
calls count depth. But I don't think the DMA case is simple enough for 
that. It's not necessarily one in - one out. Think about terminating 
transfers, timing out, closing the channel, etc. In those cases you'd have 
to count pending transfers and pm_runtime_put() for each of them. This is 
even less trivial on shdma, where DMA transfers get split into sg-lists, 
which are then all queued on a single queue. So, you'd have to scan that 
queue and check for transfer borders... That's why I decided that doing 
just one get() on the first descriptor and one put() on the last one would 
be easier and more robust.

Thanks
Guennadi

> 
> --
> ~Vinod
> > 
> > Thanks
> > Guennadi
> > 
> > > 
> > > Runtime PM framework actually counts the device usage count and whenever
> > > your device usage count goes to 0 it will call .runtime_suspend
> > > callback, thus enable you to save power.
> > > 
> > > -- 
> > > ~Vinod
> > > > 
> > > > Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> > > > ---
> > > > 
> > > > tested on mackerel (sh7372) with dmatest, sh_mobile_sdhi and sh_mmcif with 
> > > > runtime PM and STR.
> > > > 
> > > >  drivers/dma/shdma.c |   94 +++++++++++++++++++++++++++++++++++++--------------
> > > >  drivers/dma/shdma.h |    7 ++++
> > > >  2 files changed, 75 insertions(+), 26 deletions(-)
> > > > 
> > > > diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c
> > > > index e7bb747..81809c2 100644
> > > > --- a/drivers/dma/shdma.c
> > > > +++ b/drivers/dma/shdma.c
> > > > @@ -259,15 +259,23 @@ static int dmae_set_dmars(struct sh_dmae_chan *sh_chan, u16 val)
> > > >  	return 0;
> > > >  }
> > > >  
> > > > +static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan);
> > > > +
> > > >  static dma_cookie_t sh_dmae_tx_submit(struct dma_async_tx_descriptor *tx)
> > > >  {
> > > >  	struct sh_desc *desc = tx_to_sh_desc(tx), *chunk, *last = desc, *c;
> > > >  	struct sh_dmae_chan *sh_chan = to_sh_chan(tx->chan);
> > > > +	struct sh_dmae_slave *param = tx->chan->private;
> > > >  	dma_async_tx_callback callback = tx->callback;
> > > >  	dma_cookie_t cookie;
> > > > -	unsigned long flags;
> > > > +	bool power_up;
> > > >  
> > > > -	spin_lock_irqsave(&sh_chan->desc_lock, flags);
> > > > +	spin_lock_irq(&sh_chan->desc_lock);
> > > > +
> > > > +	if (list_empty(&sh_chan->ld_queue))
> > > > +		power_up = true;
> > > > +	else
> > > > +		power_up = false;
> > > >  
> > > >  	cookie = sh_chan->common.cookie;
> > > >  	cookie++;
> > > > @@ -303,7 +311,38 @@ static dma_cookie_t sh_dmae_tx_submit(struct dma_async_tx_descriptor *tx)
> > > >  		tx->cookie, &last->async_tx, sh_chan->id,
> > > >  		desc->hw.sar, desc->hw.tcr, desc->hw.dar);
> > > >  
> > > > -	spin_unlock_irqrestore(&sh_chan->desc_lock, flags);
> > > > +	if (power_up) {
> > > > +		sh_chan->pm_state = DMAE_PM_BUSY;
> > > > +
> > > > +		pm_runtime_get(sh_chan->dev);
> > > > +
> > > > +		spin_unlock_irq(&sh_chan->desc_lock);
> > > > +
> > > > +		pm_runtime_barrier(sh_chan->dev);
> > > > +
> > > > +		spin_lock_irq(&sh_chan->desc_lock);
> > > > +
> > > > +		/* Have we been reset, while waiting? */
> > > > +		if (sh_chan->pm_state != DMAE_PM_ESTABLISHED) {
> > > > +			dev_dbg(sh_chan->dev, "Bring up channel %d\n",
> > > > +				sh_chan->id);
> > > > +			if (param) {
> > > > +				const struct sh_dmae_slave_config *cfg > > > > +					param->config;
> > > > +
> > > > +				dmae_set_dmars(sh_chan, cfg->mid_rid);
> > > > +				dmae_set_chcr(sh_chan, cfg->chcr);
> > > > +			} else {
> > > > +				dmae_init(sh_chan);
> > > > +			}
> > > > +
> > > > +			if (sh_chan->pm_state = DMAE_PM_PENDING)
> > > > +				sh_chan_xfer_ld_queue(sh_chan);
> > > > +			sh_chan->pm_state = DMAE_PM_ESTABLISHED;
> > > > +		}
> > > > +	}
> > > > +
> > > > +	spin_unlock_irq(&sh_chan->desc_lock);
> > > >  
> > > >  	return cookie;
> > > >  }
> > > > @@ -347,8 +386,6 @@ static int sh_dmae_alloc_chan_resources(struct dma_chan *chan)
> > > >  	struct sh_dmae_slave *param = chan->private;
> > > >  	int ret;
> > > >  
> > > > -	pm_runtime_get_sync(sh_chan->dev);
> > > > -
> > > >  	/*
> > > >  	 * This relies on the guarantee from dmaengine that alloc_chan_resources
> > > >  	 * never runs concurrently with itself or free_chan_resources.
> > > > @@ -368,11 +405,6 @@ static int sh_dmae_alloc_chan_resources(struct dma_chan *chan)
> > > >  		}
> > > >  
> > > >  		param->config = cfg;
> > > > -
> > > > -		dmae_set_dmars(sh_chan, cfg->mid_rid);
> > > > -		dmae_set_chcr(sh_chan, cfg->chcr);
> > > > -	} else {
> > > > -		dmae_init(sh_chan);
> > > >  	}
> > > >  
> > > >  	while (sh_chan->descs_allocated < NR_DESCS_PER_CHANNEL) {
> > > > @@ -401,7 +433,6 @@ edescalloc:
> > > >  etestused:
> > > >  efindslave:
> > > >  	chan->private = NULL;
> > > > -	pm_runtime_put(sh_chan->dev);
> > > >  	return ret;
> > > >  }
> > > >  
> > > > @@ -413,7 +444,6 @@ static void sh_dmae_free_chan_resources(struct dma_chan *chan)
> > > >  	struct sh_dmae_chan *sh_chan = to_sh_chan(chan);
> > > >  	struct sh_desc *desc, *_desc;
> > > >  	LIST_HEAD(list);
> > > > -	int descs = sh_chan->descs_allocated;
> > > >  
> > > >  	/* Protect against ISR */
> > > >  	spin_lock_irq(&sh_chan->desc_lock);
> > > > @@ -440,9 +470,6 @@ static void sh_dmae_free_chan_resources(struct dma_chan *chan)
> > > >  
> > > >  	spin_unlock_irq(&sh_chan->desc_lock);
> > > >  
> > > > -	if (descs > 0)
> > > > -		pm_runtime_put(sh_chan->dev);
> > > > -
> > > >  	list_for_each_entry_safe(desc, _desc, &list, node)
> > > >  		kfree(desc);
> > > >  }
> > > > @@ -676,7 +703,6 @@ static int sh_dmae_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
> > > >  						  struct sh_desc, node);
> > > >  		desc->partial = (desc->hw.tcr - sh_dmae_readl(sh_chan, TCR)) <<
> > > >  			sh_chan->xmit_shift;
> > > > -
> > > >  	}
> > > >  	spin_unlock_irqrestore(&sh_chan->desc_lock, flags);
> > > >  
> > > > @@ -761,7 +787,13 @@ static dma_async_tx_callback __ld_cleanup(struct sh_dmae_chan *sh_chan, bool all
> > > >  		     async_tx_test_ack(&desc->async_tx)) || all) {
> > > >  			/* Remove from ld_queue list */
> > > >  			desc->mark = DESC_IDLE;
> > > > +
> > > >  			list_move(&desc->node, &sh_chan->ld_free);
> > > > +
> > > > +			if (list_empty(&sh_chan->ld_queue)) {
> > > > +				dev_dbg(sh_chan->dev, "Bring down channel %d\n", sh_chan->id);
> > > > +				pm_runtime_put(sh_chan->dev);
> > > > +			}
> > > >  		}
> > > >  	}
> > > >  
> > > > @@ -791,16 +823,14 @@ static void sh_dmae_chan_ld_cleanup(struct sh_dmae_chan *sh_chan, bool all)
> > > >  		;
> > > >  }
> > > >  
> > > > +/* Called under spin_lock_irq(&sh_chan->desc_lock) */
> > > >  static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan)
> > > >  {
> > > >  	struct sh_desc *desc;
> > > >  
> > > > -	spin_lock_irq(&sh_chan->desc_lock);
> > > >  	/* DMA work check */
> > > > -	if (dmae_is_busy(sh_chan)) {
> > > > -		spin_unlock_irq(&sh_chan->desc_lock);
> > > > +	if (dmae_is_busy(sh_chan))
> > > >  		return;
> > > > -	}
> > > >  
> > > >  	/* Find the first not transferred descriptor */
> > > >  	list_for_each_entry(desc, &sh_chan->ld_queue, node)
> > > > @@ -813,14 +843,18 @@ static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan)
> > > >  			dmae_start(sh_chan);
> > > >  			break;
> > > >  		}
> > > > -
> > > > -	spin_unlock_irq(&sh_chan->desc_lock);
> > > >  }
> > > >  
> > > >  static void sh_dmae_memcpy_issue_pending(struct dma_chan *chan)
> > > >  {
> > > >  	struct sh_dmae_chan *sh_chan = to_sh_chan(chan);
> > > > -	sh_chan_xfer_ld_queue(sh_chan);
> > > > +
> > > > +	spin_lock_irq(&sh_chan->desc_lock);
> > > > +	if (sh_chan->pm_state = DMAE_PM_ESTABLISHED)
> > > > +		sh_chan_xfer_ld_queue(sh_chan);
> > > > +	else
> > > > +		sh_chan->pm_state = DMAE_PM_PENDING;
> > > > +	spin_unlock_irq(&sh_chan->desc_lock);
> > > >  }
> > > >  
> > > >  static enum dma_status sh_dmae_tx_status(struct dma_chan *chan,
> > > > @@ -913,6 +947,12 @@ static bool sh_dmae_reset(struct sh_dmae_device *shdev)
> > > >  
> > > >  		list_splice_init(&sh_chan->ld_queue, &dl);
> > > >  
> > > > +		if (!list_empty(&dl)) {
> > > > +			dev_dbg(sh_chan->dev, "Bring down channel %d\n", sh_chan->id);
> > > > +			pm_runtime_put(sh_chan->dev);
> > > > +		}
> > > > +		sh_chan->pm_state = DMAE_PM_ESTABLISHED;
> > > > +
> > > >  		spin_unlock(&sh_chan->desc_lock);
> > > >  
> > > >  		/* Complete all  */
> > > > @@ -966,10 +1006,10 @@ static void dmae_do_tasklet(unsigned long data)
> > > >  			break;
> > > >  		}
> > > >  	}
> > > > -	spin_unlock_irq(&sh_chan->desc_lock);
> > > > -
> > > >  	/* Next desc */
> > > >  	sh_chan_xfer_ld_queue(sh_chan);
> > > > +	spin_unlock_irq(&sh_chan->desc_lock);
> > > > +
> > > >  	sh_dmae_chan_ld_cleanup(sh_chan, false);
> > > >  }
> > > >  
> > > > @@ -1037,7 +1077,9 @@ static int __devinit sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id,
> > > >  		return -ENOMEM;
> > > >  	}
> > > >  
> > > > -	/* copy struct dma_device */
> > > > +	new_sh_chan->pm_state = DMAE_PM_ESTABLISHED;
> > > > +
> > > > +	/* reference struct dma_device */
> > > >  	new_sh_chan->common.device = &shdev->common;
> > > >  
> > > >  	new_sh_chan->dev = shdev->common.dev;
> > > > diff --git a/drivers/dma/shdma.h b/drivers/dma/shdma.h
> > > > index dc56576..2b55a27 100644
> > > > --- a/drivers/dma/shdma.h
> > > > +++ b/drivers/dma/shdma.h
> > > > @@ -23,6 +23,12 @@
> > > >  
> > > >  struct device;
> > > >  
> > > > +enum dmae_pm_state {
> > > > +	DMAE_PM_ESTABLISHED,
> > > > +	DMAE_PM_BUSY,
> > > > +	DMAE_PM_PENDING,
> > > > +};
> > > > +
> > > >  struct sh_dmae_chan {
> > > >  	dma_cookie_t completed_cookie;	/* The maximum cookie completed */
> > > >  	spinlock_t desc_lock;		/* Descriptor operation lock */
> > > > @@ -38,6 +44,7 @@ struct sh_dmae_chan {
> > > >  	u32 __iomem *base;
> > > >  	char dev_id[16];		/* unique name per DMAC of channel */
> > > >  	int pm_error;
> > > > +	enum dmae_pm_state pm_state;
> > > >  };
> > > >  
> > > >  struct sh_dmae_device {
> > > 
> > > 
> > > 
> > > 
> > 
> > ---
> > Guennadi Liakhovetski, Ph.D.
> > Freelance Open-Source Software Developer
> > http://www.open-technology.de/
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > Please read the FAQ at  http://www.tux.org/lkml/
> 

---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/

^ permalink raw reply

* Re: [PATCH] dma: shdma: transfer based runtime PM
From: Koul, Vinod @ 2011-08-25 14:53 UTC (permalink / raw)
  To: Guennadi Liakhovetski; +Cc: linux-kernel, linux-sh, Dan Williams, Paul Mundt
In-Reply-To: <Pine.LNX.4.64.1108251636190.17190@axis700.grange>

On Thu, 2011-08-25 at 16:37 +0200, Guennadi Liakhovetski wrote:
> On Thu, 25 Aug 2011, Koul, Vinod wrote:
> 
> > On Thu, 2011-08-18 at 16:55 +0200, Guennadi Liakhovetski wrote:
> > > Currently the shdma dmaengine driver uses runtime PM to save power, when
> > > no channel on the specific controller is requested by a user. This patch
> > > switches the driver to count individual DMA transfers. That way the
> > > controller can be powered down between transfers, even if some of its
> > > channels are in use.
> > No, I don't agree with the approach here, you don't need to count the
> > transfers, the runtime_pm framework does that very well for you.
> > 
> > What you need to do is to call pm_runtime_get() in your .issue_pending
> > callback (NOT in tx_submit anyway, this needs to be fixed in driver, see
> > the Documentation/dmaengine.txt
> > And once the transfer has completed you need to call pm_rumtime_put()
> 
> This has been discussed before:
> 
> http://marc.info/?l=linux-sh&m\x131004613801231&w=2
uh, yes but at least the runtime_xxx needs to get fixed.

--
~Vinod
> 
> Thanks
> Guennadi
> 
> > 
> > Runtime PM framework actually counts the device usage count and whenever
> > your device usage count goes to 0 it will call .runtime_suspend
> > callback, thus enable you to save power.
> > 
> > -- 
> > ~Vinod
> > > 
> > > Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> > > ---
> > > 
> > > tested on mackerel (sh7372) with dmatest, sh_mobile_sdhi and sh_mmcif with 
> > > runtime PM and STR.
> > > 
> > >  drivers/dma/shdma.c |   94 +++++++++++++++++++++++++++++++++++++--------------
> > >  drivers/dma/shdma.h |    7 ++++
> > >  2 files changed, 75 insertions(+), 26 deletions(-)
> > > 
> > > diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c
> > > index e7bb747..81809c2 100644
> > > --- a/drivers/dma/shdma.c
> > > +++ b/drivers/dma/shdma.c
> > > @@ -259,15 +259,23 @@ static int dmae_set_dmars(struct sh_dmae_chan *sh_chan, u16 val)
> > >  	return 0;
> > >  }
> > >  
> > > +static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan);
> > > +
> > >  static dma_cookie_t sh_dmae_tx_submit(struct dma_async_tx_descriptor *tx)
> > >  {
> > >  	struct sh_desc *desc = tx_to_sh_desc(tx), *chunk, *last = desc, *c;
> > >  	struct sh_dmae_chan *sh_chan = to_sh_chan(tx->chan);
> > > +	struct sh_dmae_slave *param = tx->chan->private;
> > >  	dma_async_tx_callback callback = tx->callback;
> > >  	dma_cookie_t cookie;
> > > -	unsigned long flags;
> > > +	bool power_up;
> > >  
> > > -	spin_lock_irqsave(&sh_chan->desc_lock, flags);
> > > +	spin_lock_irq(&sh_chan->desc_lock);
> > > +
> > > +	if (list_empty(&sh_chan->ld_queue))
> > > +		power_up = true;
> > > +	else
> > > +		power_up = false;
> > >  
> > >  	cookie = sh_chan->common.cookie;
> > >  	cookie++;
> > > @@ -303,7 +311,38 @@ static dma_cookie_t sh_dmae_tx_submit(struct dma_async_tx_descriptor *tx)
> > >  		tx->cookie, &last->async_tx, sh_chan->id,
> > >  		desc->hw.sar, desc->hw.tcr, desc->hw.dar);
> > >  
> > > -	spin_unlock_irqrestore(&sh_chan->desc_lock, flags);
> > > +	if (power_up) {
> > > +		sh_chan->pm_state = DMAE_PM_BUSY;
> > > +
> > > +		pm_runtime_get(sh_chan->dev);
> > > +
> > > +		spin_unlock_irq(&sh_chan->desc_lock);
> > > +
> > > +		pm_runtime_barrier(sh_chan->dev);
> > > +
> > > +		spin_lock_irq(&sh_chan->desc_lock);
> > > +
> > > +		/* Have we been reset, while waiting? */
> > > +		if (sh_chan->pm_state != DMAE_PM_ESTABLISHED) {
> > > +			dev_dbg(sh_chan->dev, "Bring up channel %d\n",
> > > +				sh_chan->id);
> > > +			if (param) {
> > > +				const struct sh_dmae_slave_config *cfg > > > +					param->config;
> > > +
> > > +				dmae_set_dmars(sh_chan, cfg->mid_rid);
> > > +				dmae_set_chcr(sh_chan, cfg->chcr);
> > > +			} else {
> > > +				dmae_init(sh_chan);
> > > +			}
> > > +
> > > +			if (sh_chan->pm_state = DMAE_PM_PENDING)
> > > +				sh_chan_xfer_ld_queue(sh_chan);
> > > +			sh_chan->pm_state = DMAE_PM_ESTABLISHED;
> > > +		}
> > > +	}
> > > +
> > > +	spin_unlock_irq(&sh_chan->desc_lock);
> > >  
> > >  	return cookie;
> > >  }
> > > @@ -347,8 +386,6 @@ static int sh_dmae_alloc_chan_resources(struct dma_chan *chan)
> > >  	struct sh_dmae_slave *param = chan->private;
> > >  	int ret;
> > >  
> > > -	pm_runtime_get_sync(sh_chan->dev);
> > > -
> > >  	/*
> > >  	 * This relies on the guarantee from dmaengine that alloc_chan_resources
> > >  	 * never runs concurrently with itself or free_chan_resources.
> > > @@ -368,11 +405,6 @@ static int sh_dmae_alloc_chan_resources(struct dma_chan *chan)
> > >  		}
> > >  
> > >  		param->config = cfg;
> > > -
> > > -		dmae_set_dmars(sh_chan, cfg->mid_rid);
> > > -		dmae_set_chcr(sh_chan, cfg->chcr);
> > > -	} else {
> > > -		dmae_init(sh_chan);
> > >  	}
> > >  
> > >  	while (sh_chan->descs_allocated < NR_DESCS_PER_CHANNEL) {
> > > @@ -401,7 +433,6 @@ edescalloc:
> > >  etestused:
> > >  efindslave:
> > >  	chan->private = NULL;
> > > -	pm_runtime_put(sh_chan->dev);
> > >  	return ret;
> > >  }
> > >  
> > > @@ -413,7 +444,6 @@ static void sh_dmae_free_chan_resources(struct dma_chan *chan)
> > >  	struct sh_dmae_chan *sh_chan = to_sh_chan(chan);
> > >  	struct sh_desc *desc, *_desc;
> > >  	LIST_HEAD(list);
> > > -	int descs = sh_chan->descs_allocated;
> > >  
> > >  	/* Protect against ISR */
> > >  	spin_lock_irq(&sh_chan->desc_lock);
> > > @@ -440,9 +470,6 @@ static void sh_dmae_free_chan_resources(struct dma_chan *chan)
> > >  
> > >  	spin_unlock_irq(&sh_chan->desc_lock);
> > >  
> > > -	if (descs > 0)
> > > -		pm_runtime_put(sh_chan->dev);
> > > -
> > >  	list_for_each_entry_safe(desc, _desc, &list, node)
> > >  		kfree(desc);
> > >  }
> > > @@ -676,7 +703,6 @@ static int sh_dmae_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
> > >  						  struct sh_desc, node);
> > >  		desc->partial = (desc->hw.tcr - sh_dmae_readl(sh_chan, TCR)) <<
> > >  			sh_chan->xmit_shift;
> > > -
> > >  	}
> > >  	spin_unlock_irqrestore(&sh_chan->desc_lock, flags);
> > >  
> > > @@ -761,7 +787,13 @@ static dma_async_tx_callback __ld_cleanup(struct sh_dmae_chan *sh_chan, bool all
> > >  		     async_tx_test_ack(&desc->async_tx)) || all) {
> > >  			/* Remove from ld_queue list */
> > >  			desc->mark = DESC_IDLE;
> > > +
> > >  			list_move(&desc->node, &sh_chan->ld_free);
> > > +
> > > +			if (list_empty(&sh_chan->ld_queue)) {
> > > +				dev_dbg(sh_chan->dev, "Bring down channel %d\n", sh_chan->id);
> > > +				pm_runtime_put(sh_chan->dev);
> > > +			}
> > >  		}
> > >  	}
> > >  
> > > @@ -791,16 +823,14 @@ static void sh_dmae_chan_ld_cleanup(struct sh_dmae_chan *sh_chan, bool all)
> > >  		;
> > >  }
> > >  
> > > +/* Called under spin_lock_irq(&sh_chan->desc_lock) */
> > >  static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan)
> > >  {
> > >  	struct sh_desc *desc;
> > >  
> > > -	spin_lock_irq(&sh_chan->desc_lock);
> > >  	/* DMA work check */
> > > -	if (dmae_is_busy(sh_chan)) {
> > > -		spin_unlock_irq(&sh_chan->desc_lock);
> > > +	if (dmae_is_busy(sh_chan))
> > >  		return;
> > > -	}
> > >  
> > >  	/* Find the first not transferred descriptor */
> > >  	list_for_each_entry(desc, &sh_chan->ld_queue, node)
> > > @@ -813,14 +843,18 @@ static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan)
> > >  			dmae_start(sh_chan);
> > >  			break;
> > >  		}
> > > -
> > > -	spin_unlock_irq(&sh_chan->desc_lock);
> > >  }
> > >  
> > >  static void sh_dmae_memcpy_issue_pending(struct dma_chan *chan)
> > >  {
> > >  	struct sh_dmae_chan *sh_chan = to_sh_chan(chan);
> > > -	sh_chan_xfer_ld_queue(sh_chan);
> > > +
> > > +	spin_lock_irq(&sh_chan->desc_lock);
> > > +	if (sh_chan->pm_state = DMAE_PM_ESTABLISHED)
> > > +		sh_chan_xfer_ld_queue(sh_chan);
> > > +	else
> > > +		sh_chan->pm_state = DMAE_PM_PENDING;
> > > +	spin_unlock_irq(&sh_chan->desc_lock);
> > >  }
> > >  
> > >  static enum dma_status sh_dmae_tx_status(struct dma_chan *chan,
> > > @@ -913,6 +947,12 @@ static bool sh_dmae_reset(struct sh_dmae_device *shdev)
> > >  
> > >  		list_splice_init(&sh_chan->ld_queue, &dl);
> > >  
> > > +		if (!list_empty(&dl)) {
> > > +			dev_dbg(sh_chan->dev, "Bring down channel %d\n", sh_chan->id);
> > > +			pm_runtime_put(sh_chan->dev);
> > > +		}
> > > +		sh_chan->pm_state = DMAE_PM_ESTABLISHED;
> > > +
> > >  		spin_unlock(&sh_chan->desc_lock);
> > >  
> > >  		/* Complete all  */
> > > @@ -966,10 +1006,10 @@ static void dmae_do_tasklet(unsigned long data)
> > >  			break;
> > >  		}
> > >  	}
> > > -	spin_unlock_irq(&sh_chan->desc_lock);
> > > -
> > >  	/* Next desc */
> > >  	sh_chan_xfer_ld_queue(sh_chan);
> > > +	spin_unlock_irq(&sh_chan->desc_lock);
> > > +
> > >  	sh_dmae_chan_ld_cleanup(sh_chan, false);
> > >  }
> > >  
> > > @@ -1037,7 +1077,9 @@ static int __devinit sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id,
> > >  		return -ENOMEM;
> > >  	}
> > >  
> > > -	/* copy struct dma_device */
> > > +	new_sh_chan->pm_state = DMAE_PM_ESTABLISHED;
> > > +
> > > +	/* reference struct dma_device */
> > >  	new_sh_chan->common.device = &shdev->common;
> > >  
> > >  	new_sh_chan->dev = shdev->common.dev;
> > > diff --git a/drivers/dma/shdma.h b/drivers/dma/shdma.h
> > > index dc56576..2b55a27 100644
> > > --- a/drivers/dma/shdma.h
> > > +++ b/drivers/dma/shdma.h
> > > @@ -23,6 +23,12 @@
> > >  
> > >  struct device;
> > >  
> > > +enum dmae_pm_state {
> > > +	DMAE_PM_ESTABLISHED,
> > > +	DMAE_PM_BUSY,
> > > +	DMAE_PM_PENDING,
> > > +};
> > > +
> > >  struct sh_dmae_chan {
> > >  	dma_cookie_t completed_cookie;	/* The maximum cookie completed */
> > >  	spinlock_t desc_lock;		/* Descriptor operation lock */
> > > @@ -38,6 +44,7 @@ struct sh_dmae_chan {
> > >  	u32 __iomem *base;
> > >  	char dev_id[16];		/* unique name per DMAC of channel */
> > >  	int pm_error;
> > > +	enum dmae_pm_state pm_state;
> > >  };
> > >  
> > >  struct sh_dmae_device {
> > 
> > 
> > 
> > 
> 
> ---
> Guennadi Liakhovetski, Ph.D.
> Freelance Open-Source Software Developer
> http://www.open-technology.de/
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/


^ permalink raw reply

* Re: [PATCH] dma: shdma: transfer based runtime PM
From: Koul, Vinod @ 2011-08-25 14:38 UTC (permalink / raw)
  To: Guennadi Liakhovetski; +Cc: linux-kernel, linux-sh, Dan Williams, Paul Mundt
In-Reply-To: <Pine.LNX.4.64.1108181650530.5245@axis700.grange>

On Thu, 2011-08-18 at 16:55 +0200, Guennadi Liakhovetski wrote:
> Currently the shdma dmaengine driver uses runtime PM to save power, when
> no channel on the specific controller is requested by a user. This patch
> switches the driver to count individual DMA transfers. That way the
> controller can be powered down between transfers, even if some of its
> channels are in use.
No, I don't agree with the approach here, you don't need to count the
transfers, the runtime_pm framework does that very well for you.

What you need to do is to call pm_runtime_get() in your .issue_pending
callback (NOT in tx_submit anyway, this needs to be fixed in driver, see
the Documentation/dmaengine.txt
And once the transfer has completed you need to call pm_rumtime_put()

Runtime PM framework actually counts the device usage count and whenever
your device usage count goes to 0 it will call .runtime_suspend
callback, thus enable you to save power.

-- 
~Vinod
> 
> Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> ---
> 
> tested on mackerel (sh7372) with dmatest, sh_mobile_sdhi and sh_mmcif with 
> runtime PM and STR.
> 
>  drivers/dma/shdma.c |   94 +++++++++++++++++++++++++++++++++++++--------------
>  drivers/dma/shdma.h |    7 ++++
>  2 files changed, 75 insertions(+), 26 deletions(-)
> 
> diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c
> index e7bb747..81809c2 100644
> --- a/drivers/dma/shdma.c
> +++ b/drivers/dma/shdma.c
> @@ -259,15 +259,23 @@ static int dmae_set_dmars(struct sh_dmae_chan *sh_chan, u16 val)
>  	return 0;
>  }
>  
> +static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan);
> +
>  static dma_cookie_t sh_dmae_tx_submit(struct dma_async_tx_descriptor *tx)
>  {
>  	struct sh_desc *desc = tx_to_sh_desc(tx), *chunk, *last = desc, *c;
>  	struct sh_dmae_chan *sh_chan = to_sh_chan(tx->chan);
> +	struct sh_dmae_slave *param = tx->chan->private;
>  	dma_async_tx_callback callback = tx->callback;
>  	dma_cookie_t cookie;
> -	unsigned long flags;
> +	bool power_up;
>  
> -	spin_lock_irqsave(&sh_chan->desc_lock, flags);
> +	spin_lock_irq(&sh_chan->desc_lock);
> +
> +	if (list_empty(&sh_chan->ld_queue))
> +		power_up = true;
> +	else
> +		power_up = false;
>  
>  	cookie = sh_chan->common.cookie;
>  	cookie++;
> @@ -303,7 +311,38 @@ static dma_cookie_t sh_dmae_tx_submit(struct dma_async_tx_descriptor *tx)
>  		tx->cookie, &last->async_tx, sh_chan->id,
>  		desc->hw.sar, desc->hw.tcr, desc->hw.dar);
>  
> -	spin_unlock_irqrestore(&sh_chan->desc_lock, flags);
> +	if (power_up) {
> +		sh_chan->pm_state = DMAE_PM_BUSY;
> +
> +		pm_runtime_get(sh_chan->dev);
> +
> +		spin_unlock_irq(&sh_chan->desc_lock);
> +
> +		pm_runtime_barrier(sh_chan->dev);
> +
> +		spin_lock_irq(&sh_chan->desc_lock);
> +
> +		/* Have we been reset, while waiting? */
> +		if (sh_chan->pm_state != DMAE_PM_ESTABLISHED) {
> +			dev_dbg(sh_chan->dev, "Bring up channel %d\n",
> +				sh_chan->id);
> +			if (param) {
> +				const struct sh_dmae_slave_config *cfg > +					param->config;
> +
> +				dmae_set_dmars(sh_chan, cfg->mid_rid);
> +				dmae_set_chcr(sh_chan, cfg->chcr);
> +			} else {
> +				dmae_init(sh_chan);
> +			}
> +
> +			if (sh_chan->pm_state = DMAE_PM_PENDING)
> +				sh_chan_xfer_ld_queue(sh_chan);
> +			sh_chan->pm_state = DMAE_PM_ESTABLISHED;
> +		}
> +	}
> +
> +	spin_unlock_irq(&sh_chan->desc_lock);
>  
>  	return cookie;
>  }
> @@ -347,8 +386,6 @@ static int sh_dmae_alloc_chan_resources(struct dma_chan *chan)
>  	struct sh_dmae_slave *param = chan->private;
>  	int ret;
>  
> -	pm_runtime_get_sync(sh_chan->dev);
> -
>  	/*
>  	 * This relies on the guarantee from dmaengine that alloc_chan_resources
>  	 * never runs concurrently with itself or free_chan_resources.
> @@ -368,11 +405,6 @@ static int sh_dmae_alloc_chan_resources(struct dma_chan *chan)
>  		}
>  
>  		param->config = cfg;
> -
> -		dmae_set_dmars(sh_chan, cfg->mid_rid);
> -		dmae_set_chcr(sh_chan, cfg->chcr);
> -	} else {
> -		dmae_init(sh_chan);
>  	}
>  
>  	while (sh_chan->descs_allocated < NR_DESCS_PER_CHANNEL) {
> @@ -401,7 +433,6 @@ edescalloc:
>  etestused:
>  efindslave:
>  	chan->private = NULL;
> -	pm_runtime_put(sh_chan->dev);
>  	return ret;
>  }
>  
> @@ -413,7 +444,6 @@ static void sh_dmae_free_chan_resources(struct dma_chan *chan)
>  	struct sh_dmae_chan *sh_chan = to_sh_chan(chan);
>  	struct sh_desc *desc, *_desc;
>  	LIST_HEAD(list);
> -	int descs = sh_chan->descs_allocated;
>  
>  	/* Protect against ISR */
>  	spin_lock_irq(&sh_chan->desc_lock);
> @@ -440,9 +470,6 @@ static void sh_dmae_free_chan_resources(struct dma_chan *chan)
>  
>  	spin_unlock_irq(&sh_chan->desc_lock);
>  
> -	if (descs > 0)
> -		pm_runtime_put(sh_chan->dev);
> -
>  	list_for_each_entry_safe(desc, _desc, &list, node)
>  		kfree(desc);
>  }
> @@ -676,7 +703,6 @@ static int sh_dmae_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
>  						  struct sh_desc, node);
>  		desc->partial = (desc->hw.tcr - sh_dmae_readl(sh_chan, TCR)) <<
>  			sh_chan->xmit_shift;
> -
>  	}
>  	spin_unlock_irqrestore(&sh_chan->desc_lock, flags);
>  
> @@ -761,7 +787,13 @@ static dma_async_tx_callback __ld_cleanup(struct sh_dmae_chan *sh_chan, bool all
>  		     async_tx_test_ack(&desc->async_tx)) || all) {
>  			/* Remove from ld_queue list */
>  			desc->mark = DESC_IDLE;
> +
>  			list_move(&desc->node, &sh_chan->ld_free);
> +
> +			if (list_empty(&sh_chan->ld_queue)) {
> +				dev_dbg(sh_chan->dev, "Bring down channel %d\n", sh_chan->id);
> +				pm_runtime_put(sh_chan->dev);
> +			}
>  		}
>  	}
>  
> @@ -791,16 +823,14 @@ static void sh_dmae_chan_ld_cleanup(struct sh_dmae_chan *sh_chan, bool all)
>  		;
>  }
>  
> +/* Called under spin_lock_irq(&sh_chan->desc_lock) */
>  static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan)
>  {
>  	struct sh_desc *desc;
>  
> -	spin_lock_irq(&sh_chan->desc_lock);
>  	/* DMA work check */
> -	if (dmae_is_busy(sh_chan)) {
> -		spin_unlock_irq(&sh_chan->desc_lock);
> +	if (dmae_is_busy(sh_chan))
>  		return;
> -	}
>  
>  	/* Find the first not transferred descriptor */
>  	list_for_each_entry(desc, &sh_chan->ld_queue, node)
> @@ -813,14 +843,18 @@ static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan)
>  			dmae_start(sh_chan);
>  			break;
>  		}
> -
> -	spin_unlock_irq(&sh_chan->desc_lock);
>  }
>  
>  static void sh_dmae_memcpy_issue_pending(struct dma_chan *chan)
>  {
>  	struct sh_dmae_chan *sh_chan = to_sh_chan(chan);
> -	sh_chan_xfer_ld_queue(sh_chan);
> +
> +	spin_lock_irq(&sh_chan->desc_lock);
> +	if (sh_chan->pm_state = DMAE_PM_ESTABLISHED)
> +		sh_chan_xfer_ld_queue(sh_chan);
> +	else
> +		sh_chan->pm_state = DMAE_PM_PENDING;
> +	spin_unlock_irq(&sh_chan->desc_lock);
>  }
>  
>  static enum dma_status sh_dmae_tx_status(struct dma_chan *chan,
> @@ -913,6 +947,12 @@ static bool sh_dmae_reset(struct sh_dmae_device *shdev)
>  
>  		list_splice_init(&sh_chan->ld_queue, &dl);
>  
> +		if (!list_empty(&dl)) {
> +			dev_dbg(sh_chan->dev, "Bring down channel %d\n", sh_chan->id);
> +			pm_runtime_put(sh_chan->dev);
> +		}
> +		sh_chan->pm_state = DMAE_PM_ESTABLISHED;
> +
>  		spin_unlock(&sh_chan->desc_lock);
>  
>  		/* Complete all  */
> @@ -966,10 +1006,10 @@ static void dmae_do_tasklet(unsigned long data)
>  			break;
>  		}
>  	}
> -	spin_unlock_irq(&sh_chan->desc_lock);
> -
>  	/* Next desc */
>  	sh_chan_xfer_ld_queue(sh_chan);
> +	spin_unlock_irq(&sh_chan->desc_lock);
> +
>  	sh_dmae_chan_ld_cleanup(sh_chan, false);
>  }
>  
> @@ -1037,7 +1077,9 @@ static int __devinit sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id,
>  		return -ENOMEM;
>  	}
>  
> -	/* copy struct dma_device */
> +	new_sh_chan->pm_state = DMAE_PM_ESTABLISHED;
> +
> +	/* reference struct dma_device */
>  	new_sh_chan->common.device = &shdev->common;
>  
>  	new_sh_chan->dev = shdev->common.dev;
> diff --git a/drivers/dma/shdma.h b/drivers/dma/shdma.h
> index dc56576..2b55a27 100644
> --- a/drivers/dma/shdma.h
> +++ b/drivers/dma/shdma.h
> @@ -23,6 +23,12 @@
>  
>  struct device;
>  
> +enum dmae_pm_state {
> +	DMAE_PM_ESTABLISHED,
> +	DMAE_PM_BUSY,
> +	DMAE_PM_PENDING,
> +};
> +
>  struct sh_dmae_chan {
>  	dma_cookie_t completed_cookie;	/* The maximum cookie completed */
>  	spinlock_t desc_lock;		/* Descriptor operation lock */
> @@ -38,6 +44,7 @@ struct sh_dmae_chan {
>  	u32 __iomem *base;
>  	char dev_id[16];		/* unique name per DMAC of channel */
>  	int pm_error;
> +	enum dmae_pm_state pm_state;
>  };
>  
>  struct sh_dmae_device {





^ permalink raw reply

* Re: [PATCH] dma: shdma: transfer based runtime PM
From: Guennadi Liakhovetski @ 2011-08-25 14:37 UTC (permalink / raw)
  To: Koul, Vinod; +Cc: linux-kernel, linux-sh, Dan Williams, Paul Mundt
In-Reply-To: <1314282386.1606.42.camel@vkoul-udesk3>

On Thu, 25 Aug 2011, Koul, Vinod wrote:

> On Thu, 2011-08-18 at 16:55 +0200, Guennadi Liakhovetski wrote:
> > Currently the shdma dmaengine driver uses runtime PM to save power, when
> > no channel on the specific controller is requested by a user. This patch
> > switches the driver to count individual DMA transfers. That way the
> > controller can be powered down between transfers, even if some of its
> > channels are in use.
> No, I don't agree with the approach here, you don't need to count the
> transfers, the runtime_pm framework does that very well for you.
> 
> What you need to do is to call pm_runtime_get() in your .issue_pending
> callback (NOT in tx_submit anyway, this needs to be fixed in driver, see
> the Documentation/dmaengine.txt
> And once the transfer has completed you need to call pm_rumtime_put()

This has been discussed before:

http://marc.info/?l=linux-sh&m\x131004613801231&w=2

Thanks
Guennadi

> 
> Runtime PM framework actually counts the device usage count and whenever
> your device usage count goes to 0 it will call .runtime_suspend
> callback, thus enable you to save power.
> 
> -- 
> ~Vinod
> > 
> > Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> > ---
> > 
> > tested on mackerel (sh7372) with dmatest, sh_mobile_sdhi and sh_mmcif with 
> > runtime PM and STR.
> > 
> >  drivers/dma/shdma.c |   94 +++++++++++++++++++++++++++++++++++++--------------
> >  drivers/dma/shdma.h |    7 ++++
> >  2 files changed, 75 insertions(+), 26 deletions(-)
> > 
> > diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c
> > index e7bb747..81809c2 100644
> > --- a/drivers/dma/shdma.c
> > +++ b/drivers/dma/shdma.c
> > @@ -259,15 +259,23 @@ static int dmae_set_dmars(struct sh_dmae_chan *sh_chan, u16 val)
> >  	return 0;
> >  }
> >  
> > +static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan);
> > +
> >  static dma_cookie_t sh_dmae_tx_submit(struct dma_async_tx_descriptor *tx)
> >  {
> >  	struct sh_desc *desc = tx_to_sh_desc(tx), *chunk, *last = desc, *c;
> >  	struct sh_dmae_chan *sh_chan = to_sh_chan(tx->chan);
> > +	struct sh_dmae_slave *param = tx->chan->private;
> >  	dma_async_tx_callback callback = tx->callback;
> >  	dma_cookie_t cookie;
> > -	unsigned long flags;
> > +	bool power_up;
> >  
> > -	spin_lock_irqsave(&sh_chan->desc_lock, flags);
> > +	spin_lock_irq(&sh_chan->desc_lock);
> > +
> > +	if (list_empty(&sh_chan->ld_queue))
> > +		power_up = true;
> > +	else
> > +		power_up = false;
> >  
> >  	cookie = sh_chan->common.cookie;
> >  	cookie++;
> > @@ -303,7 +311,38 @@ static dma_cookie_t sh_dmae_tx_submit(struct dma_async_tx_descriptor *tx)
> >  		tx->cookie, &last->async_tx, sh_chan->id,
> >  		desc->hw.sar, desc->hw.tcr, desc->hw.dar);
> >  
> > -	spin_unlock_irqrestore(&sh_chan->desc_lock, flags);
> > +	if (power_up) {
> > +		sh_chan->pm_state = DMAE_PM_BUSY;
> > +
> > +		pm_runtime_get(sh_chan->dev);
> > +
> > +		spin_unlock_irq(&sh_chan->desc_lock);
> > +
> > +		pm_runtime_barrier(sh_chan->dev);
> > +
> > +		spin_lock_irq(&sh_chan->desc_lock);
> > +
> > +		/* Have we been reset, while waiting? */
> > +		if (sh_chan->pm_state != DMAE_PM_ESTABLISHED) {
> > +			dev_dbg(sh_chan->dev, "Bring up channel %d\n",
> > +				sh_chan->id);
> > +			if (param) {
> > +				const struct sh_dmae_slave_config *cfg > > +					param->config;
> > +
> > +				dmae_set_dmars(sh_chan, cfg->mid_rid);
> > +				dmae_set_chcr(sh_chan, cfg->chcr);
> > +			} else {
> > +				dmae_init(sh_chan);
> > +			}
> > +
> > +			if (sh_chan->pm_state = DMAE_PM_PENDING)
> > +				sh_chan_xfer_ld_queue(sh_chan);
> > +			sh_chan->pm_state = DMAE_PM_ESTABLISHED;
> > +		}
> > +	}
> > +
> > +	spin_unlock_irq(&sh_chan->desc_lock);
> >  
> >  	return cookie;
> >  }
> > @@ -347,8 +386,6 @@ static int sh_dmae_alloc_chan_resources(struct dma_chan *chan)
> >  	struct sh_dmae_slave *param = chan->private;
> >  	int ret;
> >  
> > -	pm_runtime_get_sync(sh_chan->dev);
> > -
> >  	/*
> >  	 * This relies on the guarantee from dmaengine that alloc_chan_resources
> >  	 * never runs concurrently with itself or free_chan_resources.
> > @@ -368,11 +405,6 @@ static int sh_dmae_alloc_chan_resources(struct dma_chan *chan)
> >  		}
> >  
> >  		param->config = cfg;
> > -
> > -		dmae_set_dmars(sh_chan, cfg->mid_rid);
> > -		dmae_set_chcr(sh_chan, cfg->chcr);
> > -	} else {
> > -		dmae_init(sh_chan);
> >  	}
> >  
> >  	while (sh_chan->descs_allocated < NR_DESCS_PER_CHANNEL) {
> > @@ -401,7 +433,6 @@ edescalloc:
> >  etestused:
> >  efindslave:
> >  	chan->private = NULL;
> > -	pm_runtime_put(sh_chan->dev);
> >  	return ret;
> >  }
> >  
> > @@ -413,7 +444,6 @@ static void sh_dmae_free_chan_resources(struct dma_chan *chan)
> >  	struct sh_dmae_chan *sh_chan = to_sh_chan(chan);
> >  	struct sh_desc *desc, *_desc;
> >  	LIST_HEAD(list);
> > -	int descs = sh_chan->descs_allocated;
> >  
> >  	/* Protect against ISR */
> >  	spin_lock_irq(&sh_chan->desc_lock);
> > @@ -440,9 +470,6 @@ static void sh_dmae_free_chan_resources(struct dma_chan *chan)
> >  
> >  	spin_unlock_irq(&sh_chan->desc_lock);
> >  
> > -	if (descs > 0)
> > -		pm_runtime_put(sh_chan->dev);
> > -
> >  	list_for_each_entry_safe(desc, _desc, &list, node)
> >  		kfree(desc);
> >  }
> > @@ -676,7 +703,6 @@ static int sh_dmae_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
> >  						  struct sh_desc, node);
> >  		desc->partial = (desc->hw.tcr - sh_dmae_readl(sh_chan, TCR)) <<
> >  			sh_chan->xmit_shift;
> > -
> >  	}
> >  	spin_unlock_irqrestore(&sh_chan->desc_lock, flags);
> >  
> > @@ -761,7 +787,13 @@ static dma_async_tx_callback __ld_cleanup(struct sh_dmae_chan *sh_chan, bool all
> >  		     async_tx_test_ack(&desc->async_tx)) || all) {
> >  			/* Remove from ld_queue list */
> >  			desc->mark = DESC_IDLE;
> > +
> >  			list_move(&desc->node, &sh_chan->ld_free);
> > +
> > +			if (list_empty(&sh_chan->ld_queue)) {
> > +				dev_dbg(sh_chan->dev, "Bring down channel %d\n", sh_chan->id);
> > +				pm_runtime_put(sh_chan->dev);
> > +			}
> >  		}
> >  	}
> >  
> > @@ -791,16 +823,14 @@ static void sh_dmae_chan_ld_cleanup(struct sh_dmae_chan *sh_chan, bool all)
> >  		;
> >  }
> >  
> > +/* Called under spin_lock_irq(&sh_chan->desc_lock) */
> >  static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan)
> >  {
> >  	struct sh_desc *desc;
> >  
> > -	spin_lock_irq(&sh_chan->desc_lock);
> >  	/* DMA work check */
> > -	if (dmae_is_busy(sh_chan)) {
> > -		spin_unlock_irq(&sh_chan->desc_lock);
> > +	if (dmae_is_busy(sh_chan))
> >  		return;
> > -	}
> >  
> >  	/* Find the first not transferred descriptor */
> >  	list_for_each_entry(desc, &sh_chan->ld_queue, node)
> > @@ -813,14 +843,18 @@ static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan)
> >  			dmae_start(sh_chan);
> >  			break;
> >  		}
> > -
> > -	spin_unlock_irq(&sh_chan->desc_lock);
> >  }
> >  
> >  static void sh_dmae_memcpy_issue_pending(struct dma_chan *chan)
> >  {
> >  	struct sh_dmae_chan *sh_chan = to_sh_chan(chan);
> > -	sh_chan_xfer_ld_queue(sh_chan);
> > +
> > +	spin_lock_irq(&sh_chan->desc_lock);
> > +	if (sh_chan->pm_state = DMAE_PM_ESTABLISHED)
> > +		sh_chan_xfer_ld_queue(sh_chan);
> > +	else
> > +		sh_chan->pm_state = DMAE_PM_PENDING;
> > +	spin_unlock_irq(&sh_chan->desc_lock);
> >  }
> >  
> >  static enum dma_status sh_dmae_tx_status(struct dma_chan *chan,
> > @@ -913,6 +947,12 @@ static bool sh_dmae_reset(struct sh_dmae_device *shdev)
> >  
> >  		list_splice_init(&sh_chan->ld_queue, &dl);
> >  
> > +		if (!list_empty(&dl)) {
> > +			dev_dbg(sh_chan->dev, "Bring down channel %d\n", sh_chan->id);
> > +			pm_runtime_put(sh_chan->dev);
> > +		}
> > +		sh_chan->pm_state = DMAE_PM_ESTABLISHED;
> > +
> >  		spin_unlock(&sh_chan->desc_lock);
> >  
> >  		/* Complete all  */
> > @@ -966,10 +1006,10 @@ static void dmae_do_tasklet(unsigned long data)
> >  			break;
> >  		}
> >  	}
> > -	spin_unlock_irq(&sh_chan->desc_lock);
> > -
> >  	/* Next desc */
> >  	sh_chan_xfer_ld_queue(sh_chan);
> > +	spin_unlock_irq(&sh_chan->desc_lock);
> > +
> >  	sh_dmae_chan_ld_cleanup(sh_chan, false);
> >  }
> >  
> > @@ -1037,7 +1077,9 @@ static int __devinit sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id,
> >  		return -ENOMEM;
> >  	}
> >  
> > -	/* copy struct dma_device */
> > +	new_sh_chan->pm_state = DMAE_PM_ESTABLISHED;
> > +
> > +	/* reference struct dma_device */
> >  	new_sh_chan->common.device = &shdev->common;
> >  
> >  	new_sh_chan->dev = shdev->common.dev;
> > diff --git a/drivers/dma/shdma.h b/drivers/dma/shdma.h
> > index dc56576..2b55a27 100644
> > --- a/drivers/dma/shdma.h
> > +++ b/drivers/dma/shdma.h
> > @@ -23,6 +23,12 @@
> >  
> >  struct device;
> >  
> > +enum dmae_pm_state {
> > +	DMAE_PM_ESTABLISHED,
> > +	DMAE_PM_BUSY,
> > +	DMAE_PM_PENDING,
> > +};
> > +
> >  struct sh_dmae_chan {
> >  	dma_cookie_t completed_cookie;	/* The maximum cookie completed */
> >  	spinlock_t desc_lock;		/* Descriptor operation lock */
> > @@ -38,6 +44,7 @@ struct sh_dmae_chan {
> >  	u32 __iomem *base;
> >  	char dev_id[16];		/* unique name per DMAC of channel */
> >  	int pm_error;
> > +	enum dmae_pm_state pm_state;
> >  };
> >  
> >  struct sh_dmae_device {
> 
> 
> 
> 

---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/

^ permalink raw reply

* [PATCH 7/7] ARM: mach-shmobile: kota2: add mipi display support
From: Kuninori Morimoto @ 2011-08-25  4:06 UTC (permalink / raw)
  To: linux-sh

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
 arch/arm/mach-shmobile/Kconfig       |    1 +
 arch/arm/mach-shmobile/board-kota2.c |  115 ++++++++++++++++++++++++++++++++++
 2 files changed, 116 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig
index c1b4534..8739930 100644
--- a/arch/arm/mach-shmobile/Kconfig
+++ b/arch/arm/mach-shmobile/Kconfig
@@ -73,6 +73,7 @@ config MACH_KOTA2
 	bool "KOTA2 board"
 	select ARCH_REQUIRE_GPIOLIB
 	depends on ARCH_SH73A0
+	select SH_LCD_MIPI_DSI
 
 comment "SH-Mobile System Configuration"
 
diff --git a/arch/arm/mach-shmobile/board-kota2.c b/arch/arm/mach-shmobile/board-kota2.c
index bd9a784..913176e 100644
--- a/arch/arm/mach-shmobile/board-kota2.c
+++ b/arch/arm/mach-shmobile/board-kota2.c
@@ -47,6 +47,8 @@
 #include <asm/hardware/gic.h>
 #include <asm/hardware/cache-l2x0.h>
 #include <asm/traps.h>
+#include <video/sh_mobile_lcdc.h>
+#include <video/sh_mipi_dsi.h>
 
 /* SMSC 9220 */
 static struct resource smsc9220_resources[] = {
@@ -286,6 +288,106 @@ static struct platform_device sdhi1_device = {
 	},
 };
 
+/* LCDC0 */
+static struct fb_videomode lcdc0_modes[] = {
+	{
+		.name		= "FWVGA",
+		.xres		= 480,
+		.yres		= 864,
+		.left_margin	= 16,
+		.right_margin	= 1000,
+		.hsync_len	= 16,
+		.upper_margin	= 1,
+		.lower_margin	= 4,
+		.vsync_len	= 2,
+		.sync		= FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
+	},
+};
+
+static struct sh_mobile_lcdc_info lcdc0_info = {
+	.clock_source	= LCDC_CLK_PERIPHERAL,
+	.ch[0] = {
+		.chan = LCDC_CHAN_MAINLCD,
+		.bpp = 32,
+		.lcd_cfg = lcdc0_modes,
+		.num_cfg = ARRAY_SIZE(lcdc0_modes),
+		.interface_type		= RGB24,
+		.clock_divider		= 1,
+		.flags			= LCDC_FLAGS_DWPOL,
+		.lcd_size_cfg = {
+			.width	= 44,
+			.height	= 79,
+		},
+	},
+};
+
+static struct resource lcdc0_resources[] = {
+	[0] = {
+		.name	= "LCDC",
+		.start	= 0xfe940000,
+		.end	= 0xfe943fff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= intcs_evt2irq(0x580),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device lcdc0_device = {
+	.name		= "sh_mobile_lcdc_fb",
+	.num_resources	= ARRAY_SIZE(lcdc0_resources),
+	.resource	= lcdc0_resources,
+	.id	= 0,
+	.dev	= {
+		.platform_data  = &lcdc0_info,
+		.coherent_dma_mask = ~0,
+	},
+};
+
+/* MIPI DSI 0 */
+static struct resource mipidsi0_resources[] = {
+	[0] = {
+		.start  = 0xfeab0000,
+		.end    = 0xfeab3fff,
+		.flags  = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start  = 0xfeab4000,
+		.end    = 0xfeab7fff,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+static u32 sh_mipi_extra_dcs[] = {
+	SH_MIPI_DCS_PARAM(0x53, 0x75),	/* turn on backlight */
+	SH_MIPI_DCS_PARAM(0x51, 0xff),	/* turn on backlight */
+	SH_MIPI_DCS(0x2c),		/* memory write on */
+};
+
+static struct sh_mipi_dsi_info mipidsi0_info = {
+	.data_format	= MIPI_RGB888,
+	.lcd_chan	= &lcdc0_info.ch[0],
+	.vsynw_offset	= 20,
+	.clksrc		= 1,
+	.flags		= SH_MIPI_DSI_HSABM |
+			  SH_MIPI_DSI_HBPBM |
+			  SH_MIPI_DSI_HFPBM |
+			  SH_MIPI_DSI_BL2E,
+	.extra_array	= sh_mipi_extra_dcs,
+	.extra_array_len= ARRAY_SIZE(sh_mipi_extra_dcs),
+};
+
+static struct platform_device mipidsi0_device = {
+	.name           = "sh-mipi-dsi",
+	.num_resources  = ARRAY_SIZE(mipidsi0_resources),
+	.resource       = mipidsi0_resources,
+	.id             = 0,
+	.dev	= {
+		.platform_data	= &mipidsi0_info,
+	},
+};
+
 static struct platform_device *kota2_devices[] __initdata = {
 	&eth_device,
 	&keysc_device,
@@ -294,6 +396,8 @@ static struct platform_device *kota2_devices[] __initdata = {
 	&mmcif_device,
 	&sdhi0_device,
 	&sdhi1_device,
+	&lcdc0_device,
+	&mipidsi0_device,
 };
 
 static struct map_desc kota2_io_desc[] __initdata = {
@@ -329,6 +433,9 @@ void __init kota2_init_irq(void)
 	__raw_writew(2 << 10, PINTCR0A);
 }
 
+#define DSI0PCKCR	0xe6150064
+#define DSI0PHYCR	0xe615006c
+
 static void __init kota2_init(void)
 {
 	sh73a0_pinmux_init();
@@ -426,6 +533,14 @@ static void __init kota2_init(void)
 	gpio_request(GPIO_FN_SDHID1_1_PU, NULL);
 	gpio_request(GPIO_FN_SDHID1_0_PU, NULL);
 
+	/* MIPI-DSI clock setup */
+	__raw_writel(0x00000119, DSI0PCKCR);
+	__raw_writel(0x2a8b9111, DSI0PHYCR);
+
+	/* Unreset LCD Panel */
+	gpio_request(GPIO_PORT217, NULL);
+	gpio_direction_output(GPIO_PORT217, 1);
+
 #ifdef CONFIG_CACHE_L2X0
 	/* Early BRESP enable, Shared attribute override enable, 64K*8way */
 	l2x0_init(__io(0xf0100000), 0x40460000, 0x82000fff);
-- 
1.7.4.1


^ permalink raw reply related

* [PATCH 6/7] ARM: mach-shmobile: kota2: Add comment out separator
From: Kuninori Morimoto @ 2011-08-25  4:06 UTC (permalink / raw)
  To: linux-sh

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
 arch/arm/mach-shmobile/board-kota2.c |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-shmobile/board-kota2.c b/arch/arm/mach-shmobile/board-kota2.c
index adc7312..bd9a784 100644
--- a/arch/arm/mach-shmobile/board-kota2.c
+++ b/arch/arm/mach-shmobile/board-kota2.c
@@ -48,6 +48,7 @@
 #include <asm/hardware/cache-l2x0.h>
 #include <asm/traps.h>
 
+/* SMSC 9220 */
 static struct resource smsc9220_resources[] = {
 	[0] = {
 		.start		= 0x14000000, /* CS5A */
@@ -77,6 +78,7 @@ static struct platform_device eth_device = {
 	.num_resources	= ARRAY_SIZE(smsc9220_resources),
 };
 
+/* KEYSC */
 static struct sh_keysc_info keysc_platdata = {
 	.mode		= SH_KEYSC_MODE_6,
 	.scan_timing	= 3,
@@ -120,6 +122,7 @@ static struct platform_device keysc_device = {
 	},
 };
 
+/* GPIO KEY */
 #define GPIO_KEY(c, g, d) { .code = c, .gpio = g, .desc = d, .active_low = 1 }
 
 static struct gpio_keys_button gpio_buttons[] = {
@@ -150,6 +153,7 @@ static struct platform_device gpio_keys_device = {
 	},
 };
 
+/* GPIO LED */
 #define GPIO_LED(n, g) { .name = n, .gpio = g }
 
 static struct gpio_led gpio_leds[] = {
@@ -175,6 +179,7 @@ static struct platform_device gpio_leds_device = {
 	},
 };
 
+/* MMCIF */
 static struct resource mmcif_resources[] = {
 	[0] = {
 		.name   = "MMCIF",
@@ -207,6 +212,7 @@ static struct platform_device mmcif_device = {
 	.resource       = mmcif_resources,
 };
 
+/* SDHI0 */
 static struct sh_mobile_sdhi_info sdhi0_info = {
 	.tmio_caps      = MMC_CAP_SD_HIGHSPEED,
 	.tmio_flags     = TMIO_MMC_WRPROTECT_DISABLE | TMIO_MMC_HAS_IDLE_WAIT,
@@ -243,6 +249,7 @@ static struct platform_device sdhi0_device = {
 	},
 };
 
+/* SDHI1 */
 static struct sh_mobile_sdhi_info sdhi1_info = {
 	.tmio_caps      = MMC_CAP_NONREMOVABLE | MMC_CAP_SDIO_IRQ,
 	.tmio_flags     = TMIO_MMC_WRPROTECT_DISABLE | TMIO_MMC_HAS_IDLE_WAIT,
-- 
1.7.4.1


^ permalink raw reply related

* [PATCH 5/7] fbdev: sh_mipi_dsi: add extra dcs settings for platform
From: Kuninori Morimoto @ 2011-08-25  4:05 UTC (permalink / raw)
  To: linux-sh

some platform needs extra MIPI dcs to use.
this patch add support it.

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
 drivers/video/sh_mipi_dsi.c |   24 +++++++++++++++++++++++-
 include/video/sh_mipi_dsi.h |   13 +++++++++++++
 2 files changed, 36 insertions(+), 1 deletions(-)

diff --git a/drivers/video/sh_mipi_dsi.c b/drivers/video/sh_mipi_dsi.c
index 096c76a..bdf687d 100644
--- a/drivers/video/sh_mipi_dsi.c
+++ b/drivers/video/sh_mipi_dsi.c
@@ -46,6 +46,13 @@
 /* E.g., sh7372 has 2 MIPI-DSIs - one for each LCDC */
 #define MAX_SH_MIPI_DSI 2
 
+/*
+ * for extra array
+ * see sh_mipi_dsi.h
+ */
+#define GET_EXCMD(p)	((p >> 8) & 0xFF)
+#define GET_EXPARAM(p)	(p & 0xFF)
+
 struct sh_mipi {
 	void __iomem	*base;
 	void __iomem	*linkbase;
@@ -150,8 +157,9 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi,
 {
 	void __iomem *base = mipi->base;
 	struct sh_mobile_lcdc_chan_cfg *ch = pdata->lcd_chan;
-	u32 pctype, datatype, pixfmt, linelength, vmctr2 = 0x00e00000;
+	u32 pctype, datatype, pixfmt, linelength, vmctr2 = 0x00e00000, excmd;
 	bool yuv;
+	int i;
 
 	/*
 	 * Select data format. MIPI DSI is not hot-pluggable, so, we just use
@@ -355,6 +363,20 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi,
 			  pixfmt << 4);
 	sh_mipi_dcs(ch->chan, MIPI_DCS_SET_DISPLAY_ON);
 
+	/*
+	 * FIXME
+	 *
+	 * extra dcs settings for platform
+	 */
+	for (i = 0; i < pdata->extra_array_len; i++) {
+		excmd = pdata->extra_array[i];
+		if (0x10000000 & excmd)
+			sh_mipi_dcs(ch->chan, GET_EXCMD(excmd));
+		else
+			sh_mipi_dcs_param(ch->chan, GET_EXCMD(excmd),
+						    GET_EXPARAM(excmd));
+	}
+
 	return 0;
 }
 
diff --git a/include/video/sh_mipi_dsi.h b/include/video/sh_mipi_dsi.h
index 58b78f8..e52097a 100644
--- a/include/video/sh_mipi_dsi.h
+++ b/include/video/sh_mipi_dsi.h
@@ -32,12 +32,25 @@ struct sh_mobile_lcdc_chan_cfg;
 #define SH_MIPI_DSI_HFPBM	(1 << 2)
 #define SH_MIPI_DSI_BL2E	(1 << 3)
 
+/*
+ * x000ccpp
+ *
+ * x : 1 use sh_mipi_dcs()
+ *     0 use sh_mipi_dcs_param()
+ * cc : cmd
+ * pp : param
+ */
+#define SH_MIPI_DCS(cmd)		(0x10000000 | (cmd & 0xFF) << 8)
+#define SH_MIPI_DCS_PARAM(cmd, param)	((cmd & 0xFF) << 8 | (param & 0xFF))
+
 struct sh_mipi_dsi_info {
 	enum sh_mipi_dsi_data_fmt	data_format;
 	struct sh_mobile_lcdc_chan_cfg	*lcd_chan;
 	unsigned long			flags;
 	u32				clksrc;
 	unsigned int			vsynw_offset;
+	u32				*extra_array;
+	int				extra_array_len;
 };
 
 #endif
-- 
1.7.4.1


^ permalink raw reply related

* [PATCH 4/7] fbdev: sh_mipi_dsi: add SH_MIPI_DSI_BL2E flag
From: Kuninori Morimoto @ 2011-08-25  4:05 UTC (permalink / raw)
  To: linux-sh

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
 drivers/video/sh_mipi_dsi.c |    2 ++
 include/video/sh_mipi_dsi.h |    1 +
 2 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/drivers/video/sh_mipi_dsi.c b/drivers/video/sh_mipi_dsi.c
index b35454e..096c76a 100644
--- a/drivers/video/sh_mipi_dsi.c
+++ b/drivers/video/sh_mipi_dsi.c
@@ -315,6 +315,8 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi,
 	 * Non-burst mode with sync pulses: VSE and HSE are output,
 	 * HSA period allowed, no commands in LP
 	 */
+	if (pdata->flags & SH_MIPI_DSI_BL2E)
+		vmctr2 |= 1 << 17;
 	if (pdata->flags & SH_MIPI_DSI_HSABM)
 		vmctr2 |= 1 << 5;
 	if (pdata->flags & SH_MIPI_DSI_HBPBM)
diff --git a/include/video/sh_mipi_dsi.h b/include/video/sh_mipi_dsi.h
index 86a72c0..58b78f8 100644
--- a/include/video/sh_mipi_dsi.h
+++ b/include/video/sh_mipi_dsi.h
@@ -30,6 +30,7 @@ struct sh_mobile_lcdc_chan_cfg;
 #define SH_MIPI_DSI_HSABM	(1 << 0)
 #define SH_MIPI_DSI_HBPBM	(1 << 1)
 #define SH_MIPI_DSI_HFPBM	(1 << 2)
+#define SH_MIPI_DSI_BL2E	(1 << 3)
 
 struct sh_mipi_dsi_info {
 	enum sh_mipi_dsi_data_fmt	data_format;
-- 
1.7.4.1


^ permalink raw reply related

* [PATCH 3/7] fbdev: sh_mipi_dsi: add SH_MIPI_DSI_HFPBM flag
From: Kuninori Morimoto @ 2011-08-25  4:05 UTC (permalink / raw)
  To: linux-sh

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
 drivers/video/sh_mipi_dsi.c |    2 ++
 include/video/sh_mipi_dsi.h |    1 +
 2 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/drivers/video/sh_mipi_dsi.c b/drivers/video/sh_mipi_dsi.c
index 3b408b7..b35454e 100644
--- a/drivers/video/sh_mipi_dsi.c
+++ b/drivers/video/sh_mipi_dsi.c
@@ -319,6 +319,8 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi,
 		vmctr2 |= 1 << 5;
 	if (pdata->flags & SH_MIPI_DSI_HBPBM)
 		vmctr2 |= 1 << 4;
+	if (pdata->flags & SH_MIPI_DSI_HFPBM)
+		vmctr2 |= 1 << 3;
 	iowrite32(vmctr2, mipi->linkbase + VMCTR2);
 
 	/*
diff --git a/include/video/sh_mipi_dsi.h b/include/video/sh_mipi_dsi.h
index 4e2bcb5..86a72c0 100644
--- a/include/video/sh_mipi_dsi.h
+++ b/include/video/sh_mipi_dsi.h
@@ -29,6 +29,7 @@ struct sh_mobile_lcdc_chan_cfg;
 
 #define SH_MIPI_DSI_HSABM	(1 << 0)
 #define SH_MIPI_DSI_HBPBM	(1 << 1)
+#define SH_MIPI_DSI_HFPBM	(1 << 2)
 
 struct sh_mipi_dsi_info {
 	enum sh_mipi_dsi_data_fmt	data_format;
-- 
1.7.4.1


^ permalink raw reply related

* [PATCH 2/7] fbdev: sh_mipi_dsi: tidyup VMCTR2 parameter expression
From: Kuninori Morimoto @ 2011-08-25  4:05 UTC (permalink / raw)
  To: linux-sh

VMCTR2 parameter will be supported more in the future.
1 << xx style is easy to understand.

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
 drivers/video/sh_mipi_dsi.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/video/sh_mipi_dsi.c b/drivers/video/sh_mipi_dsi.c
index 8f17efc..3b408b7 100644
--- a/drivers/video/sh_mipi_dsi.c
+++ b/drivers/video/sh_mipi_dsi.c
@@ -316,9 +316,9 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi,
 	 * HSA period allowed, no commands in LP
 	 */
 	if (pdata->flags & SH_MIPI_DSI_HSABM)
-		vmctr2 |= 0x20;
+		vmctr2 |= 1 << 5;
 	if (pdata->flags & SH_MIPI_DSI_HBPBM)
-		vmctr2 |= 0x10;
+		vmctr2 |= 1 << 4;
 	iowrite32(vmctr2, mipi->linkbase + VMCTR2);
 
 	/*
-- 
1.7.4.1


^ permalink raw reply related

* [PATCH 1/7] fbdev: sh_mipi_dsi: typo fix of SH_MIPI_DSI_HBPBM
From: Kuninori Morimoto @ 2011-08-25  4:04 UTC (permalink / raw)
  To: linux-sh

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
 drivers/video/sh_mipi_dsi.c |    2 +-
 include/video/sh_mipi_dsi.h |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/video/sh_mipi_dsi.c b/drivers/video/sh_mipi_dsi.c
index 24640c8..8f17efc 100644
--- a/drivers/video/sh_mipi_dsi.c
+++ b/drivers/video/sh_mipi_dsi.c
@@ -317,7 +317,7 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi,
 	 */
 	if (pdata->flags & SH_MIPI_DSI_HSABM)
 		vmctr2 |= 0x20;
-	if (pdata->flags & SH_MIPI_DSI_HSPBM)
+	if (pdata->flags & SH_MIPI_DSI_HBPBM)
 		vmctr2 |= 0x10;
 	iowrite32(vmctr2, mipi->linkbase + VMCTR2);
 
diff --git a/include/video/sh_mipi_dsi.h b/include/video/sh_mipi_dsi.h
index 6cb95c9..4e2bcb5 100644
--- a/include/video/sh_mipi_dsi.h
+++ b/include/video/sh_mipi_dsi.h
@@ -28,7 +28,7 @@ enum sh_mipi_dsi_data_fmt {
 struct sh_mobile_lcdc_chan_cfg;
 
 #define SH_MIPI_DSI_HSABM	(1 << 0)
-#define SH_MIPI_DSI_HSPBM	(1 << 1)
+#define SH_MIPI_DSI_HBPBM	(1 << 1)
 
 struct sh_mipi_dsi_info {
 	enum sh_mipi_dsi_data_fmt	data_format;
-- 
1.7.4.1


^ permalink raw reply related

* [PATCH 0/7] ARM: ARM: mach-shmobile: mipi display support
From: kuninori.morimoto.gx @ 2011-08-25  4:03 UTC (permalink / raw)
  To: linux-sh


Dear Paul, Magnus, Guennadi

These are MIPI display support for kota2 board

Kuninori Morimoto (7):
      fbdev: sh_mipi_dsi: typo fix of SH_MIPI_DSI_HBPBM
      fbdev: sh_mipi_dsi: tidyup VMCTR2 parameter expression
      fbdev: sh_mipi_dsi: add SH_MIPI_DSI_HFPBM flag
      fbdev: sh_mipi_dsi: add SH_MIPI_DSI_BL2E flag
      fbdev: sh_mipi_dsi: add extra dcs settings for platform
      ARM: mach-shmobile: kota2: Add comment out separator
      ARM: mach-shmobile: kota2: add mipi display support

These patches are based on current linus/master + Magnus's kota2 patch set

^ permalink raw reply

* [PATCH v2] ARM: mach-shmobile: clock-sh7372: fixup USB-DMAC1 settings
From: kuninori.morimoto.gx @ 2011-08-25  3:47 UTC (permalink / raw)
  To: linux-sh

USB-DMAC1 needs SMSTPCR4/MSTP407 controls, not MSTP214
this patch tested on mackerel board

Reported-by: Magnus Damm <damm@opensource.se>
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
v1 -> v2

- tested on mackerel board
- fix comment
- fix MSTPxxx order

 arch/arm/mach-shmobile/clock-sh7372.c |    5 +++--
 1 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c
index d407ca7..725caf1 100644
--- a/arch/arm/mach-shmobile/clock-sh7372.c
+++ b/arch/arm/mach-shmobile/clock-sh7372.c
@@ -512,7 +512,7 @@ enum { MSTP001,
        MSTP214, MSTP218, MSTP217, MSTP216,
        MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
        MSTP329, MSTP328, MSTP323, MSTP322, MSTP314, MSTP313, MSTP312,
-       MSTP423, MSTP415, MSTP413, MSTP411, MSTP410, MSTP406, MSTP403,
+       MSTP423, MSTP415, MSTP413, MSTP411, MSTP410, MSTP407, MSTP406, MSTP403,
        MSTP_NR };
 
 #define MSTP(_parent, _reg, _bit, _flags) \
@@ -558,6 +558,7 @@ static struct clk mstp_clks[MSTP_NR] = {
 	[MSTP413] = MSTP(&pllc1_div2_clk, SMSTPCR4, 13, 0), /* HDMI */
 	[MSTP411] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR4, 11, 0), /* IIC3 */
 	[MSTP410] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR4, 10, 0), /* IIC4 */
+	[MSTP407] = MSTP(&div4_clks[DIV4_HP], SMSTPCR4, 7, 0), /* USB-DMAC1 */
 	[MSTP406] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR4, 6, 0), /* USB1 */
 	[MSTP403] = MSTP(&r_clk, SMSTPCR4, 3, 0), /* KEYSC */
 };
@@ -631,7 +632,6 @@ static struct clk_lookup lookups[] = {
 	CLKDEV_DEV_ID("sh-dma-engine.1", &mstp_clks[MSTP217]), /* DMAC2 */
 	CLKDEV_DEV_ID("sh-dma-engine.2", &mstp_clks[MSTP216]), /* DMAC3 */
 	CLKDEV_DEV_ID("sh-dma-engine.3", &mstp_clks[MSTP214]), /* USB-DMAC0 */
-	CLKDEV_DEV_ID("sh-dma-engine.4", &mstp_clks[MSTP214]), /* USB-DMAC1 */
 	CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[MSTP207]), /* SCIFA5 */
 	CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[MSTP206]), /* SCIFB */
 	CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[MSTP204]), /* SCIFA0 */
@@ -653,6 +653,7 @@ static struct clk_lookup lookups[] = {
 	CLKDEV_DEV_ID("sh-mobile-hdmi", &mstp_clks[MSTP413]), /* HDMI */
 	CLKDEV_DEV_ID("i2c-sh_mobile.3", &mstp_clks[MSTP411]), /* IIC3 */
 	CLKDEV_DEV_ID("i2c-sh_mobile.4", &mstp_clks[MSTP410]), /* IIC4 */
+	CLKDEV_DEV_ID("sh-dma-engine.4", &mstp_clks[MSTP407]), /* USB-DMAC1 */
 	CLKDEV_DEV_ID("r8a66597_hcd.1", &mstp_clks[MSTP406]), /* USB1 */
 	CLKDEV_DEV_ID("r8a66597_udc.1", &mstp_clks[MSTP406]), /* USB1 */
 	CLKDEV_DEV_ID("renesas_usbhs.1", &mstp_clks[MSTP406]), /* USB1 */
-- 
1.7.4.1


^ permalink raw reply related

* Re: [PATCH 2/2 v2] sh-sci / PM: Use power.irq_safe
From: Paul Mundt @ 2011-08-25  1:33 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: linux-sh, Linux PM mailing list, LKML, Magnus Damm, Alan Stern
In-Reply-To: <201108242252.25098.rjw@sisk.pl>

On Wed, Aug 24, 2011 at 10:52:24PM +0200, Rafael J. Wysocki wrote:
> On Wednesday, August 24, 2011, Paul Mundt wrote:
> > On Sun, Aug 21, 2011 at 09:11:44PM +0200, Rafael J. Wysocki wrote:
> > > From: Rafael J. Wysocki <rjw@sisk.pl>
> > > 
> > > Since sci_port_enable() and sci_port_disable() may be run with
> > > interrupts off and they execute pm_runtime_get_sync() and
> > > pm_runtime_put_sync(), respectively, the SCI device's
> > > power.irq_safe flags has to be used to indicate that it is safe
> > > to execute runtime PM callbacks for this device with interrupts off.
> > > 
> > > Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
> > 
> > Not sure how you want this one handled. Did you simply want to roll this
> > in with your other patch with my Acked-by, or should I be taking this
> > through my tree already regardless of the 1/2 patch?
> 
> I'd prefer to push it through my tree, if you don't mind.  Magnus has
> already acked it for me, hopefully that's OK?
> 
Sure, sounds fine to me. I'll just ignore it then.

^ permalink raw reply

* [PATCH v8 4/4] ARM: shmobile: ag5evm, ap4: Named SDHI IRQ sources
From: Simon Horman @ 2011-08-25  1:27 UTC (permalink / raw)
  To: linux-mmc, linux-sh
  Cc: Chris Ball, Paul Mundt, Guennadi Liakhovetski, Magnus Damm,
	Simon Horman
In-Reply-To: <1314235648-8959-1-git-send-email-horms@verge.net.au>

This allows specific (non-multiplexed) IRQ handlers to be used.

Cc: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Cc: Paul Mundt <lethal@linux-sh.org>
Acked-by: Magnus Damm <magnus.damm@gmail.com>
Signed-off-by: Simon Horman <horms@verge.net.au>

---

Requires
"mmc: sdhi: Allow specific IRQ sources to use corresponding handlers."

v7
* Rework to use named IRQs

v4
* Update for corrected ordering of SH_MOBILE_SDHI_IRQ_SDCARD and
  SH_MOBILE_SDHI_IRQ_CARD_DETECT

v2
* Initial release
---
 arch/arm/mach-shmobile/board-ag5evm.c   |    6 ++++++
 arch/arm/mach-shmobile/board-mackerel.c |    6 ++++++
 2 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-shmobile/board-ag5evm.c b/arch/arm/mach-shmobile/board-ag5evm.c
index ce5c251..e100cad 100644
--- a/arch/arm/mach-shmobile/board-ag5evm.c
+++ b/arch/arm/mach-shmobile/board-ag5evm.c
@@ -353,14 +353,17 @@ static struct resource sdhi0_resources[] = {
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
+		.name	= SH_MOBILE_SDHI_IRQ_CARD_DETECT,
 		.start	= gic_spi(83),
 		.flags	= IORESOURCE_IRQ,
 	},
 	[2] = {
+		.name	= SH_MOBILE_SDHI_IRQ_SDCARD,
 		.start	= gic_spi(84),
 		.flags	= IORESOURCE_IRQ,
 	},
 	[3] = {
+		.name	= SH_MOBILE_SDHI_IRQ_SDIO,
 		.start	= gic_spi(85),
 		.flags	= IORESOURCE_IRQ,
 	},
@@ -396,14 +399,17 @@ static struct resource sdhi1_resources[] = {
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
+		.name	= SH_MOBILE_SDHI_IRQ_CARD_DETECT,
 		.start	= gic_spi(87),
 		.flags	= IORESOURCE_IRQ,
 	},
 	[2] = {
+		.name	= SH_MOBILE_SDHI_IRQ_SDCARD,
 		.start	= gic_spi(88),
 		.flags	= IORESOURCE_IRQ,
 	},
 	[3] = {
+		.name	= SH_MOBILE_SDHI_IRQ_SDIO,
 		.start	= gic_spi(89),
 		.flags	= IORESOURCE_IRQ,
 	},
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c
index d41c01f..492274f 100644
--- a/arch/arm/mach-shmobile/board-mackerel.c
+++ b/arch/arm/mach-shmobile/board-mackerel.c
@@ -1066,14 +1066,17 @@ static struct resource sdhi1_resources[] = {
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
+		.name	= SH_MOBILE_SDHI_IRQ_CARD_DETECT,
 		.start	= evt2irq(0x0e80), /* SDHI1_SDHI1I0 */
 		.flags	= IORESOURCE_IRQ,
 	},
 	[2] = {
+		.name	= SH_MOBILE_SDHI_IRQ_SDCARD,
 		.start	= evt2irq(0x0ea0), /* SDHI1_SDHI1I1 */
 		.flags	= IORESOURCE_IRQ,
 	},
 	[3] = {
+		.name	= SH_MOBILE_SDHI_IRQ_SDIO,
 		.start	= evt2irq(0x0ec0), /* SDHI1_SDHI1I2 */
 		.flags	= IORESOURCE_IRQ,
 	},
@@ -1117,14 +1120,17 @@ static struct resource sdhi2_resources[] = {
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
+		.name	= SH_MOBILE_SDHI_IRQ_CARD_DETECT,
 		.start	= evt2irq(0x1200), /* SDHI2_SDHI2I0 */
 		.flags	= IORESOURCE_IRQ,
 	},
 	[2] = {
+		.name	= SH_MOBILE_SDHI_IRQ_SDCARD,
 		.start	= evt2irq(0x1220), /* SDHI2_SDHI2I1 */
 		.flags	= IORESOURCE_IRQ,
 	},
 	[3] = {
+		.name	= SH_MOBILE_SDHI_IRQ_SDIO,
 		.start	= evt2irq(0x1240), /* SDHI2_SDHI2I2 */
 		.flags	= IORESOURCE_IRQ,
 	},
-- 
1.7.5.4


^ permalink raw reply related

* [PATCH v8 3/4] mmc: sdhi: Allow name IRQs to use specific handlers
From: Simon Horman @ 2011-08-25  1:27 UTC (permalink / raw)
  To: linux-mmc, linux-sh
  Cc: Chris Ball, Paul Mundt, Guennadi Liakhovetski, Magnus Damm,
	Simon Horman
In-Reply-To: <1314235648-8959-1-git-send-email-horms@verge.net.au>

Allow named IRQs to use corresponding specific  handlers.
Allow one or more such IRQ source;
Or allow one or more multiplexed (un-named) IRQ source.

Cc: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Acked-by: Magnus Damm <magnus.damm@gmail.com>
Signed-off-by: Simon Horman <horms@verge.net.au>

---

v8
* As pointed out by Guennadi Liakhovetski via Magnus Damm
  - Correct logic error introduced in v7
    The unregistration of irq handlers should
    be in a while(1) rather than a while(0) loop.

v7
* As discussed with Magnus Damm
  - The logic implemented to handle specific IRQ sources assumes
    that platform_get_irq() takes into account the index of resource
    entries. However, it does not.

    Instead implement a scheme of named IRQs for specific IRQ sources.
    And assume that un-named IRQs are (legacy) multiplexed IRQs.

    As part of this change alter the logic for allowed IRQ sources as
    follows:
        Allow one or more specific (named) IRRs or;
        One or more multiplexed (un-named) ISRs.

v6
* As discussed with Guennadi Liakhovetski:
  - The SDCARD/SDIO change in v5 was not implemented as described.
    And the logic wasn't fully described in any case. This
    version (hope to!) implement the following logic:
    1) 1 IRQ: only resource #0 (CARD_DETECT, use tmio_mmc_irq())
    2) 2 or 3 IRQs: compulsory SDCARD and any further IRQs: use respective
       specialised ISRs.

v5
* As suggested by Guennadi Liakhovetski:
  - Allow only SH_MOBILE_SDHI_IRQ_SDCARD and
    SH_MOBILE_SDHI_IRQ_SDIO to be specified in platform data

v4
* As suggested by Guennadi Liakhovetski:
  - Correct inverted values of SH_MOBILE_SDHI_IRQ_SDCARD and
    SH_MOBILE_SDHI_IRQ_CARD_DETECT

v3
* Update for changes to "mmc: tmio: Provide separate interrupt handlers"
* As suggested by Guennadi Liakhovetski:
  - Merge in patch "mmc: sdhi: Add defines for platform irq indexes"
  - Use an enum instead of defines for irq indexes

v2
* Update for changes to "mmc: tmio: Provide separate interrupt handlers"
* Make use of defines provided by
  "mmc: sdhi: Add defines for platform irq indexes"
* As suggested by Guennadi Liakhovetski:
  - Don't use a loop to initialise irq handlers, the unrolled version
    is easier on the eyes (and exactly the same number of lines of code!)

wip: driver
---
 drivers/mmc/host/sh_mobile_sdhi.c  |   92 ++++++++++++++++++++++++++----------
 include/linux/mmc/sh_mobile_sdhi.h |    4 ++
 2 files changed, 71 insertions(+), 25 deletions(-)

diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c
index 774f643..24483b9 100644
--- a/drivers/mmc/host/sh_mobile_sdhi.c
+++ b/drivers/mmc/host/sh_mobile_sdhi.c
@@ -96,7 +96,8 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
 	struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
 	struct tmio_mmc_host *host;
 	char clk_name[8];
-	int i, irq, ret;
+	int irq, ret, i = 0;
+	bool multiplexed_isr = true;
 
 	priv = kzalloc(sizeof(struct sh_mobile_sdhi), GFP_KERNEL);
 	if (priv = NULL) {
@@ -153,27 +154,54 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
 	if (ret < 0)
 		goto eprobe;
 
-	for (i = 0; i < 3; i++) {
-		irq = platform_get_irq(pdev, i);
-		if (irq < 0) {
-			if (i) {
-				continue;
-			} else {
-				ret = irq;
-				goto eirq;
-			}
-		}
-		ret = request_irq(irq, tmio_mmc_irq, 0,
+	/* Allow one or more specific (named) IRRs or;
+	 * One or more multiplexed (un-named) ISRs.
+	 */
+
+	irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_CARD_DETECT);
+	if (irq >= 0) {
+		multiplexed_isr = false;
+		ret = request_irq(irq, tmio_mmc_card_detect_irq, 0,
 				  dev_name(&pdev->dev), host);
-		if (ret) {
-			while (i--) {
-				irq = platform_get_irq(pdev, i);
-				if (irq >= 0)
-					free_irq(irq, host);
-			}
-			goto eirq;
+		if (ret)
+			goto eirq_card_detect;
+	}
+
+	irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_SDCARD);
+	if (irq >= 0) {
+		multiplexed_isr = false;
+		ret = request_irq(irq, tmio_mmc_sdcard_irq, 0,
+				  dev_name(&pdev->dev), host);
+		if (ret)
+			goto eirq_sdcard;
+	}
+
+	irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_SDIO);
+	if (irq >= 0) {
+		multiplexed_isr = false;
+		ret = request_irq(irq, tmio_mmc_sdio_irq, 0,
+				  dev_name(&pdev->dev), host);
+		if (ret)
+			goto eirq_sdio;
+	}
+
+	if (multiplexed_isr) {
+		while (1) {
+			irq = platform_get_irq(pdev, i);
+			if (irq < 0)
+				break;
+			i++;
+			ret = request_irq(irq, tmio_mmc_irq, 0,
+				          dev_name(&pdev->dev), host);
+			if (ret)
+				goto eirq_multiplexed;
 		}
+
+		/* There must be at least one IRQ source */
+		if (!i)
+			goto eirq_multiplexed;
 	}
+
 	dev_info(&pdev->dev, "%s base at 0x%08lx clock rate %u MHz\n",
 		 mmc_hostname(host->mmc), (unsigned long)
 		 (platform_get_resource(pdev,IORESOURCE_MEM, 0)->start),
@@ -181,7 +209,20 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
 
 	return ret;
 
-eirq:
+eirq_multiplexed:
+	while (i--) {
+		irq = platform_get_irq(pdev, i);
+		free_irq(irq, host);
+	}
+eirq_sdio:
+	irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_SDCARD);
+	if (irq >= 0)
+		free_irq(irq, host);
+eirq_sdcard:
+	irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_CARD_DETECT);
+	if (irq >= 0)
+		free_irq(irq, host);
+eirq_card_detect:
 	tmio_mmc_host_remove(host);
 eprobe:
 	clk_disable(priv->clk);
@@ -197,16 +238,17 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev)
 	struct tmio_mmc_host *host = mmc_priv(mmc);
 	struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data);
 	struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
-	int i, irq;
+	int i = 0, irq;
 
 	p->pdata = NULL;
 
 	tmio_mmc_host_remove(host);
 
-	for (i = 0; i < 3; i++) {
-		irq = platform_get_irq(pdev, i);
-		if (irq >= 0)
-			free_irq(irq, host);
+	while (1) {
+		irq = platform_get_irq(pdev, i++);
+		if (irq < 0)
+			break;
+		free_irq(irq, host);
 	}
 
 	clk_disable(priv->clk);
diff --git a/include/linux/mmc/sh_mobile_sdhi.h b/include/linux/mmc/sh_mobile_sdhi.h
index bd50b36..71b8054 100644
--- a/include/linux/mmc/sh_mobile_sdhi.h
+++ b/include/linux/mmc/sh_mobile_sdhi.h
@@ -6,6 +6,10 @@
 struct platform_device;
 struct tmio_mmc_data;
 
+#define SH_MOBILE_SDHI_IRQ_CARD_DETECT	"card_detect"
+#define SH_MOBILE_SDHI_IRQ_SDCARD	"sdcard"
+#define SH_MOBILE_SDHI_IRQ_SDIO		"sdio"
+
 struct sh_mobile_sdhi_info {
 	int dma_slave_tx;
 	int dma_slave_rx;
-- 
1.7.5.4


^ permalink raw reply related

* [PATCH v8 2/4] mmc: tmio: Provide separate interrupt handlers
From: Simon Horman @ 2011-08-25  1:27 UTC (permalink / raw)
  To: linux-mmc, linux-sh
  Cc: Chris Ball, Paul Mundt, Guennadi Liakhovetski, Magnus Damm,
	Simon Horman
In-Reply-To: <1314235648-8959-1-git-send-email-horms@verge.net.au>

Provide separate interrupt handlers which may be used by platforms where
SDHI has three interrupt sources.

This patch also removes the commented-out handling of CRC and other errors.

Cc: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Acked-by: Magnus Damm <magnus.damm@gmail.com>
Signed-off-by: Simon Horman <horms@verge.net.au>

---

* SDCARD portion tested on AP4/Mackerel
* SDIO portion untested

v4
* As suggested by Guennadi Liakhovetski
  - Use bool as return type for __tmio_mmc_sdcard_irq() and
    __tmio_mmc_card_detect_irq()

v3
* Rebase for updated "mmc: tmio: Cache interrupt masks"
* As suggested by Guennadi Liakhovetski
  - Do not alter logic to handle more than one interupt at once
  - Add missing "static" to declartion of __tmio_mmc_sdcard_irq()

v2
* As suggested by Guennadi Liakhovetski
  - Combine 3 patches into one
  - Reduce the number of __tmio_..._irq() functions
  - Rename "...card_access..." functions as "...sdcard..."
---
 drivers/mmc/host/tmio_mmc.h     |    3 +
 drivers/mmc/host/tmio_mmc_pio.c |  131 ++++++++++++++++++++++++--------------
 2 files changed, 86 insertions(+), 48 deletions(-)

diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
index 1cf8db5..3020f98 100644
--- a/drivers/mmc/host/tmio_mmc.h
+++ b/drivers/mmc/host/tmio_mmc.h
@@ -97,6 +97,9 @@ void tmio_mmc_do_data_irq(struct tmio_mmc_host *host);
 void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i);
 void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i);
 irqreturn_t tmio_mmc_irq(int irq, void *devid);
+irqreturn_t tmio_mmc_sdcard_irq(int irq, void *devid);
+irqreturn_t tmio_mmc_card_detect_irq(int irq, void *devid);
+irqreturn_t tmio_mmc_sdio_irq(int irq, void *devid);
 
 static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg,
 					 unsigned long *flags)
diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c
index f0c7830..6275e3d 100644
--- a/drivers/mmc/host/tmio_mmc_pio.c
+++ b/drivers/mmc/host/tmio_mmc_pio.c
@@ -545,44 +545,20 @@ out:
 	spin_unlock(&host->lock);
 }
 
-irqreturn_t tmio_mmc_irq(int irq, void *devid)
+static void tmio_mmc_card_irq_status(struct tmio_mmc_host *host,
+				       int *ireg, int *status)
 {
-	struct tmio_mmc_host *host = devid;
-	struct mmc_host *mmc = host->mmc;
-	struct tmio_mmc_data *pdata = host->pdata;
-	unsigned int ireg, status;
-	unsigned int sdio_ireg, sdio_status;
-
-	pr_debug("MMC IRQ begin\n");
-
-	status = sd_ctrl_read32(host, CTL_STATUS);
-	ireg = status & TMIO_MASK_IRQ & ~host->sdcard_irq_mask;
+	*status = sd_ctrl_read32(host, CTL_STATUS);
+	*ireg = *status & TMIO_MASK_IRQ & ~host->sdcard_irq_mask;
 
-	sdio_ireg = 0;
-	if (!ireg && pdata->flags & TMIO_MMC_SDIO_IRQ) {
-		sdio_status = sd_ctrl_read16(host, CTL_SDIO_STATUS);
-		sdio_ireg = sdio_status & TMIO_SDIO_MASK_ALL &
-				~host->sdio_irq_mask;
-
-		sd_ctrl_write16(host, CTL_SDIO_STATUS, sdio_status & ~TMIO_SDIO_MASK_ALL);
-
-		if (sdio_ireg && !host->sdio_irq_enabled) {
-			pr_warning("tmio_mmc: Spurious SDIO IRQ, disabling! 0x%04x 0x%04x 0x%04x\n",
-				   sdio_status, host->sdio_irq_mask, sdio_ireg);
-			tmio_mmc_enable_sdio_irq(mmc, 0);
-			goto out;
-		}
-
-		if (mmc->caps & MMC_CAP_SDIO_IRQ &&
-			sdio_ireg & TMIO_SDIO_STAT_IOIRQ)
-			mmc_signal_sdio_irq(mmc);
-
-		if (sdio_ireg)
-			goto out;
-	}
+	pr_debug_status(*status);
+	pr_debug_status(*ireg);
+}
 
-	pr_debug_status(status);
-	pr_debug_status(ireg);
+static bool __tmio_mmc_card_detect_irq(struct tmio_mmc_host *host,
+				      int ireg, int status)
+{
+	struct mmc_host *mmc = host->mmc;
 
 	/* Card insert / remove attempts */
 	if (ireg & (TMIO_STAT_CARD_INSERT | TMIO_STAT_CARD_REMOVE)) {
@@ -592,43 +568,102 @@ irqreturn_t tmio_mmc_irq(int irq, void *devid)
 		     ((ireg & TMIO_STAT_CARD_INSERT) && !mmc->card)) &&
 		    !work_pending(&mmc->detect.work))
 			mmc_detect_change(host->mmc, msecs_to_jiffies(100));
-		goto out;
+		return true;
 	}
 
-	/* CRC and other errors */
-/*	if (ireg & TMIO_STAT_ERR_IRQ)
- *		handled |= tmio_error_irq(host, irq, stat);
- */
+	return false;
+}
+
+irqreturn_t tmio_mmc_card_detect_irq(int irq, void *devid)
+{
+	unsigned int ireg, status;
+	struct tmio_mmc_host *host = devid;
 
+	tmio_mmc_card_irq_status(host, &ireg, &status);
+	__tmio_mmc_card_detect_irq(host, ireg, status);
+
+	return IRQ_HANDLED;
+}
+EXPORT_SYMBOL(tmio_mmc_card_detect_irq);
+
+static bool __tmio_mmc_sdcard_irq(struct tmio_mmc_host *host,
+				 int ireg, int status)
+{
 	/* Command completion */
 	if (ireg & (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT)) {
 		tmio_mmc_ack_mmc_irqs(host,
 			     TMIO_STAT_CMDRESPEND |
 			     TMIO_STAT_CMDTIMEOUT);
 		tmio_mmc_cmd_irq(host, status);
-		goto out;
+		return true;
 	}
 
 	/* Data transfer */
 	if (ireg & (TMIO_STAT_RXRDY | TMIO_STAT_TXRQ)) {
 		tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_RXRDY | TMIO_STAT_TXRQ);
 		tmio_mmc_pio_irq(host);
-		goto out;
+		return true;
 	}
 
 	/* Data transfer completion */
 	if (ireg & TMIO_STAT_DATAEND) {
 		tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_DATAEND);
 		tmio_mmc_data_irq(host);
-		goto out;
+		return true;
 	}
 
-	pr_warning("tmio_mmc: Spurious irq, disabling! "
-		"0x%08x 0x%08x 0x%08x\n", status, host->sdcard_irq_mask, ireg);
-	pr_debug_status(status);
-	tmio_mmc_disable_mmc_irqs(host, status & ~host->sdcard_irq_mask);
+	return false;
+}
+
+irqreturn_t tmio_mmc_sdcard_irq(int irq, void *devid)
+{
+	unsigned int ireg, status;
+	struct tmio_mmc_host *host = devid;
+
+	tmio_mmc_card_irq_status(host, &ireg, &status);
+	__tmio_mmc_sdcard_irq(host, ireg, status);
+
+	return IRQ_HANDLED;
+}
+EXPORT_SYMBOL(tmio_mmc_sdcard_irq);
+
+irqreturn_t tmio_mmc_sdio_irq(int irq, void *devid)
+{
+	struct tmio_mmc_host *host = devid;
+	struct mmc_host *mmc = host->mmc;
+	struct tmio_mmc_data *pdata = host->pdata;
+	unsigned int ireg, status;
+
+	if (!(pdata->flags & TMIO_MMC_SDIO_IRQ))
+		return IRQ_HANDLED;
+
+	status = sd_ctrl_read16(host, CTL_SDIO_STATUS);
+	ireg = status & TMIO_SDIO_MASK_ALL & ~host->sdcard_irq_mask;
+
+	sd_ctrl_write16(host, CTL_SDIO_STATUS, status & ~TMIO_SDIO_MASK_ALL);
+
+	if (mmc->caps & MMC_CAP_SDIO_IRQ && ireg & TMIO_SDIO_STAT_IOIRQ)
+		mmc_signal_sdio_irq(mmc);
+
+	return IRQ_HANDLED;
+}
+EXPORT_SYMBOL(tmio_mmc_sdio_irq);
+
+irqreturn_t tmio_mmc_irq(int irq, void *devid)
+{
+	struct tmio_mmc_host *host = devid;
+	unsigned int ireg, status;
+
+	pr_debug("MMC IRQ begin\n");
+
+	tmio_mmc_card_irq_status(host, &ireg, &status);
+	if (__tmio_mmc_card_detect_irq(host, ireg, status))
+		return IRQ_HANDLED;
+	if (__tmio_mmc_sdcard_irq(host, ireg, status))
+		return IRQ_HANDLED;
+
+	tmio_mmc_sdio_irq(irq, devid);
 
-out:
 	return IRQ_HANDLED;
 }
 EXPORT_SYMBOL(tmio_mmc_irq);
-- 
1.7.5.4


^ permalink raw reply related

* [PATCH v8 1/4] mmc: tmio: Cache interrupt masks
From: Simon Horman @ 2011-08-25  1:27 UTC (permalink / raw)
  To: linux-mmc, linux-sh
  Cc: Chris Ball, Paul Mundt, Guennadi Liakhovetski, Magnus Damm,
	Simon Horman
In-Reply-To: <1314235648-8959-1-git-send-email-horms@verge.net.au>

This avoids the need to look up the masks each time an interrupt
is handled.

As suggested by Guennadi.

Cc: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Acked-by: Magnus Damm <magnus.damm@gmail.com>
Signed-off-by: Simon Horman <horms@verge.net.au>

---

* SDCARD portion tested on AP4/Mackerel
* SDIO portion untested

v3
* As suggested by Guennadi Liakhovetski
  - Only read sdcard_irq_mask once and never read sdio_irq_mask,
    instead use the cached values as much as possible

v2
* Initial release
---
 drivers/mmc/host/tmio_mmc.h     |    4 ++++
 drivers/mmc/host/tmio_mmc_pio.c |   34 ++++++++++++++++++----------------
 2 files changed, 22 insertions(+), 16 deletions(-)

diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
index eeaf643..1cf8db5 100644
--- a/drivers/mmc/host/tmio_mmc.h
+++ b/drivers/mmc/host/tmio_mmc.h
@@ -79,6 +79,10 @@ struct tmio_mmc_host {
 	struct delayed_work	delayed_reset_work;
 	struct work_struct	done;
 
+	/* Cache IRQ mask */
+	u32			sdcard_irq_mask;
+	u32			sdio_irq_mask;
+
 	spinlock_t		lock;		/* protect host private data */
 	unsigned long		last_req_ts;
 	struct mutex		ios_lock;	/* protect set_ios() context */
diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c
index 1f16357..f0c7830 100644
--- a/drivers/mmc/host/tmio_mmc_pio.c
+++ b/drivers/mmc/host/tmio_mmc_pio.c
@@ -48,14 +48,14 @@
 
 void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i)
 {
-	u32 mask = sd_ctrl_read32(host, CTL_IRQ_MASK) & ~(i & TMIO_MASK_IRQ);
-	sd_ctrl_write32(host, CTL_IRQ_MASK, mask);
+	host->sdcard_irq_mask &= ~(i & TMIO_MASK_IRQ);
+	sd_ctrl_write32(host, CTL_IRQ_MASK, host->sdcard_irq_mask);
 }
 
 void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i)
 {
-	u32 mask = sd_ctrl_read32(host, CTL_IRQ_MASK) | (i & TMIO_MASK_IRQ);
-	sd_ctrl_write32(host, CTL_IRQ_MASK, mask);
+	host->sdcard_irq_mask |= (i & TMIO_MASK_IRQ);
+	sd_ctrl_write32(host, CTL_IRQ_MASK, host->sdcard_irq_mask);
 }
 
 static void tmio_mmc_ack_mmc_irqs(struct tmio_mmc_host *host, u32 i)
@@ -127,11 +127,13 @@ static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
 
 	if (enable) {
 		host->sdio_irq_enabled = 1;
+		host->sdio_irq_mask = TMIO_SDIO_MASK_ALL &
+					~TMIO_SDIO_STAT_IOIRQ;
 		sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001);
-		sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK,
-			(TMIO_SDIO_MASK_ALL & ~TMIO_SDIO_STAT_IOIRQ));
+		sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask);
 	} else {
-		sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, TMIO_SDIO_MASK_ALL);
+		host->sdio_irq_mask = TMIO_SDIO_MASK_ALL;
+		sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask);
 		sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0000);
 		host->sdio_irq_enabled = 0;
 	}
@@ -548,26 +550,25 @@ irqreturn_t tmio_mmc_irq(int irq, void *devid)
 	struct tmio_mmc_host *host = devid;
 	struct mmc_host *mmc = host->mmc;
 	struct tmio_mmc_data *pdata = host->pdata;
-	unsigned int ireg, irq_mask, status;
-	unsigned int sdio_ireg, sdio_irq_mask, sdio_status;
+	unsigned int ireg, status;
+	unsigned int sdio_ireg, sdio_status;
 
 	pr_debug("MMC IRQ begin\n");
 
 	status = sd_ctrl_read32(host, CTL_STATUS);
-	irq_mask = sd_ctrl_read32(host, CTL_IRQ_MASK);
-	ireg = status & TMIO_MASK_IRQ & ~irq_mask;
+	ireg = status & TMIO_MASK_IRQ & ~host->sdcard_irq_mask;
 
 	sdio_ireg = 0;
 	if (!ireg && pdata->flags & TMIO_MMC_SDIO_IRQ) {
 		sdio_status = sd_ctrl_read16(host, CTL_SDIO_STATUS);
-		sdio_irq_mask = sd_ctrl_read16(host, CTL_SDIO_IRQ_MASK);
-		sdio_ireg = sdio_status & TMIO_SDIO_MASK_ALL & ~sdio_irq_mask;
+		sdio_ireg = sdio_status & TMIO_SDIO_MASK_ALL &
+				~host->sdio_irq_mask;
 
 		sd_ctrl_write16(host, CTL_SDIO_STATUS, sdio_status & ~TMIO_SDIO_MASK_ALL);
 
 		if (sdio_ireg && !host->sdio_irq_enabled) {
 			pr_warning("tmio_mmc: Spurious SDIO IRQ, disabling! 0x%04x 0x%04x 0x%04x\n",
-				   sdio_status, sdio_irq_mask, sdio_ireg);
+				   sdio_status, host->sdio_irq_mask, sdio_ireg);
 			tmio_mmc_enable_sdio_irq(mmc, 0);
 			goto out;
 		}
@@ -623,9 +624,9 @@ irqreturn_t tmio_mmc_irq(int irq, void *devid)
 	}
 
 	pr_warning("tmio_mmc: Spurious irq, disabling! "
-		"0x%08x 0x%08x 0x%08x\n", status, irq_mask, ireg);
+		"0x%08x 0x%08x 0x%08x\n", status, host->sdcard_irq_mask, ireg);
 	pr_debug_status(status);
-	tmio_mmc_disable_mmc_irqs(host, status & ~irq_mask);
+	tmio_mmc_disable_mmc_irqs(host, status & ~host->sdcard_irq_mask);
 
 out:
 	return IRQ_HANDLED;
@@ -882,6 +883,7 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
 	tmio_mmc_clk_stop(_host);
 	tmio_mmc_reset(_host);
 
+	_host->sdcard_irq_mask = sd_ctrl_read32(_host, CTL_IRQ_MASK);
 	tmio_mmc_disable_mmc_irqs(_host, TMIO_MASK_ALL);
 	if (pdata->flags & TMIO_MMC_SDIO_IRQ)
 		tmio_mmc_enable_sdio_irq(mmc, 0);
-- 
1.7.5.4


^ permalink raw reply related

* [PATCH 0/4 v8] mmc: tmio, sdhi: provide multiple irq handlers
From: Simon Horman @ 2011-08-25  1:27 UTC (permalink / raw)
  To: linux-mmc, linux-sh
  Cc: Chris Ball, Paul Mundt, Guennadi Liakhovetski, Magnus Damm,
	Simon Horman

The SDHI driver already supports making use of up to three interrupt
sources.

This series breaks up the existing interrupt handler into three handlers,
one for sdcard access, one for card detect and one for SDIO interrupts.
A cover-all handler, which makes use of these new broken-out handlers
is provided for for the case where there is a multiplexed interrupt source.

This series also wires up the new IRQ handlers for the mackerel and ag4evm.

This series contains the following patches:

[PATCH v8 1/4] mmc: tmio: Cache interrupt masks
[PATCH v8 2/4] mmc: tmio: Provide separate interrupt handlers
[PATCH v8 3/4] mmc: sdhi: Allow name IRQs to use specific handlers
[PATCH v8 4/4] ARM: shmobile: ag5evm, ap4: Named SDHI IRQ sources

^ 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