Re: [PATCH v2 1/2] mmc: dw_mmc: fix bug that cause 'Timeout sending command'

2015-02-13 Thread addy ke


On 2015/2/12 21:59, Alim Akhtar wrote:
 On Thu, Feb 12, 2015 at 4:40 PM, Andrzej Hajda a.ha...@samsung.com wrote:
 On 02/12/2015 03:28 AM, addy ke wrote:
 Hi Andrzej and Alim

 On 2015/2/12 07:20, Alim Akhtar wrote:
 Hi Andrzej,

 On Wed, Feb 11, 2015 at 5:28 PM, Andrzej Hajda a.ha...@samsung.com wrote:
 Hi Alim,

 On 02/11/2015 03:57 AM, Addy wrote:
 On 2015/02/10 23:22, Alim Akhtar wrote:
 Hi Addy,

 On Mon, Feb 9, 2015 at 12:55 PM, Addy Ke addy...@rock-chips.com wrote:
 Because of some uncertain factors, such as worse card or worse 
 hardware,
 DAT[3:0](the data lines) may be pulled down by card, and mmc controller
 will be in busy state. This should not happend when mmc controller
 send command to update card clocks. If this happends, mci_send_cmd will
 be failed and we will get 'Timeout sending command', and then system 
 will
 be blocked. To avoid this, we need reset mmc controller.

 Signed-off-by: Addy Ke addy...@rock-chips.com
 ---
   drivers/mmc/host/dw_mmc.c | 28 
   1 file changed, 28 insertions(+)

 diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
 index 4d2e3c2..b0b57e3 100644
 --- a/drivers/mmc/host/dw_mmc.c
 +++ b/drivers/mmc/host/dw_mmc.c
 @@ -100,6 +100,7 @@ struct idmac_desc {
   };
   #endif /* CONFIG_MMC_DW_IDMAC */

 +static int dw_mci_card_busy(struct mmc_host *mmc);
   static bool dw_mci_reset(struct dw_mci *host);
   static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset);

 @@ -888,6 +889,31 @@ static void mci_send_cmd(struct dw_mci_slot 
 *slot, u32 cmd, u32 arg)
  cmd, arg, cmd_status);
   }

 +static void dw_mci_wait_busy(struct dw_mci_slot *slot)
 +{
 +   struct dw_mci *host = slot-host;
 +   unsigned long timeout = jiffies + msecs_to_jiffies(500);
 +
 Why 500 msec?
 This timeout value is the same as  mci_send_cmd:
 static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg)
 {
  struct dw_mci *host = slot-host;
  unsigned long timeout = jiffies + msecs_to_jiffies(500);
  
 }

 I have not clear that which is suitable.
 Do you have any suggestion on it?
 +   do {
 +   if (!dw_mci_card_busy(slot-mmc))
 +   return;
 +   cpu_relax();
 +   } while (time_before(jiffies, timeout));
 +
 +   dev_err(host-dev, Data busy (status %#x)\n,
 +   mci_readl(slot-host, STATUS));
 +
 +   /*
 +* Data busy, this should not happend when mmc controller send 
 command
 +* to update card clocks in non-volt-switch state. If it 
 happends, we
 +* should reset controller to avoid getting Timeout sending 
 command.
 +*/
 +   dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS);
 +
 Why you need to reset all blocks? may be CTRL_RESET is good enough here.
 I have tested on rk3288, if only reset ctroller, data busy bit will not
 be cleaned,and we will still get

 Timeout sending command.

 +   /* Fail to reset controller or still data busy, WARN_ON! */
 +   WARN_ON(dw_mci_card_busy(slot-mmc));
 +}
 +
   static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool 
 force_clkinit)
   {
  struct dw_mci *host = slot-host;
 @@ -899,6 +925,8 @@ static void dw_mci_setup_bus(struct dw_mci_slot 
 *slot, bool force_clkinit)
  /* We must continue to set bit 28 in CMD until the change is 
 complete */
  if (host-state == STATE_WAITING_CMD11_DONE)
  sdmmc_cmd_bits |= SDMMC_CMD_VOLT_SWITCH;
 +   else
 +   dw_mci_wait_busy(slot);

 hmm...I would suggest you to call dw_mci_wait_busy() from inside
 mci_send_cmd(), seems like dw_mmc hangs while sending update clock cmd
 in multiple cases.see [1]

 [1]: http://permalink.gmane.org/gmane.linux.kernel.mmc/31140
 I think this patch is more reasonable.
 So I will resend patches based on this patch.
 thank you!
 I have tested your patches instead [1] above and they do not solve my 
 issue:
 Board: odroid-xu3/exynos5422/dw_mmc_250a.
 MMC card: absent, broken-cd quirk
 SD card: present

 I doubt $SUBJECT patch in current form can resolve you issue. I have
 already given comments on $subject patch.

 Can you try out below patch (I have not tested yet) on top of $SUBJECT 
 patch?

 ===
 diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
 index b0b57e3..ea87844 100644
 --- a/drivers/mmc/host/dw_mmc.c
 +++ b/drivers/mmc/host/dw_mmc.c
 @@ -101,6 +101,7 @@ struct idmac_desc {
  #endif /* CONFIG_MMC_DW_IDMAC */

  static int dw_mci_card_busy(struct mmc_host *mmc);
 +static void dw_mci_wait_busy(struct dw_mci_slot *slot);
  static bool dw_mci_reset(struct dw_mci *host);
  static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset);

 @@ -874,16 +875,22 @@ static void mci_send_cmd(struct dw_mci_slot
 *slot, u32 cmd, u32 arg)
 struct dw_mci *host = slot-host;
 unsigned long timeout = jiffies + msecs_to_jiffies(500);
 unsigned int cmd_status = 0;
 +   int re_try

Re: [PATCH v2 1/2] mmc: dw_mmc: fix bug that cause 'Timeout sending command'

2015-02-11 Thread addy ke
Hi Andrzej and Alim

On 2015/2/12 07:20, Alim Akhtar wrote:
 Hi Andrzej,
 
 On Wed, Feb 11, 2015 at 5:28 PM, Andrzej Hajda a.ha...@samsung.com wrote:
 Hi Alim,

 On 02/11/2015 03:57 AM, Addy wrote:

 On 2015/02/10 23:22, Alim Akhtar wrote:
 Hi Addy,

 On Mon, Feb 9, 2015 at 12:55 PM, Addy Ke addy...@rock-chips.com wrote:
 Because of some uncertain factors, such as worse card or worse hardware,
 DAT[3:0](the data lines) may be pulled down by card, and mmc controller
 will be in busy state. This should not happend when mmc controller
 send command to update card clocks. If this happends, mci_send_cmd will
 be failed and we will get 'Timeout sending command', and then system will
 be blocked. To avoid this, we need reset mmc controller.

 Signed-off-by: Addy Ke addy...@rock-chips.com
 ---
   drivers/mmc/host/dw_mmc.c | 28 
   1 file changed, 28 insertions(+)

 diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
 index 4d2e3c2..b0b57e3 100644
 --- a/drivers/mmc/host/dw_mmc.c
 +++ b/drivers/mmc/host/dw_mmc.c
 @@ -100,6 +100,7 @@ struct idmac_desc {
   };
   #endif /* CONFIG_MMC_DW_IDMAC */

 +static int dw_mci_card_busy(struct mmc_host *mmc);
   static bool dw_mci_reset(struct dw_mci *host);
   static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset);

 @@ -888,6 +889,31 @@ static void mci_send_cmd(struct dw_mci_slot *slot, 
 u32 cmd, u32 arg)
  cmd, arg, cmd_status);
   }

 +static void dw_mci_wait_busy(struct dw_mci_slot *slot)
 +{
 +   struct dw_mci *host = slot-host;
 +   unsigned long timeout = jiffies + msecs_to_jiffies(500);
 +
 Why 500 msec?
 This timeout value is the same as  mci_send_cmd:
 static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg)
 {
  struct dw_mci *host = slot-host;
  unsigned long timeout = jiffies + msecs_to_jiffies(500);
  
 }

 I have not clear that which is suitable.
 Do you have any suggestion on it?

 +   do {
 +   if (!dw_mci_card_busy(slot-mmc))
 +   return;
 +   cpu_relax();
 +   } while (time_before(jiffies, timeout));
 +
 +   dev_err(host-dev, Data busy (status %#x)\n,
 +   mci_readl(slot-host, STATUS));
 +
 +   /*
 +* Data busy, this should not happend when mmc controller send 
 command
 +* to update card clocks in non-volt-switch state. If it 
 happends, we
 +* should reset controller to avoid getting Timeout sending 
 command.
 +*/
 +   dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS);
 +
 Why you need to reset all blocks? may be CTRL_RESET is good enough here.
 I have tested on rk3288, if only reset ctroller, data busy bit will not
 be cleaned,and we will still get

 Timeout sending command.


 +   /* Fail to reset controller or still data busy, WARN_ON! */
 +   WARN_ON(dw_mci_card_busy(slot-mmc));
 +}
 +
   static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool 
 force_clkinit)
   {
  struct dw_mci *host = slot-host;
 @@ -899,6 +925,8 @@ static void dw_mci_setup_bus(struct dw_mci_slot 
 *slot, bool force_clkinit)
  /* We must continue to set bit 28 in CMD until the change is 
 complete */
  if (host-state == STATE_WAITING_CMD11_DONE)
  sdmmc_cmd_bits |= SDMMC_CMD_VOLT_SWITCH;
 +   else
 +   dw_mci_wait_busy(slot);

 hmm...I would suggest you to call dw_mci_wait_busy() from inside
 mci_send_cmd(), seems like dw_mmc hangs while sending update clock cmd
 in multiple cases.see [1]

 [1]: http://permalink.gmane.org/gmane.linux.kernel.mmc/31140
 I think this patch is more reasonable.
 So I will resend patches based on this patch.
 thank you!

 I have tested your patches instead [1] above and they do not solve my issue:
 Board: odroid-xu3/exynos5422/dw_mmc_250a.
 MMC card: absent, broken-cd quirk
 SD card: present

 I doubt $SUBJECT patch in current form can resolve you issue. I have
 already given comments on $subject patch.
 
 Can you try out below patch (I have not tested yet) on top of $SUBJECT patch?
 
 ===
 diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
 index b0b57e3..ea87844 100644
 --- a/drivers/mmc/host/dw_mmc.c
 +++ b/drivers/mmc/host/dw_mmc.c
 @@ -101,6 +101,7 @@ struct idmac_desc {
  #endif /* CONFIG_MMC_DW_IDMAC */
 
  static int dw_mci_card_busy(struct mmc_host *mmc);
 +static void dw_mci_wait_busy(struct dw_mci_slot *slot);
  static bool dw_mci_reset(struct dw_mci *host);
  static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset);
 
 @@ -874,16 +875,22 @@ static void mci_send_cmd(struct dw_mci_slot
 *slot, u32 cmd, u32 arg)
 struct dw_mci *host = slot-host;
 unsigned long timeout = jiffies + msecs_to_jiffies(500);
 unsigned int cmd_status = 0;
 +   int re_try = 3; /* just random for now, 1 re-try should be ok */
 
 -   mci_writel(host, CMDARG, arg);
 -   wmb();
 -   mci_writel(host, CMD, SDMMC_CMD_START

Re: [PATCH] mmc: dw_mmc: fix bug that cause mmc_test failture

2015-02-10 Thread Addy


On 2015/02月10日 17:34, Olof Johansson wrote:

Hi Addy,

On Mon, Jan 26, 2015 at 4:04 AM, Addy Ke addy...@rock-chips.com wrote:

The STOP command can terminate a data transfer between a memory card and
mmc controller.

As show in Synopsys DesignWare Cores Mobile Stroage Host Databook:
Data timeout and Data end-bit error will terminate further data transfer
by mmc controller. So we should not send abort command to terminate a
data transfer again if we got DRTO and EBE interrupt.

After this patch, all mmc_test cases can pass on RK3288-Pink2 board.

Signed-off-by: Addy Ke addy...@rock-chips.com

The drawback of having so many people on your to: list on a patch is
that it's unclear who you want to review and merge it. Sometimes less
is more.
I will remove some unnecessary mail address from list in the following 
patch.

Thank you.


In this case, it seems appropriate to have Ulf do so. Ulf, ping? This
seems like a reasonable patch for 3.20 given that it fixes undesired
behavior.


-Olof






--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v2 1/2] mmc: dw_mmc: fix bug that cause 'Timeout sending command'

2015-02-10 Thread Addy


On 2015/02/09 18:01, Jaehoon Chung wrote:

Hi, Addy.

On 02/09/2015 04:25 PM, Addy Ke wrote:

Because of some uncertain factors, such as worse card or worse hardware,
DAT[3:0](the data lines) may be pulled down by card, and mmc controller
will be in busy state. This should not happend when mmc controller
send command to update card clocks. If this happends, mci_send_cmd will
be failed and we will get 'Timeout sending command', and then system will
be blocked. To avoid this, we need reset mmc controller.

Signed-off-by: Addy Ke addy...@rock-chips.com
---
  drivers/mmc/host/dw_mmc.c | 28 
  1 file changed, 28 insertions(+)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 4d2e3c2..b0b57e3 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -100,6 +100,7 @@ struct idmac_desc {
  };
  #endif /* CONFIG_MMC_DW_IDMAC */
  
+static int dw_mci_card_busy(struct mmc_host *mmc);

  static bool dw_mci_reset(struct dw_mci *host);
  static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset);
  
@@ -888,6 +889,31 @@ static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg)

cmd, arg, cmd_status);
  }
  
+static void dw_mci_wait_busy(struct dw_mci_slot *slot)

+{
+   struct dw_mci *host = slot-host;
+   unsigned long timeout = jiffies + msecs_to_jiffies(500);
+
+   do {
+   if (!dw_mci_card_busy(slot-mmc))
+   return;
+   cpu_relax();
+   } while (time_before(jiffies, timeout));
+
+   dev_err(host-dev, Data busy (status %#x)\n,
+   mci_readl(slot-host, STATUS));
+
+   /*
+* Data busy, this should not happend when mmc controller send command
+* to update card clocks in non-volt-switch state. If it happends, we
+* should reset controller to avoid getting Timeout sending command.
+*/
+   dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS);

If reset is failed, then dw_mci_ctrl_reset should return false.

ret = dw_mci_ctrl_reset();

WARN_ON(!ret || dw_mci_card_busy(slot-mmc));

Is it right?

you are right, and I will update it in my next version patch. thank you.


In my experiment, if reset is failed or card is busy, eMMC can't work 
anymore..right?
I think this patch is reasonable to prevent blocking issue.

Best Regards,
Jaehoon Chung



+
+   /* Fail to reset controller or still data busy, WARN_ON! */
+   WARN_ON(dw_mci_card_busy(slot-mmc));
+}
+
  static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
  {
struct dw_mci *host = slot-host;
@@ -899,6 +925,8 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool 
force_clkinit)
/* We must continue to set bit 28 in CMD until the change is complete */
if (host-state == STATE_WAITING_CMD11_DONE)
sdmmc_cmd_bits |= SDMMC_CMD_VOLT_SWITCH;
+   else
+   dw_mci_wait_busy(slot);
  
  	if (!clock) {

mci_writel(host, CLKENA, 0);








--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v2 1/2] mmc: dw_mmc: fix bug that cause 'Timeout sending command'

2015-02-10 Thread Addy


On 2015/02/10 23:22, Alim Akhtar wrote:

Hi Addy,

On Mon, Feb 9, 2015 at 12:55 PM, Addy Ke addy...@rock-chips.com wrote:

Because of some uncertain factors, such as worse card or worse hardware,
DAT[3:0](the data lines) may be pulled down by card, and mmc controller
will be in busy state. This should not happend when mmc controller
send command to update card clocks. If this happends, mci_send_cmd will
be failed and we will get 'Timeout sending command', and then system will
be blocked. To avoid this, we need reset mmc controller.

Signed-off-by: Addy Ke addy...@rock-chips.com
---
  drivers/mmc/host/dw_mmc.c | 28 
  1 file changed, 28 insertions(+)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 4d2e3c2..b0b57e3 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -100,6 +100,7 @@ struct idmac_desc {
  };
  #endif /* CONFIG_MMC_DW_IDMAC */

+static int dw_mci_card_busy(struct mmc_host *mmc);
  static bool dw_mci_reset(struct dw_mci *host);
  static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset);

@@ -888,6 +889,31 @@ static void mci_send_cmd(struct dw_mci_slot *slot, u32 
cmd, u32 arg)
 cmd, arg, cmd_status);
  }

+static void dw_mci_wait_busy(struct dw_mci_slot *slot)
+{
+   struct dw_mci *host = slot-host;
+   unsigned long timeout = jiffies + msecs_to_jiffies(500);
+

Why 500 msec?

This timeout value is the same as  mci_send_cmd:
static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg)
{
struct dw_mci *host = slot-host;
unsigned long timeout = jiffies + msecs_to_jiffies(500);

}

I have not clear that which is suitable.
Do you have any suggestion on it?



+   do {
+   if (!dw_mci_card_busy(slot-mmc))
+   return;
+   cpu_relax();
+   } while (time_before(jiffies, timeout));
+
+   dev_err(host-dev, Data busy (status %#x)\n,
+   mci_readl(slot-host, STATUS));
+
+   /*
+* Data busy, this should not happend when mmc controller send command
+* to update card clocks in non-volt-switch state. If it happends, we
+* should reset controller to avoid getting Timeout sending command.
+*/
+   dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS);
+

Why you need to reset all blocks? may be CTRL_RESET is good enough here.
I have tested on rk3288, if only reset ctroller, data busy bit will not 
be cleaned,and we will still get


Timeout sending command.




+   /* Fail to reset controller or still data busy, WARN_ON! */
+   WARN_ON(dw_mci_card_busy(slot-mmc));
+}
+
  static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
  {
 struct dw_mci *host = slot-host;
@@ -899,6 +925,8 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool 
force_clkinit)
 /* We must continue to set bit 28 in CMD until the change is complete 
*/
 if (host-state == STATE_WAITING_CMD11_DONE)
 sdmmc_cmd_bits |= SDMMC_CMD_VOLT_SWITCH;
+   else
+   dw_mci_wait_busy(slot);


hmm...I would suggest you to call dw_mci_wait_busy() from inside
mci_send_cmd(), seems like dw_mmc hangs while sending update clock cmd
in multiple cases.see [1]

[1]: http://permalink.gmane.org/gmane.linux.kernel.mmc/31140

I think this patch is more reasonable.
So I will resend patches based on this patch.
thank you!



 if (!clock) {
 mci_writel(host, CLKENA, 0);
--
1.8.3.2



___
linux-arm-kernel mailing list
linux-arm-ker...@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel






--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH] mmc: dw_mmc: fix bug that cause 'Timeout sending command'

2015-02-09 Thread addy ke


On 2015/2/9 15:04, Jaehoon Chung wrote:
 On 02/09/2015 03:56 PM, Addy wrote:


 On 2015.02.09 12:51, Ulf Hansson wrote:
 On 5 February 2015 at 12:13, Addy Ke addy...@rock-chips.com wrote:
 Because of some uncertain factors, such as worse card or worse hardware,
 DAT[3:0](the data lines) may be pulled down by card, and mmc controller
 will be in busy state. This should not happend when mmc controller
 send command to update card clocks. If this happends, mci_send_cmd will
 be failed and we will get 'Timeout sending command', and then system will
 be blocked. To avoid this, we need reset mmc controller.
 
 I know that it needs to check whether card is busy or not, before clock-off.
 This patch seems to related with it. right?

Yes, it is.

 
 Best Regards,
 Jaehoon Chung
 

 Signed-off-by: Addy Ke addy...@rock-chips.com

 Hi Addy,

 Should I consider $subject patch as a better option to the one below?
 No:
 This patch fix the bug, which can be found by script:
 cd /sys/bus/platform/drivers/dwmmc_rockchip
 for i in $(seq 1 1); do
   echo  $i
   echo ff0c.dwmmc  unbind
   sleep .5
   echo ff0c.dwmmc  bind
   sleep 2
 done

 [PATCH] mmc: dw_mmc: rockchip: Add DW_MCI_QUIRK_RETRY_DELAY
 This patch is for tuning issue: we should delay until card go to idle state, 
 when the previous command return error.
 https://lkml.org/lkml/2015/1/13/562

 Kind regards
 Uffe


 ---
   drivers/mmc/host/dw_mmc.c | 23 +++
   1 file changed, 23 insertions(+)

 diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
 index 4d2e3c2..b1d6dfb 100644
 --- a/drivers/mmc/host/dw_mmc.c
 +++ b/drivers/mmc/host/dw_mmc.c
 @@ -100,6 +100,7 @@ struct idmac_desc {
   };
   #endif /* CONFIG_MMC_DW_IDMAC */

 +static int dw_mci_card_busy(struct mmc_host *mmc);
   static bool dw_mci_reset(struct dw_mci *host);
   static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset);

 @@ -888,6 +889,26 @@ static void mci_send_cmd(struct dw_mci_slot *slot, 
 u32 cmd, u32 arg)
  cmd, arg, cmd_status);
   }

 +static void dw_mci_wait_busy(struct dw_mci_slot *slot)
 +{
 +   struct dw_mci *host = slot-host;
 +   unsigned long timeout = jiffies + msecs_to_jiffies(500);
 +
 +   while (time_before(jiffies, timeout)) {
 +   if (!dw_mci_card_busy(slot-mmc))
 +   return;
 +   }
 +   dev_err(host-dev, Data busy (status %#x)\n,
 +   mci_readl(slot-host, STATUS));
 +
 +   /*
 +* Data busy, this should not happend when mmc controller send 
 command
 +* to update card clocks in non-volt-switch state. If it happends, 
 we
 +* should reset controller to avoid getting Timeout sending 
 command.
 +*/
 +   dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS);
 +}
 +
   static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool 
 force_clkinit)
   {
  struct dw_mci *host = slot-host;
 @@ -899,6 +920,8 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, 
 bool force_clkinit)
  /* We must continue to set bit 28 in CMD until the change is 
 complete */
  if (host-state == STATE_WAITING_CMD11_DONE)
  sdmmc_cmd_bits |= SDMMC_CMD_VOLT_SWITCH;
 +   else
 +   dw_mci_wait_busy(slot);

  if (!clock) {
  mci_writel(host, CLKENA, 0);
 -- 
 1.8.3.2


 -- 
 To unsubscribe from this list: send the line unsubscribe linux-mmc in
 the body of a message to majord...@vger.kernel.org
 More majordomo info at  http://vger.kernel.org/majordomo-info.html





 
 
 
 

--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH] mmc: dw_mmc: fix bug that cause 'Timeout sending command'

2015-02-08 Thread Addy



On 2015.02.09 12:51, Ulf Hansson wrote:

On 5 February 2015 at 12:13, Addy Ke addy...@rock-chips.com wrote:

Because of some uncertain factors, such as worse card or worse hardware,
DAT[3:0](the data lines) may be pulled down by card, and mmc controller
will be in busy state. This should not happend when mmc controller
send command to update card clocks. If this happends, mci_send_cmd will
be failed and we will get 'Timeout sending command', and then system will
be blocked. To avoid this, we need reset mmc controller.

Signed-off-by: Addy Ke addy...@rock-chips.com


Hi Addy,

Should I consider $subject patch as a better option to the one below?

No:
This patch fix the bug, which can be found by script:
cd /sys/bus/platform/drivers/dwmmc_rockchip
for i in $(seq 1 1); do
  echo  $i
  echo ff0c.dwmmc  unbind
  sleep .5
  echo ff0c.dwmmc  bind
  sleep 2
done


[PATCH] mmc: dw_mmc: rockchip: Add DW_MCI_QUIRK_RETRY_DELAY
This patch is for tuning issue: we should delay until card go to idle 
state, when the previous command return error.

https://lkml.org/lkml/2015/1/13/562

Kind regards
Uffe



---
  drivers/mmc/host/dw_mmc.c | 23 +++
  1 file changed, 23 insertions(+)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 4d2e3c2..b1d6dfb 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -100,6 +100,7 @@ struct idmac_desc {
  };
  #endif /* CONFIG_MMC_DW_IDMAC */

+static int dw_mci_card_busy(struct mmc_host *mmc);
  static bool dw_mci_reset(struct dw_mci *host);
  static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset);

@@ -888,6 +889,26 @@ static void mci_send_cmd(struct dw_mci_slot *slot, u32 
cmd, u32 arg)
 cmd, arg, cmd_status);
  }

+static void dw_mci_wait_busy(struct dw_mci_slot *slot)
+{
+   struct dw_mci *host = slot-host;
+   unsigned long timeout = jiffies + msecs_to_jiffies(500);
+
+   while (time_before(jiffies, timeout)) {
+   if (!dw_mci_card_busy(slot-mmc))
+   return;
+   }
+   dev_err(host-dev, Data busy (status %#x)\n,
+   mci_readl(slot-host, STATUS));
+
+   /*
+* Data busy, this should not happend when mmc controller send command
+* to update card clocks in non-volt-switch state. If it happends, we
+* should reset controller to avoid getting Timeout sending command.
+*/
+   dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS);
+}
+
  static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
  {
 struct dw_mci *host = slot-host;
@@ -899,6 +920,8 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool 
force_clkinit)
 /* We must continue to set bit 28 in CMD until the change is complete 
*/
 if (host-state == STATE_WAITING_CMD11_DONE)
 sdmmc_cmd_bits |= SDMMC_CMD_VOLT_SWITCH;
+   else
+   dw_mci_wait_busy(slot);

 if (!clock) {
 mci_writel(host, CLKENA, 0);
--
1.8.3.2


--
To unsubscribe from this list: send the line unsubscribe linux-mmc in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html






--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 0/2] about data busy

2015-02-08 Thread Addy Ke
Addy Ke (2):
  mmc: dw_mmc: fix bug that cause 'Timeout sending command'
  mmc: dw_mmc: Don't start command while data busy

 drivers/mmc/host/dw_mmc.c | 35 +++
 1 file changed, 35 insertions(+)

-- 
Changes in v2:
- add new patch to handle data busy when start command
- add cpu_relaxed, suggested by Daniel Kurtz djku...@chromium.org
1.8.3.2


--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 2/2] mmc: dw_mmc: Don't start command while data busy

2015-02-08 Thread Addy Ke
We should wait for data busy here in non-volt-switch state.
This may happend when sdio sends CMD53.

Signed-off-by: Addy Ke addy...@rock-chips.com
---
 drivers/mmc/host/dw_mmc.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index b0b57e3..b40080d 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1007,6 +1007,13 @@ static void __dw_mci_start_request(struct dw_mci *host,
mci_writel(host, BLKSIZ, data-blksz);
}
 
+   /*
+* We should wait for data busy here in non-volt-switch state.
+* This may happend when sdio sends CMD53.
+*/
+   if (host-state != STATE_WAITING_CMD11_DONE)
+   dw_mci_wait_busy(slot);
+
cmdflags = dw_mci_prepare_command(slot-mmc, cmd);
 
/* this is the first command, send the initialization clock */
-- 
1.8.3.2


--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 1/2] mmc: dw_mmc: fix bug that cause 'Timeout sending command'

2015-02-08 Thread Addy Ke
Because of some uncertain factors, such as worse card or worse hardware,
DAT[3:0](the data lines) may be pulled down by card, and mmc controller
will be in busy state. This should not happend when mmc controller
send command to update card clocks. If this happends, mci_send_cmd will
be failed and we will get 'Timeout sending command', and then system will
be blocked. To avoid this, we need reset mmc controller.

Signed-off-by: Addy Ke addy...@rock-chips.com
---
 drivers/mmc/host/dw_mmc.c | 28 
 1 file changed, 28 insertions(+)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 4d2e3c2..b0b57e3 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -100,6 +100,7 @@ struct idmac_desc {
 };
 #endif /* CONFIG_MMC_DW_IDMAC */
 
+static int dw_mci_card_busy(struct mmc_host *mmc);
 static bool dw_mci_reset(struct dw_mci *host);
 static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset);
 
@@ -888,6 +889,31 @@ static void mci_send_cmd(struct dw_mci_slot *slot, u32 
cmd, u32 arg)
cmd, arg, cmd_status);
 }
 
+static void dw_mci_wait_busy(struct dw_mci_slot *slot)
+{
+   struct dw_mci *host = slot-host;
+   unsigned long timeout = jiffies + msecs_to_jiffies(500);
+
+   do {
+   if (!dw_mci_card_busy(slot-mmc))
+   return;
+   cpu_relax();
+   } while (time_before(jiffies, timeout));
+
+   dev_err(host-dev, Data busy (status %#x)\n,
+   mci_readl(slot-host, STATUS));
+
+   /*
+* Data busy, this should not happend when mmc controller send command
+* to update card clocks in non-volt-switch state. If it happends, we
+* should reset controller to avoid getting Timeout sending command.
+*/
+   dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS);
+
+   /* Fail to reset controller or still data busy, WARN_ON! */
+   WARN_ON(dw_mci_card_busy(slot-mmc));
+}
+
 static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
 {
struct dw_mci *host = slot-host;
@@ -899,6 +925,8 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool 
force_clkinit)
/* We must continue to set bit 28 in CMD until the change is complete */
if (host-state == STATE_WAITING_CMD11_DONE)
sdmmc_cmd_bits |= SDMMC_CMD_VOLT_SWITCH;
+   else
+   dw_mci_wait_busy(slot);
 
if (!clock) {
mci_writel(host, CLKENA, 0);
-- 
1.8.3.2


--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] mmc: dw_mmc: fix bug that cause 'Timeout sending command'

2015-02-05 Thread Addy Ke
Because of some uncertain factors, such as worse card or worse hardware,
DAT[3:0](the data lines) may be pulled down by card, and mmc controller
will be in busy state. This should not happend when mmc controller
send command to update card clocks. If this happends, mci_send_cmd will
be failed and we will get 'Timeout sending command', and then system will
be blocked. To avoid this, we need reset mmc controller.

Signed-off-by: Addy Ke addy...@rock-chips.com
---
 drivers/mmc/host/dw_mmc.c | 23 +++
 1 file changed, 23 insertions(+)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 4d2e3c2..b1d6dfb 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -100,6 +100,7 @@ struct idmac_desc {
 };
 #endif /* CONFIG_MMC_DW_IDMAC */
 
+static int dw_mci_card_busy(struct mmc_host *mmc);
 static bool dw_mci_reset(struct dw_mci *host);
 static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset);
 
@@ -888,6 +889,26 @@ static void mci_send_cmd(struct dw_mci_slot *slot, u32 
cmd, u32 arg)
cmd, arg, cmd_status);
 }
 
+static void dw_mci_wait_busy(struct dw_mci_slot *slot)
+{
+   struct dw_mci *host = slot-host;
+   unsigned long timeout = jiffies + msecs_to_jiffies(500);
+
+   while (time_before(jiffies, timeout)) {
+   if (!dw_mci_card_busy(slot-mmc))
+   return;
+   }
+   dev_err(host-dev, Data busy (status %#x)\n,
+   mci_readl(slot-host, STATUS));
+
+   /*
+* Data busy, this should not happend when mmc controller send command
+* to update card clocks in non-volt-switch state. If it happends, we
+* should reset controller to avoid getting Timeout sending command.
+*/
+   dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS);
+}
+
 static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
 {
struct dw_mci *host = slot-host;
@@ -899,6 +920,8 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool 
force_clkinit)
/* We must continue to set bit 28 in CMD until the change is complete */
if (host-state == STATE_WAITING_CMD11_DONE)
sdmmc_cmd_bits |= SDMMC_CMD_VOLT_SWITCH;
+   else
+   dw_mci_wait_busy(slot);
 
if (!clock) {
mci_writel(host, CLKENA, 0);
-- 
1.8.3.2


--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2] mmc: core: add runtime-resume caps to support resume at runtime_resume

2015-02-05 Thread Addy Ke
Signed-off-by: Addy Ke addy...@rock-chips.com
---
Changes in v2:
 - fix some typo 

 Documentation/devicetree/bindings/mmc/mmc.txt | 1 +
 drivers/mmc/core/host.c   | 2 ++
 2 files changed, 3 insertions(+)

diff --git a/Documentation/devicetree/bindings/mmc/mmc.txt 
b/Documentation/devicetree/bindings/mmc/mmc.txt
index 438899e..a7b800e 100644
--- a/Documentation/devicetree/bindings/mmc/mmc.txt
+++ b/Documentation/devicetree/bindings/mmc/mmc.txt
@@ -40,6 +40,7 @@ Optional properties:
 - mmc-hs200-1_2v: eMMC HS200 mode(1.2V I/O) is supported
 - mmc-hs400-1_8v: eMMC HS400 mode(1.8V I/O) is supported
 - mmc-hs400-1_2v: eMMC HS400 mode(1.2V I/O) is supported
+- runtime-resume: resume at runtime_resume is supported
 - dsr: Value the card's (optional) Driver Stage Register (DSR) should be
   programmed with. Valid range: [0 .. 0x].
 
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 8be0df7..cb44c85 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -422,6 +422,8 @@ int mmc_of_parse(struct mmc_host *host)
host-caps |= MMC_CAP_POWER_OFF_CARD;
if (of_find_property(np, cap-sdio-irq, len))
host-caps |= MMC_CAP_SDIO_IRQ;
+   if (of_find_property(np, runtime-resume, len))
+   host-caps |= MMC_CAP_RUNTIME_RESUME;
if (of_find_property(np, full-pwr-cycle, len))
host-caps2 |= MMC_CAP2_FULL_PWR_CYCLE;
if (of_find_property(np, keep-power-in-suspend, len))
-- 
1.8.3.2


--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] mmc: core: add runtime-resume caps to support resume at runtime_resume

2015-02-05 Thread Addy Ke
Signed-off-by: Addy Ke addy...@rock-chips.com
---
 Documentation/devicetree/bindings/mmc/mmc.txt | 11 +++
 drivers/mmc/core/host.c   |  2 ++
 2 files changed, 13 insertions(+)

diff --git a/Documentation/devicetree/bindings/mmc/mmc.txt 
b/Documentation/devicetree/bindings/mmc/mmc.txt
index 438899e..303b448 100644
--- a/Documentation/devicetree/bindings/mmc/mmc.txt
+++ b/Documentation/devicetree/bindings/mmc/mmc.txt
@@ -40,9 +40,20 @@ Optional properties:
 - mmc-hs200-1_2v: eMMC HS200 mode(1.2V I/O) is supported
 - mmc-hs400-1_8v: eMMC HS400 mode(1.8V I/O) is supported
 - mmc-hs400-1_2v: eMMC HS400 mode(1.2V I/O) is supported
+- runtime-resume: resume at runtime_resume is supported
 - dsr: Value the card's (optional) Driver Stage Register (DSR) should be
   programmed with. Valid range: [0 .. 0x].
 
+Card power and reset control:
+The following properties can be specified for cases where the MMC
+peripheral needs additional reset, regulator and clock lines. It is for
+example common for WiFi/BT adapters to have these separate from the main
+MMC bus:
+  - card-reset-gpios: Specify GPIOs for card reset (reset active low)
+  - card-external-vcc-supply: Regulator to drive (independent) card VCC
+  - clock with name card_ext_clock: External clock provided to the card
+ 0064e63... FROMLIST: mmc: core: add runtime-resume caps to support 
resume at runtime_resume
+
 *NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers 
line
 polarity properties, we have to fix the meaning of the normal and inverted
 line levels. We choose to follow the SDHCI standard, which specifies both those
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 8be0df7..cb44c85 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -422,6 +422,8 @@ int mmc_of_parse(struct mmc_host *host)
host-caps |= MMC_CAP_POWER_OFF_CARD;
if (of_find_property(np, cap-sdio-irq, len))
host-caps |= MMC_CAP_SDIO_IRQ;
+   if (of_find_property(np, runtime-resume, len))
+   host-caps |= MMC_CAP_RUNTIME_RESUME;
if (of_find_property(np, full-pwr-cycle, len))
host-caps2 |= MMC_CAP2_FULL_PWR_CYCLE;
if (of_find_property(np, keep-power-in-suspend, len))
-- 
1.8.3.2


--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 1/2] mmc: core: use card pointer as the first parameter of execute_tuning()

2015-01-26 Thread Addy Ke
We need to take the card pointer in execute_tuning() for mmc_send_status(),
but mmc-card is NULL in tuning state. So we need change the first parameter
of execute_tuning() to card pointer(struct mmc_card * card).

Signed-off-by: Addy Ke addy...@rock-chips.com
---
 drivers/mmc/core/core.c   | 2 +-
 drivers/mmc/host/dw_mmc.c | 3 ++-
 drivers/mmc/host/rtsx_pci_sdmmc.c | 3 ++-
 drivers/mmc/host/rtsx_usb_sdmmc.c | 3 ++-
 include/linux/mmc/host.h  | 2 +-
 5 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 1be7055..271f024 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1101,7 +1101,7 @@ int mmc_execute_tuning(struct mmc_card *card)
opcode = MMC_SEND_TUNING_BLOCK;
 
mmc_host_clk_hold(host);
-   err = host-ops-execute_tuning(host, opcode);
+   err = host-ops-execute_tuning(card, opcode);
mmc_host_clk_release(host);
 
if (err)
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 4bd22af..e54e656 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1485,8 +1485,9 @@ free_blk_test:
return ret;
 }
 
-static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode)
+static int dw_mci_execute_tuning(struct mmc_card *card, u32 opcode)
 {
+   struct mmc_host *mmc = card-host;
struct dw_mci_slot *slot = mmc_priv(mmc);
struct dw_mci *host = slot-host;
const struct dw_mci_drv_data *drv_data = host-drv_data;
diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c 
b/drivers/mmc/host/rtsx_pci_sdmmc.c
index 1d3d6c4..230bd2f 100644
--- a/drivers/mmc/host/rtsx_pci_sdmmc.c
+++ b/drivers/mmc/host/rtsx_pci_sdmmc.c
@@ -1270,8 +1270,9 @@ out:
return err;
 }
 
-static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
+static int sdmmc_execute_tuning(struct mmc_card *card, u32 opcode)
 {
+   struct mmc_host *mmc = card-host;
struct realtek_pci_sdmmc *host = mmc_priv(mmc);
struct rtsx_pcr *pcr = host-pcr;
int err = 0;
diff --git a/drivers/mmc/host/rtsx_usb_sdmmc.c 
b/drivers/mmc/host/rtsx_usb_sdmmc.c
index 88af827..c494c06 100644
--- a/drivers/mmc/host/rtsx_usb_sdmmc.c
+++ b/drivers/mmc/host/rtsx_usb_sdmmc.c
@@ -1265,8 +1265,9 @@ out:
return 0;
 }
 
-static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
+static int sdmmc_execute_tuning(struct mmc_card *card, u32 opcode)
 {
+   struct mmc_host *mmc = card-host;
struct rtsx_usb_sdmmc *host = mmc_priv(mmc);
struct rtsx_ucr *ucr = host-ucr;
int err = 0;
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 0c8cbe5..ec4128e 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -133,7 +133,7 @@ struct mmc_host_ops {
int (*card_busy)(struct mmc_host *host);
 
/* The tuning command opcode value is different for SD and eMMC cards */
-   int (*execute_tuning)(struct mmc_host *host, u32 opcode);
+   int (*execute_tuning)(struct mmc_card *card, u32 opcode);
 
/* Prepare HS400 target operating frequency depending host driver */
int (*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios 
*ios);
-- 
1.8.3.2


--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 0/2] fix bug that cause tuning failure

2015-01-26 Thread Addy Ke
Addy Ke (2):
  mmc: core: use card pointer as the first parameter of execute_tuning()
  mmc: dw_mmc: wait until card ready if tuning fails

 drivers/mmc/core/core.c   |  2 +-
 drivers/mmc/core/mmc_ops.h|  1 -
 drivers/mmc/host/dw_mmc.c | 51 +--
 drivers/mmc/host/rtsx_pci_sdmmc.c |  3 ++-
 drivers/mmc/host/rtsx_usb_sdmmc.c |  3 ++-
 include/linux/mmc/card.h  |  2 ++
 include/linux/mmc/host.h  |  2 +-
 7 files changed, 52 insertions(+), 12 deletions(-)

-- 
1.8.3.2


--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 2/2] mmc: dw_mmc: wait until card ready if tuning fails

2015-01-26 Thread Addy Ke
This patch based on Alex's patch:
https://patchwork.kernel.org/patch/5516411/

Signed-off-by: Addy Ke addy...@rock-chips.com
---
 drivers/mmc/core/mmc_ops.h |  1 -
 drivers/mmc/host/dw_mmc.c  | 48 --
 include/linux/mmc/card.h   |  2 ++
 3 files changed, 44 insertions(+), 7 deletions(-)

diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index 6f4b00e..c5be9ce 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -20,7 +20,6 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 
*rocr);
 int mmc_all_send_cid(struct mmc_host *host, u32 *cid);
 int mmc_set_relative_addr(struct mmc_card *card);
 int mmc_send_csd(struct mmc_card *card, u32 *csd);
-int mmc_send_status(struct mmc_card *card, u32 *status);
 int mmc_send_cid(struct mmc_host *host, u32 *cid);
 int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp);
 int mmc_spi_set_crc(struct mmc_host *host, int use_crc);
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index e54e656..4a31a5e 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1317,10 +1317,38 @@ static void dw_mci_enable_sdio_irq(struct mmc_host 
*mmc, int enb)
spin_unlock_irqrestore(host-irq_lock, irqflags);
 }
 
-static int dw_mci_tuning_test(struct dw_mci_slot *slot, u32 opcode,
-  struct dw_mci_tuning_data *tuning_data,
-  u8 *blk_test)
+static int dw_mci_card_busy(u32 status)
 {
+   return !(status  R1_READY_FOR_DATA) ||
+   (R1_CURRENT_STATE(status) == R1_STATE_PRG);
+}
+
+static int dw_mci_wait_for_card_ready(struct mmc_card *card)
+{
+   struct mmc_host *mmc = card-host;
+   struct dw_mci_slot *slot = mmc_priv(mmc);
+   struct dw_mci *host = slot-host;
+   int err = 0;
+   u32 status;
+
+   do {
+   err = mmc_send_status(card, status);
+   if (err) {
+   dev_err(host-dev,
+   Get card status fail in tuning state\n);
+   break;
+   }
+   } while (dw_mci_card_busy(status));
+
+   return err;
+}
+
+static int dw_mci_tuning_test(struct mmc_card *card, u32 opcode,
+ struct dw_mci_tuning_data *tuning_data,
+ u8 *blk_test)
+{
+   struct mmc_host *mmc = card-host;
+   struct dw_mci_slot *slot = mmc_priv(mmc);
struct dw_mci *host = slot-host;
struct mmc_host *mmc = slot-mmc;
const u8 *blk_pattern = tuning_data-blk_pattern;
@@ -1330,6 +1358,7 @@ static int dw_mci_tuning_test(struct dw_mci_slot *slot, 
u32 opcode,
struct mmc_command stop = {0};
struct mmc_data data = {0};
struct scatterlist sg;
+   int err;
 
memset(blk_test, 0, blksz);
 
@@ -1365,6 +1394,11 @@ static int dw_mci_tuning_test(struct dw_mci_slot *slot, 
u32 opcode,
dev_dbg(host-dev,
Tuning error: cmd.error:%d, data.error:%d\n,
cmd.error, data.error);
+
+   err = dw_mci_wait_for_card_ready(card);
+   if (err)
+   return err;
+
if (cmd.error)
return cmd.error;
else
@@ -1372,9 +1406,11 @@ static int dw_mci_tuning_test(struct dw_mci_slot *slot, 
u32 opcode,
}
 }
 
-static int dw_mci_execute_generic_tuning(struct dw_mci_slot *slot, u32 opcode,
+static int dw_mci_execute_generic_tuning(struct mmc_card *card, u32 opcode,
 struct dw_mci_tuning_data *tuning_data)
 {
+   struct mmc_host *mmc = card-host;
+   struct dw_mci_slot *slot = mmc_priv(mmc);
struct dw_mci *host = slot-host;
unsigned int blksz = tuning_data-blksz;
u8 *blk_test;
@@ -1412,7 +1448,7 @@ static int dw_mci_execute_generic_tuning(struct 
dw_mci_slot *slot, u32 opcode,
for (i = 0; i  NUM_PHASES; i++) {
clk_set_phase(host-sample_clk, i * PHASE_INCREMENT);
 
-   v = !dw_mci_tuning_test(slot, opcode, tuning_data, blk_test);
+   v = !dw_mci_tuning_test(card, opcode, tuning_data, blk_test);
 
if ((!prev_v)  v) {
range_count++;
@@ -1496,7 +1532,7 @@ static int dw_mci_execute_tuning(struct mmc_card *card, 
u32 opcode)
if (drv_data  drv_data-execute_tuning)
err = drv_data-execute_tuning(slot, opcode, tuning_data);
else
-   err = dw_mci_execute_generic_tuning(slot, opcode, tuning_data);
+   err = dw_mci_execute_generic_tuning(card, opcode, tuning_data);
return err;
 }
 
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 4d69c00..40d90ae 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -518,4 +518,6 @@ extern void mmc_unregister_driver(struct device_driver *);
 extern void

[PATCH] mmc: dw_mmc: fix bug that cause mmc_test failture

2015-01-26 Thread Addy Ke
The STOP command can terminate a data transfer between a memory card and
mmc controller.

As show in Synopsys DesignWare Cores Mobile Stroage Host Databook:
Data timeout and Data end-bit error will terminate further data transfer
by mmc controller. So we should not send abort command to terminate a
data transfer again if we got DRTO and EBE interrupt.

After this patch, all mmc_test cases can pass on RK3288-Pink2 board.

Signed-off-by: Addy Ke addy...@rock-chips.com
---
 drivers/mmc/host/dw_mmc.c | 10 --
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 4d2e3c2..4bd7df1 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1520,7 +1520,10 @@ static void dw_mci_tasklet_func(unsigned long priv)
if (test_and_clear_bit(EVENT_DATA_ERROR,
   host-pending_events)) {
dw_mci_stop_dma(host);
-   send_stop_abort(host, data);
+   if (data-stop ||
+   !(host-data_status  SDMMC_INT_DRTO) ||
+   !(host-data_status  SDMMC_INT_EBE))
+   send_stop_abort(host, data);
state = STATE_DATA_ERROR;
break;
}
@@ -1547,7 +1550,10 @@ static void dw_mci_tasklet_func(unsigned long priv)
if (test_and_clear_bit(EVENT_DATA_ERROR,
   host-pending_events)) {
dw_mci_stop_dma(host);
-   send_stop_abort(host, data);
+   if (data-stop ||
+   !(host-data_status  SDMMC_INT_DRTO) ||
+   !(host-data_status  SDMMC_INT_EBE))
+   send_stop_abort(host, data);
state = STATE_DATA_ERROR;
break;
}
-- 
1.8.3.2


--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v5] mmc: dw_mmc: add quirk for broken data transfer over scheme

2015-01-05 Thread Addy Ke
This patch add a new quirk to add a s/w timer to notify the driver
to terminate current transfer and report a data timeout to the core,
if DTO interrupt does NOT come within the given time.

dw_mmc call mmc_request_done func to finish transfer depends on
DTO interrupt. If DTO interrupt does not come in sending data state,
the current transfer will be blocked.

We got the reply from synopsys:
There are two counters but both use the same value of [31:8] bits.
Data timeout counter doesn't wait for stop clock and you should get
DRTO even when the clock is not stopped.
Host Starvation timeout counter is triggered with stop clock condition.

This means that host should get DRTO and DTO interrupt.

But this case really exists, when driver reads tuning data from
card on RK3288-pink2 board. I measured waveforms by oscilloscope
and found that card clock was always on and data lines were always
holded high level in sending data state.

There are two possibility that data over interrupt doesn't come in
reading data state on RK3X SoCs:
- get command done interrupt, but doesn't get any data-related interrupt.
- get data error interrupt, but doesn't get data over interrupt.

We don't know why we have this problem, but we need it to fix this problem now.
And I will post a follow up change when we find the root cause.

Signed-off-by: Addy Ke addy...@rock-chips.com
---
Changes in v2:
- fix some typo.
- remove extra timeout value (250ms).
- remove dw_mci_dto_start_monitor func.
- use broken-dto for new quirk and change Subject for it.

Changes in v3:
- Remove dts for broken-dto, just add this quirk in dw_mci_rockchip_init

Changes in v4:
- fix bug that may cause 32 bit overflow by (drto_clks * 1000).
- doesn't call mod_timer in writing data state, becase TMOUT register only
  for reading data.

Changes in v5:
- fix some typo.
- add a buffer for drto_ms.
- move drto_ms related code to a helper function.

 drivers/mmc/host/dw_mmc-rockchip.c |  3 ++
 drivers/mmc/host/dw_mmc.c  | 71 --
 include/linux/mmc/dw_mmc.h |  5 +++
 3 files changed, 77 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc-rockchip.c 
b/drivers/mmc/host/dw_mmc-rockchip.c
index 5650ac4..ba92ebd 100644
--- a/drivers/mmc/host/dw_mmc-rockchip.c
+++ b/drivers/mmc/host/dw_mmc-rockchip.c
@@ -73,6 +73,9 @@ static int dw_mci_rockchip_init(struct dw_mci *host)
/* It is slot 8 on Rockchip SoCs */
host-sdio_id0 = 8;
 
+   /* It needs this quirk on all Rockchip SoCs */
+   host-pdata-quirks |= DW_MCI_QUIRK_BROKEN_DTO;
+
return 0;
 }
 
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 6e4d864..ace4b40 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1468,6 +1468,20 @@ static int dw_mci_data_complete(struct dw_mci *host, 
struct mmc_data *data)
return data-error;
 }
 
+static unsigned int dw_mci_get_drto_ms(struct dw_mci *host)
+{
+   unsigned int drto_clks;
+   unsigned int drto_ms;
+
+   drto_clks = mci_readl(host, TMOUT)  8;
+   drto_ms = DIV_ROUND_UP(drto_clks, host-bus_hz / 1000);
+
+   /* add a buffer */
+   drto_ms += 10;
+
+   return drto_ms;
+}
+
 static void dw_mci_tasklet_func(unsigned long priv)
 {
struct dw_mci *host = (struct dw_mci *)priv;
@@ -1477,6 +1491,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
enum dw_mci_state state;
enum dw_mci_state prev_state;
unsigned int err;
+   unsigned int drto_ms;
 
spin_lock(host-lock);
 
@@ -1542,8 +1557,19 @@ static void dw_mci_tasklet_func(unsigned long priv)
}
 
if (!test_and_clear_bit(EVENT_XFER_COMPLETE,
-   host-pending_events))
+   host-pending_events)) {
+   /*
+* If all data-related interrupts don't come
+* within the given time in reading data state.
+*/
+   if ((host-quirks  DW_MCI_QUIRK_BROKEN_DTO) 
+   (host-dir_status == DW_MCI_RECV_STATUS)) {
+   drto_ms = dw_mci_get_drto_ms(host);
+   mod_timer(host-dto_timer, jiffies +
+ msecs_to_jiffies(drto_ms));
+   }
break;
+   }
 
set_bit(EVENT_XFER_COMPLETE, host-completed_events);
 
@@ -1573,8 +1599,20 @@ static void dw_mci_tasklet_func(unsigned long priv)
 
case STATE_DATA_BUSY:
if (!test_and_clear_bit(EVENT_DATA_COMPLETE,
-   host-pending_events))
+   host

[PATCH v4] mmc: dw_mmc: add quirk for broken data transfer over scheme

2014-12-26 Thread Addy Ke
This patch add a new quirk to add a s/w timer to notify the driver
to terminate current transfer and report a data timeout to the core,
if DTO interrupt does NOT come within the given time.

dw_mmc call mmc_request_done func to finish transfer depends on
DTO interrupt. If DTO interrupt does not come in sending data state,
the current transfer will be blocked.

We got the reply from synopsys:
There are two counters but both use the same value of [31:8] bits.
Data timeout counter doesn't wait for stop clock and you should get
DRTO even when the clock is not stopped.
Host Starvation timeout counter is triggered with stop clock condition.

This means that host should get DRTO and DTO interrupt.

But this case really exists, when driver reads tuning data from
card on RK3288-pink2 board. I measured waveforms by oscilloscope
and found that card clock was always on and data lines were always
holded high level in sending data state.

There are two possibility that data over interrupt doesn't come in
reading data state on RK3X SoCs:
- get command done interrupt, but doesn't get any data-related interrupt.
- get data error interrupt, but doesn't get data over interrupt.

We don't know why we have this problem, but we need it to fix this problem now.
And I will post a follow up change when we find the root cause.

Signed-off-by: Addy Ke addy...@rock-chips.com
---
Changes in v2:
- fix some typo.
- remove extra timeout value (250ms).
- remove dw_mci_dto_start_monitor func.
- use broken-dto for new quirk and change Subject for it.

Changes in v3:
- Remove dts for broken-dto, just add this quirk in dw_mci_rockchip_init

Changes in v4:
- fix bug that may cause 32 bit overflow by (drto_clks * 1000).
- doesn't call mod_timer in writing data state, becase TMOUT register only
  for reading data.

 drivers/mmc/host/dw_mmc-rockchip.c |  3 ++
 drivers/mmc/host/dw_mmc.c  | 64 --
 include/linux/mmc/dw_mmc.h |  5 +++
 3 files changed, 70 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc-rockchip.c 
b/drivers/mmc/host/dw_mmc-rockchip.c
index 5650ac4..ba92ebd 100644
--- a/drivers/mmc/host/dw_mmc-rockchip.c
+++ b/drivers/mmc/host/dw_mmc-rockchip.c
@@ -73,6 +73,9 @@ static int dw_mci_rockchip_init(struct dw_mci *host)
/* It is slot 8 on Rockchip SoCs */
host-sdio_id0 = 8;
 
+   /* It needs this quirk on all Rockchip SoCs */
+   host-pdata-quirks |= DW_MCI_QUIRK_BROKEN_DTO;
+
return 0;
 }
 
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 6e4d864..385dc0f 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1477,6 +1477,8 @@ static void dw_mci_tasklet_func(unsigned long priv)
enum dw_mci_state state;
enum dw_mci_state prev_state;
unsigned int err;
+   unsigned int drto_clks;
+   unsigned int drto_ms;
 
spin_lock(host-lock);
 
@@ -1542,8 +1544,22 @@ static void dw_mci_tasklet_func(unsigned long priv)
}
 
if (!test_and_clear_bit(EVENT_XFER_COMPLETE,
-   host-pending_events))
+   host-pending_events)) {
+   drto_clks = mci_readl(host, TMOUT)  8;
+   drto_ms = DIV_ROUND_UP(drto_clks,
+  host-bus_hz / 1000);
+
+   /*
+* If all data-related interrupts don't come
+* within the given time in reading data state.
+* */
+   if ((host-quirks  DW_MCI_QUIRK_BROKEN_DTO) 
+   (host-dir_status == DW_MCI_RECV_STATUS)) {
+   mod_timer(host-dto_timer, jiffies +
+ msecs_to_jiffies(drto_ms));
+   }
break;
+   }
 
set_bit(EVENT_XFER_COMPLETE, host-completed_events);
 
@@ -1573,8 +1589,22 @@ static void dw_mci_tasklet_func(unsigned long priv)
 
case STATE_DATA_BUSY:
if (!test_and_clear_bit(EVENT_DATA_COMPLETE,
-   host-pending_events))
+   host-pending_events)) {
+   drto_clks = mci_readl(host, TMOUT)  8;
+   drto_ms = DIV_ROUND_UP(drto_clks,
+  host-bus_hz / 1000);
+   /*
+* If data error interrupt comes but data over
+* interrupt doesn't come within the given time.
+* in reading data state

[PATCH] ARM: dts: rockchip: set dw_mmc max-freq 150Mhz

2014-12-03 Thread Addy Ke
All of mmc controllers include SDMMC, SDIO0, SDIO1, and EMMC on RK3288
are limited to 150Mhz. It was mainly caused by two reasons:
- RK3288's IO pad(except DDR IO pad) is generic, which can only support
  the max of 150Mhz.
- Mmc controller was designed at 150Mhz, and the pressure test by IC team
  was based on this freequency point.

Signed-off-by: Addy Ke addy...@rock-chips.com
---
 arch/arm/boot/dts/rk3288.dtsi | 4 
 1 file changed, 4 insertions(+)

diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
index acb6a2f..9c35a1d 100644
--- a/arch/arm/boot/dts/rk3288.dtsi
+++ b/arch/arm/boot/dts/rk3288.dtsi
@@ -149,6 +149,7 @@
 
sdmmc: dwmmc@ff0c {
compatible = rockchip,rk3288-dw-mshc;
+   clock-freq-min-max = 40 15000;
clocks = cru HCLK_SDMMC, cru SCLK_SDMMC;
clock-names = biu, ciu;
fifo-depth = 0x100;
@@ -159,6 +160,7 @@
 
sdio0: dwmmc@ff0d {
compatible = rockchip,rk3288-dw-mshc;
+   clock-freq-min-max = 40 15000;
clocks = cru HCLK_SDIO0, cru SCLK_SDIO0;
clock-names = biu, ciu;
fifo-depth = 0x100;
@@ -169,6 +171,7 @@
 
sdio1: dwmmc@ff0e {
compatible = rockchip,rk3288-dw-mshc;
+   clock-freq-min-max = 40 15000;
clocks = cru HCLK_SDIO1, cru SCLK_SDIO1;
clock-names = biu, ciu;
fifo-depth = 0x100;
@@ -179,6 +182,7 @@
 
emmc: dwmmc@ff0f {
compatible = rockchip,rk3288-dw-mshc;
+   clock-freq-min-max = 40 15000;
clocks = cru HCLK_EMMC, cru SCLK_EMMC;
clock-names = biu, ciu;
fifo-depth = 0x100;
-- 
1.8.3.2


--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3] mmc: dw_mmc: add quirk for broken data transfer over scheme

2014-12-02 Thread Addy Ke
This patch add a new quirk to add a s/w timer to notify the driver
to terminate current transfer and report a data timeout to the core,
if DTO interrupt does NOT come within the given time.

dw_mmc call mmc_request_done func to finish transfer depends on
DTO interrupt. If DTO interrupt does not come in sending data state,
the current transfer will be blocked.

But this case really exists, when driver reads tuning data from
card on RK3288-pink2 board. I measured waveforms by oscilloscope
and found that card clock was always on and data lines were always
holded high level in sending data state.

We got the reply from synopsys:
There are two counters but both use the same value of [31:8] bits.
Data timeout counter doesn't wait for stop clock and you should get
DRTO even when the clock is not stopped.
Host Starvation timeout counter is triggered with stop clock condition.

This means that host should get DRTO and DTO interrupt.

But we really don't get any data-related interrupt in RK3X SoCs.
And driver can't get data transfer state, it can do nothing but wait for.

We don't know why we have this problem, but we need it to fix this problem now.
And I will post a follow up change when we find the root cause.

Signed-off-by: Addy Ke addy...@rock-chips.com
---
Changes in v2:
- fix some typo.
- remove extra timeout value (250ms).
- remove dw_mci_dto_start_monitor func.
- use broken-dto for new quirk and change Subject for it.

Changes in v3:
- Remove dts for broken-dto, just add this quirk in dw_mci_rockchip_init

 drivers/mmc/host/dw_mmc-rockchip.c |  3 +++
 drivers/mmc/host/dw_mmc.c  | 41 +-
 include/linux/mmc/dw_mmc.h |  5 +
 3 files changed, 48 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/dw_mmc-rockchip.c 
b/drivers/mmc/host/dw_mmc-rockchip.c
index 5650ac4..ba92ebd 100644
--- a/drivers/mmc/host/dw_mmc-rockchip.c
+++ b/drivers/mmc/host/dw_mmc-rockchip.c
@@ -73,6 +73,9 @@ static int dw_mci_rockchip_init(struct dw_mci *host)
/* It is slot 8 on Rockchip SoCs */
host-sdio_id0 = 8;
 
+   /* It needs this quirk on all Rockchip SoCs */
+   host-pdata-quirks |= DW_MCI_QUIRK_BROKEN_DTO;
+
return 0;
 }
 
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 67c0451..e222122 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1464,6 +1464,8 @@ static void dw_mci_tasklet_func(unsigned long priv)
enum dw_mci_state state;
enum dw_mci_state prev_state;
unsigned int err;
+   unsigned int drto_clks;
+   unsigned int drto_ms;
 
spin_lock(host-lock);
 
@@ -1529,8 +1531,17 @@ static void dw_mci_tasklet_func(unsigned long priv)
}
 
if (!test_and_clear_bit(EVENT_XFER_COMPLETE,
-   host-pending_events))
+   host-pending_events)) {
+   if (host-quirks  DW_MCI_QUIRK_BROKEN_DTO) {
+   drto_clks = mci_readl(host, TMOUT)  8;
+   drto_ms = DIV_ROUND_UP(drto_clks * 1000,
+  host-bus_hz);
+
+   mod_timer(host-dto_timer, jiffies +
+   msecs_to_jiffies(drto_ms));
+   }
break;
+   }
 
set_bit(EVENT_XFER_COMPLETE, host-completed_events);
 
@@ -2122,6 +2133,9 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
}
 
if (pending  SDMMC_INT_DATA_OVER) {
+   if (host-quirks  DW_MCI_QUIRK_BROKEN_DTO)
+   del_timer(host-dto_timer);
+
mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER);
if (!host-data_status)
host-data_status = pending;
@@ -2509,6 +2523,28 @@ ciu_out:
return ret;
 }
 
+static void dw_mci_dto_timer(unsigned long arg)
+{
+   struct dw_mci *host = (struct dw_mci *)arg;
+
+   switch (host-state) {
+   case STATE_SENDING_DATA:
+   case STATE_DATA_BUSY:
+   /*
+   * If DTO interrupt does NOT come in sending data state,
+   * we should notify the driver to terminate current transfer
+   * and report a data timeout to the core.
+   */
+   host-data_status = SDMMC_INT_DRTO;
+   set_bit(EVENT_DATA_ERROR, host-pending_events);
+   set_bit(EVENT_DATA_COMPLETE, host-pending_events);
+   tasklet_schedule(host-tasklet);
+   break;
+   default:
+   break;
+   }
+}
+
 #ifdef CONFIG_OF
 static struct dw_mci_of_quirks {
char *quirk;
@@ -2661,6 +2697,9 @@ int dw_mci_probe

Re: [PATCH v2] mmc: dw_mmc: add quirk for broken data transfer over scheme

2014-12-01 Thread addy ke
Hi,
On 2014/11/27 06:46, Doug Anderson wrote:
 Hi,
 
 On Tue, Nov 25, 2014 at 12:10 AM, Addy Ke addy...@rock-chips.com wrote:
 This patch add a new quirk to add a s/w timer to notify the driver
 to terminate current transfer and report a data timeout to the core,
 if DTO interrupt does NOT come within the given time.

 dw_mmc call mmc_request_done func to finish transfer depends on
 DTO interrupt. If DTO interrupt does not come in sending data state,
 the current transfer will be blocked.

 But this case really exists, when driver reads tuning data from
 card on RK3288-pink2 board. I measured waveforms by oscilloscope
 and found that card clock was always on and data lines were always
 holded high level in sending data state.

 We got the reply from synopsys:
 There are two counters but both use the same value of [31:8] bits.
 Data timeout counter doesn't wait for stop clock and you should get
 DRTO even when the clock is not stopped.
 Host Starvation timeout counter is triggered with stop clock condition.

 This means that host should get DRTO and DTO interrupt.

 But we really don't get any data-related interrupt in RK3X SoCs.
 And driver can't get data transfer state, it can do nothing but wait for.
 
 Have you asked someone on your IC team to confirm this is an SoC
 errata on your SoC?  ...or is there something else we could be doing
 wrong (overclocking?  jitter in the clock?  bad dividers?) that could
 be causing this problem?
 
 
  #ifdef CONFIG_OF
  static struct dw_mci_of_quirks {
 char *quirk;
 @@ -2513,6 +2549,9 @@ static struct dw_mci_of_quirks {
 }, {
 .quirk  = disable-wp,
 .id = DW_MCI_QUIRK_NO_WRITE_PROTECT,
 +   }, {
 +   .quirk  = broken-dto,
 +   .id = DW_MCI_QUIRK_BROKEN_DTO,
 
 You're adding a device tree property without any binding.  If you need
 to add this please send a patch before this one modifying the device
 tree bindings.
 
 ...but that brings up the question: do you _really_ need to add a
 property?  You already know that all rk3288 SoCs need this and you
 already know that you're an rk3288 SoC.  Just add this quirk in the
 rk3288 code always and be done with it.  ...and if this is also needed
 on other Rockchip parts, add it there too.
 
 -Doug

We don't know why we have this problem,
but this problem is really exist, and we need patch to fix this problem now.
I will post a follow up change when we find the root cause.

And there is a little probability of this problem on RK SoC, such as RK3188, 
RK3066,
when worse card inserted in.
Maybe the other SoCs have the similar problem.

So I will add this quirk in rockchip code(dw_mmc-rockchip.c) as follows:
static int dw_mci_rockchip_parse_dt(struct dw_mci *host)
{
host-quirk |= DW_MCI_QUIRK_BROKEN_DTO;

return 0;
}

..
.parse_dt = dw_mci_rockchip_parse_dt,
..

is right?

 
 
 

--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2] mmc: dw_mmc: add quirk for broken data transfer over scheme

2014-11-25 Thread Addy Ke
This patch add a new quirk to add a s/w timer to notify the driver
to terminate current transfer and report a data timeout to the core,
if DTO interrupt does NOT come within the given time.

dw_mmc call mmc_request_done func to finish transfer depends on
DTO interrupt. If DTO interrupt does not come in sending data state,
the current transfer will be blocked.

But this case really exists, when driver reads tuning data from
card on RK3288-pink2 board. I measured waveforms by oscilloscope
and found that card clock was always on and data lines were always
holded high level in sending data state.

We got the reply from synopsys:
There are two counters but both use the same value of [31:8] bits.
Data timeout counter doesn't wait for stop clock and you should get
DRTO even when the clock is not stopped.
Host Starvation timeout counter is triggered with stop clock condition.

This means that host should get DRTO and DTO interrupt.

But we really don't get any data-related interrupt in RK3X SoCs.
And driver can't get data transfer state, it can do nothing but wait for.

Signed-off-by: Addy Ke addy...@rock-chips.com
---
- fix some typo.
- remove extra timeout value (250ms).
- remove dw_mci_dto_start_monitor func.
- use broken-dto for new quirk and change Subject for it.

 drivers/mmc/host/dw_mmc.c  | 44 +++-
 include/linux/mmc/dw_mmc.h |  5 +
 2 files changed, 48 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index b4c3044..bc09f50 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1457,6 +1457,8 @@ static void dw_mci_tasklet_func(unsigned long priv)
enum dw_mci_state state;
enum dw_mci_state prev_state;
unsigned int err;
+   unsigned int drto_clks;
+   unsigned int drto_ms;
 
spin_lock(host-lock);
 
@@ -1522,8 +1524,17 @@ static void dw_mci_tasklet_func(unsigned long priv)
}
 
if (!test_and_clear_bit(EVENT_XFER_COMPLETE,
-   host-pending_events))
+   host-pending_events)) {
+   if (host-quirks  DW_MCI_QUIRK_BROKEN_DTO) {
+   drto_clks = mci_readl(host, TMOUT)  8;
+   drto_ms = DIV_ROUND_UP(drto_clks * 1000,
+  host-bus_hz);
+
+   mod_timer(host-dto_timer, jiffies +
+   msecs_to_jiffies(drto_ms));
+   }
break;
+   }
 
set_bit(EVENT_XFER_COMPLETE, host-completed_events);
 
@@ -2115,6 +2126,9 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
}
 
if (pending  SDMMC_INT_DATA_OVER) {
+   if (host-quirks  DW_MCI_QUIRK_BROKEN_DTO)
+   del_timer(host-dto_timer);
+
mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER);
if (!host-data_status)
host-data_status = pending;
@@ -2502,6 +2516,28 @@ ciu_out:
return ret;
 }
 
+static void dw_mci_dto_timer(unsigned long arg)
+{
+   struct dw_mci *host = (struct dw_mci *)arg;
+
+   switch (host-state) {
+   case STATE_SENDING_DATA:
+   case STATE_DATA_BUSY:
+   /*
+   * If DTO interrupt does NOT come in sending data state,
+   * we should notify the driver to terminate current transfer
+   * and report a data timeout to the core.
+   */
+   host-data_status = SDMMC_INT_DRTO;
+   set_bit(EVENT_DATA_ERROR, host-pending_events);
+   set_bit(EVENT_DATA_COMPLETE, host-pending_events);
+   tasklet_schedule(host-tasklet);
+   break;
+   default:
+   break;
+   }
+}
+
 #ifdef CONFIG_OF
 static struct dw_mci_of_quirks {
char *quirk;
@@ -2513,6 +2549,9 @@ static struct dw_mci_of_quirks {
}, {
.quirk  = disable-wp,
.id = DW_MCI_QUIRK_NO_WRITE_PROTECT,
+   }, {
+   .quirk  = broken-dto,
+   .id = DW_MCI_QUIRK_BROKEN_DTO,
},
 };
 
@@ -2654,6 +2693,9 @@ int dw_mci_probe(struct dw_mci *host)
 
spin_lock_init(host-lock);
INIT_LIST_HEAD(host-queue);
+   if (host-quirks  DW_MCI_QUIRK_BROKEN_DTO)
+   setup_timer(host-dto_timer,
+   dw_mci_dto_timer, (unsigned long)host);
 
/*
 * Get the host data width - this assumes that HCON has been set with
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index 42b724e..ff9bd1e 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux

Re: [PATCH] mmc: dw_mmc: try pick the exact same voltage as vmmc for vqmmc

2014-11-24 Thread Addy


On Fri, Nov 24, 2014 at 9:29 PM, Ulf Hansson ulf.hans...@linaro.org 
wrote:



On 21 November 2014 at 22:04, Doug Anderson diand...@chromium.org wrote:

Hi,

On Fri, Nov 21, 2014 at 9:42 AM, Doug Anderson diand...@chromium.org wrote:

Ulf,

On Fri, Nov 21, 2014 at 4:06 AM, Ulf Hansson ulf.hans...@linaro.org wrote:

[...]


Sure
If the first card is sd2.0 since startup, dw_mci_switch_voltage will not be 
called,

That can't be right. mmc_power_up() should trigger
dw_mci_switch_voltage() to be invoked.

Hmmm, I think you're right.  Addy: can you double check if it's only
the 2nd card for you?  I was thinking that if a regulator is currently
3.3V and you request 2.7 - 3.3V the regulator framework will treat
that as a noop.  ...but that definitely doesn't appear to be the case.
When I boot up the first time even with no SD card plugged in, I see
this at bootup:

[3.042234] vccio_sd: 1800 -- 3300 mV at 3300 mV

...showing that it started at 3.3V.  Then I see:

$ grep  /sys/class/regulator/regulator.16/{name,microvolts}
/sys/class/regulator/regulator.16/name:vccio_sd
/sys/class/regulator/regulator.16/microvolts:270

...so it is certainly getting changed even with no card plugged in.


BTW: I don't actually have one of these failing cards--all of mine
work.  Addy, do you know the make and model of the card you have that
fails?

Just as a bit of a followup, I did some more digging...

1. It looks as if we now have a bit of opposite logic for vmmc vs.
vqmmc.  In mmc_power_up() I see that it sets the initial voltage as:

   host-ios.vdd = fls(ocr) - 1;

That's because we would like to supports as many cards as possible.
The policy is based upon that some cards may not support lower
voltages, but most will support higher.


That actually means that we're going to pick the maximum voltage for
vmmc (of the supported voltages).  For vqmmc dw_mmc is using the
regulator framework which (as described in my previous message) will
pick the minimum.

Correct. I have thought this has been inside spec and choosing the
lower value would be preferred to lower power consumption. Maybe we
needs to re-visit this one more time.

Here are some of the interesting sections in the eMMC spec:
10.3.3 Power supply Voltages
The VCCQ must be defined at equal to or less than VCC.

10.5 Bus signal levels
Push-pull mode:
Voh = 0.75 * VCCQ. (Do note, its VCCQ not VCC).

Summary eMMC: VCCQ must be less and VCC, we should be inside spec.

From SD spec:
6.6.1 Threshold Level for High Voltage Range
Voh = 0.75 * VDD.

In worst case scenario, VDD = 3.6V and VIO = 2.7V. That gives as the
factor of 0.75, thus we are inside spec but without margins.

* From eMMC4.5 spec:
  1. (VDDF)vcc: Supply voltage for flash memory,  which is  2.7v -- 3.3v
  2. (VDD)vccq: Supply voltage for memory controller, which is  1.7v -- 
1.95v  and 2,7v -- 3.6v


* And from RK3288 datasheet:
  Digtial GPIO Power(SDMMC0_VDD -- vccq) is 3.0v -- 3.6v and 1.62v - 1.98v

So I think:
3.3v:  (2.7v  vccq  3.6v) (3.0v  vccq  3.6v)  == (3.0v  vccq 
 3.6v)
1.8v:  (1.7v  vccq  1.95v)   (1.62v  vccq  1.98v) == (1.7v  vccq 
 1.95v)


and (2.7v  vcc  3.3v)

* And according to our hardware engineer:
  All of supply voltage must have +/- 10% cushion.

* And we have found in some worse card that there is 200mv voltage 
collapse when these card is insert.


So I think the best resolution is that vcc and vccq is configurable int 
dt table.



2. Several people I've talked to have expressed concerns that our
minimum value is 2.7V.  Apparently that's really on the edge and makes
EEs a little nervous.  The quick sample of cards sitting on my desk
shows that they seem to claim 0x00ff8000, which doesn't include 2.7V.

0x00ff8000 states what values of VDD levels the device supports. Not VIO.



Both of the above make me feel like dw_mmc should try its best to pick
a value for vqmmc that is closest to the value of vmmc (and = 2.7V).
That also happens to make us work exactly like hosts where vmmc and
vqmmc are supplied by the same supply.

I do see your point. And I agree that it would be nice to achieve
something like this.

The question is how to do this. For sure, we need to involve the mmc
core to handle this correctly.

Kind regards
Uffe






--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH] mmc: dw_mmc: add quirk for data over interrupt timeout

2014-11-24 Thread Addy

Hi, Jaehoon

On 2014/11/20 18:01, Jaehoon Chung wrote:

Hi, Addy.

On 11/20/2014 06:33 PM, addy ke wrote:

Hi, Jaehoon

On 2014/11/19 13:56, addy ke wrote:

Hi Jaehoon

On 2014/11/19 09:22, Jaehoon Chung Wrote:

Hi, Addy.

On 11/18/2014 09:32 AM, Addy wrote:

On 2014年11月14日 21:18, Jaehoon Chung wrote:

Hi, Addy.

Did you use the DW_MCI_QUIRK_IDMAC_DTO?
I'm not sure, but i wonder if you get what result when you use above quirk.

DW_MCI_QUIRK_IDMAC_DTO is only for version2.0 or below.
 /*
  * DTO fix - version 2.10a and below, and only if internal DMA
  * is configured.
  */
 if (host-quirks  DW_MCI_QUIRK_IDMAC_DTO) {
 if (!pending 
 ((mci_readl(host, STATUS)  17)  0x1fff))
 pending |= SDMMC_INT_DATA_OVER;
 }

It meams that if interrupt comes, but pending = 0  FIFO_COUNT(bit17-29) !=0,
then force to set SDMMC_INT_DATA_OVER.
But in our case, FIFO_COUNT = 0 (STATUS register value is 0xad06). This is
because that the card does not send data to host. So there is no interrupts 
come,
and interrupt handle function(dw_mci_interrupt) will not be called. So we need a
timer to handle this case.

So I think  SDMMC_INT_DATA_OVER is not suitable for this case, and we need a new
quirk.


And i will check more this patch at next week.

Thanks for your efforts.

Best Regards,
Jaehoon Chung

On 11/14/2014 10:05 PM, Addy Ke wrote:

From: Addy addy...@rock-chips.com

This patch add a new quirk to notify the driver to teminate
current transfer and report a data timeout to the core,
if data over interrupt does NOT come within the given time.

dw_mmc call mmc_request_done func to finish transfer depends on
data over interrupt. If data over interrupt does not come in
sending data state, the current transfer will be blocked.

But this case really exists, when driver reads tuning data from
card on rk3288-pink2 board. I measured waveforms by oscilloscope
and found that card clock was always on and data lines were always
holded high level in sending data state. This is the cause that
card does NOT send data to host.

According to synopsys designware databook, the timeout counter is
started only after the card clock is stopped.

So if card clock is always on, data read timeout interrupt will NOT come,
and if data lines are always holded high level, all data-related
interrupt such as start-bit error, data crc error, data over interrupt,
end-bit error, and so on, will NOT come too.

So driver can't get the current state, it can do nothing but wait for.

This patch is based on https://patchwork.kernel.org/patch/5227941/

Signed-off-by: Addy addy...@rock-chips.com
---
   drivers/mmc/host/dw_mmc.c  | 47 
+-
   include/linux/mmc/dw_mmc.h |  5 +
   2 files changed, 51 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index b4c3044..3960fc3 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1448,6 +1448,17 @@ static int dw_mci_data_complete(struct dw_mci *host, 
struct mmc_data *data)
   return data-error;
   }
   +static inline void dw_mci_dto_start_monitor(struct dw_mci *host)
+{
+unsigned int data_tmout_clks;
+unsigned int data_tmout_ms;
+
+data_tmout_clks = (mci_readl(host, TMOUT)  8);
+data_tmout_ms = (data_tmout_clks * 1000 / host-bus_hz) + 250;

What's 250? And how about using the DIV_ROUND_UP?


250ms is only for more timeout.
maybe data timeout read from TMOUT register is enough.
So, I will remove 250.
new code:
data_tmout_clks = (mci_readl(host, TMOUT)  8);
data_tmout_ms = DIV_ROUND_UP(data_tmout_clks * 100, host-bus_hz);
Is right?


+
+mod_timer(host-dto_timer, jiffies + msecs_to_jiffies(data_tmout_ms));
+}
+
   static void dw_mci_tasklet_func(unsigned long priv)
   {
   struct dw_mci *host = (struct dw_mci *)priv;
@@ -1522,8 +1533,11 @@ static void dw_mci_tasklet_func(unsigned long priv)
   }
 if (!test_and_clear_bit(EVENT_XFER_COMPLETE,
-host-pending_events))
+host-pending_events)) {
+if (host-quirks  DW_MCI_QUIRK_DTO_TIMER)
+dw_mci_dto_start_monitor(host);

if timer is starting at only here, dw_mci_dto_start_monitor() doesn't need.


Ok, I will change it in the next patch.

   break;
+}
 set_bit(EVENT_XFER_COMPLETE, host-completed_events);
   @@ -2115,6 +2129,9 @@ static irqreturn_t dw_mci_interrupt(int irq, void 
*dev_id)
   }
 if (pending  SDMMC_INT_DATA_OVER) {
+if (host-quirks  DW_MCI_QUIRK_DTO_TIMER)
+del_timer(host-dto_timer);
+
   mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER);
   if (!host-data_status)
   host-data_status = pending;
@@ -2502,6 +2519,28 @@ ciu_out:
   return ret;
   }
   +static void dw_mci_dto_timer(unsigned

Re: [PATCH] mmc: dw_mmc: add quirk for data over interrupt timeout

2014-11-20 Thread addy ke
Hi, Jaehoon

On 2014/11/19 13:56, addy ke wrote:
 Hi Jaehoon
 
 On 2014/11/19 09:22, Jaehoon Chung Wrote:
 Hi, Addy.

 On 11/18/2014 09:32 AM, Addy wrote:

 On 2014年11月14日 21:18, Jaehoon Chung wrote:
 Hi, Addy.

 Did you use the DW_MCI_QUIRK_IDMAC_DTO?
 I'm not sure, but i wonder if you get what result when you use above quirk.

 DW_MCI_QUIRK_IDMAC_DTO is only for version2.0 or below.
 /*
  * DTO fix - version 2.10a and below, and only if internal DMA
  * is configured.
  */
 if (host-quirks  DW_MCI_QUIRK_IDMAC_DTO) {
 if (!pending 
 ((mci_readl(host, STATUS)  17)  0x1fff))
 pending |= SDMMC_INT_DATA_OVER;
 }

 It meams that if interrupt comes, but pending = 0  FIFO_COUNT(bit17-29) 
 !=0,
 then force to set SDMMC_INT_DATA_OVER.
 But in our case, FIFO_COUNT = 0 (STATUS register value is 0xad06). This is
 because that the card does not send data to host. So there is no interrupts 
 come,
 and interrupt handle function(dw_mci_interrupt) will not be called. So we 
 need a
 timer to handle this case.

 So I think  SDMMC_INT_DATA_OVER is not suitable for this case, and we need 
 a new
 quirk.


 And i will check more this patch at next week.

 Thanks for your efforts.

 Best Regards,
 Jaehoon Chung

 On 11/14/2014 10:05 PM, Addy Ke wrote:
 From: Addy addy...@rock-chips.com

 This patch add a new quirk to notify the driver to teminate
 current transfer and report a data timeout to the core,
 if data over interrupt does NOT come within the given time.

 dw_mmc call mmc_request_done func to finish transfer depends on
 data over interrupt. If data over interrupt does not come in
 sending data state, the current transfer will be blocked.

 But this case really exists, when driver reads tuning data from
 card on rk3288-pink2 board. I measured waveforms by oscilloscope
 and found that card clock was always on and data lines were always
 holded high level in sending data state. This is the cause that
 card does NOT send data to host.

 According to synopsys designware databook, the timeout counter is
 started only after the card clock is stopped.

 So if card clock is always on, data read timeout interrupt will NOT come,
 and if data lines are always holded high level, all data-related
 interrupt such as start-bit error, data crc error, data over interrupt,
 end-bit error, and so on, will NOT come too.

 So driver can't get the current state, it can do nothing but wait for.

 This patch is based on https://patchwork.kernel.org/patch/5227941/

 Signed-off-by: Addy addy...@rock-chips.com
 ---
   drivers/mmc/host/dw_mmc.c  | 47 
 +-
   include/linux/mmc/dw_mmc.h |  5 +
   2 files changed, 51 insertions(+), 1 deletion(-)

 diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
 index b4c3044..3960fc3 100644
 --- a/drivers/mmc/host/dw_mmc.c
 +++ b/drivers/mmc/host/dw_mmc.c
 @@ -1448,6 +1448,17 @@ static int dw_mci_data_complete(struct dw_mci 
 *host, struct mmc_data *data)
   return data-error;
   }
   +static inline void dw_mci_dto_start_monitor(struct dw_mci *host)
 +{
 +unsigned int data_tmout_clks;
 +unsigned int data_tmout_ms;
 +
 +data_tmout_clks = (mci_readl(host, TMOUT)  8);
 +data_tmout_ms = (data_tmout_clks * 1000 / host-bus_hz) + 250;

 What's 250? And how about using the DIV_ROUND_UP? 

 250ms is only for more timeout.
 maybe data timeout read from TMOUT register is enough.
 So, I will remove 250.
 new code:
 data_tmout_clks = (mci_readl(host, TMOUT)  8);
 data_tmout_ms = DIV_ROUND_UP(data_tmout_clks * 100, host-bus_hz);
 Is right?
 
 +
 +mod_timer(host-dto_timer, jiffies + 
 msecs_to_jiffies(data_tmout_ms));
 +}
 +
   static void dw_mci_tasklet_func(unsigned long priv)
   {
   struct dw_mci *host = (struct dw_mci *)priv;
 @@ -1522,8 +1533,11 @@ static void dw_mci_tasklet_func(unsigned long priv)
   }
 if (!test_and_clear_bit(EVENT_XFER_COMPLETE,
 -host-pending_events))
 +host-pending_events)) {
 +if (host-quirks  DW_MCI_QUIRK_DTO_TIMER)
 +dw_mci_dto_start_monitor(host);

 if timer is starting at only here, dw_mci_dto_start_monitor() doesn't need.

 Ok, I will change it in the next patch.
   break;
 +}
 set_bit(EVENT_XFER_COMPLETE, host-completed_events);
   @@ -2115,6 +2129,9 @@ static irqreturn_t dw_mci_interrupt(int irq, void 
 *dev_id)
   }
 if (pending  SDMMC_INT_DATA_OVER) {
 +if (host-quirks  DW_MCI_QUIRK_DTO_TIMER)
 +del_timer(host-dto_timer);
 +
   mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER);
   if (!host-data_status)
   host-data_status = pending;
 @@ -2502,6 +2519,28 @@ ciu_out:
   return ret;
   }
   +static void dw_mci_dto_timer(unsigned long arg

Re: [PATCH] mmc: dw_mmc: add quirk for data over interrupt timeout

2014-11-18 Thread addy ke
Hi Jaehoon

On 2014/11/19 09:22, Jaehoon Chung Wrote:
 Hi, Addy.
 
 On 11/18/2014 09:32 AM, Addy wrote:

 On 2014年11月14日 21:18, Jaehoon Chung wrote:
 Hi, Addy.

 Did you use the DW_MCI_QUIRK_IDMAC_DTO?
 I'm not sure, but i wonder if you get what result when you use above quirk.

 DW_MCI_QUIRK_IDMAC_DTO is only for version2.0 or below.
 /*
  * DTO fix - version 2.10a and below, and only if internal DMA
  * is configured.
  */
 if (host-quirks  DW_MCI_QUIRK_IDMAC_DTO) {
 if (!pending 
 ((mci_readl(host, STATUS)  17)  0x1fff))
 pending |= SDMMC_INT_DATA_OVER;
 }

 It meams that if interrupt comes, but pending = 0  FIFO_COUNT(bit17-29) 
 !=0,
 then force to set SDMMC_INT_DATA_OVER.
 But in our case, FIFO_COUNT = 0 (STATUS register value is 0xad06). This is
 because that the card does not send data to host. So there is no interrupts 
 come,
 and interrupt handle function(dw_mci_interrupt) will not be called. So we 
 need a
 timer to handle this case.

 So I think  SDMMC_INT_DATA_OVER is not suitable for this case, and we need a 
 new
 quirk.


 And i will check more this patch at next week.

 Thanks for your efforts.

 Best Regards,
 Jaehoon Chung

 On 11/14/2014 10:05 PM, Addy Ke wrote:
 From: Addy addy...@rock-chips.com

 This patch add a new quirk to notify the driver to teminate
 current transfer and report a data timeout to the core,
 if data over interrupt does NOT come within the given time.

 dw_mmc call mmc_request_done func to finish transfer depends on
 data over interrupt. If data over interrupt does not come in
 sending data state, the current transfer will be blocked.

 But this case really exists, when driver reads tuning data from
 card on rk3288-pink2 board. I measured waveforms by oscilloscope
 and found that card clock was always on and data lines were always
 holded high level in sending data state. This is the cause that
 card does NOT send data to host.

 According to synopsys designware databook, the timeout counter is
 started only after the card clock is stopped.

 So if card clock is always on, data read timeout interrupt will NOT come,
 and if data lines are always holded high level, all data-related
 interrupt such as start-bit error, data crc error, data over interrupt,
 end-bit error, and so on, will NOT come too.

 So driver can't get the current state, it can do nothing but wait for.

 This patch is based on https://patchwork.kernel.org/patch/5227941/

 Signed-off-by: Addy addy...@rock-chips.com
 ---
   drivers/mmc/host/dw_mmc.c  | 47 
 +-
   include/linux/mmc/dw_mmc.h |  5 +
   2 files changed, 51 insertions(+), 1 deletion(-)

 diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
 index b4c3044..3960fc3 100644
 --- a/drivers/mmc/host/dw_mmc.c
 +++ b/drivers/mmc/host/dw_mmc.c
 @@ -1448,6 +1448,17 @@ static int dw_mci_data_complete(struct dw_mci 
 *host, struct mmc_data *data)
   return data-error;
   }
   +static inline void dw_mci_dto_start_monitor(struct dw_mci *host)
 +{
 +unsigned int data_tmout_clks;
 +unsigned int data_tmout_ms;
 +
 +data_tmout_clks = (mci_readl(host, TMOUT)  8);
 +data_tmout_ms = (data_tmout_clks * 1000 / host-bus_hz) + 250;
 
 What's 250? And how about using the DIV_ROUND_UP? 
 
250ms is only for more timeout.
maybe data timeout read from TMOUT register is enough.
So, I will remove 250.
new code:
data_tmout_clks = (mci_readl(host, TMOUT)  8);
data_tmout_ms = DIV_ROUND_UP(data_tmout_clks * 100, host-bus_hz);
Is right?

 +
 +mod_timer(host-dto_timer, jiffies + 
 msecs_to_jiffies(data_tmout_ms));
 +}
 +
   static void dw_mci_tasklet_func(unsigned long priv)
   {
   struct dw_mci *host = (struct dw_mci *)priv;
 @@ -1522,8 +1533,11 @@ static void dw_mci_tasklet_func(unsigned long priv)
   }
 if (!test_and_clear_bit(EVENT_XFER_COMPLETE,
 -host-pending_events))
 +host-pending_events)) {
 +if (host-quirks  DW_MCI_QUIRK_DTO_TIMER)
 +dw_mci_dto_start_monitor(host);
 
 if timer is starting at only here, dw_mci_dto_start_monitor() doesn't need.
 
Ok, I will change it in the next patch.
   break;
 +}
 set_bit(EVENT_XFER_COMPLETE, host-completed_events);
   @@ -2115,6 +2129,9 @@ static irqreturn_t dw_mci_interrupt(int irq, void 
 *dev_id)
   }
 if (pending  SDMMC_INT_DATA_OVER) {
 +if (host-quirks  DW_MCI_QUIRK_DTO_TIMER)
 +del_timer(host-dto_timer);
 +
   mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER);
   if (!host-data_status)
   host-data_status = pending;
 @@ -2502,6 +2519,28 @@ ciu_out:
   return ret;
   }
   +static void dw_mci_dto_timer(unsigned long arg)
 +{
 +struct dw_mci *host = (struct dw_mci *)arg;
 
 I prefer

Re: [PATCH] mmc: dw_mmc: add quirk for data over interrupt timeout

2014-11-17 Thread Addy


On 2014年11月14日 21:18, Jaehoon Chung wrote:

Hi, Addy.

Did you use the DW_MCI_QUIRK_IDMAC_DTO?
I'm not sure, but i wonder if you get what result when you use above quirk.


DW_MCI_QUIRK_IDMAC_DTO is only for version2.0 or below.
/*
 * DTO fix - version 2.10a and below, and only if internal DMA
 * is configured.
 */
if (host-quirks  DW_MCI_QUIRK_IDMAC_DTO) {
if (!pending 
((mci_readl(host, STATUS)  17)  0x1fff))
pending |= SDMMC_INT_DATA_OVER;
}

It meams that if interrupt comes, but pending = 0  FIFO_COUNT(bit17-29) !=0,
then force to set SDMMC_INT_DATA_OVER.
But in our case, FIFO_COUNT = 0 (STATUS register value is 0xad06). This is
because that the card does not send data to host. So there is no interrupts 
come,
and interrupt handle function(dw_mci_interrupt) will not be called. So we need a
timer to handle this case.

So I think  SDMMC_INT_DATA_OVER is not suitable for this case, and we need a new
quirk.



And i will check more this patch at next week.

Thanks for your efforts.

Best Regards,
Jaehoon Chung

On 11/14/2014 10:05 PM, Addy Ke wrote:

From: Addy addy...@rock-chips.com

This patch add a new quirk to notify the driver to teminate
current transfer and report a data timeout to the core,
if data over interrupt does NOT come within the given time.

dw_mmc call mmc_request_done func to finish transfer depends on
data over interrupt. If data over interrupt does not come in
sending data state, the current transfer will be blocked.

But this case really exists, when driver reads tuning data from
card on rk3288-pink2 board. I measured waveforms by oscilloscope
and found that card clock was always on and data lines were always
holded high level in sending data state. This is the cause that
card does NOT send data to host.

According to synopsys designware databook, the timeout counter is
started only after the card clock is stopped.

So if card clock is always on, data read timeout interrupt will NOT come,
and if data lines are always holded high level, all data-related
interrupt such as start-bit error, data crc error, data over interrupt,
end-bit error, and so on, will NOT come too.

So driver can't get the current state, it can do nothing but wait for.

This patch is based on https://patchwork.kernel.org/patch/5227941/

Signed-off-by: Addy addy...@rock-chips.com
---
  drivers/mmc/host/dw_mmc.c  | 47 +-
  include/linux/mmc/dw_mmc.h |  5 +
  2 files changed, 51 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index b4c3044..3960fc3 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1448,6 +1448,17 @@ static int dw_mci_data_complete(struct dw_mci *host, 
struct mmc_data *data)
return data-error;
  }
  
+static inline void dw_mci_dto_start_monitor(struct dw_mci *host)

+{
+   unsigned int data_tmout_clks;
+   unsigned int data_tmout_ms;
+
+   data_tmout_clks = (mci_readl(host, TMOUT)  8);
+   data_tmout_ms = (data_tmout_clks * 1000 / host-bus_hz) + 250;
+
+   mod_timer(host-dto_timer, jiffies + msecs_to_jiffies(data_tmout_ms));
+}
+
  static void dw_mci_tasklet_func(unsigned long priv)
  {
struct dw_mci *host = (struct dw_mci *)priv;
@@ -1522,8 +1533,11 @@ static void dw_mci_tasklet_func(unsigned long priv)
}
  
  			if (!test_and_clear_bit(EVENT_XFER_COMPLETE,

-   host-pending_events))
+   host-pending_events)) {
+   if (host-quirks  DW_MCI_QUIRK_DTO_TIMER)
+   dw_mci_dto_start_monitor(host);
break;
+   }
  
  			set_bit(EVENT_XFER_COMPLETE, host-completed_events);
  
@@ -2115,6 +2129,9 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)

}
  
  		if (pending  SDMMC_INT_DATA_OVER) {

+   if (host-quirks  DW_MCI_QUIRK_DTO_TIMER)
+   del_timer(host-dto_timer);
+
mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER);
if (!host-data_status)
host-data_status = pending;
@@ -2502,6 +2519,28 @@ ciu_out:
return ret;
  }
  
+static void dw_mci_dto_timer(unsigned long arg)

+{
+   struct dw_mci *host = (struct dw_mci *)arg;
+
+   switch (host-state) {
+   case STATE_SENDING_DATA:
+   case STATE_DATA_BUSY:
+   /*
+   * If data over interrupt does NOT come in sending data state,
+   * we should notify the driver to teminate current transfer
+   * and report a data timeout to the core.
+   */
+   host-data_status = SDMMC_INT_DRTO;
+   set_bit(EVENT_DATA_ERROR, host-pending_events

[PATCH] mmc: dw_mmc: add quirk for data over interrupt timeout

2014-11-14 Thread Addy Ke
From: Addy addy...@rock-chips.com

This patch add a new quirk to notify the driver to teminate
current transfer and report a data timeout to the core,
if data over interrupt does NOT come within the given time.

dw_mmc call mmc_request_done func to finish transfer depends on
data over interrupt. If data over interrupt does not come in
sending data state, the current transfer will be blocked.

But this case really exists, when driver reads tuning data from
card on rk3288-pink2 board. I measured waveforms by oscilloscope
and found that card clock was always on and data lines were always
holded high level in sending data state. This is the cause that
card does NOT send data to host.

According to synopsys designware databook, the timeout counter is
started only after the card clock is stopped.

So if card clock is always on, data read timeout interrupt will NOT come,
and if data lines are always holded high level, all data-related
interrupt such as start-bit error, data crc error, data over interrupt,
end-bit error, and so on, will NOT come too.

So driver can't get the current state, it can do nothing but wait for.

This patch is based on https://patchwork.kernel.org/patch/5227941/

Signed-off-by: Addy addy...@rock-chips.com
---
 drivers/mmc/host/dw_mmc.c  | 47 +-
 include/linux/mmc/dw_mmc.h |  5 +
 2 files changed, 51 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index b4c3044..3960fc3 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1448,6 +1448,17 @@ static int dw_mci_data_complete(struct dw_mci *host, 
struct mmc_data *data)
return data-error;
 }
 
+static inline void dw_mci_dto_start_monitor(struct dw_mci *host)
+{
+   unsigned int data_tmout_clks;
+   unsigned int data_tmout_ms;
+
+   data_tmout_clks = (mci_readl(host, TMOUT)  8);
+   data_tmout_ms = (data_tmout_clks * 1000 / host-bus_hz) + 250;
+
+   mod_timer(host-dto_timer, jiffies + msecs_to_jiffies(data_tmout_ms));
+}
+
 static void dw_mci_tasklet_func(unsigned long priv)
 {
struct dw_mci *host = (struct dw_mci *)priv;
@@ -1522,8 +1533,11 @@ static void dw_mci_tasklet_func(unsigned long priv)
}
 
if (!test_and_clear_bit(EVENT_XFER_COMPLETE,
-   host-pending_events))
+   host-pending_events)) {
+   if (host-quirks  DW_MCI_QUIRK_DTO_TIMER)
+   dw_mci_dto_start_monitor(host);
break;
+   }
 
set_bit(EVENT_XFER_COMPLETE, host-completed_events);
 
@@ -2115,6 +2129,9 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
}
 
if (pending  SDMMC_INT_DATA_OVER) {
+   if (host-quirks  DW_MCI_QUIRK_DTO_TIMER)
+   del_timer(host-dto_timer);
+
mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER);
if (!host-data_status)
host-data_status = pending;
@@ -2502,6 +2519,28 @@ ciu_out:
return ret;
 }
 
+static void dw_mci_dto_timer(unsigned long arg)
+{
+   struct dw_mci *host = (struct dw_mci *)arg;
+
+   switch (host-state) {
+   case STATE_SENDING_DATA:
+   case STATE_DATA_BUSY:
+   /*
+   * If data over interrupt does NOT come in sending data state,
+   * we should notify the driver to teminate current transfer
+   * and report a data timeout to the core.
+   */
+   host-data_status = SDMMC_INT_DRTO;
+   set_bit(EVENT_DATA_ERROR, host-pending_events);
+   set_bit(EVENT_DATA_COMPLETE, host-pending_events);
+   tasklet_schedule(host-tasklet);
+   break;
+   default:
+   break;
+   }
+}
+
 #ifdef CONFIG_OF
 static struct dw_mci_of_quirks {
char *quirk;
@@ -2513,6 +2552,9 @@ static struct dw_mci_of_quirks {
}, {
.quirk  = disable-wp,
.id = DW_MCI_QUIRK_NO_WRITE_PROTECT,
+   }, {
+   .quirk  = dto-timer,
+   .id = DW_MCI_QUIRK_DTO_TIMER,
},
 };
 
@@ -2654,6 +2696,9 @@ int dw_mci_probe(struct dw_mci *host)
 
spin_lock_init(host-lock);
INIT_LIST_HEAD(host-queue);
+   if (host-quirks  DW_MCI_QUIRK_DTO_TIMER)
+   setup_timer(host-dto_timer,
+   dw_mci_dto_timer, (unsigned long)host);
 
/*
 * Get the host data width - this assumes that HCON has been set with
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index 42b724e..2477813 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -98,6 +98,7 @@ struct mmc_data

Re: [PATCH] mmc: dw_mmc: try pick the exact same voltage as vmmc for vqmmc

2014-11-12 Thread addy ke
On 2014/11/13 02:04, Doug Anderson wrote:
 Ulf,
 
 On Tue, Nov 11, 2014 at 12:52 AM, Ulf Hansson ulf.hans...@linaro.org wrote:
 On 11 November 2014 05:02, Addy Ke addy...@rock-chips.com wrote:
 SD2.0 cards need vqmmc and vmmc to be the same.

 No, that's not correct.

 If I remember the spec correctly, the bus signal threshold is 0.75 * VDD.
 
 As usual, I will first state my utter lack of knowledge of all things mmc.
 
 Now that's out of the way, on two separate board with two separate
 SoCs I've heard stories of cards that don't work when there's a big
 gap between vmmc and vqmmc.
 
 If my memory serves, previously I heard of problems with vmmc=3.3V and
 vqmmc=2.8V.  That means there were problems with .85 * VDD.  Certainly
 Addy seems to have a card that has problems with vmmc=3.3V and
 vqmmc=2.7V (but worked with vmmc=3.3V and vqmmc=2.8V).  That is .82 *
 VDD.
 
 I have no idea if these old cards are to spec, but they exist and it
 would be nice to support them.
 
 It seems like the absolute safest thing would be to try to keep vmmc
 and vqmmc matching if possible, especially during card probe.  Once
 voltage negotiation happened then the vqmmc could go down.
 
 
 But vqmmc call regulator_set_voltage to set min_uv(2.7v) as far as possible.

 I guess you want to do that to save as much power as possible.
 
 I don't think it's Addy wanting it, I think it's the regulator framework.
 
 If a regulator is current 1.8V and you request 2.7 - 3.3V, the
 framework needs to pick one of those voltages.  I believe it will pick
 2.7V.
 
 ...so I think we get into trouble only when the 2.0 card is plugged in
 after a UHS card has negotiated down the voltage, but I could be
 wrong.  Maybe Addy can clarify.
 
Sure
If the first card is sd2.0 since startup, dw_mci_switch_voltage will not be 
called,
and card can be identified. But if UHS card is pulgged in first, the vqmmc will 
be down to 1.8v.

when sd2.0 card is pulgged in, mmc core will call dw_mci_switch_voltage to 
change vqmmc to 3.3v
(MMC_SINGLE_VOTAGE_330). So vqmmc will be set 2.7v, if we request 2.7-3.6v.

But vmmc is always 3.3v,becuase it be set min_volt = max_volt = 3.3v in dt 
tables.

So the result:
vmmc = 3.3v and vqmmc = 2.7v, and sd2.0 card is failed to identify in my test.

 
 @@ -1163,8 +1163,14 @@ static int dw_mci_switch_voltage(struct mmc_host 
 *mmc, struct mmc_ios *ios)
  */
 uhs = mci_readl(host, UHS_REG);
 if (ios-signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
 -   min_uv = 270;
 -   max_uv = 360;
 +   /* try pick the exact same voltage as vmmc for vqmmc */

 This seems like a generic SD protocol issue.

 Should we maybe provide some helper function from the mmc core, which
 in principle take the negotiated card-ocr into account while
 calculating the signal voltage level. Typically min_uv should be 0.75
 x (card-ocr), for these cases.
 
 Yes, if there are ways to make the solution more generic I would
 certainly support that.
 
 -Doug
 
 
 

--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] mmc: dw_mmc: try pick the exact same voltage as vmmc for vqmmc

2014-11-10 Thread Addy Ke
SD2.0 cards need vqmmc and vmmc to be the same.
But vqmmc call regulator_set_voltage to set min_uv(2.7v) as far as possible.
So if we set vmmc 3.3V in dt table, we will get error information as follows:

[   17.785398] mmc_host mmc1: Bus speed (slot 0) = 5000Hz (slot req
5000Hz, actual 5000HZ div = 0)
[   17.795175] mmc1: new high speed SDHC card at address e624
[   17.801283] mmcblk1: mmc1:e624 SU08G 7.40 GiB
[   17.816033]  mmcblk1: p1
[   17.839318] mmcblk1: error -110 sending status command, retrying
[   17.845363] mmcblk1: error -115 sending stop command, original cmd
response 0x900, card status 0x800b00
[   17.854758] mmcblk1: error -84 transferring data, sector 32, nr 24,
cmd response 0x900, card status 0xb00
[   17.864328] mmcblk1: retrying using single block read
[   17.873647] mmcblk1: error -110 sending status command, retrying
[   17.879660] mmcblk1: error -84 transferring data, sector 44, nr 12,
cmd response 0x900, card status 0x0
[   17.889051] end_request: I/O error, dev mmcblk1, sector 44
[   17.895594] Buffer I/O error on device mmcblk1, logical block 5
[   17.902484] mmcblk1: error -110 sending status command, retrying
[   17.908498] mmcblk1: error -84 transferring data, sector 50, nr 6,
cmd response 0x900, card status 0x0
[   17.917802] end_request: I/O error, dev mmcblk1, sector 50
[   17.924984] Buffer I/O error on device mmcblk1, logical block 6
[   18.431258] mmc_host mmc1: Timeout sending command (cmd 0x20 arg
0x0 status 0x8020)

Signed-off-by: Addy Ke addy...@rock-chips.com
---
 drivers/mmc/host/dw_mmc.c | 10 --
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index b4c3044..a8b70b5 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1163,8 +1163,14 @@ static int dw_mci_switch_voltage(struct mmc_host *mmc, 
struct mmc_ios *ios)
 */
uhs = mci_readl(host, UHS_REG);
if (ios-signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
-   min_uv = 270;
-   max_uv = 360;
+   /* try pick the exact same voltage as vmmc for vqmmc */
+   if (!IS_ERR(mmc-supply.vmmc)) {
+   min_uv = regulator_get_voltage(mmc-supply.vmmc);
+   max_uv = min_uv;
+   } else {
+   min_uv = 270;
+   max_uv = 360;
+   }
uhs = ~v18;
} else {
min_uv = 170;
-- 
1.8.3.2


--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v4] mmc: dw_mmc: add support for the other bit of sdio interrupt

2014-11-04 Thread Addy Ke
The bit of sdio interrupt is 16 in designware implementation,
but it is 24 on Rockchip SoCs.This patch add sdio_id0 for the
number of slot0 in the SDIO interrupt registers.

Signed-off-by: Addy Ke addy...@rock-chips.com
---
Changes in v2:
- rebase on http://git.linaro.org/git/people/ulf.hansson/mmc.git, next branch
Changes in v3:
- Remove dts for sdio_id0, just replace this with 8, suggested by Doug
- Change to support all Rockchip Socs, suggested by Heiko
Changes in v4:
- use init-hook to set sdio_id0, suggested by Jaehoon

 drivers/mmc/host/dw_mmc-rockchip.c | 10 ++
 drivers/mmc/host/dw_mmc.c  | 12 +++-
 drivers/mmc/host/dw_mmc.h  |  2 ++
 include/linux/mmc/dw_mmc.h |  3 +++
 4 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc-rockchip.c 
b/drivers/mmc/host/dw_mmc-rockchip.c
index bbb4ec3..5650ac4 100644
--- a/drivers/mmc/host/dw_mmc-rockchip.c
+++ b/drivers/mmc/host/dw_mmc-rockchip.c
@@ -68,14 +68,24 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, 
struct mmc_ios *ios)
}
 }
 
+static int dw_mci_rockchip_init(struct dw_mci *host)
+{
+   /* It is slot 8 on Rockchip SoCs */
+   host-sdio_id0 = 8;
+
+   return 0;
+}
+
 static const struct dw_mci_drv_data rk2928_drv_data = {
.prepare_command= dw_mci_rockchip_prepare_command,
+   .init   = dw_mci_rockchip_init,
 };
 
 static const struct dw_mci_drv_data rk3288_drv_data = {
.prepare_command= dw_mci_rockchip_prepare_command,
.set_ios= dw_mci_rk3288_set_ios,
.setup_clock= dw_mci_rk3288_setup_clock,
+   .init   = dw_mci_rockchip_init,
 };
 
 static const struct of_device_id dw_mci_rockchip_match[] = {
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index bb46b1b..a633b58 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -823,7 +823,7 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool 
force_clkinit)
 
/* enable clock; only low power if no SDIO */
clk_en_a = SDMMC_CLKEN_ENABLE  slot-id;
-   if (!(mci_readl(host, INTMASK)  SDMMC_INT_SDIO(slot-id)))
+   if (!(mci_readl(host, INTMASK)  SDMMC_INT_SDIO(slot-sdio_id)))
clk_en_a |= SDMMC_CLKEN_LOW_PWR  slot-id;
mci_writel(host, CLKENA, clk_en_a);
 
@@ -1184,10 +1184,10 @@ static void dw_mci_enable_sdio_irq(struct mmc_host 
*mmc, int enb)
dw_mci_disable_low_power(slot);
 
mci_writel(host, INTMASK,
-  (int_mask | SDMMC_INT_SDIO(slot-id)));
+  (int_mask | SDMMC_INT_SDIO(slot-sdio_id)));
} else {
mci_writel(host, INTMASK,
-  (int_mask  ~SDMMC_INT_SDIO(slot-id)));
+  (int_mask  ~SDMMC_INT_SDIO(slot-sdio_id)));
}
 }
 
@@ -2056,8 +2056,9 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
/* Handle SDIO Interrupts */
for (i = 0; i  host-num_slots; i++) {
struct dw_mci_slot *slot = host-slot[i];
-   if (pending  SDMMC_INT_SDIO(i)) {
-   mci_writel(host, RINTSTS, SDMMC_INT_SDIO(i));
+   if (pending  SDMMC_INT_SDIO(slot-sdio_id)) {
+   mci_writel(host, RINTSTS,
+  SDMMC_INT_SDIO(slot-sdio_id));
mmc_signal_sdio_irq(slot-mmc);
}
}
@@ -2145,6 +2146,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned 
int id)
 
slot = mmc_priv(mmc);
slot-id = id;
+   slot-sdio_id = host-sdio_id0 + id;
slot-mmc = mmc;
slot-host = host;
host-slot[id] = slot;
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index 71d4995..0562f10 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -214,6 +214,7 @@ extern int dw_mci_resume(struct dw_mci *host);
  * with CONFIG_MMC_CLKGATE.
  * @flags: Random state bits associated with the slot.
  * @id: Number of this slot.
+ * @sdio_id: Number of this slot in the SDIO interrupt registers.
  */
 struct dw_mci_slot {
struct mmc_host *mmc;
@@ -233,6 +234,7 @@ struct dw_mci_slot {
 #define DW_MMC_CARD_PRESENT0
 #define DW_MMC_CARD_NEED_INIT  1
int id;
+   int sdio_id;
 };
 
 struct dw_mci_tuning_data {
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index 69d0814..72c319f 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -96,6 +96,7 @@ struct mmc_data;
  * @quirks: Set of quirks that apply to specific versions of the IP.
  * @irq_flags: The flags to be passed to request_irq.
  * @irq: The irq value to be passed to request_irq

Re: [PATCH v3] mmc: dw_mmc: add support for the other bit of sdio interrupt

2014-11-03 Thread addy ke
Hi, Jaehoo

On 2014/11/3 16:59, Jaehoon Chung wrote:
 Hi, Addy.
 
 On 11/03/2014 10:20 AM, Addy Ke wrote:
 The bit of sdio interrupt is 16 in designware implementation,
 but it is 24 on Rockchip SoCs.This patch add sdio_id0 for the
 number of slot0 in the SDIO interrupt registers.

 Signed-off-by: Addy Ke addy...@rock-chips.com
 ---
 Changes in v2:
 - rebase on http://git.linaro.org/git/people/ulf.hansson/mmc.git, next branch
 Changes in v3:
 - Remove dts for sdio_id0, just replace this with 8, suggested by Doug
 - Change to support all Rockchip Socs, suggested by Heiko

  drivers/mmc/host/dw_mmc-rockchip.c | 10 ++
  drivers/mmc/host/dw_mmc.c  | 12 +++-
  drivers/mmc/host/dw_mmc.h  |  2 ++
  include/linux/mmc/dw_mmc.h |  3 +++
  4 files changed, 22 insertions(+), 5 deletions(-)

 diff --git a/drivers/mmc/host/dw_mmc-rockchip.c 
 b/drivers/mmc/host/dw_mmc-rockchip.c
 index bbb4ec3..b997c8f 100644
 --- a/drivers/mmc/host/dw_mmc-rockchip.c
 +++ b/drivers/mmc/host/dw_mmc-rockchip.c
 @@ -68,14 +68,24 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, 
 struct mmc_ios *ios)
  }
  }
  
 +static int dw_mci_rockchip_parse_dt(struct dw_mci *host)
 +{
 +/* It is slot 8 on Rockchip SoCs */
 +host-sdio_id0 = 8;
 +
 +return 0;
 +}
 
 Well, function is __parse_dt__, but this function don't parse anything.
 If All rockchip soc is supported, i think that it can be located to other 
 place.
 
Can add it in init function? like this:
int dw_mci_rockchip_init(struct dw_mci *host)
{
/* It is slot 8 on Rockchip SoCs */
host-sdio_id0 = 8;

return 0;
}
static const struct dw_mci_drv_data  {

.init = dw_mci_rockchip_init,
};


 Best Regards,
 Jaehoon Chung
 
 +
  static const struct dw_mci_drv_data rk2928_drv_data = {
  .prepare_command= dw_mci_rockchip_prepare_command,
 +.parse_dt   = dw_mci_rockchip_parse_dt,
  };
  
  static const struct dw_mci_drv_data rk3288_drv_data = {
  .prepare_command= dw_mci_rockchip_prepare_command,
  .set_ios= dw_mci_rk3288_set_ios,
  .setup_clock= dw_mci_rk3288_setup_clock,
 +.parse_dt   = dw_mci_rockchip_parse_dt,
  };
  
  static const struct of_device_id dw_mci_rockchip_match[] = {
 diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
 index bb46b1b..a633b58 100644
 --- a/drivers/mmc/host/dw_mmc.c
 +++ b/drivers/mmc/host/dw_mmc.c
 @@ -823,7 +823,7 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, 
 bool force_clkinit)
  
  /* enable clock; only low power if no SDIO */
  clk_en_a = SDMMC_CLKEN_ENABLE  slot-id;
 -if (!(mci_readl(host, INTMASK)  SDMMC_INT_SDIO(slot-id)))
 +if (!(mci_readl(host, INTMASK)  SDMMC_INT_SDIO(slot-sdio_id)))
  clk_en_a |= SDMMC_CLKEN_LOW_PWR  slot-id;
  mci_writel(host, CLKENA, clk_en_a);
  
 @@ -1184,10 +1184,10 @@ static void dw_mci_enable_sdio_irq(struct mmc_host 
 *mmc, int enb)
  dw_mci_disable_low_power(slot);
  
  mci_writel(host, INTMASK,
 -   (int_mask | SDMMC_INT_SDIO(slot-id)));
 +   (int_mask | SDMMC_INT_SDIO(slot-sdio_id)));
  } else {
  mci_writel(host, INTMASK,
 -   (int_mask  ~SDMMC_INT_SDIO(slot-id)));
 +   (int_mask  ~SDMMC_INT_SDIO(slot-sdio_id)));
  }
  }
  
 @@ -2056,8 +2056,9 @@ static irqreturn_t dw_mci_interrupt(int irq, void 
 *dev_id)
  /* Handle SDIO Interrupts */
  for (i = 0; i  host-num_slots; i++) {
  struct dw_mci_slot *slot = host-slot[i];
 -if (pending  SDMMC_INT_SDIO(i)) {
 -mci_writel(host, RINTSTS, SDMMC_INT_SDIO(i));
 +if (pending  SDMMC_INT_SDIO(slot-sdio_id)) {
 +mci_writel(host, RINTSTS,
 +   SDMMC_INT_SDIO(slot-sdio_id));
  mmc_signal_sdio_irq(slot-mmc);
  }
  }
 @@ -2145,6 +2146,7 @@ static int dw_mci_init_slot(struct dw_mci *host, 
 unsigned int id)
  
  slot = mmc_priv(mmc);
  slot-id = id;
 +slot-sdio_id = host-sdio_id0 + id;
  slot-mmc = mmc;
  slot-host = host;
  host-slot[id] = slot;
 diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
 index 71d4995..0562f10 100644
 --- a/drivers/mmc/host/dw_mmc.h
 +++ b/drivers/mmc/host/dw_mmc.h
 @@ -214,6 +214,7 @@ extern int dw_mci_resume(struct dw_mci *host);
   *  with CONFIG_MMC_CLKGATE.
   * @flags: Random state bits associated with the slot.
   * @id: Number of this slot.
 + * @sdio_id: Number of this slot in the SDIO interrupt registers.
   */
  struct dw_mci_slot {
  struct mmc_host *mmc;
 @@ -233,6 +234,7 @@ struct dw_mci_slot {
  #define DW_MMC_CARD_PRESENT 0
  #define DW_MMC_CARD_NEED_INIT   1
  int

Re: [PATCH v2] mmc: dw_mmc: add support for the other bit of sdio interrupt

2014-11-02 Thread addy ke
On 2014/10/31 18:43, Heiko Stübner wrote:
 Am Freitag, 31. Oktober 2014, 11:50:09 schrieb Addy Ke:
 The bit of sdio interrupt is 16 in designware implementation,
 but it is 24 in RK3288. This patch add sdio_id0 for the number
 of slot0 in the SDIO interrupt registers, which can be set in
 platform DT table, such as:
 - rockchip,sdio-interrupt-slot0 = 8;
 
 I just checked the manuals of rk3066 and rk3188 - and it seems the sdio 
 interrupt is in bit 24 on all of them.
 
 Addy, could you check this and maybe enable this for all two variants we 
 currently support?
OK, I will do so in my next patch. thank you!
 
 
 Thanks
 Heiko
 
 

 Signed-off-by: Addy Ke addy...@rock-chips.com
 ---
 Changes in v2:
 - rebase on http://git.linaro.org/git/people/ulf.hansson/mmc.git, next
 branch

  drivers/mmc/host/dw_mmc-rockchip.c | 13 +
  drivers/mmc/host/dw_mmc.c  | 12 +++-
  drivers/mmc/host/dw_mmc.h  |  2 ++
  include/linux/mmc/dw_mmc.h |  3 +++
  4 files changed, 25 insertions(+), 5 deletions(-)

 diff --git a/drivers/mmc/host/dw_mmc-rockchip.c
 b/drivers/mmc/host/dw_mmc-rockchip.c index bbb4ec3..1cb3bc6 100644
 --- a/drivers/mmc/host/dw_mmc-rockchip.c
 +++ b/drivers/mmc/host/dw_mmc-rockchip.c
 @@ -68,6 +68,18 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host,
 struct mmc_ios *ios) }
  }

 +static int dw_mci_rk3288_parse_dt(struct dw_mci *host)
 +{
 +struct device_node *np = host-dev-of_node;
 +int sdio_id0;
 +
 +if (!of_property_read_u32(np, rockchip,sdio-interrupt-slot0,
 +  sdio_id0))
 +host-sdio_id0 = sdio_id0;
 +
 +return 0;
 +}
 +
  static const struct dw_mci_drv_data rk2928_drv_data = {
  .prepare_command= dw_mci_rockchip_prepare_command,
  };
 @@ -76,6 +88,7 @@ static const struct dw_mci_drv_data rk3288_drv_data = {
  .prepare_command= dw_mci_rockchip_prepare_command,
  .set_ios= dw_mci_rk3288_set_ios,
  .setup_clock= dw_mci_rk3288_setup_clock,
 +.parse_dt   = dw_mci_rk3288_parse_dt,
  };

  static const struct of_device_id dw_mci_rockchip_match[] = {
 diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
 index bb46b1b..a633b58 100644
 --- a/drivers/mmc/host/dw_mmc.c
 +++ b/drivers/mmc/host/dw_mmc.c
 @@ -823,7 +823,7 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot,
 bool force_clkinit)

  /* enable clock; only low power if no SDIO */
  clk_en_a = SDMMC_CLKEN_ENABLE  slot-id;
 -if (!(mci_readl(host, INTMASK)  SDMMC_INT_SDIO(slot-id)))
 +if (!(mci_readl(host, INTMASK)  SDMMC_INT_SDIO(slot-sdio_id)))
  clk_en_a |= SDMMC_CLKEN_LOW_PWR  slot-id;
  mci_writel(host, CLKENA, clk_en_a);

 @@ -1184,10 +1184,10 @@ static void dw_mci_enable_sdio_irq(struct mmc_host
 *mmc, int enb) dw_mci_disable_low_power(slot);

  mci_writel(host, INTMASK,
 -   (int_mask | SDMMC_INT_SDIO(slot-id)));
 +   (int_mask | SDMMC_INT_SDIO(slot-sdio_id)));
  } else {
  mci_writel(host, INTMASK,
 -   (int_mask  ~SDMMC_INT_SDIO(slot-id)));
 +   (int_mask  ~SDMMC_INT_SDIO(slot-sdio_id)));
  }
  }

 @@ -2056,8 +2056,9 @@ static irqreturn_t dw_mci_interrupt(int irq, void
 *dev_id) /* Handle SDIO Interrupts */
  for (i = 0; i  host-num_slots; i++) {
  struct dw_mci_slot *slot = host-slot[i];
 -if (pending  SDMMC_INT_SDIO(i)) {
 -mci_writel(host, RINTSTS, SDMMC_INT_SDIO(i));
 +if (pending  SDMMC_INT_SDIO(slot-sdio_id)) {
 +mci_writel(host, RINTSTS,
 +   SDMMC_INT_SDIO(slot-sdio_id));
  mmc_signal_sdio_irq(slot-mmc);
  }
  }
 @@ -2145,6 +2146,7 @@ static int dw_mci_init_slot(struct dw_mci *host,
 unsigned int id)

  slot = mmc_priv(mmc);
  slot-id = id;
 +slot-sdio_id = host-sdio_id0 + id;
  slot-mmc = mmc;
  slot-host = host;
  host-slot[id] = slot;
 diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
 index 71d4995..0562f10 100644
 --- a/drivers/mmc/host/dw_mmc.h
 +++ b/drivers/mmc/host/dw_mmc.h
 @@ -214,6 +214,7 @@ extern int dw_mci_resume(struct dw_mci *host);
   *  with CONFIG_MMC_CLKGATE.
   * @flags: Random state bits associated with the slot.
   * @id: Number of this slot.
 + * @sdio_id: Number of this slot in the SDIO interrupt registers.
   */
  struct dw_mci_slot {
  struct mmc_host *mmc;
 @@ -233,6 +234,7 @@ struct dw_mci_slot {
  #define DW_MMC_CARD_PRESENT 0
  #define DW_MMC_CARD_NEED_INIT   1
  int id;
 +int sdio_id;
  };

  struct dw_mci_tuning_data {
 diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
 index 69d0814..72c319f

[PATCH v3] mmc: dw_mmc: add support for the other bit of sdio interrupt

2014-11-02 Thread Addy Ke
The bit of sdio interrupt is 16 in designware implementation,
but it is 24 on Rockchip SoCs.This patch add sdio_id0 for the
number of slot0 in the SDIO interrupt registers.

Signed-off-by: Addy Ke addy...@rock-chips.com
---
Changes in v2:
- rebase on http://git.linaro.org/git/people/ulf.hansson/mmc.git, next branch
Changes in v3:
- Remove dts for sdio_id0, just replace this with 8, suggested by Doug
- Change to support all Rockchip Socs, suggested by Heiko

 drivers/mmc/host/dw_mmc-rockchip.c | 10 ++
 drivers/mmc/host/dw_mmc.c  | 12 +++-
 drivers/mmc/host/dw_mmc.h  |  2 ++
 include/linux/mmc/dw_mmc.h |  3 +++
 4 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc-rockchip.c 
b/drivers/mmc/host/dw_mmc-rockchip.c
index bbb4ec3..b997c8f 100644
--- a/drivers/mmc/host/dw_mmc-rockchip.c
+++ b/drivers/mmc/host/dw_mmc-rockchip.c
@@ -68,14 +68,24 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, 
struct mmc_ios *ios)
}
 }
 
+static int dw_mci_rockchip_parse_dt(struct dw_mci *host)
+{
+   /* It is slot 8 on Rockchip SoCs */
+   host-sdio_id0 = 8;
+
+   return 0;
+}
+
 static const struct dw_mci_drv_data rk2928_drv_data = {
.prepare_command= dw_mci_rockchip_prepare_command,
+   .parse_dt   = dw_mci_rockchip_parse_dt,
 };
 
 static const struct dw_mci_drv_data rk3288_drv_data = {
.prepare_command= dw_mci_rockchip_prepare_command,
.set_ios= dw_mci_rk3288_set_ios,
.setup_clock= dw_mci_rk3288_setup_clock,
+   .parse_dt   = dw_mci_rockchip_parse_dt,
 };
 
 static const struct of_device_id dw_mci_rockchip_match[] = {
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index bb46b1b..a633b58 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -823,7 +823,7 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool 
force_clkinit)
 
/* enable clock; only low power if no SDIO */
clk_en_a = SDMMC_CLKEN_ENABLE  slot-id;
-   if (!(mci_readl(host, INTMASK)  SDMMC_INT_SDIO(slot-id)))
+   if (!(mci_readl(host, INTMASK)  SDMMC_INT_SDIO(slot-sdio_id)))
clk_en_a |= SDMMC_CLKEN_LOW_PWR  slot-id;
mci_writel(host, CLKENA, clk_en_a);
 
@@ -1184,10 +1184,10 @@ static void dw_mci_enable_sdio_irq(struct mmc_host 
*mmc, int enb)
dw_mci_disable_low_power(slot);
 
mci_writel(host, INTMASK,
-  (int_mask | SDMMC_INT_SDIO(slot-id)));
+  (int_mask | SDMMC_INT_SDIO(slot-sdio_id)));
} else {
mci_writel(host, INTMASK,
-  (int_mask  ~SDMMC_INT_SDIO(slot-id)));
+  (int_mask  ~SDMMC_INT_SDIO(slot-sdio_id)));
}
 }
 
@@ -2056,8 +2056,9 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
/* Handle SDIO Interrupts */
for (i = 0; i  host-num_slots; i++) {
struct dw_mci_slot *slot = host-slot[i];
-   if (pending  SDMMC_INT_SDIO(i)) {
-   mci_writel(host, RINTSTS, SDMMC_INT_SDIO(i));
+   if (pending  SDMMC_INT_SDIO(slot-sdio_id)) {
+   mci_writel(host, RINTSTS,
+  SDMMC_INT_SDIO(slot-sdio_id));
mmc_signal_sdio_irq(slot-mmc);
}
}
@@ -2145,6 +2146,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned 
int id)
 
slot = mmc_priv(mmc);
slot-id = id;
+   slot-sdio_id = host-sdio_id0 + id;
slot-mmc = mmc;
slot-host = host;
host-slot[id] = slot;
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index 71d4995..0562f10 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -214,6 +214,7 @@ extern int dw_mci_resume(struct dw_mci *host);
  * with CONFIG_MMC_CLKGATE.
  * @flags: Random state bits associated with the slot.
  * @id: Number of this slot.
+ * @sdio_id: Number of this slot in the SDIO interrupt registers.
  */
 struct dw_mci_slot {
struct mmc_host *mmc;
@@ -233,6 +234,7 @@ struct dw_mci_slot {
 #define DW_MMC_CARD_PRESENT0
 #define DW_MMC_CARD_NEED_INIT  1
int id;
+   int sdio_id;
 };
 
 struct dw_mci_tuning_data {
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index 69d0814..72c319f 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -96,6 +96,7 @@ struct mmc_data;
  * @quirks: Set of quirks that apply to specific versions of the IP.
  * @irq_flags: The flags to be passed to request_irq.
  * @irq: The irq value to be passed to request_irq.
+ * @sdio_id0: Number of slot0 in the SDIO interrupt registers

Re: [PATCH] mmc: dw_mmc: add a quirk for the defferent bit of sdio interrupt

2014-10-30 Thread addy ke
Hi, Doug,

On 2014/10/30 12:49, Doug Anderson wrote:
 Addy,
 
 On Wed, Oct 29, 2014 at 9:41 PM, Doug Anderson diand...@chromium.org wrote:
 You can avoid a lot of if tests if you just add a new sdio-id
 
 Whoops, I mean slot-sdio_id
 

To use slot-sdio_id, I think the subject must be changed.
So I will drop this patch ,and send new patch to use slot-sdio_id for this 
difference.

thank you!

 
 

--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] mmc: dw_mmc: add support for the other bit of sdio interrupt

2014-10-30 Thread Addy Ke
The bit of sdio interrupt is 16 in designware implementation,
but it is 24 in RK3288. This patch add sdio_id0 for the number
of slot0 in the SDIO interrupt registers, which can be set in
platform DT table, such as:
- rockchip,sdio-interrupt-slot0 = 8;

Signed-off-by: Addy Ke addy...@rock-chips.com
---
 drivers/mmc/host/dw_mmc-rockchip.c | 13 +
 drivers/mmc/host/dw_mmc.c  | 12 +++-
 drivers/mmc/host/dw_mmc.h  |  2 ++
 include/linux/mmc/dw_mmc.h |  3 +++
 4 files changed, 25 insertions(+), 5 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc-rockchip.c 
b/drivers/mmc/host/dw_mmc-rockchip.c
index f0c2cb1..54655e7 100644
--- a/drivers/mmc/host/dw_mmc-rockchip.c
+++ b/drivers/mmc/host/dw_mmc-rockchip.c
@@ -65,6 +65,18 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, 
struct mmc_ios *ios)
}
 }
 
+static int dw_mci_rk3288_parse_dt(struct dw_mci *host)
+{
+   struct device_node *np = host-dev-of_node;
+   int sdio_id0;
+
+   if (!of_property_read_u32(np, rockchip,sdio-interrupt-slot0,
+ sdio_id0))
+   host-sdio_id0 = sdio_id0;
+
+   return 0;
+}
+
 static const struct dw_mci_drv_data rk2928_drv_data = {
.prepare_command= dw_mci_rockchip_prepare_command,
 };
@@ -73,6 +85,7 @@ static const struct dw_mci_drv_data rk3288_drv_data = {
.prepare_command= dw_mci_rockchip_prepare_command,
.set_ios= dw_mci_rk3288_set_ios,
.setup_clock= dw_mci_rk3288_setup_clock,
+   .parse_dt   = dw_mci_rk3288_parse_dt,
 };
 
 static const struct of_device_id dw_mci_rockchip_match[] = {
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 69f0cc6..2ea7467 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -819,7 +819,7 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool 
force_clkinit)
 
/* enable clock; only low power if no SDIO */
clk_en_a = SDMMC_CLKEN_ENABLE  slot-id;
-   if (!(mci_readl(host, INTMASK)  SDMMC_INT_SDIO(slot-id)))
+   if (!(mci_readl(host, INTMASK)  SDMMC_INT_SDIO(slot-sdio_id)))
clk_en_a |= SDMMC_CLKEN_LOW_PWR  slot-id;
mci_writel(host, CLKENA, clk_en_a);
 
@@ -1180,10 +1180,10 @@ static void dw_mci_enable_sdio_irq(struct mmc_host 
*mmc, int enb)
dw_mci_disable_low_power(slot);
 
mci_writel(host, INTMASK,
-  (int_mask | SDMMC_INT_SDIO(slot-id)));
+  (int_mask | SDMMC_INT_SDIO(slot-sdio_id)));
} else {
mci_writel(host, INTMASK,
-  (int_mask  ~SDMMC_INT_SDIO(slot-id)));
+  (int_mask  ~SDMMC_INT_SDIO(slot-sdio_id)));
}
 }
 
@@ -2035,8 +2035,9 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
/* Handle SDIO Interrupts */
for (i = 0; i  host-num_slots; i++) {
struct dw_mci_slot *slot = host-slot[i];
-   if (pending  SDMMC_INT_SDIO(i)) {
-   mci_writel(host, RINTSTS, SDMMC_INT_SDIO(i));
+   if (pending  SDMMC_INT_SDIO(slot-sdio_id)) {
+   mci_writel(host, RINTSTS,
+  SDMMC_INT_SDIO(slot-sdio_id));
mmc_signal_sdio_irq(slot-mmc);
}
}
@@ -2206,6 +2207,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned 
int id)
 
slot = mmc_priv(mmc);
slot-id = id;
+   slot-sdio_id = host-sdio_id0 + id;
slot-mmc = mmc;
slot-host = host;
host-slot[id] = slot;
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index 01b99e8..3e966a9 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -214,6 +214,7 @@ extern int dw_mci_resume(struct dw_mci *host);
  * with CONFIG_MMC_CLKGATE.
  * @flags: Random state bits associated with the slot.
  * @id: Number of this slot.
+ * @sdio_id: Number of this slot in the SDIO interrupt registers.
  * @last_detect_state: Most recently observed card detect state.
  */
 struct dw_mci_slot {
@@ -234,6 +235,7 @@ struct dw_mci_slot {
 #define DW_MMC_CARD_PRESENT0
 #define DW_MMC_CARD_NEED_INIT  1
int id;
+   int sdio_id;
int last_detect_state;
 };
 
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index 0013669..4c0d3f2 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -96,6 +96,7 @@ struct mmc_data;
  * @quirks: Set of quirks that apply to specific versions of the IP.
  * @irq_flags: The flags to be passed to request_irq.
  * @irq: The irq value to be passed to request_irq.
+ * @sdio_id0: Number of slot0 in the SDIO interrupt

Re: [PATCH] mmc: dw_mmc: add support for the other bit of sdio interrupt

2014-10-30 Thread addy ke
Hi, Jaehoon

On 2014/10/30 19:02, Jaehoon Chung wrote:
 Hi, Addy.
 
 This patch is conflicted..Could you rebase on latest Ulf's tree?
I have not found ulf's tree in git.kernel.org.
I can't 'git clone git://git.kernel.org/pub/scm/linux/kernel/git/ulf/xxx.git'.
So my patch is based on kernel-3.18.
I will send patch v2 for this.
Would you please give me a git url for it?
Thank you.

 
 Best Regards,
 Jaehoon Chung
 
 On 10/30/2014 07:50 PM, Addy Ke wrote:
 The bit of sdio interrupt is 16 in designware implementation,
 but it is 24 in RK3288. This patch add sdio_id0 for the number
 of slot0 in the SDIO interrupt registers, which can be set in
 platform DT table, such as:
 - rockchip,sdio-interrupt-slot0 = 8;

 Signed-off-by: Addy Ke addy...@rock-chips.com
 ---
  drivers/mmc/host/dw_mmc-rockchip.c | 13 +
  drivers/mmc/host/dw_mmc.c  | 12 +++-
  drivers/mmc/host/dw_mmc.h  |  2 ++
  include/linux/mmc/dw_mmc.h |  3 +++
  4 files changed, 25 insertions(+), 5 deletions(-)

 diff --git a/drivers/mmc/host/dw_mmc-rockchip.c 
 b/drivers/mmc/host/dw_mmc-rockchip.c
 index f0c2cb1..54655e7 100644
 --- a/drivers/mmc/host/dw_mmc-rockchip.c
 +++ b/drivers/mmc/host/dw_mmc-rockchip.c
 @@ -65,6 +65,18 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, 
 struct mmc_ios *ios)
  }
  }
  
 +static int dw_mci_rk3288_parse_dt(struct dw_mci *host)
 +{
 +struct device_node *np = host-dev-of_node;
 +int sdio_id0;
 +
 +if (!of_property_read_u32(np, rockchip,sdio-interrupt-slot0,
 +  sdio_id0))
 +host-sdio_id0 = sdio_id0;
 +
 +return 0;
 +}
 +
  static const struct dw_mci_drv_data rk2928_drv_data = {
  .prepare_command= dw_mci_rockchip_prepare_command,
  };
 @@ -73,6 +85,7 @@ static const struct dw_mci_drv_data rk3288_drv_data = {
  .prepare_command= dw_mci_rockchip_prepare_command,
  .set_ios= dw_mci_rk3288_set_ios,
  .setup_clock= dw_mci_rk3288_setup_clock,
 +.parse_dt   = dw_mci_rk3288_parse_dt,
  };
  
  static const struct of_device_id dw_mci_rockchip_match[] = {
 diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
 index 69f0cc6..2ea7467 100644
 --- a/drivers/mmc/host/dw_mmc.c
 +++ b/drivers/mmc/host/dw_mmc.c
 @@ -819,7 +819,7 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, 
 bool force_clkinit)
  
  /* enable clock; only low power if no SDIO */
  clk_en_a = SDMMC_CLKEN_ENABLE  slot-id;
 -if (!(mci_readl(host, INTMASK)  SDMMC_INT_SDIO(slot-id)))
 +if (!(mci_readl(host, INTMASK)  SDMMC_INT_SDIO(slot-sdio_id)))
  clk_en_a |= SDMMC_CLKEN_LOW_PWR  slot-id;
  mci_writel(host, CLKENA, clk_en_a);
  
 @@ -1180,10 +1180,10 @@ static void dw_mci_enable_sdio_irq(struct mmc_host 
 *mmc, int enb)
  dw_mci_disable_low_power(slot);
  
  mci_writel(host, INTMASK,
 -   (int_mask | SDMMC_INT_SDIO(slot-id)));
 +   (int_mask | SDMMC_INT_SDIO(slot-sdio_id)));
  } else {
  mci_writel(host, INTMASK,
 -   (int_mask  ~SDMMC_INT_SDIO(slot-id)));
 +   (int_mask  ~SDMMC_INT_SDIO(slot-sdio_id)));
  }
  }
  
 @@ -2035,8 +2035,9 @@ static irqreturn_t dw_mci_interrupt(int irq, void 
 *dev_id)
  /* Handle SDIO Interrupts */
  for (i = 0; i  host-num_slots; i++) {
  struct dw_mci_slot *slot = host-slot[i];
 -if (pending  SDMMC_INT_SDIO(i)) {
 -mci_writel(host, RINTSTS, SDMMC_INT_SDIO(i));
 +if (pending  SDMMC_INT_SDIO(slot-sdio_id)) {
 +mci_writel(host, RINTSTS,
 +   SDMMC_INT_SDIO(slot-sdio_id));
  mmc_signal_sdio_irq(slot-mmc);
  }
  }
 @@ -2206,6 +2207,7 @@ static int dw_mci_init_slot(struct dw_mci *host, 
 unsigned int id)
  
  slot = mmc_priv(mmc);
  slot-id = id;
 +slot-sdio_id = host-sdio_id0 + id;
  slot-mmc = mmc;
  slot-host = host;
  host-slot[id] = slot;
 diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
 index 01b99e8..3e966a9 100644
 --- a/drivers/mmc/host/dw_mmc.h
 +++ b/drivers/mmc/host/dw_mmc.h
 @@ -214,6 +214,7 @@ extern int dw_mci_resume(struct dw_mci *host);
   *  with CONFIG_MMC_CLKGATE.
   * @flags: Random state bits associated with the slot.
   * @id: Number of this slot.
 + * @sdio_id: Number of this slot in the SDIO interrupt registers.
   * @last_detect_state: Most recently observed card detect state.
   */
  struct dw_mci_slot {
 @@ -234,6 +235,7 @@ struct dw_mci_slot {
  #define DW_MMC_CARD_PRESENT 0
  #define DW_MMC_CARD_NEED_INIT   1
  int id;
 +int sdio_id;
  int last_detect_state;
  };
  
 diff

Re: [PATCH] mmc: dw_mmc: add support for the other bit of sdio interrupt

2014-10-30 Thread addy ke
On 2014/10/30 19:17, Jaehoon Chung wrote:
 On 10/30/2014 08:11 PM, Ulf Hansson wrote:
 On 30 October 2014 11:50, Addy Ke addy...@rock-chips.com wrote:
 The bit of sdio interrupt is 16 in designware implementation,
 but it is 24 in RK3288. This patch add sdio_id0 for the number
 of slot0 in the SDIO interrupt registers, which can be set in
 platform DT table, such as:
 - rockchip,sdio-interrupt-slot0 = 8;

 No, this shouldn't be information in DT.

 Instead this can be kept in the driver, depending on what version of
 the mmc controller that is being used. Right!?
 
 sdio-interrupt slot doesn't depend on IP version.
 maybe it depends on rock-chip board.

sure, it is denpends on rockchip soc, not IP version.
As far as I know, only our socs(such as RK3288) have this difference.
 
 Best Regards,
 Jaehoon Chung
 

 Kind regards
 Uffe


 Signed-off-by: Addy Ke addy...@rock-chips.com
 ---
  drivers/mmc/host/dw_mmc-rockchip.c | 13 +
  drivers/mmc/host/dw_mmc.c  | 12 +++-
  drivers/mmc/host/dw_mmc.h  |  2 ++
  include/linux/mmc/dw_mmc.h |  3 +++
  4 files changed, 25 insertions(+), 5 deletions(-)

 diff --git a/drivers/mmc/host/dw_mmc-rockchip.c 
 b/drivers/mmc/host/dw_mmc-rockchip.c
 index f0c2cb1..54655e7 100644
 --- a/drivers/mmc/host/dw_mmc-rockchip.c
 +++ b/drivers/mmc/host/dw_mmc-rockchip.c
 @@ -65,6 +65,18 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, 
 struct mmc_ios *ios)
 }
  }

 +static int dw_mci_rk3288_parse_dt(struct dw_mci *host)
 +{
 +   struct device_node *np = host-dev-of_node;
 +   int sdio_id0;
 +
 +   if (!of_property_read_u32(np, rockchip,sdio-interrupt-slot0,
 + sdio_id0))
 +   host-sdio_id0 = sdio_id0;
 +
 +   return 0;
 +}
 +
  static const struct dw_mci_drv_data rk2928_drv_data = {
 .prepare_command= dw_mci_rockchip_prepare_command,
  };
 @@ -73,6 +85,7 @@ static const struct dw_mci_drv_data rk3288_drv_data = {
 .prepare_command= dw_mci_rockchip_prepare_command,
 .set_ios= dw_mci_rk3288_set_ios,
 .setup_clock= dw_mci_rk3288_setup_clock,
 +   .parse_dt   = dw_mci_rk3288_parse_dt,
  };

  static const struct of_device_id dw_mci_rockchip_match[] = {
 diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
 index 69f0cc6..2ea7467 100644
 --- a/drivers/mmc/host/dw_mmc.c
 +++ b/drivers/mmc/host/dw_mmc.c
 @@ -819,7 +819,7 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, 
 bool force_clkinit)

 /* enable clock; only low power if no SDIO */
 clk_en_a = SDMMC_CLKEN_ENABLE  slot-id;
 -   if (!(mci_readl(host, INTMASK)  SDMMC_INT_SDIO(slot-id)))
 +   if (!(mci_readl(host, INTMASK)  
 SDMMC_INT_SDIO(slot-sdio_id)))
 clk_en_a |= SDMMC_CLKEN_LOW_PWR  slot-id;
 mci_writel(host, CLKENA, clk_en_a);

 @@ -1180,10 +1180,10 @@ static void dw_mci_enable_sdio_irq(struct mmc_host 
 *mmc, int enb)
 dw_mci_disable_low_power(slot);

 mci_writel(host, INTMASK,
 -  (int_mask | SDMMC_INT_SDIO(slot-id)));
 +  (int_mask | SDMMC_INT_SDIO(slot-sdio_id)));
 } else {
 mci_writel(host, INTMASK,
 -  (int_mask  ~SDMMC_INT_SDIO(slot-id)));
 +  (int_mask  ~SDMMC_INT_SDIO(slot-sdio_id)));
 }
  }

 @@ -2035,8 +2035,9 @@ static irqreturn_t dw_mci_interrupt(int irq, void 
 *dev_id)
 /* Handle SDIO Interrupts */
 for (i = 0; i  host-num_slots; i++) {
 struct dw_mci_slot *slot = host-slot[i];
 -   if (pending  SDMMC_INT_SDIO(i)) {
 -   mci_writel(host, RINTSTS, 
 SDMMC_INT_SDIO(i));
 +   if (pending  SDMMC_INT_SDIO(slot-sdio_id)) {
 +   mci_writel(host, RINTSTS,
 +  SDMMC_INT_SDIO(slot-sdio_id));
 mmc_signal_sdio_irq(slot-mmc);
 }
 }
 @@ -2206,6 +2207,7 @@ static int dw_mci_init_slot(struct dw_mci *host, 
 unsigned int id)

 slot = mmc_priv(mmc);
 slot-id = id;
 +   slot-sdio_id = host-sdio_id0 + id;
 slot-mmc = mmc;
 slot-host = host;
 host-slot[id] = slot;
 diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
 index 01b99e8..3e966a9 100644
 --- a/drivers/mmc/host/dw_mmc.h
 +++ b/drivers/mmc/host/dw_mmc.h
 @@ -214,6 +214,7 @@ extern int dw_mci_resume(struct dw_mci *host);
   * with CONFIG_MMC_CLKGATE.
   * @flags: Random state bits associated with the slot.
   * @id: Number of this slot.
 + * @sdio_id: Number of this slot in the SDIO interrupt registers.
   * @last_detect_state: Most recently observed card detect state.
   */
  struct dw_mci_slot

[PATCH v2] mmc: dw_mmc: add support for the other bit of sdio interrupt

2014-10-30 Thread Addy Ke
The bit of sdio interrupt is 16 in designware implementation,
but it is 24 in RK3288. This patch add sdio_id0 for the number
of slot0 in the SDIO interrupt registers, which can be set in
platform DT table, such as:
- rockchip,sdio-interrupt-slot0 = 8;

Signed-off-by: Addy Ke addy...@rock-chips.com
---
Changes in v2:
- rebase on http://git.linaro.org/git/people/ulf.hansson/mmc.git, next branch

 drivers/mmc/host/dw_mmc-rockchip.c | 13 +
 drivers/mmc/host/dw_mmc.c  | 12 +++-
 drivers/mmc/host/dw_mmc.h  |  2 ++
 include/linux/mmc/dw_mmc.h |  3 +++
 4 files changed, 25 insertions(+), 5 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc-rockchip.c 
b/drivers/mmc/host/dw_mmc-rockchip.c
index bbb4ec3..1cb3bc6 100644
--- a/drivers/mmc/host/dw_mmc-rockchip.c
+++ b/drivers/mmc/host/dw_mmc-rockchip.c
@@ -68,6 +68,18 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, 
struct mmc_ios *ios)
}
 }
 
+static int dw_mci_rk3288_parse_dt(struct dw_mci *host)
+{
+   struct device_node *np = host-dev-of_node;
+   int sdio_id0;
+
+   if (!of_property_read_u32(np, rockchip,sdio-interrupt-slot0,
+ sdio_id0))
+   host-sdio_id0 = sdio_id0;
+
+   return 0;
+}
+
 static const struct dw_mci_drv_data rk2928_drv_data = {
.prepare_command= dw_mci_rockchip_prepare_command,
 };
@@ -76,6 +88,7 @@ static const struct dw_mci_drv_data rk3288_drv_data = {
.prepare_command= dw_mci_rockchip_prepare_command,
.set_ios= dw_mci_rk3288_set_ios,
.setup_clock= dw_mci_rk3288_setup_clock,
+   .parse_dt   = dw_mci_rk3288_parse_dt,
 };
 
 static const struct of_device_id dw_mci_rockchip_match[] = {
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index bb46b1b..a633b58 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -823,7 +823,7 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool 
force_clkinit)
 
/* enable clock; only low power if no SDIO */
clk_en_a = SDMMC_CLKEN_ENABLE  slot-id;
-   if (!(mci_readl(host, INTMASK)  SDMMC_INT_SDIO(slot-id)))
+   if (!(mci_readl(host, INTMASK)  SDMMC_INT_SDIO(slot-sdio_id)))
clk_en_a |= SDMMC_CLKEN_LOW_PWR  slot-id;
mci_writel(host, CLKENA, clk_en_a);
 
@@ -1184,10 +1184,10 @@ static void dw_mci_enable_sdio_irq(struct mmc_host 
*mmc, int enb)
dw_mci_disable_low_power(slot);
 
mci_writel(host, INTMASK,
-  (int_mask | SDMMC_INT_SDIO(slot-id)));
+  (int_mask | SDMMC_INT_SDIO(slot-sdio_id)));
} else {
mci_writel(host, INTMASK,
-  (int_mask  ~SDMMC_INT_SDIO(slot-id)));
+  (int_mask  ~SDMMC_INT_SDIO(slot-sdio_id)));
}
 }
 
@@ -2056,8 +2056,9 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
/* Handle SDIO Interrupts */
for (i = 0; i  host-num_slots; i++) {
struct dw_mci_slot *slot = host-slot[i];
-   if (pending  SDMMC_INT_SDIO(i)) {
-   mci_writel(host, RINTSTS, SDMMC_INT_SDIO(i));
+   if (pending  SDMMC_INT_SDIO(slot-sdio_id)) {
+   mci_writel(host, RINTSTS,
+  SDMMC_INT_SDIO(slot-sdio_id));
mmc_signal_sdio_irq(slot-mmc);
}
}
@@ -2145,6 +2146,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned 
int id)
 
slot = mmc_priv(mmc);
slot-id = id;
+   slot-sdio_id = host-sdio_id0 + id;
slot-mmc = mmc;
slot-host = host;
host-slot[id] = slot;
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index 71d4995..0562f10 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -214,6 +214,7 @@ extern int dw_mci_resume(struct dw_mci *host);
  * with CONFIG_MMC_CLKGATE.
  * @flags: Random state bits associated with the slot.
  * @id: Number of this slot.
+ * @sdio_id: Number of this slot in the SDIO interrupt registers.
  */
 struct dw_mci_slot {
struct mmc_host *mmc;
@@ -233,6 +234,7 @@ struct dw_mci_slot {
 #define DW_MMC_CARD_PRESENT0
 #define DW_MMC_CARD_NEED_INIT  1
int id;
+   int sdio_id;
 };
 
 struct dw_mci_tuning_data {
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index 69d0814..72c319f 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -96,6 +96,7 @@ struct mmc_data;
  * @quirks: Set of quirks that apply to specific versions of the IP.
  * @irq_flags: The flags to be passed to request_irq.
  * @irq: The irq value to be passed to request_irq.
+ * @sdio_id0

[PATCH] mmc: dw_mmc: add a quirk for the defferent bit of sdio interrupt

2014-10-29 Thread Addy Ke
This patch add a quirk: DW_MCI_QUIRK_SDIO_INT_24BIT.

The bit of sdio interrupt is 16 in designware implementation, but
is 24 in RK3288. To support RK3288 mmc controller, we need add
a quirk for it.

Signed-off-by: Addy Ke addy...@rock-chips.com
---
 drivers/mmc/host/dw_mmc.c  | 32 +++-
 drivers/mmc/host/dw_mmc.h  |  1 +
 include/linux/mmc/dw_mmc.h |  2 ++
 3 files changed, 30 insertions(+), 5 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 69f0cc6..db29621 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -778,6 +778,12 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, 
bool force_clkinit)
u32 div;
u32 clk_en_a;
u32 sdmmc_cmd_bits = SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT;
+   u32 sdio_int_bit;
+
+   if (host-quirks  DW_MCI_QUIRK_SDIO_INT_24BIT)
+   sdio_int_bit = SDMMC_INT_SDIO_24BIT(slot-id);
+   else
+   sdio_int_bit = SDMMC_INT_SDIO(slot-id);
 
/* We must continue to set bit 28 in CMD until the change is complete */
if (host-state == STATE_WAITING_CMD11_DONE)
@@ -819,7 +825,7 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool 
force_clkinit)
 
/* enable clock; only low power if no SDIO */
clk_en_a = SDMMC_CLKEN_ENABLE  slot-id;
-   if (!(mci_readl(host, INTMASK)  SDMMC_INT_SDIO(slot-id)))
+   if (!(mci_readl(host, INTMASK)  sdio_int_bit))
clk_en_a |= SDMMC_CLKEN_LOW_PWR  slot-id;
mci_writel(host, CLKENA, clk_en_a);
 
@@ -1167,6 +1173,12 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, 
int enb)
struct dw_mci_slot *slot = mmc_priv(mmc);
struct dw_mci *host = slot-host;
u32 int_mask;
+   u32 sdio_int_bit;
+
+   if (host-quirks  DW_MCI_QUIRK_SDIO_INT_24BIT)
+   sdio_int_bit = SDMMC_INT_SDIO_24BIT(slot-id);
+   else
+   sdio_int_bit = SDMMC_INT_SDIO(slot-id);
 
/* Enable/disable Slot Specific SDIO interrupt */
int_mask = mci_readl(host, INTMASK);
@@ -1180,10 +1192,10 @@ static void dw_mci_enable_sdio_irq(struct mmc_host 
*mmc, int enb)
dw_mci_disable_low_power(slot);
 
mci_writel(host, INTMASK,
-  (int_mask | SDMMC_INT_SDIO(slot-id)));
+  (int_mask | sdio_int_bit));
} else {
mci_writel(host, INTMASK,
-  (int_mask  ~SDMMC_INT_SDIO(slot-id)));
+  (int_mask  ~sdio_int_bit));
}
 }
 
@@ -2035,8 +2047,15 @@ static irqreturn_t dw_mci_interrupt(int irq, void 
*dev_id)
/* Handle SDIO Interrupts */
for (i = 0; i  host-num_slots; i++) {
struct dw_mci_slot *slot = host-slot[i];
-   if (pending  SDMMC_INT_SDIO(i)) {
-   mci_writel(host, RINTSTS, SDMMC_INT_SDIO(i));
+   u32 sdio_int_bit;
+
+   if (host-quirks  DW_MCI_QUIRK_SDIO_INT_24BIT)
+   sdio_int_bit = SDMMC_INT_SDIO_24BIT(i);
+   else
+   sdio_int_bit = SDMMC_INT_SDIO(i);
+
+   if (pending  sdio_int_bit) {
+   mci_writel(host, RINTSTS, sdio_int_bit);
mmc_signal_sdio_irq(slot-mmc);
}
}
@@ -2452,6 +2471,9 @@ static struct dw_mci_of_quirks {
}, {
.quirk  = disable-wp,
.id = DW_MCI_QUIRK_NO_WRITE_PROTECT,
+   }, {
+   .quirk  = sdio-int-24bit,
+   .id = DW_MCI_QUIRK_SDIO_INT_24BIT,
},
 };
 
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index 01b99e8..6a48015 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -92,6 +92,7 @@
 #define SDMMC_CTYPE_4BIT   BIT(0)
 #define SDMMC_CTYPE_1BIT   0
 /* Interrupt status  mask register defines */
+#define SDMMC_INT_SDIO_24BIT(n)BIT(24 + (n))
 #define SDMMC_INT_SDIO(n)  BIT(16 + (n))
 #define SDMMC_INT_EBE  BIT(15)
 #define SDMMC_INT_ACD  BIT(14)
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index 0013669..6d4669e 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -217,6 +217,8 @@ struct dw_mci_dma_ops {
 #define DW_MCI_QUIRK_BROKEN_CARD_DETECTION BIT(3)
 /* No write protect */
 #define DW_MCI_QUIRK_NO_WRITE_PROTECT  BIT(4)
+/* In RK3288, the bit of sdio interrupt is 24 */
+#define DW_MCI_QUIRK_SDIO_INT_24BITBIT(5)
 
 /* Slot level quirks */
 /* This slot has no write protect */
-- 
1.8.3.2


--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord

Re: [PATCH 1/2] spi/rockchip: fix bug that case spi can't go as fast as slave request

2014-10-16 Thread addy ke


On 2014/10/16 17:34, Mark Brown wrote:
 On Thu, Oct 16, 2014 at 05:16:02PM +0800, addy ke wrote:
 On 2014/10/15 21:04, Mark Brown wrote:
 On Wed, Oct 15, 2014 at 07:25:49PM +0800, Addy Ke wrote:
 
 +  if (WARN_ON(rs-speed  MAX_SCLK_OUT))
 +  rs-speed = MAX_SCLK_OUT;
 
 +  /* the minimum divsor is 2 */
 +  if (rs-max_freq  2 * rs-speed) {
 +  clk_set_rate(rs-spiclk, 2 * rs-speed);
 +  rs-max_freq = clk_get_rate(rs-spiclk);
 +  }
 
 I'll apply this but you should be checking the return code from
 clk_set_rate() here, please send a followup patch doing that.  It might
 
 If clk_set_rate return error, do I only put dev_warn here or return error 
 value to spi core?
 
 It'd be better to return an error if we need to set the rate and can't
 do it.
 
 also be worth consdering just setting the rate unconditionally here, it
 seems like it should make things simpler.
 
 I think we need.
 If we set the rate unconditionally here, clk_set_rate() will be executed in 
 each spi transfer.
 
 Is that really such a high cost?
 
Not high cost, but  I think if the default spi_clk is enough, we do not need to 
set spi_clk again.

Maybe we can only set spi_clk as (2 * MAX_SCLK_OUT) in probe().



--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] spi/rockchip: spi controller must be disabled in tx callback too

2014-10-16 Thread Addy Ke
Signed-off-by: Addy Ke addy...@rock-chips.com
---
 drivers/spi/spi-rockchip.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 153269b..87bc16f 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -418,8 +418,10 @@ static void rockchip_spi_dma_txcb(void *data)
spin_lock_irqsave(rs-lock, flags);
 
rs-state = ~TXBUSY;
-   if (!(rs-state  RXBUSY))
+   if (!(rs-state  RXBUSY)) {
+   spi_enable_chip(rs, 0);
spi_finalize_current_transfer(rs-master);
+   }
 
spin_unlock_irqrestore(rs-lock, flags);
 }
-- 
1.8.3.2


--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 0/2] spi: fix two bugs

2014-10-15 Thread Addy Ke
Patch 1: fix bug that case spi can't go as fast as slave request
Patch 2: fix bug that cause spi transfer timed out in DMA duplex mode

Tested on rk3288-pinky-version2 board.

Addy Ke (2):
  spi/rockchip: fix bug that case spi can't go as fast as slave request
  spi/rockchip: fix bug that cause spi transfer timed out in DMA duplex
mode

 drivers/spi/spi-rockchip.c | 46 +++---
 1 file changed, 35 insertions(+), 11 deletions(-)

-- 
1.8.3.2


--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 1/2] spi/rockchip: fix bug that case spi can't go as fast as slave request

2014-10-15 Thread Addy Ke
Because the minimum divisor in rk3x's spi controller is 2,
if spi_clk is less than 2 * sclk_out, we can't get the right divisor.
So we must set spi_clk again to match slave request.

Signed-off-by: Addy Ke addy...@rock-chips.com
---
 drivers/spi/spi-rockchip.c | 12 
 1 file changed, 12 insertions(+)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index f96ea8a..3044c6c 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -145,6 +145,9 @@
 #define RXBUSY (1  0)
 #define TXBUSY (1  1)
 
+/* sclk_out: spi master internal logic in rk3x can support 50Mhz */
+#define MAX_SCLK_OUT   5000
+
 enum rockchip_ssi_type {
SSI_MOTO_SPI = 0,
SSI_TI_SSP,
@@ -496,6 +499,15 @@ static void rockchip_spi_config(struct rockchip_spi *rs)
dmacr |= RF_DMA_EN;
}
 
+   if (WARN_ON(rs-speed  MAX_SCLK_OUT))
+   rs-speed = MAX_SCLK_OUT;
+
+   /* the minimum divsor is 2 */
+   if (rs-max_freq  2 * rs-speed) {
+   clk_set_rate(rs-spiclk, 2 * rs-speed);
+   rs-max_freq = clk_get_rate(rs-spiclk);
+   }
+
/* div doesn't support odd number */
div = max_t(u32, rs-max_freq / rs-speed, 1);
div = (div + 1)  0xfffe;
-- 
1.8.3.2


--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 2/2] spi/rockchip: fix bug that cause spi transfer timed out in DMA duplex mode

2014-10-15 Thread Addy Ke
In rx mode, dma must be prepared before spi is enabled.
But in tx and tr mode, spi must be enabled first.

Signed-off-by: Addy Ke addy...@rock-chips.com
---
 drivers/spi/spi-rockchip.c | 34 +++---
 1 file changed, 23 insertions(+), 11 deletions(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 3044c6c..153269b 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -328,6 +328,8 @@ static int rockchip_spi_unprepare_message(struct spi_master 
*master,
 
spin_unlock_irqrestore(rs-lock, flags);
 
+   spi_enable_chip(rs, 0);
+
return 0;
 }
 
@@ -384,6 +386,8 @@ static int rockchip_spi_pio_transfer(struct rockchip_spi 
*rs)
if (rs-tx)
wait_for_idle(rs);
 
+   spi_enable_chip(rs, 0);
+
return 0;
 }
 
@@ -395,8 +399,10 @@ static void rockchip_spi_dma_rxcb(void *data)
spin_lock_irqsave(rs-lock, flags);
 
rs-state = ~RXBUSY;
-   if (!(rs-state  TXBUSY))
+   if (!(rs-state  TXBUSY)) {
+   spi_enable_chip(rs, 0);
spi_finalize_current_transfer(rs-master);
+   }
 
spin_unlock_irqrestore(rs-lock, flags);
 }
@@ -512,8 +518,6 @@ static void rockchip_spi_config(struct rockchip_spi *rs)
div = max_t(u32, rs-max_freq / rs-speed, 1);
div = (div + 1)  0xfffe;
 
-   spi_enable_chip(rs, 0);
-
writel_relaxed(cr0, rs-regs + ROCKCHIP_SPI_CTRLR0);
 
writel_relaxed(rs-len - 1, rs-regs + ROCKCHIP_SPI_CTRLR1);
@@ -527,8 +531,6 @@ static void rockchip_spi_config(struct rockchip_spi *rs)
spi_set_clk(rs, div);
 
dev_dbg(rs-dev, cr0 0x%x, div %d\n, cr0, div);
-
-   spi_enable_chip(rs, 1);
 }
 
 static int rockchip_spi_transfer_one(
@@ -536,7 +538,7 @@ static int rockchip_spi_transfer_one(
struct spi_device *spi,
struct spi_transfer *xfer)
 {
-   int ret = 0;
+   int ret = 1;
struct rockchip_spi *rs = spi_master_get_devdata(master);
 
WARN_ON(readl_relaxed(rs-regs + ROCKCHIP_SPI_SSIENR) 
@@ -568,17 +570,27 @@ static int rockchip_spi_transfer_one(
rs-tmode = CR0_XFM_RO;
 
/* we need prepare dma before spi was enabled */
-   if (master-can_dma  master-can_dma(master, spi, xfer)) {
+   if (master-can_dma  master-can_dma(master, spi, xfer))
rs-use_dma = 1;
-   rockchip_spi_prepare_dma(rs);
-   } else {
+   else
rs-use_dma = 0;
-   }
 
rockchip_spi_config(rs);
 
-   if (!rs-use_dma)
+   if (rs-use_dma) {
+   if (rs-tmode == CR0_XFM_RO) {
+   /* rx: dma must be prepared first */
+   rockchip_spi_prepare_dma(rs);
+   spi_enable_chip(rs, 1);
+   } else {
+   /* tx or tr: spi must be enabled first */
+   spi_enable_chip(rs, 1);
+   rockchip_spi_prepare_dma(rs);
+   }
+   } else {
+   spi_enable_chip(rs, 1);
ret = rockchip_spi_pio_transfer(rs);
+   }
 
return ret;
 }
-- 
1.8.3.2


--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] spi/rockchip: fix bug that cause the failture to read data in DMA mode

2014-09-25 Thread Addy Ke
In my test on RK3288-pinky board, if spi is enabled, it will begin to
read data from slave regardless of whether the DMA is ready. So we
need prepare DMA before spi is enable.

Signed-off-by: Addy Ke addy...@rock-chips.com
---
 drivers/spi/spi-rockchip.c | 15 +++
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 3afc266..f96ea8a 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -415,7 +415,7 @@ static void rockchip_spi_dma_txcb(void *data)
spin_unlock_irqrestore(rs-lock, flags);
 }
 
-static int rockchip_spi_dma_transfer(struct rockchip_spi *rs)
+static void rockchip_spi_prepare_dma(struct rockchip_spi *rs)
 {
unsigned long flags;
struct dma_slave_config rxconf, txconf;
@@ -474,8 +474,6 @@ static int rockchip_spi_dma_transfer(struct rockchip_spi 
*rs)
dmaengine_submit(txdesc);
dma_async_issue_pending(rs-dma_tx.ch);
}
-
-   return 1;
 }
 
 static void rockchip_spi_config(struct rockchip_spi *rs)
@@ -557,16 +555,17 @@ static int rockchip_spi_transfer_one(
else if (rs-rx)
rs-tmode = CR0_XFM_RO;
 
-   if (master-can_dma  master-can_dma(master, spi, xfer))
+   /* we need prepare dma before spi was enabled */
+   if (master-can_dma  master-can_dma(master, spi, xfer)) {
rs-use_dma = 1;
-   else
+   rockchip_spi_prepare_dma(rs);
+   } else {
rs-use_dma = 0;
+   }
 
rockchip_spi_config(rs);
 
-   if (rs-use_dma)
-   ret = rockchip_spi_dma_transfer(rs);
-   else
+   if (!rs-use_dma)
ret = rockchip_spi_pio_transfer(rs);
 
return ret;
-- 
1.8.3.2


--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH] ARM: dts: Switch i2c0 to 400kHz on rk3288-evb-rk808

2014-09-11 Thread Addy

On 11 Sep 2014 12:30, Doug Anderson writes:
 We should be able to talk to the PMIC at 400kHz.  No need to talk at
 the slow 100kHz.

 As measured by ftrace (with a bunch of extra patches, since cpufreq
 for rk808 hasn't landed yet):
   before this change: cpu0_set_target() = ~500us
   after this change:  cpu0_set_target() = ~300us

 Signed-off-by: Doug Anderson diand...@chromium.org
 ---
  arch/arm/boot/dts/rk3288-evb-rk808.dts | 1 +
  1 file changed, 1 insertion(+)

 diff --git a/arch/arm/boot/dts/rk3288-evb-rk808.dts 
 b/arch/arm/boot/dts/rk3288-evb-rk808.dts
 index 36db177..ff522f8 100644
 --- a/arch/arm/boot/dts/rk3288-evb-rk808.dts
 +++ b/arch/arm/boot/dts/rk3288-evb-rk808.dts
 @@ -18,6 +18,7 @@
  };
  
  i2c0 {
 + clock-frequency = 40;
   status = okay;
  
   rk808: pmic@1b {
I have tested on rk3288-pinky board, it work well. so

Reviewed-by Addy Ke addy...@rock-chips.com
Tested-by Addy Ke addy...@rock-chips.com


--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3] ARM: dts: Add sdio0 and sdio1 to the rk3288

2014-08-19 Thread Addy Ke
This patch requires that https://patchwork.kernel.org/patch/4701721/
land in order to compile.

Signed-off-by: Addy Ke addy...@rock-chips.com
---
Changes in v2:
- repost patch to match what's in Heiko's wip/v3.18-next/dts tree
  for the other dwmmc controllers
- add cd and int line, suggested by Doug Anderson
- fix up sdio1 configuration error

Changes in v3:
- sort sdio0 and sdio1 by pin number, suggested by Doug Anderson
- add ro and bkpwr line, suggested by Doug Anderson

 arch/arm/boot/dts/rk3288.dtsi | 102 ++
 1 file changed, 102 insertions(+)

diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
index 36be7bb..12c0297 100644
--- a/arch/arm/boot/dts/rk3288.dtsi
+++ b/arch/arm/boot/dts/rk3288.dtsi
@@ -88,6 +88,26 @@
status = disabled;
};
 
+   sdio0: dwmmc@ff0d {
+   compatible = rockchip,rk3288-dw-mshc;
+   clocks = cru HCLK_SDIO0, cru SCLK_SDIO0;
+   clock-names = biu, ciu;
+   fifo-depth = 0x100;
+   interrupts = GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH;
+   reg = 0xff0d 0x4000;
+   status = disabled;
+   };
+
+   sdio1: dwmmc@ff0e {
+   compatible = rockchip,rk3288-dw-mshc;
+   clocks = cru HCLK_SDIO1, cru SCLK_SDIO1;
+   clock-names = biu, ciu;
+   fifo-depth = 0x100;
+   interrupts = GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH;
+   reg = 0xff0e 0x4000;
+   status = disabled;
+   };
+
emmc: dwmmc@ff0f {
compatible = rockchip,rk3288-dw-mshc;
clocks = cru HCLK_EMMC, cru SCLK_EMMC;
@@ -508,6 +528,88 @@
};
};
 
+   sdio0 {
+   sdio0_bus1: sdio0-bus1 {
+   rockchip,pins = 4 20 RK_FUNC_1 pcfg_pull_up;
+   };
+
+   sdio0_bus4: sdio0-bus4 {
+   rockchip,pins = 4 20 RK_FUNC_1 pcfg_pull_up,
+   4 21 RK_FUNC_1 pcfg_pull_up,
+   4 22 RK_FUNC_1 pcfg_pull_up,
+   4 23 RK_FUNC_1 pcfg_pull_up;
+   };
+
+   sdio0_cmd: sdio0-cmd {
+   rockchip,pins = 4 24 RK_FUNC_1 pcfg_pull_up;
+   };
+
+   sdio0_clk: sdio0-clk {
+   rockchip,pins = 4 25 RK_FUNC_1 
pcfg_pull_none;
+   };
+
+   sdio0_cd: sdio0-cd {
+   rockchip,pins = 4 26 RK_FUNC_1 pcfg_pull_up;
+   };
+
+   sdio0_ro: sdio0-ro {
+   rockchip,pins = 4 27 RK_FUNC_1 pcfg_pull_up;
+   };
+
+   sdio0_pwr: sdio0-pwr {
+   rockchip,pins = 4 28 RK_FUNC_1 pcfg_pull_up;
+   };
+
+   sdio0_bkpwr: sdio0-bkpwr {
+   rockchip,pins = 4 29 RK_FUNC_1 pcfg_pull_up;
+   };
+
+   sdio0_int: sdio0-int {
+   rockchip,pins = 4 30 RK_FUNC_1 pcfg_pull_up;
+   };
+   };
+
+   sdio1 {
+   sdio1_bus1: sdio1-bus1 {
+   rockchip,pins = 3 24 RK_FUNC_4 pcfg_pull_up;
+   };
+
+   sdio1_bus4: sdio1-bus4 {
+   rockchip,pins = 3 24 RK_FUNC_4 pcfg_pull_up,
+   3 25 RK_FUNC_4 pcfg_pull_up,
+   3 26 RK_FUNC_4 pcfg_pull_up,
+   3 27 RK_FUNC_4 pcfg_pull_up;
+   };
+
+   sdio1_cd: sdio1-cd {
+   rockchip,pins = 3 28 RK_FUNC_4 pcfg_pull_up;
+   };
+
+   sdio1_ro: sdio1-ro {
+   rockchip,pins = 3 29 RK_FUNC_4 pcfg_pull_up;
+   };
+
+   sdio1_bkpwr: sdio1-bkpwr {
+   rockchip,pins = 3 30 RK_FUNC_4 pcfg_pull_up;
+   };
+
+   sdio1_int: sdio1-int {
+   rockchip,pins = 3 31 RK_FUNC_4 pcfg_pull_up;
+   };
+
+   sdio1_cmd: sdio1-cmd {
+   rockchip,pins = 4 6 RK_FUNC_4 pcfg_pull_up;
+   };
+
+   sdio1_clk: sdio1-clk {
+   rockchip,pins = 4 7 RK_FUNC_4 pcfg_pull_none;
+   };
+
+   sdio1_pwr: sdio1-pwr

[PATCH] spi/rockchip: fixup incorrect dma direction setting

2014-08-19 Thread Addy Ke
Signed-off-by: Addy Ke addy...@rock-chips.com
---
 drivers/spi/spi-rockchip.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index cb8fd6f..4ef3fd3 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -679,7 +679,7 @@ static int rockchip_spi_probe(struct platform_device *pdev)
rs-dma_tx.addr = (dma_addr_t)(mem-start + ROCKCHIP_SPI_TXDR);
rs-dma_rx.addr = (dma_addr_t)(mem-start + ROCKCHIP_SPI_RXDR);
rs-dma_tx.direction = DMA_MEM_TO_DEV;
-   rs-dma_tx.direction = DMA_DEV_TO_MEM;
+   rs-dma_rx.direction = DMA_DEV_TO_MEM;
 
master-can_dma = rockchip_spi_can_dma;
master-dma_tx = rs-dma_tx.ch;
-- 
1.8.3.2


--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2] ARM: dts: Add sdio0 and sdio1 to the rk3288

2014-08-18 Thread Addy Ke
This patch requires that https://patchwork.kernel.org/patch/4701721/
land in order to compile.

Signed-off-by: Addy Ke addy...@rock-chips.com
---
Changes in v2:
- repost patch to match what's in Heiko's wip/v3.18-next/dts tree
  for the other dwmmc controllers
- add cd and int line, suggested by Doug Anderson
- fix up sdio1 configuration error 

 arch/arm/boot/dts/rk3288.dtsi | 86 +++
 1 file changed, 86 insertions(+)

diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
index 36be7bb..91576ae 100644
--- a/arch/arm/boot/dts/rk3288.dtsi
+++ b/arch/arm/boot/dts/rk3288.dtsi
@@ -88,6 +88,26 @@
status = disabled;
};
 
+   sdio0: dwmmc@ff0d {
+   compatible = rockchip,rk3288-dw-mshc;
+   clocks = cru HCLK_SDIO0, cru SCLK_SDIO0;
+   clock-names = biu, ciu;
+   fifo-depth = 0x100;
+   interrupts = GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH;
+   reg = 0xff0d 0x4000;
+   status = disabled;
+   };
+
+   sdio1: dwmmc@ff0e {
+   compatible = rockchip,rk3288-dw-mshc;
+   clocks = cru HCLK_SDIO1, cru SCLK_SDIO1;
+   clock-names = biu, ciu;
+   fifo-depth = 0x100;
+   interrupts = GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH;
+   reg = 0xff0e 0x4000;
+   status = disabled;
+   };
+
emmc: dwmmc@ff0f {
compatible = rockchip,rk3288-dw-mshc;
clocks = cru HCLK_EMMC, cru SCLK_EMMC;
@@ -508,6 +528,72 @@
};
};
 
+   sdio0 {
+   sdio0_clk: sdio0-clk {
+   rockchip,pins = 4 25 RK_FUNC_1 
pcfg_pull_none;
+   };
+
+   sdio0_cmd: sdio0-cmd {
+   rockchip,pins = 4 24 RK_FUNC_1 pcfg_pull_up;
+   };
+
+   sdio0_cd: sdio0-cd {
+   rockchip,pins = 4 26 RK_FUNC_1 pcfg_pull_up;
+   };
+
+   sdio0_pwr: sdio0-pwr {
+   rockchip,pins = 4 28 RK_FUNC_1 pcfg_pull_up;
+   };
+
+   sdio0_int: sdio0-int {
+   rockchip,pins = 4 30 RK_FUNC_1 pcfg_pull_up;
+   };
+
+   sdio0_bus1: sdio0-bus1 {
+   rockchip,pins = 4 20 RK_FUNC_1 pcfg_pull_up;
+   };
+
+   sdio0_bus4: sdio0-bus4 {
+   rockchip,pins = 4 20 RK_FUNC_1 pcfg_pull_up,
+   4 21 RK_FUNC_1 pcfg_pull_up,
+   4 22 RK_FUNC_1 pcfg_pull_up,
+   4 23 RK_FUNC_1 pcfg_pull_up;
+   };
+   };
+
+   sdio1 {
+   sdio1_clk: sdio1-clk {
+   rockchip,pins = 4 7 RK_FUNC_4 pcfg_pull_none;
+   };
+
+   sdio1_cmd: sdio1-cmd {
+   rockchip,pins = 4 6 RK_FUNC_4 pcfg_pull_up;
+   };
+
+   sdio1_cd: sdio1-cd {
+   rockchip,pins = 3 28 RK_FUNC_4 pcfg_pull_up;
+   };
+
+   sdio1_pwr: sdio1-pwr {
+   rockchip,pins = 4 9 RK_FUNC_4 pcfg_pull_up;
+   };
+
+   sdio1_int: sdio1-int {
+   rockchip,pins = 3 31 RK_FUNC_4 pcfg_pull_up;
+   };
+
+   sdio1_bus1: sdio1-bus1 {
+   rockchip,pins = 3 24 RK_FUNC_4 pcfg_pull_up;
+   };
+
+   sdio1_bus4: sdio1-bus4 {
+   rockchip,pins = 3 24 RK_FUNC_4 pcfg_pull_up,
+   3 25 RK_FUNC_4 pcfg_pull_up,
+   3 26 RK_FUNC_4 pcfg_pull_up,
+   3 27 RK_FUNC_4 pcfg_pull_up;
+   };
+   };
+
emmc {
emmc_clk: emmc-clk {
rockchip,pins = 3 18 RK_FUNC_2 
pcfg_pull_none;
-- 
1.8.3.2


--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2] mmc: dw_mmc: move rockchip related code to a separate file

2014-08-18 Thread Addy Ke
To support HS200 and UHS-1, we need add a big hunk of code,
as shown in the following patches. So a separate file for
rockchip SOCs is suitable.

Signed-off-by: Addy Ke addy...@rock-chips.com
---
Changes in v2:
- Kconfig: depend on ARCH_ROCKCHIP, suggested by Bartlomiej Zolnierkiewicz
- Kconfig: depend on OF, suggested by Doug Anderson
- Not change suspend/resume code, suggested by Doug Anderson
- If pdev-dev.of_node is NULL, then return -ENODEV, suggested by Heiko Stübner

 drivers/mmc/host/Kconfig   |   9 +++
 drivers/mmc/host/Makefile  |   1 +
 drivers/mmc/host/dw_mmc-pltfm.c|  57 
 drivers/mmc/host/dw_mmc-rockchip.c | 136 +
 4 files changed, 146 insertions(+), 57 deletions(-)
 create mode 100644 drivers/mmc/host/dw_mmc-rockchip.c

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index a565254..f6095f6 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -621,6 +621,15 @@ config MMC_DW_PCI
 
  If unsure, say N.
 
+config MMC_DW_ROCKCHIP
+   tristate Rockchip specific extensions for Synopsys DW Memory Card 
Interface
+   depends on MMC_DW  ARCH_ROCKCHIP  OF
+   select MMC_DW_PLTFM
+   help
+ This selects support for Rockchip SoC specific extensions to the
+ Synopsys DesignWare Memory Card Interface driver. Select this option
+ for platforms based on RK3066, RK3188 and RK3288 SoC's.
+
 config MMC_SH_MMCIF
tristate SuperH Internal MMCIF support
depends on MMC_BLOCK
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 7f81ddf..5fce465 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -45,6 +45,7 @@ obj-$(CONFIG_MMC_DW_PLTFM)+= dw_mmc-pltfm.o
 obj-$(CONFIG_MMC_DW_EXYNOS)+= dw_mmc-exynos.o
 obj-$(CONFIG_MMC_DW_K3)+= dw_mmc-k3.o
 obj-$(CONFIG_MMC_DW_PCI)   += dw_mmc-pci.o
+obj-$(CONFIG_MMC_DW_ROCKCHIP)  += dw_mmc-rockchip.o
 obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o
 obj-$(CONFIG_MMC_JZ4740)   += jz4740_mmc.o
 obj-$(CONFIG_MMC_VUB300)   += vub300.o
diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
index b547f7a..0c56c41 100644
--- a/drivers/mmc/host/dw_mmc-pltfm.c
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -26,64 +26,11 @@
 #include dw_mmc.h
 #include dw_mmc-pltfm.h
 
-#define RK3288_CLKGEN_DIV  2
-
 static void dw_mci_pltfm_prepare_command(struct dw_mci *host, u32 *cmdr)
 {
*cmdr |= SDMMC_CMD_USE_HOLD_REG;
 }
 
-static int dw_mci_rk3288_setup_clock(struct dw_mci *host)
-{
-   host-bus_hz /= RK3288_CLKGEN_DIV;
-
-   return 0;
-}
-
-static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
-{
-   int ret;
-   unsigned int cclkin;
-   u32 bus_hz;
-
-   /*
-* cclkin: source clock of mmc controller.
-* bus_hz: card interface clock generated by CLKGEN.
-* bus_hz = cclkin / RK3288_CLKGEN_DIV;
-* ios-clock = (div == 0) ? bus_hz : (bus_hz / (2 * div))
-*
-* Note: div can only be 0 or 1
-*   if DDR50 8bit mode(only emmc work in 8bit mode),
-*   div must be set 1
-*/
-   if ((ios-bus_width == MMC_BUS_WIDTH_8) 
-   (ios-timing == MMC_TIMING_MMC_DDR52))
-   cclkin = 2 * ios-clock * RK3288_CLKGEN_DIV;
-   else
-   cclkin = ios-clock * RK3288_CLKGEN_DIV;
-
-   ret = clk_set_rate(host-ciu_clk, cclkin);
-   if (ret)
-   dev_warn(host-dev, failed to set rate %uHz\n, ios-clock);
-
-   bus_hz = clk_get_rate(host-ciu_clk) / RK3288_CLKGEN_DIV;
-   if (bus_hz != host-bus_hz) {
-   host-bus_hz = bus_hz;
-   /* force dw_mci_setup_bus() */
-   host-current_speed = 0;
-   }
-}
-
-static const struct dw_mci_drv_data rk2928_drv_data = {
-   .prepare_command= dw_mci_pltfm_prepare_command,
-};
-
-static const struct dw_mci_drv_data rk3288_drv_data = {
-   .prepare_command= dw_mci_pltfm_prepare_command,
-   .set_ios= dw_mci_rk3288_set_ios,
-   .setup_clock= dw_mci_rk3288_setup_clock,
-};
-
 static const struct dw_mci_drv_data socfpga_drv_data = {
.prepare_command= dw_mci_pltfm_prepare_command,
 };
@@ -144,10 +91,6 @@ EXPORT_SYMBOL_GPL(dw_mci_pltfm_pmops);
 
 static const struct of_device_id dw_mci_pltfm_match[] = {
{ .compatible = snps,dw-mshc, },
-   { .compatible = rockchip,rk2928-dw-mshc,
-   .data = rk2928_drv_data },
-   { .compatible = rockchip,rk3288-dw-mshc,
-   .data = rk3288_drv_data },
{ .compatible = altr,socfpga-dw-mshc,
.data = socfpga_drv_data },
{},
diff --git a/drivers/mmc/host/dw_mmc-rockchip.c 
b/drivers/mmc/host/dw_mmc-rockchip.c
new file mode 100644
index 000..f0c2cb1
--- /dev/null
+++ b/drivers/mmc/host/dw_mmc-rockchip.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2014

[PATCH] mmc: dw_mmc: move rockchip related code to a separate file

2014-08-14 Thread Addy Ke
To support HS200 and UHS-1, we need add a big hunk of code,
as shown in the following patches. So a separate file for
rockchip SOCs is suitable.

Signed-off-by: Addy Ke addy...@rock-chips.com
---
 drivers/mmc/host/Kconfig   |   9 +++
 drivers/mmc/host/Makefile  |   1 +
 drivers/mmc/host/dw_mmc-pltfm.c|  57 ---
 drivers/mmc/host/dw_mmc-rockchip.c | 146 +
 4 files changed, 156 insertions(+), 57 deletions(-)
 create mode 100644 drivers/mmc/host/dw_mmc-rockchip.c

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index a565254..ae61df6 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -621,6 +621,15 @@ config MMC_DW_PCI
 
  If unsure, say N.
 
+config MMC_DW_ROCKCHIP
+   tristate Rockchip specific extensions for Synopsys DW Memory Card 
Interface
+   depends on MMC_DW
+   select MMC_DW_PLTFM
+   help
+ This selects support for Rockchip SoC specific extensions to the
+ Synopsys DesignWare Memory Card Interface driver. Select this option
+ for platforms based on RK3066, RK3188 and RK3288 SoC's.
+
 config MMC_SH_MMCIF
tristate SuperH Internal MMCIF support
depends on MMC_BLOCK
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 7f81ddf..5fce465 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -45,6 +45,7 @@ obj-$(CONFIG_MMC_DW_PLTFM)+= dw_mmc-pltfm.o
 obj-$(CONFIG_MMC_DW_EXYNOS)+= dw_mmc-exynos.o
 obj-$(CONFIG_MMC_DW_K3)+= dw_mmc-k3.o
 obj-$(CONFIG_MMC_DW_PCI)   += dw_mmc-pci.o
+obj-$(CONFIG_MMC_DW_ROCKCHIP)  += dw_mmc-rockchip.o
 obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o
 obj-$(CONFIG_MMC_JZ4740)   += jz4740_mmc.o
 obj-$(CONFIG_MMC_VUB300)   += vub300.o
diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
index b547f7a..0c56c41 100644
--- a/drivers/mmc/host/dw_mmc-pltfm.c
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -26,64 +26,11 @@
 #include dw_mmc.h
 #include dw_mmc-pltfm.h
 
-#define RK3288_CLKGEN_DIV  2
-
 static void dw_mci_pltfm_prepare_command(struct dw_mci *host, u32 *cmdr)
 {
*cmdr |= SDMMC_CMD_USE_HOLD_REG;
 }
 
-static int dw_mci_rk3288_setup_clock(struct dw_mci *host)
-{
-   host-bus_hz /= RK3288_CLKGEN_DIV;
-
-   return 0;
-}
-
-static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
-{
-   int ret;
-   unsigned int cclkin;
-   u32 bus_hz;
-
-   /*
-* cclkin: source clock of mmc controller.
-* bus_hz: card interface clock generated by CLKGEN.
-* bus_hz = cclkin / RK3288_CLKGEN_DIV;
-* ios-clock = (div == 0) ? bus_hz : (bus_hz / (2 * div))
-*
-* Note: div can only be 0 or 1
-*   if DDR50 8bit mode(only emmc work in 8bit mode),
-*   div must be set 1
-*/
-   if ((ios-bus_width == MMC_BUS_WIDTH_8) 
-   (ios-timing == MMC_TIMING_MMC_DDR52))
-   cclkin = 2 * ios-clock * RK3288_CLKGEN_DIV;
-   else
-   cclkin = ios-clock * RK3288_CLKGEN_DIV;
-
-   ret = clk_set_rate(host-ciu_clk, cclkin);
-   if (ret)
-   dev_warn(host-dev, failed to set rate %uHz\n, ios-clock);
-
-   bus_hz = clk_get_rate(host-ciu_clk) / RK3288_CLKGEN_DIV;
-   if (bus_hz != host-bus_hz) {
-   host-bus_hz = bus_hz;
-   /* force dw_mci_setup_bus() */
-   host-current_speed = 0;
-   }
-}
-
-static const struct dw_mci_drv_data rk2928_drv_data = {
-   .prepare_command= dw_mci_pltfm_prepare_command,
-};
-
-static const struct dw_mci_drv_data rk3288_drv_data = {
-   .prepare_command= dw_mci_pltfm_prepare_command,
-   .set_ios= dw_mci_rk3288_set_ios,
-   .setup_clock= dw_mci_rk3288_setup_clock,
-};
-
 static const struct dw_mci_drv_data socfpga_drv_data = {
.prepare_command= dw_mci_pltfm_prepare_command,
 };
@@ -144,10 +91,6 @@ EXPORT_SYMBOL_GPL(dw_mci_pltfm_pmops);
 
 static const struct of_device_id dw_mci_pltfm_match[] = {
{ .compatible = snps,dw-mshc, },
-   { .compatible = rockchip,rk2928-dw-mshc,
-   .data = rk2928_drv_data },
-   { .compatible = rockchip,rk3288-dw-mshc,
-   .data = rk3288_drv_data },
{ .compatible = altr,socfpga-dw-mshc,
.data = socfpga_drv_data },
{},
diff --git a/drivers/mmc/host/dw_mmc-rockchip.c 
b/drivers/mmc/host/dw_mmc-rockchip.c
new file mode 100644
index 000..3d86ef3
--- /dev/null
+++ b/drivers/mmc/host/dw_mmc-rockchip.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
+ * Author: addy ke addy...@rock-chips.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License

Re: [PATCH] ARM: dts: Add mmc0 and mmc1 aliases for rk3288

2014-08-13 Thread Addy

 It's convenient (and less confusing to people reading logs) if the
 eMMC port on rk3288 is consistenly marked with mmc0 and the sdmmc port
 on rk3288 is consistently marked with mmc1.  Add the appropriate
 aliases.

 These aliases only actually do something if a patch like
 (https://patchwork.kernel.org/patch/3925551/) lands, but they don't
 hurt even before that patch.

 Signed-off-by: Doug Anderson diand...@chromium.org
 Reviewed-by: Sonny Rao sonny...@chromium.org
 ---
  arch/arm/boot/dts/rk3288.dtsi | 2 ++
  1 file changed, 2 insertions(+)

 diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
 index 36be7bb..0b54b0d 100644
 --- a/arch/arm/boot/dts/rk3288.dtsi
 +++ b/arch/arm/boot/dts/rk3288.dtsi
 @@ -29,6 +29,8 @@
   i2c3 = i2c3;
   i2c4 = i2c4;
   i2c5 = i2c5;
 + mmc0 = emmc;
 + mmc1 = sdmmc;
There are 8 registers can be configured for clock tunning(see chapter 3,
page 133):
sdmmc: CRU_SDMMC_CON0(offset: 0x200)
CRU_SDMMC_CON1(offset: 0x204)
sdio0: CRU_SDMMC_CON2(offset: 0x208)
CRU_SDMMC_CON3(offset: 0x20c)
sdio1: CRU_SDMMC_CON4(offset: 0x210)
CRU_SDMMC_CON5(offset: 0x214)
emmc: CRU_SDMMC_CON6(offset: 0x218)
CRU_SDMMC_CON7(offset: 0x21c)

I think maybe it is suitable as follows:
mmc0 = sdmmc
mmc1 = sdio0
mmc2 = sdio1
mmc3 = emmc

So we can get ctrl_id:
ctrl_id = of_alias_get_id(host-dev-of_node, mshc);

and can get offset of registers:
offset = 0x200 + ctrl_id * 8 + 4 * drive_or_sample

   serial0 = uart0;
   serial1 = uart1;
   serial2 = uart2;


--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH] ARM: dts: Add mmc0 and mmc1 aliases for rk3288

2014-08-13 Thread addy ke
 Addy,
 
 On Wed, Aug 13, 2014 at 6:57 PM, Addy addy...@rock-chips.com wrote:
 
 I think maybe it is suitable as follows:
 mmc0 = sdmmc
 mmc1 = sdio0
 mmc2 = sdio1
 mmc3 = emmc
 
 Right, except the only ones that have landed in Heiko's tree are sdmmc
 and emmc, so we can't do sdio0 and sdio1 yet.  You could post support
 for sdio0 and adio1?

yes, I will post it today.
 
 Also: it's really handy if emmc is 0.  See below: I don't think it's
 great to use the ID to find the sysconfig registers.
 
 
 So we can get ctrl_id:
 ctrl_id = of_alias_get_id(host-dev-of_node, mshc);
 
 Somehow I hadn't realized that was there.  I guess we could use that
 too.  I'd vote to remove that and use the standard mmc numbering
 (and get some momentum to land those patches).  If you want I'll
 repost using the mshc stuff, though.
 
 
 and can get offset of registers:
 offset = 0x200 + ctrl_id * 8 + 4 * drive_or_sample
 
 I thought the plan was to actually implement the phase stuff as a clock 
 driver.
 
 ...even if we didn't, I'd rather not rely on ID like this to find the
 right address.  It's really non-obvious.
 
 
 

--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] ARM: dts: Add sdio0 and sdio1 to the rk3288

2014-08-13 Thread Addy Ke
Signed-off-by: Addy Ke addy...@rock-chips.com
---
 arch/arm/boot/dts/rk3288.dtsi | 76 +++
 1 file changed, 76 insertions(+)

diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
index 7a9173d..a440869 100644
--- a/arch/arm/boot/dts/rk3288.dtsi
+++ b/arch/arm/boot/dts/rk3288.dtsi
@@ -120,6 +120,32 @@
//fifo-depth = 0x100;
};
 
+   sdio0: dwmmc@ff0d {
+   compatible = rockchip,rk3288-dw-mshc;
+   reg = 0xff0d 0x4000;
+   interrupts = GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH;
+   #address-cells = 1;
+   #size-cells = 0;
+
+   clocks = cru HCLK_SDIO0, cru SCLK_SDIO0;
+   clock-names = biu, ciu;
+
+   fifo-depth = 0x100;
+   };
+
+   sdio1: dwmmc@ff0e {
+   compatible = rockchip,rk3288-dw-mshc;
+   reg = 0xff0e 0x4000;
+   interrupts = GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH;
+   #address-cells = 1;
+   #size-cells = 0;
+
+   clocks = cru HCLK_SDIO1, cru SCLK_SDIO1;
+   clock-names = biu, ciu;
+
+   fifo-depth = 0x100;
+   };
+
emmc: dwmmc@ff0f {
compatible = rockchip,rk3288-dw-mshc;
reg = 0xff0f 0x4000;
@@ -589,6 +615,56 @@
};
};
 
+   sdio0 {
+   sdio0_clk: sdio0-clk {
+   rockchip,pins = 4 25 RK_FUNC_1 
pcfg_pull_none;
+   };
+
+   sdio0_cmd: sdio0-cmd {
+   rockchip,pins = 4 24 RK_FUNC_1 pcfg_pull_up;
+   };
+
+   sdio0_pwr: sdio0-pwr {
+   rockchip,pins = 4 28 RK_FUNC_1 pcfg_pull_up;
+   };
+
+   sdio0_bus1: sdio0-bus1 {
+   rockchip,pins = 4 20 RK_FUNC_1 pcfg_pull_up;
+   };
+
+   sdio0_bus4: sdio0-bus4 {
+   rockchip,pins = 4 20 RK_FUNC_1 pcfg_pull_up,
+   4 21 RK_FUNC_1 pcfg_pull_up,
+   4 22 RK_FUNC_1 pcfg_pull_up,
+   4 23 RK_FUNC_1 pcfg_pull_up;
+   };
+   };
+
+   sdio1 {
+   sdio1_clk: sdio1-clk {
+   rockchip,pins = 4 7 RK_FUNC_4 pcfg_pull_none;
+   };
+
+   sdio1_cmd: sdio1-cmd {
+   rockchip,pins = 4 6 RK_FUNC_4 pcfg_pull_up;
+   };
+
+   sdio1_pwr: sdio1-pwr {
+   rockchip,pins = 4 9 RK_FUNC_4 pcfg_pull_up;
+   };
+
+   sdio1_bus1: sdio1-bus1 {
+   rockchip,pins = 4 24 RK_FUNC_4 pcfg_pull_up;
+   };
+
+   sdio1_bus4: sdio1-bus4 {
+   rockchip,pins = 3 24 RK_FUNC_4 pcfg_pull_up,
+   3 25 RK_FUNC_4 pcfg_pull_up,
+   3 26 RK_FUNC_4 pcfg_pull_up,
+   3 27 RK_FUNC_4 pcfg_pull_up;
+   };
+   };
+
emmc {
emmc_clk: emmc-clk {
rockchip,pins = 3 18 RK_FUNC_2 
pcfg_pull_none;
-- 
1.8.3.2


--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 0/4] patches for rockchip spi driver

2014-07-10 Thread Addy Ke
From: Addy Ke addy...@rockchip.com

These patches based on:
- git: kernel/git/broonie/spi.git
- branch: topic/rockchip
- commit: c15369087ae5c7db7f3e3604822eac6ab87429bd

Addy Ke (4):
  spi/rockchip: cleanup some coding issues and uncessary output
  spi/rockchip: call wait_for_idle() for the transfer to complete
  spi/rockchip: master-mode_bits: remove SPI_CS_HIGH bit
  spi/rockchip: add compatible strings for RK3188 and RK3288

 drivers/spi/spi-rockchip.c | 74 --
 1 file changed, 45 insertions(+), 29 deletions(-)

-- 
1.8.3.2


--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 1/4] spi/rockchip: cleanup some coding issues and uncessary output

2014-07-10 Thread Addy Ke
From: Addy Ke addy...@rockchip.com

Suggested-by: Mark Brown broo...@kernel.org
Signed-off-by: Addy Ke addy...@rockchip.com
---
 drivers/spi/spi-rockchip.c | 41 +++--
 1 file changed, 23 insertions(+), 18 deletions(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 72fb287..8c24708 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
- * Author: addy ke addy...@rock-chips.com
+ * Author: Addy Ke addy...@rock-chips.com
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -186,7 +186,7 @@ struct rockchip_spi {
void *rx_end;
 
u32 state;
-
+   /* protect state */
spinlock_t lock;
 
struct completion xfer_completion;
@@ -278,7 +278,7 @@ static void rockchip_spi_set_cs(struct spi_device *spi, 
bool enable)
 }
 
 static int rockchip_spi_prepare_message(struct spi_master *master,
-   struct spi_message *msg)
+   struct spi_message *msg)
 {
struct rockchip_spi *rs = spi_master_get_devdata(master);
struct spi_device *spi = msg-spi;
@@ -294,13 +294,19 @@ static int rockchip_spi_prepare_message(struct spi_master 
*master,
 }
 
 static int rockchip_spi_unprepare_message(struct spi_master *master,
-   struct spi_message *msg)
+ struct spi_message *msg)
 {
unsigned long flags;
struct rockchip_spi *rs = spi_master_get_devdata(master);
 
spin_lock_irqsave(rs-lock, flags);
 
+   /*
+* For DMA mode, we need terminate DMA channel and flush
+* fifo for the next transfer if DMA thansfer timeout.
+* unprepare_message() was called by core if transfer complete
+* or timeout. Maybe it is reasonable for error handling here.
+*/
if (rs-use_dma) {
if (rs-state  RXBUSY) {
dmaengine_terminate_all(rs-dma_rx.ch);
@@ -344,7 +350,7 @@ static void rockchip_spi_pio_reader(struct rockchip_spi *rs)
else
*(u16 *)(rs-rx) = (u16)rxw;
rs-rx += rs-n_bytes;
-   };
+   }
 }
 
 static int rockchip_spi_pio_transfer(struct rockchip_spi *rs)
@@ -414,7 +420,8 @@ static int rockchip_spi_dma_transfer(struct rockchip_spi 
*rs)
rxconf.src_maxburst = rs-n_bytes;
dmaengine_slave_config(rs-dma_rx.ch, rxconf);
 
-   rxdesc = dmaengine_prep_slave_sg(rs-dma_rx.ch,
+   rxdesc = dmaengine_prep_slave_sg(
+   rs-dma_rx.ch,
rs-rx_sg.sgl, rs-rx_sg.nents,
rs-dma_rx.direction, DMA_PREP_INTERRUPT);
 
@@ -429,7 +436,8 @@ static int rockchip_spi_dma_transfer(struct rockchip_spi 
*rs)
txconf.dst_maxburst = rs-n_bytes;
dmaengine_slave_config(rs-dma_tx.ch, txconf);
 
-   txdesc = dmaengine_prep_slave_sg(rs-dma_tx.ch,
+   txdesc = dmaengine_prep_slave_sg(
+   rs-dma_tx.ch,
rs-tx_sg.sgl, rs-tx_sg.nents,
rs-dma_tx.direction, DMA_PREP_INTERRUPT);
 
@@ -495,13 +503,13 @@ static void rockchip_spi_config(struct rockchip_spi *rs)
 
spi_set_clk(rs, div);
 
-   dev_dbg(rs-dev, cr0 0x%x, div %d\n,
-   cr0, div);
+   dev_dbg(rs-dev, cr0 0x%x, div %d\n, cr0, div);
 
spi_enable_chip(rs, 1);
 }
 
-static int rockchip_spi_transfer_one(struct spi_master *master,
+static int rockchip_spi_transfer_one(
+   struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *xfer)
 {
@@ -556,8 +564,8 @@ static int rockchip_spi_transfer_one(struct spi_master 
*master,
 }
 
 static bool rockchip_spi_can_dma(struct spi_master *master,
-   struct spi_device *spi,
-   struct spi_transfer *xfer)
+struct spi_device *spi,
+struct spi_transfer *xfer)
 {
struct rockchip_spi *rs = spi_master_get_devdata(master);
 
@@ -572,10 +580,9 @@ static int rockchip_spi_probe(struct platform_device *pdev)
struct resource *mem;
 
master = spi_alloc_master(pdev-dev, sizeof(struct rockchip_spi));
-   if (!master) {
-   dev_err(pdev-dev, No memory for spi_master\n);
+   if (!master)
return -ENOMEM;
-   }
+
platform_set_drvdata(pdev, master);
 
rs = spi_master_get_devdata(master);
@@ -676,8 +683,6 @@ static int rockchip_spi_probe(struct platform_device *pdev)
goto err_register_master;
}
 
-   dev_info(pdev-dev, Rockchip SPI controller initialized\n);
-
return

[PATCH 3/4] spi/rockchip: master-mode_bits: remove SPI_CS_HIGH bit

2014-07-10 Thread Addy Ke
From: Addy Ke addy...@rockchip.com

Suggested-by: Jonas Gorski j...@openwrt.org
Signed-off-by: Addy Ke addy...@rockchip.com
---
 drivers/spi/spi-rockchip.c | 7 +--
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 09c690c..a8866c9 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -295,11 +295,6 @@ static int rockchip_spi_prepare_message(struct spi_master 
*master,
struct rockchip_spi *rs = spi_master_get_devdata(master);
struct spi_device *spi = msg-spi;
 
-   if (spi-mode  SPI_CS_HIGH) {
-   dev_err(rs-dev, spi_cs_hign: not support\n);
-   return -EINVAL;
-   }
-
rs-mode = spi-mode;
 
return 0;
@@ -657,7 +652,7 @@ static int rockchip_spi_probe(struct platform_device *pdev)
 
master-auto_runtime_pm = true;
master-bus_num = pdev-id;
-   master-mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
+   master-mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP;
master-num_chipselect = 2;
master-dev.of_node = pdev-dev.of_node;
master-bits_per_word_mask = SPI_BPW_MASK(16) | SPI_BPW_MASK(8);
-- 
1.8.3.2


--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 4/4] spi/rockchip: add compatible strings for RK3188 and RK3288

2014-07-10 Thread Addy Ke
From: Addy Ke addy...@rockchip.com

Suggested-by: Mark Brown broo...@kernel.org
Signed-off-by: Addy Ke addy...@rockchip.com
---
 drivers/spi/spi-rockchip.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index a8866c9..cb8fd6f 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -814,6 +814,8 @@ static const struct dev_pm_ops rockchip_spi_pm = {
 
 static const struct of_device_id rockchip_spi_dt_match[] = {
{ .compatible = rockchip,rk3066-spi, },
+   { .compatible = rockchip,rk3188-spi, },
+   { .compatible = rockchip,rk3288-spi, },
{ },
 };
 MODULE_DEVICE_TABLE(of, rockchip_spi_dt_match);
-- 
1.8.3.2


--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2] mmc: dw_mmc: add support for RK3288

2014-07-09 Thread Addy Ke
This patch focuses on clock setting for RK3288 mmc controller.

In RK3288 mmc controller, CLKDIV register can only be set 0 or 1,
and if DDR 8bit mode, CLKDIV register must be set 1.

Signed-off-by: Addy Ke addy...@rock-chips.com
---
changes since v1:
- dw_mci_rk3288_setup_clock: do not call clk_get_rate(), just use the
  host-bus_hz which is already called by dw_mmc.c, suggested by Jaehoon Chung

 .../devicetree/bindings/mmc/rockchip-dw-mshc.txt   |  4 +-
 drivers/mmc/host/dw_mmc-pltfm.c| 50 +-
 2 files changed, 51 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt 
b/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt
index c559f3f..e3f95cd 100644
--- a/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt
+++ b/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt
@@ -10,7 +10,9 @@ extensions to the Synopsys Designware Mobile Storage Host 
Controller.
 Required Properties:
 
 * compatible: should be
-   - rockchip,rk2928-dw-mshc: for Rockchip RK2928 and following
+   - rockchip,rk2928-dw-mshc: for Rockchip RK2928 and following,
+   before RK3288
+   - rockchip,rk3288-dw-mshc: for Rockchip RK3288
 
 Example:
 
diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
index d4a47a9..809c28b 100644
--- a/drivers/mmc/host/dw_mmc-pltfm.c
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -21,17 +21,61 @@
 #include linux/mmc/mmc.h
 #include linux/mmc/dw_mmc.h
 #include linux/of.h
+#include linux/clk.h
 
 #include dw_mmc.h
 #include dw_mmc-pltfm.h
 
+#define RK3288_CLKGEN_DIV  2
+
 static void dw_mci_pltfm_prepare_command(struct dw_mci *host, u32 *cmdr)
 {
*cmdr |= SDMMC_CMD_USE_HOLD_REG;
 }
 
-static const struct dw_mci_drv_data rockchip_drv_data = {
+static int dw_mci_rk3288_setup_clock(struct dw_mci *host)
+{
+   host-bus_hz /= RK3288_CLKGEN_DIV;
+
+   return 0;
+}
+
+static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
+{
+   int ret;
+   unsigned int cclkin;
+
+   /*
+* cclkin: source clock of mmc controller.
+* bus_hz: card interface clock generated by CLKGEN.
+* bus_hz = cclkin / RK3288_CLKGEN_DIV;
+* ios-clock = (div == 0) ? bus_hz : (bus_hz / (2 * div))
+*
+* Note: div can only be 0 or 1
+*   if DDR50 8bit mode, div must be set 1
+*/
+   if ((ios-bus_width == MMC_BUS_WIDTH_8) 
+   (ios-timing == MMC_TIMING_UHS_DDR50 ||
+ios-timing == MMC_TIMING_MMC_DDR52))
+   cclkin = 2 * ios-clock * RK3288_CLKGEN_DIV;
+   else
+   cclkin = ios-clock * RK3288_CLKGEN_DIV;
+
+   ret = clk_set_rate(host-ciu_clk, cclkin);
+   if (ret)
+   dev_warn(host-dev, failed to set rate %uHz\n, ios-clock);
+
+   host-bus_hz = clk_get_rate(host-ciu_clk) / RK3288_CLKGEN_DIV;
+}
+
+static const struct dw_mci_drv_data rk2928_drv_data = {
+   .prepare_command= dw_mci_pltfm_prepare_command,
+};
+
+static const struct dw_mci_drv_data rk3288_drv_data = {
.prepare_command= dw_mci_pltfm_prepare_command,
+   .set_ios= dw_mci_rk3288_set_ios,
+   .setup_clock= dw_mci_rk3288_setup_clock,
 };
 
 static const struct dw_mci_drv_data socfpga_drv_data = {
@@ -95,7 +139,9 @@ EXPORT_SYMBOL_GPL(dw_mci_pltfm_pmops);
 static const struct of_device_id dw_mci_pltfm_match[] = {
{ .compatible = snps,dw-mshc, },
{ .compatible = rockchip,rk2928-dw-mshc,
-   .data = rockchip_drv_data },
+   .data = rk2928_drv_data },
+   { .compatible = rockchip,rk3288-dw-mshc,
+   .data = rk3288_drv_data },
{ .compatible = altr,socfpga-dw-mshc,
.data = socfpga_drv_data },
{},
-- 
1.8.3.2


--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3 2/2] spi: add driver for Rockchip RK3xxx SoCs integrated SPI

2014-07-07 Thread Addy Ke
In order to facilitate understanding, rockchip SPI controller IP design
looks similar in its registers to designware. But IC implementation
is different from designware, So we need a dedicated driver for Rockchip
RK3XXX SoCs integrated SPI. The main differences:

- dma request line: rockchip SPI controller have two DMA request line
  for tx and rx.

- Register offset:
  RK3288DW

  SPI_CTRLR0  0x0x
  SPI_CTRLR1  0x00040x0004
  SPI_SSIENR  0x00080x0008
  SPI_MWCRNONE  0x000c
  SPI_SER 0x000c0x0010
  SPI_BAUDR   0x00100x0014
  SPI_TXFTLR  0x00140x0018
  SPI_RXFTLR  0x00180x001c
  SPI_TXFLR   0x001c0x0020
  SPI_RXFLR   0x00200x0024
  SPI_SR  0x00240x0028
  SPI_IPR 0x0028NONE
  SPI_IMR 0x002c0x002c
  SPI_ISR 0x00300x0030
  SPI_RISR0x00340x0034
  SPI_TXOICR  NONE  0x0038
  SPI_RXOICR  NONE  0x003c
  SPI_RXUICR  NONE  0x0040
  SPI_MSTICR  NONE  0x0044
  SPI_ICR 0x00380x0048
  SPI_DMACR   0x003c0x004c
  SPI_DMATDLR 0x00400x0050
  SPI_DMARDLR 0x00440x0054
  SPI_TXDR0x0400NONE
  SPI_RXDR0x0800NONE
  SPI_IDR NONE  0x0058
  SPI_VERSION NONE  0x005c
  SPI_DR  NONE  0x0060

- register configuration:
  RK3288  DW
  - SPI_CTROL0:
control frame sizebit[5:2]bit[15:12]
shift register loop   NONEbit[11]
transfer mode bit[19:18]  bit[9:8]
frame format  bit[17:16]  bit[5:4]
data frame size   bit[1:0]bit[3:0]
 
  For more information, see RK3288 chip manual.

- Wait for idle: Must ensure that the FIFO data has been sent out
  before the next transfer.

Signed-off-by: Addy Ke addy...@rock-chips.com
---
changes since v1:
- more specific about the differences according to comments from Mark Brown
- not to cast away const according to comments from Mark Brown
- add set_cs() operation provided to the core
- change rockchip_spi_hw_init() to get_fifo_len() 
- remove spi_setup() and spi_clean() operations
- remove wait_for_dma(), replaced by calling spi_finalize_current_transfer() 
when done
- remove wait_for_not_busy(), replaced by setting xfer-delay_usecs
- remove interrupt handler
- call clk_disable_unprepare() if spi_master_resume() failed

changes since v2:
- Kconfig: add depends on (ARCH_ROCKCHIP || COMPILE_TEST) for SPI_ROCKCHIP
- use wait_for_idle and do not set xfer-delay_uses suggested by Mark Brown
- master-mode_bits: remove SPI_CS_HIGH bit, according to comments from Jonas 
Gorski
- remove some log information suggested by Mark Brown
- remove Unneeded semicolon
- add compatible strings for RK3188 and RK3288
- improve differences between RK3288 and DW, provided by IC engineer. 
- fixed some warning checked by ./scripts/checkpatch.pl --strict

 drivers/spi/Kconfig|  12 +
 drivers/spi/Makefile   |   1 +
 drivers/spi/spi-rockchip.c | 837 +
 3 files changed, 850 insertions(+)
 create mode 100644 drivers/spi/spi-rockchip.c

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 60f2b41..c4e307b 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -375,6 +375,18 @@ config SPI_PXA2XX
 config SPI_PXA2XX_PCI
def_tristate SPI_PXA2XX  PCI
 
+config SPI_ROCKCHIP
+   tristate Rockchip SPI controller driver
+   depends on (ARCH_ROCKCHIP || COMPILE_TEST)
+   help
+ This selects a driver for Rockchip SPI controller.
+
+ If you say yes to this option, support will be included for
+ RK3066, RK3188 and RK3288 families of SPI controller.
+ Rockchip SPI controller support DMA transport and PIO mode.
+ The main usecase of this controller is to use spi flash as boot
+ device.
+
 config SPI_RSPI
tristate Renesas RSPI/QSPI controller
depends on (SUPERH  SH_DMAE_BASE) || ARCH_SHMOBILE
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index bd79266..361fbf3 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -60,6 +60,7 @@ spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_DMA)  += 
spi-pxa2xx-dma.o
 obj-$(CONFIG_SPI_PXA2XX)   += spi-pxa2xx-platform.o
 obj-$(CONFIG_SPI_PXA2XX_PCI)   += spi-pxa2xx-pci.o
 obj-$(CONFIG_SPI_QUP)  += spi-qup.o
+obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o
 obj-$(CONFIG_SPI_RSPI) += spi-rspi.o
 obj-$(CONFIG_SPI_S3C24XX)  += spi-s3c24xx-hw.o
 spi-s3c24xx-hw-y   := spi-s3c24xx.o
diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
new file mode 100644
index 000..488a7b8
--- /dev/null
+++ b/drivers/spi/spi-rockchip.c
@@ -0,0 +1,837 @@
+/*
+ * Copyright (c

Re: [PATCH v2 2/2] spi: add driver for Rockchip RK3xxx SoCs integrated SPI

2014-07-06 Thread addy ke
 On Tue, Jul 01, 2014 at 09:03:59AM +0800, addy ke wrote:
 In order to facilitate understanding, rockchip SPI controller IP design
 looks similar in its registers to designware. But IC implementation
 is different from designware, So we need a dedicated driver for Rockchip
 RK3XXX SoCs integrated SPI. The main differences:
 
 This looks good overall, a nice clean driver.  I've applied it but there
 are a few small issues that need fixing up which I've noted below, can
 you please send followup patches dealing with these?
 
 + * static void spi_set_cs(struct spi_device *spi, bool enable)
 + * {
 + *  if (spi-mode  SPI_CS_HIGH)
 + *  enable = !enable;
 + *
 + *  if (spi-cs_gpio = 0)
 + *  gpio_set_value(spi-cs_gpio, !enable);
 + *  else if (spi-master-set_cs)
 + *  spi-master-set_cs(spi, !enable);
 + * }
 + *
 + * Note: enable(rockchip_spi_set_cs) = !enable(spi_set_cs)
 + */
 
 So, the point here is that chip select is an active low signal by
 default which means that if chip select is asserted we have a low logic
 level and the parameter means asserted not logic level for the
 output.  It doesn't really matter but it might be clearer to say so
 directly.
 
 +if (spi-mode  SPI_CS_HIGH) {
 +dev_err(rs-dev, spi_cs_hign: not support\n);
 +return -EINVAL;
 
 Typo here (high).
 
 +static int rockchip_spi_unprepare_message(struct spi_master *master,
 +struct spi_message *msg)
 +{
 +unsigned long flags;
 +struct rockchip_spi *rs = spi_master_get_devdata(master);
 +
 +spin_lock_irqsave(rs-lock, flags);
 +
 +if (rs-use_dma) {
 +if (rs-state  RXBUSY) {
 +dmaengine_terminate_all(rs-dma_rx.ch);
 +flush_fifo(rs);
 +}
 +
 +if (rs-state  TXBUSY)
 +dmaengine_terminate_all(rs-dma_tx.ch);
 +}
 
 This initially looks wrong - the DMA should all be quiesced by the time
 that we get to unpreparing the hardware, otherwise the transfer might be
 ongoing while the chip select is deasserted.  However this is really
 just error handling in case something went wrong which is sensible and
 reasonable, a comment explaining this would help so can you please send
 a followup patch adding one.
 
 The error handling here is actually a good point - we should probably
 add a callback for the core to use when it times out since the issue
 also applies if there are further transactions queued with the hardware.
 I'll look into that later unless someone does it first.
 
 +/* Delay until the FIFO data completely */
 +if (xfer-tx_buf)
 +xfer-delay_usecs
 += rs-fifo_len * rs-bpw * 100 / rs-speed;
 
 The driver shouldn't be doing this, if it needs a delay it needs to
 implement it itself.  delay_usecs can be set by devices if they need a
 delay between transfers, it should be in addition to the time taken for
 the transfer to complete.
 
 Please send a followup patch fixing this.
 
Are the following modifications reasonable?

+static inline void wait_for_idle(struct rockchip_spi *rs)
+{
+unsigned long timeout = jiffies + msecs_to_jiffies(5);
+
+while (time_before(jiffies, timeout)) {
+if (!(readl_relaxed(rs-regs + ROCKCHIP_SPI_SR)  SR_BUSY))
+return;
+}
+
+dev_warn(rs-dev, spi controller is in busy state!\n);
+}

static int rockchip_spi_pio_transfer(struct rockchip_spi *rs)
{
int remain = 0;

do {
if (rs-tx) {
remain = rs-tx_end - rs-tx;
rockchip_spi_pio_writer(rs);
}

if (rs-rx) {
remain = rs-rx_end - rs-rx;
rockchip_spi_pio_reader(rs);
}

cpu_relax();
} while (remain);

+/* If tx, wait until the FIFO data completely. */
+if (rs-tx)
+wait_for_idle(rs);

return 0;
}

static void rockchip_spi_dma_txcb(void *data)
{
unsigned long flags;
struct rockchip_spi *rs = data;

+/* Wait until the FIFO data completely. */
+wait_for_idle(rs);

spin_lock_irqsave(rs-lock, flags);

rs-state = ~TXBUSY;
if (!(rs-state  RXBUSY))
spi_finalize_current_transfer(rs-master);

spin_unlock_irqrestore(rs-lock, flags);
}

 +static bool rockchip_spi_can_dma(struct spi_master *master,
 +struct spi_device *spi,
 +struct spi_transfer *xfer)
 +{
 +struct rockchip_spi *rs = spi_master_get_devdata(master);
 +
 +return (xfer-len  rs-fifo_len);
 +}
 
 We should factor this out into the core as well, just let the driver set
 the minimum size for DMA since it's such a common pattern.  I'll look
 into this as well.
 
 +master

Re: [PATCH] mmc: dw_mmc: add support for RK3288.

2014-07-06 Thread addy ke
 Hi, Addy,
 
 On 07/05/2014 09:59 PM, addy ke wrote:
 This patch focuses on clock setting for RK3288 mmc controller.

 In RK3288 mmc controller, CLKDIV register can only be set 0 or 1,
 and if DDR 8bit mode, CLKDIV register must be set 1.

 Signed-off-by: addy ke addy...@rock-chips.com
 ---
  .../devicetree/bindings/mmc/rockchip-dw-mshc.txt   |  4 +-
  drivers/mmc/host/dw_mmc-pltfm.c| 50 
 +-
  2 files changed, 51 insertions(+), 3 deletions(-)

 diff --git a/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt 
 b/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt
 index c559f3f..e3f95cd 100644
 --- a/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt
 +++ b/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt
 @@ -10,7 +10,9 @@ extensions to the Synopsys Designware Mobile Storage Host 
 Controller.
  Required Properties:
  
  * compatible: should be
 -- rockchip,rk2928-dw-mshc: for Rockchip RK2928 and following
 +- rockchip,rk2928-dw-mshc: for Rockchip RK2928 and following,
 +before RK3288
 +- rockchip,rk3288-dw-mshc: for Rockchip RK3288
  
  Example:
  
 diff --git a/drivers/mmc/host/dw_mmc-pltfm.c 
 b/drivers/mmc/host/dw_mmc-pltfm.c
 index d4a47a9..15d796e 100644
 --- a/drivers/mmc/host/dw_mmc-pltfm.c
 +++ b/drivers/mmc/host/dw_mmc-pltfm.c
 @@ -21,17 +21,61 @@
  #include linux/mmc/mmc.h
  #include linux/mmc/dw_mmc.h
  #include linux/of.h
 +#include linux/clk.h
  
  #include dw_mmc.h
  #include dw_mmc-pltfm.h
  
 +#define RK3288_CLKGEN_DIV   2
 2 is used to the general div value at rockchip?
 
Yes, In RK3288, the div generated by CLKGEN is 2 and can not be changed by 
software.
 +
  static void dw_mci_pltfm_prepare_command(struct dw_mci *host, u32 *cmdr)
  {
  *cmdr |= SDMMC_CMD_USE_HOLD_REG;
  }
  
 -static const struct dw_mci_drv_data rockchip_drv_data = {
 +static int dw_mci_rk3288_setup_clock(struct dw_mci *host)
 +{
 +host-bus_hz = clk_get_rate(host-ciu_clk) / RK3288_CLKGEN_DIV;
 I knew that you need not to call clk_get_rate(). In dw-mmc.c, it's already 
 called.
 So you can just use the host-bus_hz.
 
 host-bus_hz /= RK3288_CLKGEN_DIV;
 
 Best Regards,
 Jaehoon Chung
 
 +
 +return 0;
 +}
 +
 +static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
 +{
 +int ret;
 +unsigned int cclkin;
 +
 +/*
 + * cclkin: source clock of mmc controller.
 + * bus_hz: card interface clock generated by CLKGEN.
 + * bus_hz = cclkin / RK3288_CLKGEN_DIV;
 + * ios-clock = (div == 0) ? bus_hz : (bus_hz / (2 * div))
 + *
 + * Note: div can only be 0 or 1
 + *   if DDR50 8bit mode, div must be set 1
 + */
 +if ((ios-bus_width == MMC_BUS_WIDTH_8) 
 +(ios-timing == MMC_TIMING_UHS_DDR50 ||
 + ios-timing == MMC_TIMING_MMC_DDR52))
 +cclkin = 2 * ios-clock * RK3288_CLKGEN_DIV;
 +else
 +cclkin = ios-clock * RK3288_CLKGEN_DIV;
 +
 +ret = clk_set_rate(host-ciu_clk, cclkin);
 +if (ret)
 +dev_warn(host-dev, failed to set rate %uHz\n, ios-clock);
 +
 +host-bus_hz = clk_get_rate(host-ciu_clk) / RK3288_CLKGEN_DIV;
 +}
 +
 +static const struct dw_mci_drv_data rk2928_drv_data = {
 +.prepare_command= dw_mci_pltfm_prepare_command,
 +};
 +
 +static const struct dw_mci_drv_data rk3288_drv_data = {
  .prepare_command= dw_mci_pltfm_prepare_command,
 +.set_ios= dw_mci_rk3288_set_ios,
 +.setup_clock= dw_mci_rk3288_setup_clock,
  };
  
  static const struct dw_mci_drv_data socfpga_drv_data = {
 @@ -95,7 +139,9 @@ EXPORT_SYMBOL_GPL(dw_mci_pltfm_pmops);
  static const struct of_device_id dw_mci_pltfm_match[] = {
  { .compatible = snps,dw-mshc, },
  { .compatible = rockchip,rk2928-dw-mshc,
 -.data = rockchip_drv_data },
 +.data = rk2928_drv_data },
 +{ .compatible = rockchip,rk3288-dw-mshc,
 +.data = rk3288_drv_data },
  { .compatible = altr,socfpga-dw-mshc,
  .data = socfpga_drv_data },
  {},

 
 
 
 

--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] mmc: dw_mmc: add support for RK3288.

2014-07-05 Thread addy ke
This patch focuses on clock setting for RK3288 mmc controller.

In RK3288 mmc controller, CLKDIV register can only be set 0 or 1,
and if DDR 8bit mode, CLKDIV register must be set 1.

Signed-off-by: addy ke addy...@rock-chips.com
---
 .../devicetree/bindings/mmc/rockchip-dw-mshc.txt   |  4 +-
 drivers/mmc/host/dw_mmc-pltfm.c| 50 +-
 2 files changed, 51 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt 
b/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt
index c559f3f..e3f95cd 100644
--- a/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt
+++ b/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt
@@ -10,7 +10,9 @@ extensions to the Synopsys Designware Mobile Storage Host 
Controller.
 Required Properties:
 
 * compatible: should be
-   - rockchip,rk2928-dw-mshc: for Rockchip RK2928 and following
+   - rockchip,rk2928-dw-mshc: for Rockchip RK2928 and following,
+   before RK3288
+   - rockchip,rk3288-dw-mshc: for Rockchip RK3288
 
 Example:
 
diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
index d4a47a9..15d796e 100644
--- a/drivers/mmc/host/dw_mmc-pltfm.c
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -21,17 +21,61 @@
 #include linux/mmc/mmc.h
 #include linux/mmc/dw_mmc.h
 #include linux/of.h
+#include linux/clk.h
 
 #include dw_mmc.h
 #include dw_mmc-pltfm.h
 
+#define RK3288_CLKGEN_DIV  2
+
 static void dw_mci_pltfm_prepare_command(struct dw_mci *host, u32 *cmdr)
 {
*cmdr |= SDMMC_CMD_USE_HOLD_REG;
 }
 
-static const struct dw_mci_drv_data rockchip_drv_data = {
+static int dw_mci_rk3288_setup_clock(struct dw_mci *host)
+{
+   host-bus_hz = clk_get_rate(host-ciu_clk) / RK3288_CLKGEN_DIV;
+
+   return 0;
+}
+
+static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
+{
+   int ret;
+   unsigned int cclkin;
+
+   /*
+* cclkin: source clock of mmc controller.
+* bus_hz: card interface clock generated by CLKGEN.
+* bus_hz = cclkin / RK3288_CLKGEN_DIV;
+* ios-clock = (div == 0) ? bus_hz : (bus_hz / (2 * div))
+*
+* Note: div can only be 0 or 1
+*   if DDR50 8bit mode, div must be set 1
+*/
+   if ((ios-bus_width == MMC_BUS_WIDTH_8) 
+   (ios-timing == MMC_TIMING_UHS_DDR50 ||
+ios-timing == MMC_TIMING_MMC_DDR52))
+   cclkin = 2 * ios-clock * RK3288_CLKGEN_DIV;
+   else
+   cclkin = ios-clock * RK3288_CLKGEN_DIV;
+
+   ret = clk_set_rate(host-ciu_clk, cclkin);
+   if (ret)
+   dev_warn(host-dev, failed to set rate %uHz\n, ios-clock);
+
+   host-bus_hz = clk_get_rate(host-ciu_clk) / RK3288_CLKGEN_DIV;
+}
+
+static const struct dw_mci_drv_data rk2928_drv_data = {
+   .prepare_command= dw_mci_pltfm_prepare_command,
+};
+
+static const struct dw_mci_drv_data rk3288_drv_data = {
.prepare_command= dw_mci_pltfm_prepare_command,
+   .set_ios= dw_mci_rk3288_set_ios,
+   .setup_clock= dw_mci_rk3288_setup_clock,
 };
 
 static const struct dw_mci_drv_data socfpga_drv_data = {
@@ -95,7 +139,9 @@ EXPORT_SYMBOL_GPL(dw_mci_pltfm_pmops);
 static const struct of_device_id dw_mci_pltfm_match[] = {
{ .compatible = snps,dw-mshc, },
{ .compatible = rockchip,rk2928-dw-mshc,
-   .data = rockchip_drv_data },
+   .data = rk2928_drv_data },
+   { .compatible = rockchip,rk3288-dw-mshc,
+   .data = rk3288_drv_data },
{ .compatible = altr,socfpga-dw-mshc,
.data = socfpga_drv_data },
{},
-- 
1.8.3.2


--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 1/2] documentation: add rockchip spi documentation

2014-06-30 Thread addy ke
Signed-off-by: addy ke addy...@rock-chips.com
---
changes since v1:
- fix binding document according to comments from Mark Rutland
- fix address according to comments from Mark Brown
- combine all properties into Required Properties suggested by Heiko Stübner
- remove Board Specific Portion suggested by Heiko Stübner

 .../devicetree/bindings/spi/spi-rockchip.txt   | 37 ++
 1 file changed, 37 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/spi/spi-rockchip.txt

diff --git a/Documentation/devicetree/bindings/spi/spi-rockchip.txt 
b/Documentation/devicetree/bindings/spi/spi-rockchip.txt
new file mode 100644
index 000..7bab355
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/spi-rockchip.txt
@@ -0,0 +1,37 @@
+* Rockchip SPI Controller
+
+The Rockchip SPI controller is used to interface with various devices such as 
flash
+and display controllers using the SPI communication interface.
+
+Required Properties:
+
+- compatible: should be one of the following.
+rockchip,rk3066-spi for rk3066.
+rockchip,rk3188-spi, rockchip,rk3066-spi for rk3188.
+rockchip,rk3288-spi, rockchip,rk3066-spi for rk3288.
+- reg: physical base address of the controller and length of memory mapped
+   region.
+- interrupts: The interrupt number to the cpu. The interrupt specifier format
+  depends on the interrupt controller.
+- clocks: Must contain an entry for each entry in clock-names.
+- clock-names: Shall be spiclk for the transfer-clock, and apb_pclk for
+  the peripheral clock.
+- dmas: DMA specifiers for tx and rx dma. See the DMA client binding,
+   Documentation/devicetree/bindings/dma/dma.txt
+- dma-names: DMA request names should include tx and rx if present.
+- #address-cells: should be 1.
+- #size-cells: should be 0.
+
+Example:
+
+   spi0: spi@ff11 {
+   compatible = rockchip,rk3066-spi;
+   reg = 0xff11 0x1000;
+   dmas = pdma1 11, pdma1 12;
+   dma-names = tx, rx;
+   #address-cells = 1;
+   #size-cells = 0;
+   interrupts = GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH;
+   clocks = cru SCLK_SPI0, cru PCLK_SPI0;
+   clock-names = spiclk, apb_pclk;
+   };
-- 
1.8.3.2


--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 2/2] spi: add driver for Rockchip RK3xxx SoCs integrated SPI

2014-06-30 Thread addy ke
In order to facilitate understanding, rockchip SPI controller IP design
looks similar in its registers to designware. But IC implementation
is different from designware, So we need a dedicated driver for Rockchip
RK3XXX SoCs integrated SPI. The main differences:

- dma request line: rockchip SPI controller have two DMA request line
  for tx and rx.

- Register offset:
  RK3288dw
  SPI_CTRLR0  0x0x
  SPI_CTRLR1  0x00040x0004
  SPI_SSIENR  0x00080x0008
  SPI_MWCRNONE  0x000c
  SPI_SER 0x000c0x0010
  SPI_BAUDR   0x00100x0014
  SPI_TXFTLR  0x00140x0018
  SPI_RXFTLR  0x00180x001c
  SPI_TXFLR   0x001c0x0020
  SPI_RXFLR   0x00200x0024
  SPI_SR  0x00240x0028
  SPI_IPR 0x0028NONE
  SPI_IMR 0x002c0x002c
  SPI_ISR 0x00300x0030
  SPI_RISR0x00340x0034
  SPI_TXOICR  NONE  0x0038
  SPI_RXOICR  NONE  0x003c
  SPI_RXUICR  NONE  0x0040
  SPI_MSTICR  NONE  0x0044
  SPI_ICR 0x00380x0048
  SPI_DMACR   0x003c0x004c
  SPI_DMATDLR 0x00400x0050
  SPI_DMARDLR 0x00440x0054
  SPI_TXDR0x0400NONE
  SPI_RXDR0x0800NONE
  SPI_IDR NONE  0x0058
  SPI_VERSION NONE  0x005c
  SPI_DR  NONE  0x0060

- register configuration:
  such as SPI_CTRLRO in rockchip SPI controller:
cr0 = (CR0_BHT_8BIT  CR0_BHT_OFFSET)
| (CR0_SSD_ONE  CR0_SSD_OFFSET);
cr0 |= (rs-n_bytes  CR0_DFS_OFFSET);
cr0 |= ((rs-mode  0x3)  CR0_SCPH_OFFSET);
cr0 |= (rs-tmode  CR0_XFM_OFFSET);
cr0 |= (rs-type  CR0_FRF_OFFSET);
  For more information, see RK3288 chip manual.

- Wait for idle: Must ensure that the FIFO data has been sent out
  before the next transfer.

Signed-off-by: addy ke addy...@rock-chips.com
---
changes since v1:
- more specific about the differences according to comments from Mark Brown
- not to cast away const according to comments from Mark Brown
- add set_cs() operation provided to the core
- change rockchip_spi_hw_init() to get_fifo_len() 
- remove spi_setup() and spi_clean() operations
- remove wait_for_dma(), replaced by calling spi_finalize_current_transfer() 
when done
- remove wait_for_not_busy(), replaced by setting xfer-delay_usecs
- remove interrupt handler
- call clk_disable_unprepare() if spi_master_resume() failed

 drivers/spi/Kconfig|  11 +
 drivers/spi/Makefile   |   1 +
 drivers/spi/spi-rockchip.c | 822 +
 3 files changed, 834 insertions(+)
 create mode 100644 drivers/spi/spi-rockchip.c

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 60f2b41..5b51ab2 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -375,6 +375,17 @@ config SPI_PXA2XX
 config SPI_PXA2XX_PCI
def_tristate SPI_PXA2XX  PCI
 
+config SPI_ROCKCHIP
+   tristate Rockchip SPI controller driver
+   help
+ This selects a driver for Rockchip SPI controller.
+
+ If you say yes to this option, support will be included for
+ RK3066, RK3188 and RK3288 families of SPI controller.
+ Rockchip SPI controller support DMA transport and PIO mode.
+ The main usecase of this controller is to use spi flash as boot
+ device.
+
 config SPI_RSPI
tristate Renesas RSPI/QSPI controller
depends on (SUPERH  SH_DMAE_BASE) || ARCH_SHMOBILE
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index bd79266..361fbf3 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -60,6 +60,7 @@ spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_DMA)  += 
spi-pxa2xx-dma.o
 obj-$(CONFIG_SPI_PXA2XX)   += spi-pxa2xx-platform.o
 obj-$(CONFIG_SPI_PXA2XX_PCI)   += spi-pxa2xx-pci.o
 obj-$(CONFIG_SPI_QUP)  += spi-qup.o
+obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o
 obj-$(CONFIG_SPI_RSPI) += spi-rspi.o
 obj-$(CONFIG_SPI_S3C24XX)  += spi-s3c24xx-hw.o
 spi-s3c24xx-hw-y   := spi-s3c24xx.o
diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
new file mode 100644
index 000..72fb287
--- /dev/null
+++ b/drivers/spi/spi-rockchip.c
@@ -0,0 +1,822 @@
+/*
+ * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
+ * Author: addy ke addy...@rock-chips.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include linux

[PATCH 0/2] add rockchip spi drive

2014-06-23 Thread addy ke
Patch 1 add rockchip spi documentation
Patch 2 add driver for Rockchip RK3XXX SoCs integrated SPI.

Tested on rk3288 sdk board with polling mode and DMA mode.

addy ke (2):
  documentation: add rockchip spi documentation
  spi: add driver for Rockchip RK3xxx SoCs integrated SPI

 .../devicetree/bindings/spi/spi-rockchip.txt   |  51 ++
 drivers/spi/Kconfig|  11 +
 drivers/spi/Makefile   |   1 +
 drivers/spi/spi-rockchip.c | 894 +
 4 files changed, 957 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/spi/spi-rockchip.txt
 create mode 100644 drivers/spi/spi-rockchip.c

-- 
1.8.3.2


--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 1/2] documentation: add rockchip spi documentation

2014-06-23 Thread addy ke
Signed-off-by: addy ke addy...@rock-chips.com
---
 .../devicetree/bindings/spi/spi-rockchip.txt   | 51 ++
 1 file changed, 51 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/spi/spi-rockchip.txt

diff --git a/Documentation/devicetree/bindings/spi/spi-rockchip.txt 
b/Documentation/devicetree/bindings/spi/spi-rockchip.txt
new file mode 100644
index 000..ce9c881
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/spi-rockchip.txt
@@ -0,0 +1,51 @@
+* Rockchip SPI Controller
+
+The Rockchip SPI controller is used to interface with various devices such as 
flash
+and display controllers using the SPI communication interface.
+
+Required SoC Specific Properties:
+
+- compatible: should be one of the following.
+- rockchip,rk3066-spi: for rk3066, rk3188 and rk3288 platforms.
+- reg: physical base address of the controller and length of memory mapped
+   region.
+- interrupts: The interrupt number to the cpu. The interrupt specifier format
+  depends on the interrupt controller.
+- clocks: Must contain an entry for each entry in clock-names.
+- clock-names: Shall be spiclk for the transfer-clock, and apb_pclk for
+  the peripheral clock.
+
+Optional properties:
+- dmas: DMA specifiers for tx and rx dma. See the DMA client binding,
+   Documentation/devicetree/bindings/dma/dma.txt
+- dma-names: DMA request names should include tx and rx if present.
+
+Example:
+
+- SoC Specific Portion:
+
+   spi0: spi@ff11 {
+   compatible = rockchip,rockchip-spi;
+   reg = 0xff11 0x1000;
+   dmas = pdma1 11, pdma1 12;
+   dma-names = tx, rx;
+   #address-cells = 1;
+   #size-cells = 0;
+   interrupts = GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH;
+   pinctrl-names = default;
+   pinctrl-0 = spi0_clk spi0_tx spi0_rx spi0_cs0 spi0_cs1;
+   clocks = cru SCLK_SPI0, cru PCLK_SPI0;
+   clock-names = spiclk, apb_pclk;
+   status = disabled;
+   };
+
+- Board Specific Portion:
+
+   spi0 {
+   status = okay;
+   spi_test@00 {
+   compatible = rockchip,spi_test;
+   reg = 0;
+   spi-max-frequency = 2400;
+   };
+   };
-- 
1.8.3.2


--
To unsubscribe from this list: send the line unsubscribe devicetree in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 2/2] spi: add driver for Rockchip RK3xxx SoCs integrated SPI

2014-06-23 Thread addy ke
In order to facilitate understanding,rockchip SPI controller IP design looks
similar in its registers to designware. But IC implementation is different from
designware, such as dma request line, register offset, register configuration,
and so on.So we need a dedicated driver for Rockchip RK3XXX SoCs integrated SPI.

Signed-off-by: addy ke addy...@rock-chips.com
---
 drivers/spi/Kconfig|  11 +
 drivers/spi/Makefile   |   1 +
 drivers/spi/spi-rockchip.c | 894 +
 3 files changed, 906 insertions(+)
 create mode 100644 drivers/spi/spi-rockchip.c

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 60f2b41..5b51ab2 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -375,6 +375,17 @@ config SPI_PXA2XX
 config SPI_PXA2XX_PCI
def_tristate SPI_PXA2XX  PCI
 
+config SPI_ROCKCHIP
+   tristate Rockchip SPI controller driver
+   help
+ This selects a driver for Rockchip SPI controller.
+
+ If you say yes to this option, support will be included for
+ RK3066, RK3188 and RK3288 families of SPI controller.
+ Rockchip SPI controller support DMA transport and PIO mode.
+ The main usecase of this controller is to use spi flash as boot
+ device.
+
 config SPI_RSPI
tristate Renesas RSPI/QSPI controller
depends on (SUPERH  SH_DMAE_BASE) || ARCH_SHMOBILE
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index bd79266..361fbf3 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -60,6 +60,7 @@ spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_DMA)  += 
spi-pxa2xx-dma.o
 obj-$(CONFIG_SPI_PXA2XX)   += spi-pxa2xx-platform.o
 obj-$(CONFIG_SPI_PXA2XX_PCI)   += spi-pxa2xx-pci.o
 obj-$(CONFIG_SPI_QUP)  += spi-qup.o
+obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o
 obj-$(CONFIG_SPI_RSPI) += spi-rspi.o
 obj-$(CONFIG_SPI_S3C24XX)  += spi-s3c24xx-hw.o
 spi-s3c24xx-hw-y   := spi-s3c24xx.o
diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
new file mode 100644
index 000..bd7c218
--- /dev/null
+++ b/drivers/spi/spi-rockchip.c
@@ -0,0 +1,894 @@
+/*
+ * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
+ * Author: addy ke addy...@rock-chips.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include linux/init.h
+#include linux/module.h
+#include linux/clk.h
+#include linux/err.h
+#include linux/delay.h
+#include linux/interrupt.h
+#include linux/platform_device.h
+#include linux/slab.h
+#include linux/spi/spi.h
+#include linux/scatterlist.h
+#include linux/of.h
+#include linux/pm_runtime.h
+#include linux/io.h
+#include linux/scatterlist.h
+#include linux/dmaengine.h
+
+#define DRIVER_NAME rockchip-spi
+
+/* SPI register offsets */
+#define ROCKCHIP_SPI_CTRLR00x
+#define ROCKCHIP_SPI_CTRLR10x0004
+#define ROCKCHIP_SPI_SSIENR0x0008
+#define ROCKCHIP_SPI_SER   0x000c
+#define ROCKCHIP_SPI_BAUDR 0x0010
+#define ROCKCHIP_SPI_TXFTLR0x0014
+#define ROCKCHIP_SPI_RXFTLR0x0018
+#define ROCKCHIP_SPI_TXFLR 0x001c
+#define ROCKCHIP_SPI_RXFLR 0x0020
+#define ROCKCHIP_SPI_SR0x0024
+#define ROCKCHIP_SPI_IPR   0x0028
+#define ROCKCHIP_SPI_IMR   0x002c
+#define ROCKCHIP_SPI_ISR   0x0030
+#define ROCKCHIP_SPI_RISR  0x0034
+#define ROCKCHIP_SPI_ICR   0x0038
+#define ROCKCHIP_SPI_DMACR 0x003c
+#define ROCKCHIP_SPI_DMATDLR   0x0040
+#define ROCKCHIP_SPI_DMARDLR   0x0044
+#define ROCKCHIP_SPI_TXDR  0x0400
+#define ROCKCHIP_SPI_RXDR  0x0800
+
+/* Bit fields in CTRLR0 */
+#define CR0_DFS_OFFSET 0
+
+#define CR0_CFS_OFFSET 2
+
+#define CR0_SCPH_OFFSET6
+
+#define CR0_SCPOL_OFFSET   7
+
+#define CR0_CSM_OFFSET 8
+#define CR0_CSM_KEEP   0x0
+/* ss_n be high for half sclk_out cycles */
+#define CR0_CSM_HALF   0X1
+/* ss_n be high for one sclk_out cycle */
+#define CR0_CSM_ONE0x2
+
+/* ss_n to sclk_out delay */
+#define CR0_SSD_OFFSET 10
+/*
+ * The period between