[PATCH] mmc: sdhci-pci-gli: Enlarge ASPM L1 entry delay of GL975x

2021-04-14 Thread Ben Chuang
GL975x enters ASPM L1 state after a short idle in default.
Enlarge the idle period to 7.9us for improving the R/W performance.

Signed-off-by: Ben Chuang 
---
 drivers/mmc/host/sdhci-pci-gli.c | 32 
 1 file changed, 32 insertions(+)

diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c
index eb1ebb67e113..592d79082f58 100644
--- a/drivers/mmc/host/sdhci-pci-gli.c
+++ b/drivers/mmc/host/sdhci-pci-gli.c
@@ -22,6 +22,10 @@
 #define   GLI_9750_WT_EN_ON0x1
 #define   GLI_9750_WT_EN_OFF   0x0
 
+#define SDHCI_GLI_9750_CFG2  0x848
+#define   SDHCI_GLI_9750_CFG2_L1DLYGENMASK(28, 24)
+#define   GLI_9750_CFG2_L1DLY_VALUE0x1F
+
 #define SDHCI_GLI_9750_DRIVING  0x860
 #define   SDHCI_GLI_9750_DRIVING_1GENMASK(11, 0)
 #define   SDHCI_GLI_9750_DRIVING_2GENMASK(27, 26)
@@ -113,6 +117,10 @@
 #define   PCI_GLI_9755_LFCLKGENMASK(14, 12)
 #define   PCI_GLI_9755_DMACLK   BIT(29)
 
+#define PCI_GLI_9755_CFG2  0x48
+#define   PCI_GLI_9755_CFG2_L1DLYGENMASK(28, 24)
+#define   GLI_9755_CFG2_L1DLY_VALUE  0x1F
+
 #define PCI_GLI_9755_PLL0x64
 #define   PCI_GLI_9755_PLL_LDIV   GENMASK(9, 0)
 #define   PCI_GLI_9755_PLL_PDIV   GENMASK(14, 12)
@@ -408,6 +416,22 @@ static void sdhci_gl9750_set_clock(struct sdhci_host 
*host, unsigned int clock)
sdhci_enable_clk(host, clk);
 }
 
+static void gl9750_hw_setting(struct sdhci_host *host)
+{
+   u32 value;
+
+   gl9750_wt_on(host);
+
+   value = sdhci_readl(host, SDHCI_GLI_9750_CFG2);
+   value &= ~SDHCI_GLI_9750_CFG2_L1DLY;
+   /* set ASPM L1 entry delay to 7.9us */
+   value |= FIELD_PREP(SDHCI_GLI_9750_CFG2_L1DLY,
+   GLI_9750_CFG2_L1DLY_VALUE);
+   sdhci_writel(host, value, SDHCI_GLI_9750_CFG2);
+
+   gl9750_wt_off(host);
+}
+
 static void gli_pcie_enable_msi(struct sdhci_pci_slot *slot)
 {
int ret;
@@ -555,6 +579,13 @@ static void gl9755_hw_setting(struct sdhci_pci_slot *slot)
value &= ~PCI_GLI_9755_SCP_DIS;
pci_write_config_dword(pdev, PCI_GLI_9755_SerDes, value);
 
+   pci_read_config_dword(pdev, PCI_GLI_9755_CFG2, );
+   value &= ~PCI_GLI_9755_CFG2_L1DLY;
+   /* set ASPM L1 entry delay to 7.9us */
+   value |= FIELD_PREP(PCI_GLI_9755_CFG2_L1DLY,
+   GLI_9755_CFG2_L1DLY_VALUE);
+   pci_write_config_dword(pdev, PCI_GLI_9755_CFG2, value);
+
gl9755_wt_off(pdev);
 }
 
@@ -562,6 +593,7 @@ static int gli_probe_slot_gl9750(struct sdhci_pci_slot 
*slot)
 {
struct sdhci_host *host = slot->host;
 
+   gl9750_hw_setting(host);
gli_pcie_enable_msi(slot);
slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO;
sdhci_enable_v4_mode(host);
-- 
2.30.0



[RESEND, PATCH] mmc: sdhci-pci-gli: Improve GL9763E L1 entry delay to increase battery life

2021-04-07 Thread Ben Chuang
From: Ben Chuang 

For GL9763E, although there is the best performance at the maximum delay.
Change the value to 20us in order to have better power consumption.
This change may reduce the maximum performance by 10%.

Signed-off-by: Ben Chuang 
---
 drivers/mmc/host/sdhci-pci-gli.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c
index 4a0f69b97a78..3b0a049d4124 100644
--- a/drivers/mmc/host/sdhci-pci-gli.c
+++ b/drivers/mmc/host/sdhci-pci-gli.c
@@ -90,7 +90,7 @@
 
 #define PCIE_GLI_9763E_CFG2  0x8A4
 #define   GLI_9763E_CFG2_L1DLY GENMASK(28, 19)
-#define   GLI_9763E_CFG2_L1DLY_MAX 0x3FF
+#define   GLI_9763E_CFG2_L1DLY_MID 0x50
 
 #define PCIE_GLI_9763E_MMC_CTRL  0x960
 #define   GLI_9763E_HS400_SLOW BIT(3)
@@ -802,8 +802,8 @@ static void gli_set_gl9763e(struct sdhci_pci_slot *slot)
 
pci_read_config_dword(pdev, PCIE_GLI_9763E_CFG2, );
value &= ~GLI_9763E_CFG2_L1DLY;
-   /* set ASPM L1 entry delay to 260us */
-   value |= FIELD_PREP(GLI_9763E_CFG2_L1DLY, GLI_9763E_CFG2_L1DLY_MAX);
+   /* set ASPM L1 entry delay to 20us */
+   value |= FIELD_PREP(GLI_9763E_CFG2_L1DLY, GLI_9763E_CFG2_L1DLY_MID);
pci_write_config_dword(pdev, PCIE_GLI_9763E_CFG2, value);
 
pci_read_config_dword(pdev, PCIE_GLI_9763E_CLKRXDLY, );
-- 
2.30.0



[PATCH] mmc: sdhci-pci-gli: Improve L1 entry delay to increase battery life

2021-04-06 Thread Ben Chuang
From: Ben Chuang 

Although there is the best performance at the maximum delay.
Change the value to 20us in order to have better power consumption.
This change may reduce the maximum performance by 10%.

Signed-off-by: Ben Chuang 
---
 drivers/mmc/host/sdhci-pci-gli.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c
index 4a0f69b97a78..3b0a049d4124 100644
--- a/drivers/mmc/host/sdhci-pci-gli.c
+++ b/drivers/mmc/host/sdhci-pci-gli.c
@@ -90,7 +90,7 @@
 
 #define PCIE_GLI_9763E_CFG2  0x8A4
 #define   GLI_9763E_CFG2_L1DLY GENMASK(28, 19)
-#define   GLI_9763E_CFG2_L1DLY_MAX 0x3FF
+#define   GLI_9763E_CFG2_L1DLY_MID 0x50
 
 #define PCIE_GLI_9763E_MMC_CTRL  0x960
 #define   GLI_9763E_HS400_SLOW BIT(3)
@@ -802,8 +802,8 @@ static void gli_set_gl9763e(struct sdhci_pci_slot *slot)
 
pci_read_config_dword(pdev, PCIE_GLI_9763E_CFG2, );
value &= ~GLI_9763E_CFG2_L1DLY;
-   /* set ASPM L1 entry delay to 260us */
-   value |= FIELD_PREP(GLI_9763E_CFG2_L1DLY, GLI_9763E_CFG2_L1DLY_MAX);
+   /* set ASPM L1 entry delay to 20us */
+   value |= FIELD_PREP(GLI_9763E_CFG2_L1DLY, GLI_9763E_CFG2_L1DLY_MID);
pci_write_config_dword(pdev, PCIE_GLI_9763E_CFG2, value);
 
pci_read_config_dword(pdev, PCIE_GLI_9763E_CLKRXDLY, );
-- 
2.30.0



[PATCH,v2] mmc: sdhci-pci-gli: Disable slow mode in HS400 mode for GL9763E

2020-11-25 Thread Ben Chuang
From: Ben Chuang 

The GL9763E uses 150Mhz (slow mode) by default in HS400 mode. In order
to make HS400 mode run at 200Mhz, the slow mode needs to be turned off.

Signed-off-by: Ben Chuang 
---
 drivers/mmc/host/sdhci-pci-gli.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c
index 9887485a4134..d45d7e529150 100644
--- a/drivers/mmc/host/sdhci-pci-gli.c
+++ b/drivers/mmc/host/sdhci-pci-gli.c
@@ -87,6 +87,9 @@
 #define PCIE_GLI_9763E_SCR  0x8E0
 #define   GLI_9763E_SCR_AXI_REQ   BIT(9)
 
+#define PCIE_GLI_9763E_MMC_CTRL  0x960
+#define   GLI_9763E_HS400_SLOW BIT(3)
+
 #define SDHCI_GLI_9763E_CQE_BASE_ADDR   0x200
 #define GLI_9763E_CQE_TRNS_MODE   (SDHCI_TRNS_MULTI | \
SDHCI_TRNS_BLK_CNT_EN | \
@@ -764,6 +767,10 @@ static void gli_set_gl9763e(struct sdhci_pci_slot *slot)
value |= GLI_9763E_SCR_AXI_REQ;
pci_write_config_dword(pdev, PCIE_GLI_9763E_SCR, value);
 
+   pci_read_config_dword(pdev, PCIE_GLI_9763E_MMC_CTRL, );
+   value &= ~GLI_9763E_HS400_SLOW;
+   pci_write_config_dword(pdev, PCIE_GLI_9763E_MMC_CTRL, value);
+
pci_read_config_dword(pdev, PCIE_GLI_9763E_VHS, );
value &= ~GLI_9763E_VHS_REV;
value |= FIELD_PREP(GLI_9763E_VHS_REV, GLI_9763E_VHS_REV_R);
-- 
2.29.2



Re: [PATCH] mmc: sdhci-pci-gli: Disable slow mode in HS400 mode for GL9763E

2020-11-25 Thread Ben Chuang
Hi Ulf,

On Wed, Nov 25, 2020 at 6:49 PM Ulf Hansson  wrote:
>
> On Wed, 25 Nov 2020 at 11:43, Ben Chuang  wrote:
> >
> > Hi Ulf,
> >
> > On Wed, Nov 25, 2020 at 6:04 PM Ulf Hansson  wrote:
> > >
> > > On Wed, 25 Nov 2020 at 10:59, Ben Chuang  wrote:
> > > >
> > > > From: Ben Chuang 
> > > >
> > > > The GL9763E uses 150Mhz (slow mode) by default in HS400 mode. In order
> > > > to make HS400 mode run at 200Mhz, the slow mode needs to be turned off.
> > > >
> > > > Fixes: 1ae1d2d6e555 ("mmc: sdhci-pci-gli: Add Genesys Logic GL9763E 
> > > > support")
> > >
> > > Why a fixes tag? This patch looks like an improvement and not a fix, 
> > > right?
> > >
> >
> > Since the specification defines that the HS400 mode must run at 200Mhz,
> > this patch fixes the HS400 mode to 200Mhz.
>
> The spec states that in HS400 mode the clock can be *up to 200MHz* -
> not that it must run at 200MHz. At least at those places I have looked
> at in the spec.
>

You are right. I will resend v2.

Best regards,
Ben

> [...]
>
> Kind regards
> Uffe


Re: [PATCH] mmc: sdhci-pci-gli: Disable slow mode in HS400 mode for GL9763E

2020-11-25 Thread Ben Chuang
Hi Ulf,

On Wed, Nov 25, 2020 at 6:04 PM Ulf Hansson  wrote:
>
> On Wed, 25 Nov 2020 at 10:59, Ben Chuang  wrote:
> >
> > From: Ben Chuang 
> >
> > The GL9763E uses 150Mhz (slow mode) by default in HS400 mode. In order
> > to make HS400 mode run at 200Mhz, the slow mode needs to be turned off.
> >
> > Fixes: 1ae1d2d6e555 ("mmc: sdhci-pci-gli: Add Genesys Logic GL9763E 
> > support")
>
> Why a fixes tag? This patch looks like an improvement and not a fix, right?
>

Since the specification defines that the HS400 mode must run at 200Mhz,
this patch fixes the HS400 mode to 200Mhz.

Best regards,
Ben

> Kind regards
> Uffe
>
> > Signed-off-by: Ben Chuang 
> > ---
> >  drivers/mmc/host/sdhci-pci-gli.c | 7 +++
> >  1 file changed, 7 insertions(+)
> >
> > diff --git a/drivers/mmc/host/sdhci-pci-gli.c 
> > b/drivers/mmc/host/sdhci-pci-gli.c
> > index 9887485a4134..d45d7e529150 100644
> > --- a/drivers/mmc/host/sdhci-pci-gli.c
> > +++ b/drivers/mmc/host/sdhci-pci-gli.c
> > @@ -87,6 +87,9 @@
> >  #define PCIE_GLI_9763E_SCR  0x8E0
> >  #define   GLI_9763E_SCR_AXI_REQ   BIT(9)
> >
> > +#define PCIE_GLI_9763E_MMC_CTRL  0x960
> > +#define   GLI_9763E_HS400_SLOW BIT(3)
> > +
> >  #define SDHCI_GLI_9763E_CQE_BASE_ADDR   0x200
> >  #define GLI_9763E_CQE_TRNS_MODE   (SDHCI_TRNS_MULTI | \
> > SDHCI_TRNS_BLK_CNT_EN | \
> > @@ -764,6 +767,10 @@ static void gli_set_gl9763e(struct sdhci_pci_slot 
> > *slot)
> > value |= GLI_9763E_SCR_AXI_REQ;
> > pci_write_config_dword(pdev, PCIE_GLI_9763E_SCR, value);
> >
> > +   pci_read_config_dword(pdev, PCIE_GLI_9763E_MMC_CTRL, );
> > +   value &= ~GLI_9763E_HS400_SLOW;
> > +   pci_write_config_dword(pdev, PCIE_GLI_9763E_MMC_CTRL, value);
> > +
> > pci_read_config_dword(pdev, PCIE_GLI_9763E_VHS, );
> > value &= ~GLI_9763E_VHS_REV;
> > value |= FIELD_PREP(GLI_9763E_VHS_REV, GLI_9763E_VHS_REV_R);
> > --
> > 2.29.2
> >


[PATCH] mmc: sdhci-pci-gli: Disable slow mode in HS400 mode for GL9763E

2020-11-25 Thread Ben Chuang
From: Ben Chuang 

The GL9763E uses 150Mhz (slow mode) by default in HS400 mode. In order
to make HS400 mode run at 200Mhz, the slow mode needs to be turned off.

Fixes: 1ae1d2d6e555 ("mmc: sdhci-pci-gli: Add Genesys Logic GL9763E support")
Signed-off-by: Ben Chuang 
---
 drivers/mmc/host/sdhci-pci-gli.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c
index 9887485a4134..d45d7e529150 100644
--- a/drivers/mmc/host/sdhci-pci-gli.c
+++ b/drivers/mmc/host/sdhci-pci-gli.c
@@ -87,6 +87,9 @@
 #define PCIE_GLI_9763E_SCR  0x8E0
 #define   GLI_9763E_SCR_AXI_REQ   BIT(9)
 
+#define PCIE_GLI_9763E_MMC_CTRL  0x960
+#define   GLI_9763E_HS400_SLOW BIT(3)
+
 #define SDHCI_GLI_9763E_CQE_BASE_ADDR   0x200
 #define GLI_9763E_CQE_TRNS_MODE   (SDHCI_TRNS_MULTI | \
SDHCI_TRNS_BLK_CNT_EN | \
@@ -764,6 +767,10 @@ static void gli_set_gl9763e(struct sdhci_pci_slot *slot)
value |= GLI_9763E_SCR_AXI_REQ;
pci_write_config_dword(pdev, PCIE_GLI_9763E_SCR, value);
 
+   pci_read_config_dword(pdev, PCIE_GLI_9763E_MMC_CTRL, );
+   value &= ~GLI_9763E_HS400_SLOW;
+   pci_write_config_dword(pdev, PCIE_GLI_9763E_MMC_CTRL, value);
+
pci_read_config_dword(pdev, PCIE_GLI_9763E_VHS, );
value &= ~GLI_9763E_VHS_REV;
value |= FIELD_PREP(GLI_9763E_VHS_REV, GLI_9763E_VHS_REV_R);
-- 
2.29.2



[PATCH] mmc: sdhci-pci-gli: Reduce power consumption for GL9755

2020-11-22 Thread Ben Chuang
From: Ben Chuang 

For GL9755, reduce power consumption by lowering the LFCLK and disabling
the DMACLK on low-power.

Signed-off-by: Ben Chuang 
---
 drivers/mmc/host/sdhci-pci-gli.c | 20 
 1 file changed, 20 insertions(+)

diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c
index 9887485a4134..f10bdfbfce36 100644
--- a/drivers/mmc/host/sdhci-pci-gli.c
+++ b/drivers/mmc/host/sdhci-pci-gli.c
@@ -97,6 +97,10 @@
 #define   GLI_9755_WT_EN_ON 0x1
 #define   GLI_9755_WT_EN_OFF0x0
 
+#define PCI_GLI_9755_PECONF   0x44
+#define   PCI_GLI_9755_LFCLKGENMASK(14, 12)
+#define   PCI_GLI_9755_DMACLK   BIT(29)
+
 #define PCI_GLI_9755_PLL0x64
 #define   PCI_GLI_9755_PLL_LDIV   GENMASK(9, 0)
 #define   PCI_GLI_9755_PLL_PDIV   GENMASK(14, 12)
@@ -519,6 +523,21 @@ static void sdhci_gl9755_set_clock(struct sdhci_host 
*host, unsigned int clock)
sdhci_enable_clk(host, clk);
 }
 
+static void gl9755_hw_setting(struct sdhci_pci_slot *slot)
+{
+   struct pci_dev *pdev = slot->chip->pdev;
+   u32 value;
+
+   gl9755_wt_on(pdev);
+
+   pci_read_config_dword(pdev, PCI_GLI_9755_PECONF, );
+   value &= ~PCI_GLI_9755_LFCLK;
+   value &= ~PCI_GLI_9755_DMACLK;
+   pci_write_config_dword(pdev, PCI_GLI_9755_PECONF, value);
+
+   gl9755_wt_off(pdev);
+}
+
 static int gli_probe_slot_gl9750(struct sdhci_pci_slot *slot)
 {
struct sdhci_host *host = slot->host;
@@ -534,6 +553,7 @@ static int gli_probe_slot_gl9755(struct sdhci_pci_slot 
*slot)
 {
struct sdhci_host *host = slot->host;
 
+   gl9755_hw_setting(slot);
gli_pcie_enable_msi(slot);
slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO;
sdhci_enable_v4_mode(host);
-- 
2.29.2



Re: [PATCH] mmc: sdhci-pci-gli: Set SDR104's clock to 205MHz and enable SSC for GL975x

2020-10-12 Thread Ben Chuang
Hi Ulf,

On Mon, Oct 12, 2020 at 6:25 PM Ulf Hansson  wrote:
>
> On Mon, 12 Oct 2020 at 10:41, Ben Chuang  wrote:
> >
> > Hi Ulf,
> >
> > Regarding this patch, we also want to fix the EMI of one hardware
> > using the old version(such as v5.4).
> > Is there a chance to append a Fixes tag on this patch ?
>
> Unfortunately no. $subject patch is a part of the pull request with
> mmc updates for v5.10, that I just sent to Linus.
>
> > Or what should I do ?
>
> If you think that $subject patch should be included into an LTS
> kernel, please send a manual backport to sta...@vger.kernel.org. For
> more information about the process, please have a look at
> Documentation/process/stable-kernel-rules.rst
>
> [...]

I got it. Thanks for your answer.

Best regards,
Ben

>
> Kind regards
> Uffe


Re: [PATCH] mmc: sdhci-pci-gli: Set SDR104's clock to 205MHz and enable SSC for GL975x

2020-10-12 Thread Ben Chuang
Hi Ulf,

Regarding this patch, we also want to fix the EMI of one hardware
using the old version(such as v5.4).
Is there a chance to append a Fixes tag on this patch ?
Or what should I do ?

Best Regards,
Ben

On Wed, Aug 5, 2020 at 2:34 PM Ulf Hansson  wrote:
>
> On Fri, 17 Jul 2020 at 05:33, Ben Chuang  wrote:
> >
> > From: Ben Chuang 
> >
> > Set SDR104's clock to 205MHz and enable SSC for GL9750 and GL9755
> >
> > Signed-off-by: Ben Chuang 
>
> Applied for next (a while ago), thanks!
>
> Kind regards
> Uffe
>
>
> > ---
> >  drivers/mmc/host/sdhci-pci-gli.c | 220 ++-
> >  1 file changed, 218 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/mmc/host/sdhci-pci-gli.c 
> > b/drivers/mmc/host/sdhci-pci-gli.c
> > index ca0166d9bf82..5da2b06d84ae 100644
> > --- a/drivers/mmc/host/sdhci-pci-gli.c
> > +++ b/drivers/mmc/host/sdhci-pci-gli.c
> > @@ -31,10 +31,18 @@
> >  #define   SDHCI_GLI_9750_ALL_RST  (BIT(24)|BIT(25)|BIT(28)|BIT(30))
> >
> >  #define SDHCI_GLI_9750_PLL   0x864
> > +#define   SDHCI_GLI_9750_PLL_LDIV   GENMASK(9, 0)
> > +#define   SDHCI_GLI_9750_PLL_PDIV   GENMASK(14, 12)
> > +#define   SDHCI_GLI_9750_PLL_DIRBIT(15)
> >  #define   SDHCI_GLI_9750_PLL_TX2_INVBIT(23)
> >  #define   SDHCI_GLI_9750_PLL_TX2_DLYGENMASK(22, 20)
> >  #define   GLI_9750_PLL_TX2_INV_VALUE0x1
> >  #define   GLI_9750_PLL_TX2_DLY_VALUE0x0
> > +#define   SDHCI_GLI_9750_PLLSSC_STEPGENMASK(28, 24)
> > +#define   SDHCI_GLI_9750_PLLSSC_EN  BIT(31)
> > +
> > +#define SDHCI_GLI_9750_PLLSSC0x86C
> > +#define   SDHCI_GLI_9750_PLLSSC_PPMGENMASK(31, 16)
> >
> >  #define SDHCI_GLI_9750_SW_CTRL  0x874
> >  #define   SDHCI_GLI_9750_SW_CTRL_4GENMASK(7, 6)
> > @@ -76,6 +84,21 @@
> >  #define PCIE_GLI_9763E_SCR  0x8E0
> >  #define   GLI_9763E_SCR_AXI_REQ   BIT(9)
> >
> > +#define PCI_GLI_9755_WT   0x800
> > +#define   PCI_GLI_9755_WT_ENBIT(0)
> > +#define   GLI_9755_WT_EN_ON 0x1
> > +#define   GLI_9755_WT_EN_OFF0x0
> > +
> > +#define PCI_GLI_9755_PLL0x64
> > +#define   PCI_GLI_9755_PLL_LDIV   GENMASK(9, 0)
> > +#define   PCI_GLI_9755_PLL_PDIV   GENMASK(14, 12)
> > +#define   PCI_GLI_9755_PLL_DIRBIT(15)
> > +#define   PCI_GLI_9755_PLLSSC_STEPGENMASK(28, 24)
> > +#define   PCI_GLI_9755_PLLSSC_EN  BIT(31)
> > +
> > +#define PCI_GLI_9755_PLLSSC0x68
> > +#define   PCI_GLI_9755_PLLSSC_PPMGENMASK(15, 0)
> > +
> >  #define GLI_MAX_TUNING_LOOP 40
> >
> >  /* Genesys Logic chipset */
> > @@ -280,6 +303,84 @@ static int gl9750_execute_tuning(struct sdhci_host 
> > *host, u32 opcode)
> > return 0;
> >  }
> >
> > +static void gl9750_disable_ssc_pll(struct sdhci_host *host)
> > +{
> > +   u32 pll;
> > +
> > +   gl9750_wt_on(host);
> > +   pll = sdhci_readl(host, SDHCI_GLI_9750_PLL);
> > +   pll &= ~(SDHCI_GLI_9750_PLL_DIR | SDHCI_GLI_9750_PLLSSC_EN);
> > +   sdhci_writel(host, pll, SDHCI_GLI_9750_PLL);
> > +   gl9750_wt_off(host);
> > +}
> > +
> > +static void gl9750_set_pll(struct sdhci_host *host, u8 dir, u16 ldiv, u8 
> > pdiv)
> > +{
> > +   u32 pll;
> > +
> > +   gl9750_wt_on(host);
> > +   pll = sdhci_readl(host, SDHCI_GLI_9750_PLL);
> > +   pll &= ~(SDHCI_GLI_9750_PLL_LDIV |
> > +SDHCI_GLI_9750_PLL_PDIV |
> > +SDHCI_GLI_9750_PLL_DIR);
> > +   pll |= FIELD_PREP(SDHCI_GLI_9750_PLL_LDIV, ldiv) |
> > +  FIELD_PREP(SDHCI_GLI_9750_PLL_PDIV, pdiv) |
> > +  FIELD_PREP(SDHCI_GLI_9750_PLL_DIR, dir);
> > +   sdhci_writel(host, pll, SDHCI_GLI_9750_PLL);
> > +   gl9750_wt_off(host);
> > +
> > +   /* wait for pll stable */
> > +   mdelay(1);
> > +}
> > +
> > +static void gl9750_set_ssc(struct sdhci_host *host, u8 enable, u8 step, 
> > u16 ppm)
> > +{
> > +   u32 pll;
> > +   u32 ssc;
> > +
> > +   gl9750_wt_on(host);
> > +   pll = sdhci_readl(host, SDHCI_GLI_9750_PLL);
> > +   ssc = sdhci_readl(host, SDHCI_GLI_9750_PLLSSC);
> > +   pll &= ~(SDHCI_GLI_9750_PLLSSC_STEP |
> > +SDHCI_GLI_9750_PLLSSC_EN);
> > +   ssc &= ~SDHCI_GLI_9750_PLLSSC_PPM;
> > +   pll |= FIELD_PREP(SDHCI_GLI_9750_PLLSSC_STEP, step) |
> > +  FIELD_PREP(SDHCI_GLI_

[PATCH -next] mmc: sdhci-pci-gli: Add CQHCI Support for GL9763E

2020-10-05 Thread Ben Chuang
From: Ben Chuang 

Add CQHCI initialization and implement CQHCI operations for GL9763E.
Use bit19 of the register (0x888) to decide whether to disable command
queuing. If the bit is set, the command queuing will be disabled.

Signed-off-by: Ben Chuang 
---
 drivers/mmc/host/sdhci-pci-gli.c | 150 ++-
 1 file changed, 148 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c
index 5da2b06d84ae..9887485a4134 100644
--- a/drivers/mmc/host/sdhci-pci-gli.c
+++ b/drivers/mmc/host/sdhci-pci-gli.c
@@ -14,6 +14,7 @@
 #include 
 #include "sdhci.h"
 #include "sdhci-pci.h"
+#include "cqhci.h"
 
 /*  Genesys Logic extra registers */
 #define SDHCI_GLI_9750_WT 0x800
@@ -81,9 +82,16 @@
 #define   GLI_9763E_VHS_REV_R  0x0
 #define   GLI_9763E_VHS_REV_M  0x1
 #define   GLI_9763E_VHS_REV_W  0x2
+#define PCIE_GLI_9763E_MB   0x888
+#define   GLI_9763E_MB_CMDQ_OFF   BIT(19)
 #define PCIE_GLI_9763E_SCR  0x8E0
 #define   GLI_9763E_SCR_AXI_REQ   BIT(9)
 
+#define SDHCI_GLI_9763E_CQE_BASE_ADDR   0x200
+#define GLI_9763E_CQE_TRNS_MODE   (SDHCI_TRNS_MULTI | \
+   SDHCI_TRNS_BLK_CNT_EN | \
+   SDHCI_TRNS_DMA)
+
 #define PCI_GLI_9755_WT   0x800
 #define   PCI_GLI_9755_WT_ENBIT(0)
 #define   GLI_9755_WT_EN_ON 0x1
@@ -578,6 +586,30 @@ static int sdhci_pci_gli_resume(struct sdhci_pci_chip 
*chip)
 
return sdhci_pci_resume_host(chip);
 }
+
+static int sdhci_cqhci_gli_resume(struct sdhci_pci_chip *chip)
+{
+   struct sdhci_pci_slot *slot = chip->slots[0];
+   int ret;
+
+   ret = sdhci_pci_gli_resume(chip);
+   if (ret)
+   return ret;
+
+   return cqhci_resume(slot->host->mmc);
+}
+
+static int sdhci_cqhci_gli_suspend(struct sdhci_pci_chip *chip)
+{
+   struct sdhci_pci_slot *slot = chip->slots[0];
+   int ret;
+
+   ret = cqhci_suspend(slot->host->mmc);
+   if (ret)
+   return ret;
+
+   return sdhci_suspend_host(slot->host);
+}
 #endif
 
 static void gl9763e_hs400_enhanced_strobe(struct mmc_host *mmc,
@@ -614,6 +646,110 @@ static void sdhci_set_gl9763e_signaling(struct sdhci_host 
*host,
sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
 }
 
+static void sdhci_gl9763e_dumpregs(struct mmc_host *mmc)
+{
+   sdhci_dumpregs(mmc_priv(mmc));
+}
+
+static void sdhci_gl9763e_cqe_pre_enable(struct mmc_host *mmc)
+{
+   struct cqhci_host *cq_host = mmc->cqe_private;
+   u32 value;
+
+   value = cqhci_readl(cq_host, CQHCI_CFG);
+   value |= CQHCI_ENABLE;
+   cqhci_writel(cq_host, value, CQHCI_CFG);
+}
+
+static void sdhci_gl9763e_cqe_enable(struct mmc_host *mmc)
+{
+   struct sdhci_host *host = mmc_priv(mmc);
+
+   sdhci_writew(host, GLI_9763E_CQE_TRNS_MODE, SDHCI_TRANSFER_MODE);
+   sdhci_cqe_enable(mmc);
+}
+
+static u32 sdhci_gl9763e_cqhci_irq(struct sdhci_host *host, u32 intmask)
+{
+   int cmd_error = 0;
+   int data_error = 0;
+
+   if (!sdhci_cqe_irq(host, intmask, _error, _error))
+   return intmask;
+
+   cqhci_irq(host->mmc, intmask, cmd_error, data_error);
+
+   return 0;
+}
+
+static void sdhci_gl9763e_cqe_post_disable(struct mmc_host *mmc)
+{
+   struct sdhci_host *host = mmc_priv(mmc);
+   struct cqhci_host *cq_host = mmc->cqe_private;
+   u32 value;
+
+   value = cqhci_readl(cq_host, CQHCI_CFG);
+   value &= ~CQHCI_ENABLE;
+   cqhci_writel(cq_host, value, CQHCI_CFG);
+   sdhci_writew(host, 0x0, SDHCI_TRANSFER_MODE);
+}
+
+static const struct cqhci_host_ops sdhci_gl9763e_cqhci_ops = {
+   .enable = sdhci_gl9763e_cqe_enable,
+   .disable= sdhci_cqe_disable,
+   .dumpregs   = sdhci_gl9763e_dumpregs,
+   .pre_enable = sdhci_gl9763e_cqe_pre_enable,
+   .post_disable   = sdhci_gl9763e_cqe_post_disable,
+};
+
+static int gl9763e_add_host(struct sdhci_pci_slot *slot)
+{
+   struct device *dev = >chip->pdev->dev;
+   struct sdhci_host *host = slot->host;
+   struct cqhci_host *cq_host;
+   bool dma64;
+   int ret;
+
+   ret = sdhci_setup_host(host);
+   if (ret)
+   return ret;
+
+   cq_host = devm_kzalloc(dev, sizeof(*cq_host), GFP_KERNEL);
+   if (!cq_host) {
+   ret = -ENOMEM;
+   goto cleanup;
+   }
+
+   cq_host->mmio = host->ioaddr + SDHCI_GLI_9763E_CQE_BASE_ADDR;
+   cq_host->ops = _gl9763e_cqhci_ops;
+
+   dma64 = host->flags & SDHCI_USE_64_BIT_DMA;
+   if (dma64)
+   cq_host->caps |= CQHCI_TASK_DESC_SZ_128;
+
+   ret = cqhci_init(cq_host, host->mmc, dma64);
+   if (ret)
+   goto cleanup;
+
+   ret = __sdhci_add_host(host);
+   if (ret)
+   goto cleanup;
+
+  

Re: [RFC PATCH V3 12/21] mmc: sdhci: UHS-II support, add hooks for additional operations

2020-09-25 Thread Ben Chuang
Takahiro,

On Thu, Sep 24, 2020 at 5:46 PM AKASHI Takahiro
 wrote:
>
> Ben,
>
> On Fri, Sep 18, 2020 at 06:27:01PM +0800, Ben Chuang wrote:
> > On Fri, Sep 18, 2020 at 9:15 AM AKASHI Takahiro
> >  wrote:
> > >
> > > Ben,
> > >
> > > On Thu, Sep 17, 2020 at 06:12:27PM +0800, Ben Chuang wrote:
> > > > Hi Takahiro,
> > > >
> > > > On Thu, Sep 17, 2020 at 1:12 PM AKASHI Takahiro
> > > >  wrote:
> > > > >
> > > > > Adrian, Ben,
> > > > >
> > > > > Regarding _reset() function,
> > > > >
> > > > > On Fri, Aug 21, 2020 at 05:08:32PM +0300, Adrian Hunter wrote:
> > > > > > On 10/07/20 2:10 pm, Ben Chuang wrote:
> > > > > > > From: Ben Chuang 
> > > > > > >
> > > > > > > In this commit, UHS-II related operations will be called via a 
> > > > > > > function
> > > > > > > pointer array, sdhci_uhs2_ops, in order to make UHS-II support as
> > > > > > > a kernel module.
> > > > > > > This array will be initialized only if CONFIG_MMC_SDHCI_UHS2 is 
> > > > > > > enabled
> > > > > > > and when the UHS-II module is loaded. Otherwise, all the functions
> > > > > > > stay void.
> > > > > > >
> > > > > > > Signed-off-by: Ben Chuang 
> > > > > > > Signed-off-by: AKASHI Takahiro 
> > > > > > > ---
> > > > > > >  drivers/mmc/host/sdhci.c | 152 
> > > > > > > ++-
> > > > > > >  1 file changed, 136 insertions(+), 16 deletions(-)
> > > > > > >
> > > > >
> > > > >   (snip)
> > > > >
> > > > > > > if (host->ops->platform_send_init_74_clocks)
> > > > > > > host->ops->platform_send_init_74_clocks(host, 
> > > > > > > ios->power_mode);
> > > > > > >
> > > > > > > @@ -2331,7 +2411,7 @@ void sdhci_set_ios(struct mmc_host *mmc, 
> > > > > > > struct mmc_ios *ios)
> > > > > > > }
> > > > > > >
> > > > > > > if (host->version >= SDHCI_SPEC_300) {
> > > > > > > -   u16 clk, ctrl_2;
> > > > > > > +   u16 clk;
> > > > > > >
> > > > > > > if (!host->preset_enabled) {
> > > > > > > sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
> > > > > > > @@ -3173,11 +3253,19 @@ static bool sdhci_request_done(struct 
> > > > > > > sdhci_host *host)
> > > > > > > /* This is to force an update */
> > > > > > > host->ops->set_clock(host, host->clock);
> > > > > > >
> > > > > > > -   /* Spec says we should do both at the same time, but 
> > > > > > > Ricoh
> > > > > > > -  controllers do not like that. */
> > > > > > > -   sdhci_do_reset(host, SDHCI_RESET_CMD);
> > > > > > > -   sdhci_do_reset(host, SDHCI_RESET_DATA);
> > > > > > > -
> > > > > > > +   if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> > > > > > > +   host->mmc->flags & MMC_UHS2_INITIALIZED) {
> > > > > > > +   if (sdhci_uhs2_ops.reset)
> > > > > > > +   sdhci_uhs2_ops.reset(host,
> > > > > > > +
> > > > > > > SDHCI_UHS2_SW_RESET_SD);
> > > > > > > +   } else {
> > > > > > > +   /*
> > > > > > > +* Spec says we should do both at the same 
> > > > > > > time, but
> > > > > > > +* Ricoh controllers do not like that.
> > > > > > > +*/
> > > > > > > +   sdhci_do_reset(host, SDHCI_RESET_CMD);
> > > > > > > +   sdhci_do_reset(host, SDHCI_RESET_DATA);
> > > > > > > +   }
> > > > >

Re: [RFC PATCH V3 12/21] mmc: sdhci: UHS-II support, add hooks for additional operations

2020-09-25 Thread Ben Chuang
Takahiro,

On Thu, Sep 24, 2020 at 5:57 PM AKASHI Takahiro
 wrote:
>
> Ben,
>
> On Fri, Sep 18, 2020 at 06:50:24PM +0800, Ben Chuang wrote:
> > On Fri, Sep 18, 2020 at 2:38 PM AKASHI Takahiro
> >  wrote:
> > >
> > > Adrian, Ben,
> > >
> > > Regarding _set_ios() function,
> > >
> > > On Fri, Aug 21, 2020 at 05:08:32PM +0300, Adrian Hunter wrote:
> > > > On 10/07/20 2:10 pm, Ben Chuang wrote:
> > > > > From: Ben Chuang 
> > > > >
> > > > > In this commit, UHS-II related operations will be called via a 
> > > > > function
> > > > > pointer array, sdhci_uhs2_ops, in order to make UHS-II support as
> > > > > a kernel module.
> > > > > This array will be initialized only if CONFIG_MMC_SDHCI_UHS2 is 
> > > > > enabled
> > > > > and when the UHS-II module is loaded. Otherwise, all the functions
> > > > > stay void.
> > > > >
> > > > > Signed-off-by: Ben Chuang 
> > > > > Signed-off-by: AKASHI Takahiro 
> > >
> > >   (snip)
> > >
> > > > > @@ -2261,6 +2324,7 @@ void sdhci_set_ios(struct mmc_host *mmc, struct 
> > > > > mmc_ios *ios)
> > > > >  {
> > > > > struct sdhci_host *host = mmc_priv(mmc);
> > > > > u8 ctrl;
> > > > > +   u16 ctrl_2;
> > > > >
> > > > > if (ios->power_mode == MMC_POWER_UNDEFINED)
> > > > > return;
> > > > > @@ -2287,6 +2351,10 @@ void sdhci_set_ios(struct mmc_host *mmc, 
> > > > > struct mmc_ios *ios)
> > > > > sdhci_enable_preset_value(host, false);
> > > > >
> > > > > if (!ios->clock || ios->clock != host->clock) {
> > > > > +   if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> > > > > +   ios->timing == MMC_TIMING_UHS2)
> > > > > +   host->timing = ios->timing;
> > > > > +
> > > > > host->ops->set_clock(host, ios->clock);
> > > > > host->clock = ios->clock;
> > > > >
> > > > > @@ -2308,6 +2376,18 @@ void sdhci_set_ios(struct mmc_host *mmc, 
> > > > > struct mmc_ios *ios)
> > > > > else
> > > > > sdhci_set_power(host, ios->power_mode, ios->vdd);
> > > > >
> > > > > +   /* 4.0 host support */
> > > > > +   if (host->version >= SDHCI_SPEC_400) {
> > > > > +   /* UHS2 Support */
> > > > > +   if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> > > > > +   host->mmc->flags & MMC_UHS2_SUPPORT &&
> > > > > +   host->mmc->caps & MMC_CAP_UHS2) {
> > > > > +   if (sdhci_uhs2_ops.do_set_ios)
> > > > > +   sdhci_uhs2_ops.do_set_ios(host, ios);
> > > > > +   return;
> > > > > +   }
> > > > > +   }
> > > > > +
> > > >
> > > > Please look at using existing callbacks instead, maybe creating 
> > > > uhs2_set_ios(), uhs2_set_clock(), uhs2_set_power()
> > >
> > > I think that we will create uhs2_set_ios() (and uhs2_set_power()
> > > as we discussed on patch#15/21), but not uhs_set_clock().
> > >
> > > Since we have a hook only in struct mmc_host_ops, but not in struct
> > > sdhci_ops, all the drivers who want to support UHS-II need to
> > > set host->mmc_host_ops->set_ios to sdhci_uhs2_set_ios explicitly
> > > in their own init (or probe) function.
> > > (Again, sdhci_uhs2_set_ios() seems to be generic though.)
> > >
> > > Is this okay for you?
> > > -> Adrian
> > >
> > > During refactoring the code, I found that sdhci_set_power() is called
> > > twice in sdhci_set_ios():
> > > sdhci_set_ios(host, power_mode, vdd1, -1); in sdhci_set_ios(), and
> > > sdhci_set_ios(host, power_mode, vdd1, vdd2) in ush2_do_set_ios()
> > >
> > > Can you please confirm that those are redundant?
> >
> > Yes, uhs2 set power is independent with uhs1.
> > But set  uhs2 power process  should meet  uhs2 spec.
>
> Can you elaborate a bit more about the last sentence, please?
>
> What I meant above is that
>  sdhci_set_ios(host, power_mode, vdd1, vdd2) in ush2_do_set_ios()
>
> this code will 'set_power' both vdd and vdd2 anyway and so
>  sdhci_set_ios(host, power_mode, vdd1, -1); in sdhci_set_ios(), and
> is just redundant.
>

Yes, for uhs-2 flow,  sdhci_set_ios(host, power_mode, vdd1, -1) is redundant.

>
> > > -> Ben
> > >
> > > I also wonder why we need spin locks in uhs2_do_set_ios() while
> > > not in sdhci_set_ios().
> >
> > You can check if  spin locks in uhs2_do_set_ios() is necessary.
>
> I'm asking you.
>
> While calling set_ios() doesn't require spin locks, are you aware of
> any cases where we need spin locks in calling set_ios() for uhs-2?
> (I mean that callers/contexts are the same either for uhs or uhs-2.)

I agree that it can be removed. I just didn't modify intel's original codes.

>
> -Takahiro Akashi
>
> > If set/clear irq can be execute safely without spin locks, you can
> > remove spin locks.
> >
> > >
> > > -> Ben
> > >
> > > -Takahiro Akashi


Re: [RFC PATCH V3 12/21] mmc: sdhci: UHS-II support, add hooks for additional operations

2020-09-18 Thread Ben Chuang
On Fri, Sep 18, 2020 at 2:38 PM AKASHI Takahiro
 wrote:
>
> Adrian, Ben,
>
> Regarding _set_ios() function,
>
> On Fri, Aug 21, 2020 at 05:08:32PM +0300, Adrian Hunter wrote:
> > On 10/07/20 2:10 pm, Ben Chuang wrote:
> > > From: Ben Chuang 
> > >
> > > In this commit, UHS-II related operations will be called via a function
> > > pointer array, sdhci_uhs2_ops, in order to make UHS-II support as
> > > a kernel module.
> > > This array will be initialized only if CONFIG_MMC_SDHCI_UHS2 is enabled
> > > and when the UHS-II module is loaded. Otherwise, all the functions
> > > stay void.
> > >
> > > Signed-off-by: Ben Chuang 
> > > Signed-off-by: AKASHI Takahiro 
>
>   (snip)
>
> > > @@ -2261,6 +2324,7 @@ void sdhci_set_ios(struct mmc_host *mmc, struct 
> > > mmc_ios *ios)
> > >  {
> > > struct sdhci_host *host = mmc_priv(mmc);
> > > u8 ctrl;
> > > +   u16 ctrl_2;
> > >
> > > if (ios->power_mode == MMC_POWER_UNDEFINED)
> > > return;
> > > @@ -2287,6 +2351,10 @@ void sdhci_set_ios(struct mmc_host *mmc, struct 
> > > mmc_ios *ios)
> > > sdhci_enable_preset_value(host, false);
> > >
> > > if (!ios->clock || ios->clock != host->clock) {
> > > +   if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> > > +   ios->timing == MMC_TIMING_UHS2)
> > > +   host->timing = ios->timing;
> > > +
> > > host->ops->set_clock(host, ios->clock);
> > > host->clock = ios->clock;
> > >
> > > @@ -2308,6 +2376,18 @@ void sdhci_set_ios(struct mmc_host *mmc, struct 
> > > mmc_ios *ios)
> > > else
> > > sdhci_set_power(host, ios->power_mode, ios->vdd);
> > >
> > > +   /* 4.0 host support */
> > > +   if (host->version >= SDHCI_SPEC_400) {
> > > +   /* UHS2 Support */
> > > +   if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> > > +   host->mmc->flags & MMC_UHS2_SUPPORT &&
> > > +   host->mmc->caps & MMC_CAP_UHS2) {
> > > +   if (sdhci_uhs2_ops.do_set_ios)
> > > +   sdhci_uhs2_ops.do_set_ios(host, ios);
> > > +   return;
> > > +   }
> > > +   }
> > > +
> >
> > Please look at using existing callbacks instead, maybe creating 
> > uhs2_set_ios(), uhs2_set_clock(), uhs2_set_power()
>
> I think that we will create uhs2_set_ios() (and uhs2_set_power()
> as we discussed on patch#15/21), but not uhs_set_clock().
>
> Since we have a hook only in struct mmc_host_ops, but not in struct
> sdhci_ops, all the drivers who want to support UHS-II need to
> set host->mmc_host_ops->set_ios to sdhci_uhs2_set_ios explicitly
> in their own init (or probe) function.
> (Again, sdhci_uhs2_set_ios() seems to be generic though.)
>
> Is this okay for you?
> -> Adrian
>
> During refactoring the code, I found that sdhci_set_power() is called
> twice in sdhci_set_ios():
> sdhci_set_ios(host, power_mode, vdd1, -1); in sdhci_set_ios(), and
> sdhci_set_ios(host, power_mode, vdd1, vdd2) in ush2_do_set_ios()
>
> Can you please confirm that those are redundant?

Yes, uhs2 set power is independent with uhs1.
But set  uhs2 power process  should meet  uhs2 spec.

> -> Ben
>
> I also wonder why we need spin locks in uhs2_do_set_ios() while
> not in sdhci_set_ios().

You can check if  spin locks in uhs2_do_set_ios() is necessary.
If set/clear irq can be execute safely without spin locks, you can
remove spin locks.

>
> -> Ben
>
> -Takahiro Akashi


Re: [RFC PATCH V3 12/21] mmc: sdhci: UHS-II support, add hooks for additional operations

2020-09-18 Thread Ben Chuang
On Fri, Sep 18, 2020 at 9:15 AM AKASHI Takahiro
 wrote:
>
> Ben,
>
> On Thu, Sep 17, 2020 at 06:12:27PM +0800, Ben Chuang wrote:
> > Hi Takahiro,
> >
> > On Thu, Sep 17, 2020 at 1:12 PM AKASHI Takahiro
> >  wrote:
> > >
> > > Adrian, Ben,
> > >
> > > Regarding _reset() function,
> > >
> > > On Fri, Aug 21, 2020 at 05:08:32PM +0300, Adrian Hunter wrote:
> > > > On 10/07/20 2:10 pm, Ben Chuang wrote:
> > > > > From: Ben Chuang 
> > > > >
> > > > > In this commit, UHS-II related operations will be called via a 
> > > > > function
> > > > > pointer array, sdhci_uhs2_ops, in order to make UHS-II support as
> > > > > a kernel module.
> > > > > This array will be initialized only if CONFIG_MMC_SDHCI_UHS2 is 
> > > > > enabled
> > > > > and when the UHS-II module is loaded. Otherwise, all the functions
> > > > > stay void.
> > > > >
> > > > > Signed-off-by: Ben Chuang 
> > > > > Signed-off-by: AKASHI Takahiro 
> > > > > ---
> > > > >  drivers/mmc/host/sdhci.c | 152 
> > > > > ++-
> > > > >  1 file changed, 136 insertions(+), 16 deletions(-)
> > > > >
> > >
> > >   (snip)
> > >
> > > > > if (host->ops->platform_send_init_74_clocks)
> > > > > host->ops->platform_send_init_74_clocks(host, 
> > > > > ios->power_mode);
> > > > >
> > > > > @@ -2331,7 +2411,7 @@ void sdhci_set_ios(struct mmc_host *mmc, struct 
> > > > > mmc_ios *ios)
> > > > > }
> > > > >
> > > > > if (host->version >= SDHCI_SPEC_300) {
> > > > > -   u16 clk, ctrl_2;
> > > > > +   u16 clk;
> > > > >
> > > > > if (!host->preset_enabled) {
> > > > > sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
> > > > > @@ -3173,11 +3253,19 @@ static bool sdhci_request_done(struct 
> > > > > sdhci_host *host)
> > > > > /* This is to force an update */
> > > > > host->ops->set_clock(host, host->clock);
> > > > >
> > > > > -   /* Spec says we should do both at the same time, but Ricoh
> > > > > -  controllers do not like that. */
> > > > > -   sdhci_do_reset(host, SDHCI_RESET_CMD);
> > > > > -   sdhci_do_reset(host, SDHCI_RESET_DATA);
> > > > > -
> > > > > +   if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> > > > > +   host->mmc->flags & MMC_UHS2_INITIALIZED) {
> > > > > +   if (sdhci_uhs2_ops.reset)
> > > > > +   sdhci_uhs2_ops.reset(host,
> > > > > +
> > > > > SDHCI_UHS2_SW_RESET_SD);
> > > > > +   } else {
> > > > > +   /*
> > > > > +* Spec says we should do both at the same time, 
> > > > > but
> > > > > +* Ricoh controllers do not like that.
> > > > > +*/
> > > > > +   sdhci_do_reset(host, SDHCI_RESET_CMD);
> > > > > +   sdhci_do_reset(host, SDHCI_RESET_DATA);
> > > > > +   }
> > > >
> > > > Please look at using the existing ->reset() sdhci host op instead.
> > >
> > > Well, the second argument to those reset functions is a bit-wise value
> > > to different "reset" registers, SDHCI_SOFTWARE_RESET and 
> > > SDHCI_UHS2_SW_RESET,
> > > respectively.
> > >
> > > This fact raises a couple of questions to me:
> > >
> > > 1) Does it make sense to merge two functionality into one, i.e.
> > >sdhci_do_reset(), which is set to call ->reset hook?
> > >
> > > -> Adrian
> > >
> > > 2) UHS2_SW_RESET_SD is done only at this place while there are many 
> > > callsites
> > >of reset(RESET_CMD|RESET_DATA) in sdhci.c.
> > >Why does the current code work?
> > >
> > >I found, in sdhci-pci-gli.c,
> > >sdhci_gl9755_reset()
>

Re: [RFC PATCH V3 13/21] mmc: sdhci: UHS-II support, skip signal_voltage_switch()

2020-09-17 Thread Ben Chuang
On Thu, Sep 17, 2020 at 8:56 AM AKASHI Takahiro
 wrote:
>
> Ben,
>
> On Wed, Sep 16, 2020 at 05:42:07PM +0800, Ben Chuang wrote:
> > On Wed, Sep 16, 2020 at 8:52 AM AKASHI Takahiro
> >  wrote:
> > >
> > > On Tue, Sep 15, 2020 at 07:36:14PM +0800, Ben Chuang wrote:
> > > > Hi Takahiro,
> > > >
> > > > On Tue, Sep 15, 2020 at 2:03 PM AKASHI Takahiro
> > > >  wrote:
> > > > >
> > > > > Ben, Adrian,
> > > > >
> > > > > On Mon, Sep 14, 2020 at 11:08:14AM +0300, Adrian Hunter wrote:
> > > > > > On 14/09/20 9:40 am, AKASHI Takahiro wrote:
> > > > > > > Adrian,
> > > > > > >
> > > > > > > On Fri, Aug 21, 2020 at 05:09:01PM +0300, Adrian Hunter wrote:
> > > > > > >> On 10/07/20 2:11 pm, Ben Chuang wrote:
> > > > > > >>> From: AKASHI Takahiro 
> > > > > > >>>
> > > > > > >>> sdhci_start_signal_voltage_switch() should be called only in 
> > > > > > >>> UHS-I mode,
> > > > > > >>> and not for UHS-II mode.
> > > > > > >>>
> > > > > > >>> Signed-off-by: Ben Chuang 
> > > > > > >>> Signed-off-by: AKASHI Takahiro 
> > > > > > >>> ---
> > > > > > >>>  drivers/mmc/host/sdhci.c | 7 ++-
> > > > > > >>>  1 file changed, 6 insertions(+), 1 deletion(-)
> > > > > > >>>
> > > > > > >>> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> > > > > > >>> index 5511649946b9..7f2537648a08 100644
> > > > > > >>> --- a/drivers/mmc/host/sdhci.c
> > > > > > >>> +++ b/drivers/mmc/host/sdhci.c
> > > > > > >>> @@ -2623,8 +2623,13 @@ int 
> > > > > > >>> sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
> > > > > > >>>   /*
> > > > > > >>>* Signal Voltage Switching is only applicable for Host 
> > > > > > >>> Controllers
> > > > > > >>>* v3.00 and above.
> > > > > > >>> +  * But for UHS2, the signal voltage is supplied by vdd2 which 
> > > > > > >>> is
> > > > > > >>> +  * already 1.8v so no voltage switch required.
> > > > >
> > > > > I have been confused with this comment.
> > > > > (I know it came from the original Intel code, not from Ben.)
> > > > >
> > > > > If this comment is true,
> > > > >
> > > > > > >>>*/
> > > > > > >>> - if (host->version < SDHCI_SPEC_300)
> > > > > > >>> + if (host->version < SDHCI_SPEC_300 ||
> > > > > > >>> + (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> > > > > > >>> +  host->version >= SDHCI_SPEC_400 &&
> > > > > > >>> +  host->mmc->flags & MMC_UHS2_SUPPORT))
> > > > >
> > > > > the condition above must be wrong since 'flags & MMC_UHS2_SUPPORT'
> > > > > is one of capabilities for a host controller, not a card
> > > > > while the selection of voltage depends on a card type.
> > > >
> > > > The flag MMC_UHS2_SUPPORT is set at the beginning of 
> > > > mmc_uhs2_rescan_try_freq().
> > > > In UHS-II flow, it stays set.
> > > > If the attempt to UHS-II fails finally, it will be unset.
> > >
> > > Right, but MMC_UHS2_SUPPORT is also set, at least initially,
> > > in sdhci_uhs2_add_host(). It is confusing, isn't it?
> >
> > I think it can be removed from sdhci_uhs2_add_host() to avoid making 
> > confusion.
>
> Okay,
>
> > >
> > > As we discussed before, any card-specific properties, like UHS-II mode,
> > > should be placed in a card structure, not a host structure.
>
> Do you have any idea on this?
> I remember that Ulf also made a similar comment on the "core" side.

We may list those properties to do first. i.e. MMC_UHS2_INITIALIZED.

>
> -Takahiro Akashi
>
> > >
> > > > >
> > > > > So I wonder why this code still works.
> > > > > I guess that it is because set_signal_voltage(), or ot

Re: [RFC PATCH V3 12/21] mmc: sdhci: UHS-II support, add hooks for additional operations

2020-09-17 Thread Ben Chuang
Hi Takahiro,

On Thu, Sep 17, 2020 at 1:12 PM AKASHI Takahiro
 wrote:
>
> Adrian, Ben,
>
> Regarding _reset() function,
>
> On Fri, Aug 21, 2020 at 05:08:32PM +0300, Adrian Hunter wrote:
> > On 10/07/20 2:10 pm, Ben Chuang wrote:
> > > From: Ben Chuang 
> > >
> > > In this commit, UHS-II related operations will be called via a function
> > > pointer array, sdhci_uhs2_ops, in order to make UHS-II support as
> > > a kernel module.
> > > This array will be initialized only if CONFIG_MMC_SDHCI_UHS2 is enabled
> > > and when the UHS-II module is loaded. Otherwise, all the functions
> > > stay void.
> > >
> > > Signed-off-by: Ben Chuang 
> > > Signed-off-by: AKASHI Takahiro 
> > > ---
> > >  drivers/mmc/host/sdhci.c | 152 ++-
> > >  1 file changed, 136 insertions(+), 16 deletions(-)
> > >
>
>   (snip)
>
> > > if (host->ops->platform_send_init_74_clocks)
> > > host->ops->platform_send_init_74_clocks(host, 
> > > ios->power_mode);
> > >
> > > @@ -2331,7 +2411,7 @@ void sdhci_set_ios(struct mmc_host *mmc, struct 
> > > mmc_ios *ios)
> > > }
> > >
> > > if (host->version >= SDHCI_SPEC_300) {
> > > -   u16 clk, ctrl_2;
> > > +   u16 clk;
> > >
> > > if (!host->preset_enabled) {
> > > sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
> > > @@ -3173,11 +3253,19 @@ static bool sdhci_request_done(struct sdhci_host 
> > > *host)
> > > /* This is to force an update */
> > > host->ops->set_clock(host, host->clock);
> > >
> > > -   /* Spec says we should do both at the same time, but Ricoh
> > > -  controllers do not like that. */
> > > -   sdhci_do_reset(host, SDHCI_RESET_CMD);
> > > -   sdhci_do_reset(host, SDHCI_RESET_DATA);
> > > -
> > > +   if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> > > +   host->mmc->flags & MMC_UHS2_INITIALIZED) {
> > > +   if (sdhci_uhs2_ops.reset)
> > > +   sdhci_uhs2_ops.reset(host,
> > > +SDHCI_UHS2_SW_RESET_SD);
> > > +   } else {
> > > +   /*
> > > +* Spec says we should do both at the same time, but
> > > +* Ricoh controllers do not like that.
> > > +*/
> > > +   sdhci_do_reset(host, SDHCI_RESET_CMD);
> > > +   sdhci_do_reset(host, SDHCI_RESET_DATA);
> > > +   }
> >
> > Please look at using the existing ->reset() sdhci host op instead.
>
> Well, the second argument to those reset functions is a bit-wise value
> to different "reset" registers, SDHCI_SOFTWARE_RESET and SDHCI_UHS2_SW_RESET,
> respectively.
>
> This fact raises a couple of questions to me:
>
> 1) Does it make sense to merge two functionality into one, i.e.
>sdhci_do_reset(), which is set to call ->reset hook?
>
> -> Adrian
>
> 2) UHS2_SW_RESET_SD is done only at this place while there are many callsites
>of reset(RESET_CMD|RESET_DATA) in sdhci.c.
>Why does the current code work?
>
>I found, in sdhci-pci-gli.c,
>sdhci_gl9755_reset()
> /* reset sd-tran on UHS2 mode if need to reset cmd/data */
> if ((mask & SDHCI_RESET_CMD) | (mask & SDHCI_RESET_DATA))
> gl9755_uhs2_reset_sd_tran(host);
>
>Is this the trick to avoid the issue?
>(It looks redundant in terms of the hack above in sdhci_request_done()
>and even quite dirty to me. Moreover, no corresponding code for gl9750
>and gl9763.)

GL9755 currently does SD reset and UHS-II reset together.
There is no UHS-II interface on gl9750 and gl9763e.

>
> -> Ben
>
> 3) (More or less SD specification issue)
>In UHS-II mode, do we have to call reset(SHCI_RESET_ALL) along with
>reset(UHS2_SW_RESET_FULL)?
>Under the current implementation, both will be called at the end.
>

As I know, the UHS2_SW_RESET_FULL is only for UHS-II.
Can you list the lines that reset(SHCI_RESET_ALL) and
reset(UHS2_SW_RESET_FULL) are both called?

> -> Adrian, Ben
>
> 4) (Not directly linked to UHS-II support)
>   In some places, we see the sequence:
> sdhci_do_reset(host, SDHCI_RESET_CMD);
>   

Re: [RFC PATCH V3 13/21] mmc: sdhci: UHS-II support, skip signal_voltage_switch()

2020-09-16 Thread Ben Chuang
On Wed, Sep 16, 2020 at 8:52 AM AKASHI Takahiro
 wrote:
>
> On Tue, Sep 15, 2020 at 07:36:14PM +0800, Ben Chuang wrote:
> > Hi Takahiro,
> >
> > On Tue, Sep 15, 2020 at 2:03 PM AKASHI Takahiro
> >  wrote:
> > >
> > > Ben, Adrian,
> > >
> > > On Mon, Sep 14, 2020 at 11:08:14AM +0300, Adrian Hunter wrote:
> > > > On 14/09/20 9:40 am, AKASHI Takahiro wrote:
> > > > > Adrian,
> > > > >
> > > > > On Fri, Aug 21, 2020 at 05:09:01PM +0300, Adrian Hunter wrote:
> > > > >> On 10/07/20 2:11 pm, Ben Chuang wrote:
> > > > >>> From: AKASHI Takahiro 
> > > > >>>
> > > > >>> sdhci_start_signal_voltage_switch() should be called only in UHS-I 
> > > > >>> mode,
> > > > >>> and not for UHS-II mode.
> > > > >>>
> > > > >>> Signed-off-by: Ben Chuang 
> > > > >>> Signed-off-by: AKASHI Takahiro 
> > > > >>> ---
> > > > >>>  drivers/mmc/host/sdhci.c | 7 ++-
> > > > >>>  1 file changed, 6 insertions(+), 1 deletion(-)
> > > > >>>
> > > > >>> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> > > > >>> index 5511649946b9..7f2537648a08 100644
> > > > >>> --- a/drivers/mmc/host/sdhci.c
> > > > >>> +++ b/drivers/mmc/host/sdhci.c
> > > > >>> @@ -2623,8 +2623,13 @@ int sdhci_start_signal_voltage_switch(struct 
> > > > >>> mmc_host *mmc,
> > > > >>>   /*
> > > > >>>* Signal Voltage Switching is only applicable for Host 
> > > > >>> Controllers
> > > > >>>* v3.00 and above.
> > > > >>> +  * But for UHS2, the signal voltage is supplied by vdd2 which is
> > > > >>> +  * already 1.8v so no voltage switch required.
> > >
> > > I have been confused with this comment.
> > > (I know it came from the original Intel code, not from Ben.)
> > >
> > > If this comment is true,
> > >
> > > > >>>*/
> > > > >>> - if (host->version < SDHCI_SPEC_300)
> > > > >>> + if (host->version < SDHCI_SPEC_300 ||
> > > > >>> + (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> > > > >>> +  host->version >= SDHCI_SPEC_400 &&
> > > > >>> +  host->mmc->flags & MMC_UHS2_SUPPORT))
> > >
> > > the condition above must be wrong since 'flags & MMC_UHS2_SUPPORT'
> > > is one of capabilities for a host controller, not a card
> > > while the selection of voltage depends on a card type.
> >
> > The flag MMC_UHS2_SUPPORT is set at the beginning of 
> > mmc_uhs2_rescan_try_freq().
> > In UHS-II flow, it stays set.
> > If the attempt to UHS-II fails finally, it will be unset.
>
> Right, but MMC_UHS2_SUPPORT is also set, at least initially,
> in sdhci_uhs2_add_host(). It is confusing, isn't it?

I think it can be removed from sdhci_uhs2_add_host() to avoid making confusion.

>
> As we discussed before, any card-specific properties, like UHS-II mode,
> should be placed in a card structure, not a host structure.
>
> > >
> > > So I wonder why this code still works.
> > > I guess that it is because set_signal_voltage(), or other variant 
> > > functions,
> > > will never be called for UHS-II cards under the current implementation.
> > >
> > > Looking at mmc_sd_init_card(), we have added some hack:
> > > mmc_sd_init_card()
> > > {
> > > ...
> > > /* For UHS2, skip the UHS-I initialization. */
> > > if ((host->flags & MMC_UHS2_SUPPORT) &&
> > > (host->flags & MMC_UHS2_INITIALIZED))
> > > goto done;
> > > ...
> > > if (mmc_sd_card_using_v18(card)) {
> > > if (mmc_host_set_uhs_voltage(host) ||
> > > mmc_sd_init_uhs_card(card)) {
> > > ...
> > > }
> > >
> > > Ben, can you confirm this?
> > > (There is another callsite of mmc_host_set_uhs_voltage() though.)
> >
> > UHS-II cards use differential signals and don't need to signal voltage 
> > switch.
> > But the main task is to set the parameters of UHS-II card interface.
>
> Whoever sets MMC_UHS2_SUPPORT (and MMC_UHS2_INITIALIZED), my assertion above
> (mmc_host_set_uhs_voltage, and hence [sdhci_]start_signal_voltage_switch(), is
> never called for UHS-II cards) will be valid, isn't it?
>
> -Takahiro Akashi
>
> > >
> > > > >> Please look at hooking ->start_signal_voltage_switch() instead
> > > > >
> > > > > Do you mean that you want every platform driver who wants to support 
> > > > > UHS-II
> > > > > to set NULL to start_signal_voltage_switch hook even if this hack is
> > > > > platform agnostic?
> > > >
> > > > No, I see UHS-II as a separate layer i.e.
> > > >
> > > >  UHS-II host controller driver
> > > >   |   |
> > > >   |   v
> > > >   |   sdhci-uhs2 e.g. sdhci_uhs2_start_signal_voltage_switch
> > > >   |   |
> > > >   v   v
> > > >   sdhci e.g. sdhci_start_signal_voltage_switch
> > > >
> > > > Most things should go through sdhci-uhs2 but not nessarily everything.
> > >
> > > What I meant by my previous comment is that we don't have to
> > > call any function, sdhci_uhs2_start_signal_voltage_switch in above 
> > > example,
> > > for UHS-II cards in any case since it is always simply empty.
> > >
> > > -Takahiro Akashi


Re: [RFC PATCH V3 13/21] mmc: sdhci: UHS-II support, skip signal_voltage_switch()

2020-09-15 Thread Ben Chuang
Hi Takahiro,

On Tue, Sep 15, 2020 at 2:03 PM AKASHI Takahiro
 wrote:
>
> Ben, Adrian,
>
> On Mon, Sep 14, 2020 at 11:08:14AM +0300, Adrian Hunter wrote:
> > On 14/09/20 9:40 am, AKASHI Takahiro wrote:
> > > Adrian,
> > >
> > > On Fri, Aug 21, 2020 at 05:09:01PM +0300, Adrian Hunter wrote:
> > >> On 10/07/20 2:11 pm, Ben Chuang wrote:
> > >>> From: AKASHI Takahiro 
> > >>>
> > >>> sdhci_start_signal_voltage_switch() should be called only in UHS-I mode,
> > >>> and not for UHS-II mode.
> > >>>
> > >>> Signed-off-by: Ben Chuang 
> > >>> Signed-off-by: AKASHI Takahiro 
> > >>> ---
> > >>>  drivers/mmc/host/sdhci.c | 7 ++-
> > >>>  1 file changed, 6 insertions(+), 1 deletion(-)
> > >>>
> > >>> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> > >>> index 5511649946b9..7f2537648a08 100644
> > >>> --- a/drivers/mmc/host/sdhci.c
> > >>> +++ b/drivers/mmc/host/sdhci.c
> > >>> @@ -2623,8 +2623,13 @@ int sdhci_start_signal_voltage_switch(struct 
> > >>> mmc_host *mmc,
> > >>>   /*
> > >>>* Signal Voltage Switching is only applicable for Host Controllers
> > >>>* v3.00 and above.
> > >>> +  * But for UHS2, the signal voltage is supplied by vdd2 which is
> > >>> +  * already 1.8v so no voltage switch required.
>
> I have been confused with this comment.
> (I know it came from the original Intel code, not from Ben.)
>
> If this comment is true,
>
> > >>>*/
> > >>> - if (host->version < SDHCI_SPEC_300)
> > >>> + if (host->version < SDHCI_SPEC_300 ||
> > >>> + (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> > >>> +  host->version >= SDHCI_SPEC_400 &&
> > >>> +  host->mmc->flags & MMC_UHS2_SUPPORT))
>
> the condition above must be wrong since 'flags & MMC_UHS2_SUPPORT'
> is one of capabilities for a host controller, not a card
> while the selection of voltage depends on a card type.

The flag MMC_UHS2_SUPPORT is set at the beginning of mmc_uhs2_rescan_try_freq().
In UHS-II flow, it stays set.
If the attempt to UHS-II fails finally, it will be unset.

>
> So I wonder why this code still works.
> I guess that it is because set_signal_voltage(), or other variant functions,
> will never be called for UHS-II cards under the current implementation.
>
> Looking at mmc_sd_init_card(), we have added some hack:
> mmc_sd_init_card()
> {
> ...
> /* For UHS2, skip the UHS-I initialization. */
> if ((host->flags & MMC_UHS2_SUPPORT) &&
> (host->flags & MMC_UHS2_INITIALIZED))
> goto done;
> ...
> if (mmc_sd_card_using_v18(card)) {
> if (mmc_host_set_uhs_voltage(host) ||
> mmc_sd_init_uhs_card(card)) {
> ...
> }
>
> Ben, can you confirm this?
> (There is another callsite of mmc_host_set_uhs_voltage() though.)

UHS-II cards use differential signals and don't need to signal voltage switch.
But the main task is to set the parameters of UHS-II card interface.

>
> > >> Please look at hooking ->start_signal_voltage_switch() instead
> > >
> > > Do you mean that you want every platform driver who wants to support 
> > > UHS-II
> > > to set NULL to start_signal_voltage_switch hook even if this hack is
> > > platform agnostic?
> >
> > No, I see UHS-II as a separate layer i.e.
> >
> >  UHS-II host controller driver
> >   |   |
> >   |   v
> >   |   sdhci-uhs2 e.g. sdhci_uhs2_start_signal_voltage_switch
> >   |   |
> >   v   v
> >   sdhci e.g. sdhci_start_signal_voltage_switch
> >
> > Most things should go through sdhci-uhs2 but not nessarily everything.
>
> What I meant by my previous comment is that we don't have to
> call any function, sdhci_uhs2_start_signal_voltage_switch in above example,
> for UHS-II cards in any case since it is always simply empty.
>
> -Takahiro Akashi


Re: [RFC PATCH V3 04/21] mmc: core: UHS-II support, try to select UHS-II interface

2020-08-21 Thread Ben Chuang
On Tue, Aug 18, 2020 at 7:42 PM Ulf Hansson  wrote:
>
> On Fri, 10 Jul 2020 at 13:08, Ben Chuang  wrote:
> >
> > From: Ben Chuang 
> >
> > The flow of "interface selection and initialization" was a bit modified
> > for UHS-II card. This commit follows the sequence defined in SD
> > specification (Part 1).
> > See section 7.2.3 in "UHS-II Simplified Addendum."
> >
> > Signed-off-by: Ben Chuang 
> > Signed-off-by: AKASHI Takahiro 
> > ---
> >  drivers/mmc/core/Makefile |   2 +-
> >  drivers/mmc/core/bus.c|   5 +-
> >  drivers/mmc/core/core.c   |  33 +-
> >  drivers/mmc/core/sd.c |  26 ++
> >  drivers/mmc/core/uhs2.c   | 800 ++
> >  drivers/mmc/core/uhs2.h   |  20 +
> >  6 files changed, 882 insertions(+), 4 deletions(-)
> >  create mode 100644 drivers/mmc/core/uhs2.c
> >  create mode 100644 drivers/mmc/core/uhs2.h
> >
> > diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile
> > index 95ffe008ebdf..e2a90dc98afc 100644
> > --- a/drivers/mmc/core/Makefile
> > +++ b/drivers/mmc/core/Makefile
> > @@ -8,7 +8,7 @@ mmc_core-y  := core.o bus.o host.o \
> >mmc.o mmc_ops.o sd.o sd_ops.o \
> >sdio.o sdio_ops.o sdio_bus.o \
> >sdio_cis.o sdio_io.o sdio_irq.o \
> > -  slot-gpio.o regulator.o
> > +  slot-gpio.o regulator.o uhs2.o
> >  mmc_core-$(CONFIG_OF)  += pwrseq.o
> >  obj-$(CONFIG_PWRSEQ_SIMPLE)+= pwrseq_simple.o
> >  obj-$(CONFIG_PWRSEQ_SD8787)+= pwrseq_sd8787.o
> > diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
> > index 70207f11a654..66d3e942f3fc 100644
> > --- a/drivers/mmc/core/bus.c
> > +++ b/drivers/mmc/core/bus.c
> > @@ -350,8 +350,9 @@ int mmc_add_card(struct mmc_card *card)
> > } else {
> > pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
> > mmc_hostname(card->host),
> > -   mmc_card_uhs(card) ? "ultra high speed " :
> > -   (mmc_card_hs(card) ? "high speed " : ""),
> > +   mmc_card_uhs2(card) ? "ultra high speed 2 " :
> > +   (mmc_card_uhs(card) ? "ultra high speed 1 " :
>
> Perhaps use "UHS-I" and "UHS-II" instead.

OK, The next version will be changed.

>
> > +   (mmc_card_hs(card) ? "high speed " : "")),
> > mmc_card_hs400(card) ? "HS400 " :
> > (mmc_card_hs200(card) ? "HS200 " : ""),
> > mmc_card_hs400es(card) ? "Enhanced strobe " : "",
> > diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
> > index c6540d56646b..e2534f3446ce 100644
> > --- a/drivers/mmc/core/core.c
> > +++ b/drivers/mmc/core/core.c
> > @@ -31,6 +31,7 @@
> >  #include 
> >  #include 
> >  #include 
> > +#include 
> >
> >  #define CREATE_TRACE_POINTS
> >  #include 
> > @@ -41,6 +42,7 @@
> >  #include "host.h"
> >  #include "sdio_bus.h"
> >  #include "pwrseq.h"
> > +#include "uhs2.h"
> >
> >  #include "mmc_ops.h"
> >  #include "sd_ops.h"
> > @@ -51,6 +53,7 @@
> >  #define SD_DISCARD_TIMEOUT_MS  (250)
> >
> >  static const unsigned freqs[] = { 40, 30, 20, 10 };
> > +static const unsigned int uhs2_freqs[] = { 5200, 2600 };
> >
> >  /*
> >   * Enabling software CRCs on the data blocks can be a significant (30%)
> > @@ -2165,9 +2168,10 @@ static int mmc_rescan_try_freq(struct mmc_host 
> > *host, unsigned freq)
> > if (!mmc_attach_sdio(host))
> > return 0;
> >
> > -   if (!(host->caps2 & MMC_CAP2_NO_SD))
> > +   if (!(host->caps2 & MMC_CAP2_NO_SD)) {
> > if (!mmc_attach_sd(host))
> > return 0;
> > +   }
> >
> > if (!(host->caps2 & MMC_CAP2_NO_MMC))
> > if (!mmc_attach_mmc(host))
> > @@ -2300,6 +2304,33 @@ void mmc_rescan(struct work_struct *work)
> > goto out;
> > }
> >
> > +   if (host->caps & MMC_CAP_UHS2) {
> > +

Re: [RFC PATCH V3 02/21] mmc: core: UHS-II support, modify power-up sequence

2020-08-21 Thread Ben Chuang
On Fri, Jul 24, 2020 at 8:36 PM Ulf Hansson  wrote:
>
> On Fri, 24 Jul 2020 at 13:11, Ben Chuang  wrote:
> >
> > Hi Ulf,
> >
> > On Fri, Jul 17, 2020 at 7:26 PM Ulf Hansson  wrote:
> > >
> > > On Fri, 10 Jul 2020 at 13:07, Ben Chuang  wrote:
> > > >
> > > > From: AKASHI Takahiro 
> > > >
> > > > According to Fig. 3-35 in "SD Host Controller Simplified Spec. Ver4.20":
> > > > - Prepare vdd1, vdd2 and ios.timing for using after/in step (2)
> > > > - chip_select is not used in UHS-II, used to return to the legacy flow
> > >
> > > Thanks for pointing to the spec, but please explain why/what/how for
> > > the change - as this helps me to review.
> > >
> > > I am going to stop commenting on each patch's commit message, beyond
> > > this patch - as it seems the same comment applies to more patches.
> > >
> > > >
> > > > Signed-off-by: Ben Chuang 
> > > > Signed-off-by: AKASHI Takahiro 
> > > > ---
> > > >  drivers/mmc/core/core.c  | 62 
> > > >  drivers/mmc/core/regulator.c | 14 
> > > >  2 files changed, 56 insertions(+), 20 deletions(-)
> > > >
> > > > diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
> > > > index 8d2b808e9b58..85c83c82ad0c 100644
> > > > --- a/drivers/mmc/core/core.c
> > > > +++ b/drivers/mmc/core/core.c
> > > > @@ -1315,33 +1315,51 @@ void mmc_power_up(struct mmc_host *host, u32 
> > > > ocr)
> > > > if (host->ios.power_mode == MMC_POWER_ON)
> > > > return;
> > > >
> > > > -   mmc_pwrseq_pre_power_on(host);
> > > > +   if (host->flags & MMC_UHS2_SUPPORT) {
> > > > +   /* TODO: handle 'ocr' parameter */
> > > > +   host->ios.vdd = fls(host->ocr_avail) - 1;
> > > > +   host->ios.vdd2 = fls(host->ocr_avail_uhs2) - 1;
> > > > +   if (mmc_host_is_spi(host))
> > > > +   host->ios.chip_select = MMC_CS_HIGH;
> > > > +   else
> > > > +   host->ios.chip_select = MMC_CS_DONTCARE;
> > > > +   host->ios.timing = MMC_TIMING_UHS2;
> > >
> > > If I understand correctly, the intent is to always try to initialize
> > > the UHS-II interface/phy if that is supported. That doesn't seem
> > > correct to me. What about if the SD card doesn't support UHS-II, then
> > > we should use the legacy SD interface instead right?
> >
> > Please always try UHS-II I/F first, then if UHS-II I/F fails, then
> > switch to SD I/F.
> >
> > >
> > > Or perhaps the MMC_UHS2_SUPPORT bit becomes cleared somewhere in the
> > > error path when first trying to initialize an UHS-II card, from
> > > subsequent changes?
> >
> > Yes, MMC_UHS2_SUPPORT will be cleared in some cases.
> >
> > >
> > > So, assuming that is the intent then, I am still not sure about this 
> > > approach.
> > >
> > > What about if we instead always start with legacy SD initialization?
> > > When we have read the OCR register, via mmc_send_app_op_cond(), we can
> > > check if the card supports UHS-II by looking at the UHS-II Card Status
> > > (bit 29).
> >
> > UHS-II spec recommends to detect UHS-II first.
> > Or in Host controller spec, section 3.13.2 card interface detection 
> > sequence,
> > it also starts from UHS-II path, then go SD legacy path if UHS-II
> > initialization fails.
>
> I have carefully read the specs. While you are right, that the flow
> charts seem to prefer to start with UHS-II - I don't think it's a good
> idea.
>
> Have a look at "7.2.3.2 Interface Selection after Power Up", in the
> UHS-II Addendum Version 2.00. This section states this:
>
> "If Host intends to use only Legacy SD interface or detects that
> Legacy SD Card is inserted, it is allowed to supply only VDD1 and
> SDCLK, and issue CMD8 in order to accelerate initialization of Legacy
> SD interface. Note that once UHS-II I/F is disabled, Host requires
> power cycle to enable UHS-II again."
>
> That said, I am also concerned about the case when a bootloader has
> initialized the SD card. When the kernel tries to re-initialize the
> card during boot, it may fail with UHS-II - unless the legacy SD init
> path is tried first.
>
> >
> &g

Re: [RFC PATCH V3 02/21] mmc: core: UHS-II support, modify power-up sequence

2020-07-24 Thread Ben Chuang
Hi Ulf,

On Fri, Jul 17, 2020 at 7:26 PM Ulf Hansson  wrote:
>
> On Fri, 10 Jul 2020 at 13:07, Ben Chuang  wrote:
> >
> > From: AKASHI Takahiro 
> >
> > According to Fig. 3-35 in "SD Host Controller Simplified Spec. Ver4.20":
> > - Prepare vdd1, vdd2 and ios.timing for using after/in step (2)
> > - chip_select is not used in UHS-II, used to return to the legacy flow
>
> Thanks for pointing to the spec, but please explain why/what/how for
> the change - as this helps me to review.
>
> I am going to stop commenting on each patch's commit message, beyond
> this patch - as it seems the same comment applies to more patches.
>
> >
> > Signed-off-by: Ben Chuang 
> > Signed-off-by: AKASHI Takahiro 
> > ---
> >  drivers/mmc/core/core.c  | 62 
> >  drivers/mmc/core/regulator.c | 14 
> >  2 files changed, 56 insertions(+), 20 deletions(-)
> >
> > diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
> > index 8d2b808e9b58..85c83c82ad0c 100644
> > --- a/drivers/mmc/core/core.c
> > +++ b/drivers/mmc/core/core.c
> > @@ -1315,33 +1315,51 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
> > if (host->ios.power_mode == MMC_POWER_ON)
> > return;
> >
> > -   mmc_pwrseq_pre_power_on(host);
> > +   if (host->flags & MMC_UHS2_SUPPORT) {
> > +   /* TODO: handle 'ocr' parameter */
> > +   host->ios.vdd = fls(host->ocr_avail) - 1;
> > +   host->ios.vdd2 = fls(host->ocr_avail_uhs2) - 1;
> > +   if (mmc_host_is_spi(host))
> > +   host->ios.chip_select = MMC_CS_HIGH;
> > +   else
> > +   host->ios.chip_select = MMC_CS_DONTCARE;
> > +   host->ios.timing = MMC_TIMING_UHS2;
>
> If I understand correctly, the intent is to always try to initialize
> the UHS-II interface/phy if that is supported. That doesn't seem
> correct to me. What about if the SD card doesn't support UHS-II, then
> we should use the legacy SD interface instead right?

Please always try UHS-II I/F first, then if UHS-II I/F fails, then
switch to SD I/F.

>
> Or perhaps the MMC_UHS2_SUPPORT bit becomes cleared somewhere in the
> error path when first trying to initialize an UHS-II card, from
> subsequent changes?

Yes, MMC_UHS2_SUPPORT will be cleared in some cases.

>
> So, assuming that is the intent then, I am still not sure about this approach.
>
> What about if we instead always start with legacy SD initialization?
> When we have read the OCR register, via mmc_send_app_op_cond(), we can
> check if the card supports UHS-II by looking at the UHS-II Card Status
> (bit 29).

UHS-II spec recommends to detect UHS-II first.
Or in Host controller spec, section 3.13.2 card interface detection sequence,
it also starts from UHS-II path, then go SD legacy path if UHS-II
initialization fails.

The bit29 in response of ACMD41 is defined as “UHS-II Card Status”,
not UHS-II supported.
We have experience using this value to determine whether a card supports UHS-II,
but not every card reports if they support UHS-II by the response of
ACMD41 correctly.

>
> If it turns out that the card supports UHS-II and the host does as
> well, then we do a mmc_power_off() to completely reset the
> card/host/phy. Then we can call into a UHS-II specific path, that
> tries to power on and initialize things according to the UHS-II spec.
>
> In this way, we are going to prioritize initialization of legacy SD
> cards to remain quick, as we won't try to use UHS-II unless the card
> supports it. Moreover, I get the impression that we can keep the
> existing code more as is - and instead introduce UHS-II specifics in a
> separate path. This also also for UHS-II specific optimizations, I
> think.

Agree that we can try to keep the existing code and also need your advice/help.

>
> > +   } else {
> > +   mmc_pwrseq_pre_power_on(host);
> >
> > -   host->ios.vdd = fls(ocr) - 1;
> > -   host->ios.power_mode = MMC_POWER_UP;
> > -   /* Set initial state and call mmc_set_ios */
> > -   mmc_set_initial_state(host);
> > +   host->ios.vdd = fls(ocr) - 1;
> > +   host->ios.power_mode = MMC_POWER_UP;
> > +   /* Set initial state and call mmc_set_ios */
> > +   mmc_set_initial_state(host);
> >
> > -   mmc_set_initial_signal_voltage(host);
> > +   mmc_set_initial_signal_voltage(host);
> >
> > -   /*
> > -* This delay should be sufficient to allow the pow

Re: [RFC PATCH V3 01/21] mmc: add UHS-II related definitions in public headers

2020-07-22 Thread Ben Chuang
Hi Ulf,

On Fri, Jul 17, 2020 at 6:55 PM Ulf Hansson  wrote:
>
> On Fri, 10 Jul 2020 at 13:07, Ben Chuang  wrote:
> >
> > From: Ben Chuang 
> >
> > Add UHS-II support in public headers
>
> I realized that many of the patches in the series have quite limited
> information in the commit message. I would really appreciate it if you
> could extend this/them to further explain the change(s).
>
> Please consider answering, "what", "why" and "how" for each patch.
>
> That said, the below changes seems overall like they will be needed
> (in one way or the other).
>
> >
> > Signed-off-by: Ben Chuang 
> > Signed-off-by: AKASHI Takahiro 
> > ---
> >  include/linux/mmc/card.h |   1 +
> >  include/linux/mmc/core.h |   6 +
> >  include/linux/mmc/host.h |  30 +
> >  include/linux/mmc/uhs2.h | 268 +++
> >  4 files changed, 305 insertions(+)
> >  create mode 100644 include/linux/mmc/uhs2.h
> >
> > diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> > index 7d46411ffaa2..b7a7ce928155 100644
> > --- a/include/linux/mmc/card.h
> > +++ b/include/linux/mmc/card.h
> > @@ -181,6 +181,7 @@ struct sd_switch_caps {
> >  #define SD_SET_CURRENT_LIMIT_400   1
> >  #define SD_SET_CURRENT_LIMIT_600   2
> >  #define SD_SET_CURRENT_LIMIT_800   3
> > +#define SD_SET_CURRENT_LIMIT_1000   4
> >  #define SD_SET_CURRENT_NO_CHANGE   (-1)
> >
> >  #define SD_MAX_CURRENT_200 (1 << SD_SET_CURRENT_LIMIT_200)
> > diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
> > index 29aa50711626..52cb628d03fd 100644
> > --- a/include/linux/mmc/core.h
> > +++ b/include/linux/mmc/core.h
> > @@ -7,6 +7,7 @@
> >
> >  #include 
> >  #include 
> > +#include 
> >
> >  struct mmc_data;
> >  struct mmc_request;
> > @@ -109,6 +110,11 @@ struct mmc_command {
> > unsigned intbusy_timeout;   /* busy detect timeout in 
> > ms */
> > struct mmc_data *data;  /* data segment associated 
> > with cmd */
> > struct mmc_request  *mrq;   /* associated request */
> > +
> > +   struct uhs2_command *uhs2_cmd;  /* UHS2 command */
> > +   u8  *uhs2_resp; /* UHS2 native cmd resp */
> > +   u8  uhs2_resp_len;  /* UHS2 native cmd resp len 
> > */
> > +   u8  uhs2_tmode0_flag; /* UHS2 transfer mode 
> > flag */
> >  };
> >
> >  struct mmc_data {
> > diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> > index 7149bab555d7..56bdb153ef16 100644
> > --- a/include/linux/mmc/host.h
> > +++ b/include/linux/mmc/host.h
> > @@ -15,10 +15,12 @@
> >  #include 
> >  #include 
> >  #include 
> > +#include 
> >
> >  struct mmc_ios {
> > unsigned intclock;  /* clock rate */
> > unsigned short  vdd;
> > +   unsigned short  vdd2;   /* UHS2 VDD2 power supply */
> > unsigned intpower_delay_ms; /* waiting for stable power 
> > */
> >
> >  /* vdd stores the bit number of the selected voltage range from below. */
> > @@ -60,6 +62,7 @@ struct mmc_ios {
> >  #define MMC_TIMING_MMC_DDR52   8
> >  #define MMC_TIMING_MMC_HS200   9
> >  #define MMC_TIMING_MMC_HS400   10
> > +#define MMC_TIMING_UHS211
>
> I believe it could it make sense to replace/extend this to:
>
> MMC_TIMING_UHSII_FD156
> MMC_TIMING_UHSII_HD312
> MMC_TIMING_UHSII_FD312
> MMC_TIMING_UHSII_FD624

MMC_TIMING_UHS2 is used in sdhci_get_preset_value(), it selects uhs-ii
bus speed mode.
I can replace/extend it with MMC_TIMING_UHSII_{FD156|HD312|FD312|FD624}.
Please also help comment sdhci_get_preset_value().

>
> >
> > unsigned char   signal_voltage; /* signalling voltage (1.8V 
> > or 3.3V) */
> >
> > @@ -172,6 +175,11 @@ struct mmc_host_ops {
> >  */
> > int (*multi_io_quirk)(struct mmc_card *card,
> >   unsigned int direction, int blk_size);
> > +   /* UHS2 interfaces */
> > +   int (*uhs2_detect_init)(struct mmc_host *host);
> > +   int (*uhs2_set_reg)(struct mmc_host *host, enum uhs2_act act);
> > +   void(*uhs2_disable_clk)(struct mmc_host *host);
> > +   void(*uhs2_enable_clk)(struct mmc_host *host);
>
> Certainly we will need to add some new callbacks, but 

Re: [RFC PATCH V3 00/21] Add support UHS-II for GL9755

2020-07-20 Thread Ben Chuang
On Fri, Jul 17, 2020 at 6:18 PM Ulf Hansson  wrote:
>
> On Fri, 10 Jul 2020 at 13:07, Ben Chuang  wrote:
> >
> > Summary
> > ===
> > These patches[1] support UHS-II and fix GL9755 UHS-II compatibility.
>
> First of all, thanks for posting this - and my apologies for not
> having the bandwidth to review the earlier versions.
>
> >
> > About UHS-II, roughly deal with the following three parts:
> > 1) A UHS-II detection and initialization:
> > - Host setup to support UHS-II (Section 3.13.1 Host Controller Setup 
> > Sequence
> >   [2]).
> > - Detect a UHS-II I/F (Section 3.13.2 Card Interface Detection Sequence[2]).
> > - In step(9) of Section 3.13.2 in [2], UHS-II initialization is include 
> > Section
> >   3.13.3 UHS-II Card Initialization and Section 3.13.4 UHS-II Setting 
> > Register
> >   Setup Sequence.
> >
> > 2) Send Legacy SD command through SD-TRAN
> > - Encapsulated SD packets are defined in SD-TRAN in order to ensure Legacy 
> > SD
> >   compatibility and preserve Legacy SD infrastructures (Section 7.1.1 Packet
> >   Types and Format Overview[3]).
> > - Host issue a UHS-II CCMD packet or a UHS-II DCMD (Section 3.13.5 UHS-II
> >   CCMD Packet issuing and Section 3.13.6 UHS-II DCMD Packet issuing[2]).
> >
> > 3) UHS-II Interrupt
> > - Except for UHS-II error interrupts, most interrupts share the original
> >   interrupt registers.
>
> The above points to some specifications, which is good, but what I
> really need to be able to do a proper review -  is an explanation of
> *what*, *why* and *how* the series implements the UHS-II support.

What:
 1. detect UHS-II interface of a card
 2. change card to UHS-II mode
 3. send SD command through SD-TRAN
 4. go back to legacy interface if not detect UHS-II interface

Why:
 1. UHS-II card support Legacy Interface and UHS-II interface

How:
  a) Using 3.13.2 Card Interface Detection Sequence
  1. power up, host provides RCLK and STB.L to D0.lane.
  2. host waits D1.lane to change EIDL to STB.L
  3. host starts UHS-II initialization if STB.L

>
> To be clear, I don't need in-depth details, as that should be
> described in each patch's commit message, but I would appreciate an
> overall description of the approach you have taken to implement this.
>
> The reason I need this is because UHS-II is a completely new
> interface/protocol. If it wasn't because that a UHS-II card is also
> required to be backwards compatible with the legacy SD interface, one
> could even consider introducing an entirely new subsystem. Not saying
> that we should, but just pointing out that the series is not trivial
> to review.
>
> That said, I am going to give it a real try to do the review. I will
> try to focus on the overall approach, rather than on the details, at
> least to start with.
>

Thank you, I will be patient.

> >
> > Patch structure
> > ===
> > patch#1-#7: for core
> > patch#8-#17: for sdhci
> > patch#18-#21: for GL9755
> >
> > Tests
> > =
> > Ran 'dd' command to evaluate the performance:
> > (SanDisk UHS-II card on GL9755 controller)
> >  ReadWrite
> > UHS-II disabled (UHS-I): 88.3MB/s 60.7MB/s
> > UHS-II enabled :  206MB/s   80MB/s
>
> I like these comparisons, thanks for sharing!
>
> What UHS-II interface mode does you HW support? FD156, HD312, FD312 FD624?

GL9755 supports up to HD312.

>
> >
> > TODO
> > 
> > - replace some define with BIT macro
> >
> > Reference
> > =
> > [1] https://gitlab.com/ben.chuang/linux-uhs2-gl9755.git
> > [2] SD Host Controller Simplified Specification 4.20
> > [3] UHS-II Simplified Addendum 1.02
> >
> > Changes in v3 (Jul. 10, 2020)
> > * rebased to v5.8-rc4
> > * add copyright notice
> > * reorganize the patch set and split some commits into smaller ones
> > * separate uhs-2 headers from others
> > * correct wrong spellings
> > * fix most of checkpatch warnings/errors
> > * remove all k[cz]alloc() from the code
> > * guard sdhci-uhs2 specific code with
> >   'if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2))'
> > * make sdhci-uhs2.c as a module
> > * trivial changes, including
> >   - rename back sdhci-core.c to sdhci.c
> >   - allow vendor code to disable uhs2 if v4_mode == 0
> >   in __sdhci_add_host()
> >   - merge uhs2_power_up() into mmc_power_up()
> >   - remove flag_uhs2 from mmc_attach_sd()
> >   - add function descriptions to EXPORT'ed functions
> >   - other minor code optimization
> >
> > Changes in v2 (Jan. 9, 2020)
>

[PATCH] mmc: sdhci-pci-gli: Set SDR104's clock to 205MHz and enable SSC for GL975x

2020-07-16 Thread Ben Chuang
From: Ben Chuang 

Set SDR104's clock to 205MHz and enable SSC for GL9750 and GL9755

Signed-off-by: Ben Chuang 
---
 drivers/mmc/host/sdhci-pci-gli.c | 220 ++-
 1 file changed, 218 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c
index ca0166d9bf82..5da2b06d84ae 100644
--- a/drivers/mmc/host/sdhci-pci-gli.c
+++ b/drivers/mmc/host/sdhci-pci-gli.c
@@ -31,10 +31,18 @@
 #define   SDHCI_GLI_9750_ALL_RST  (BIT(24)|BIT(25)|BIT(28)|BIT(30))
 
 #define SDHCI_GLI_9750_PLL   0x864
+#define   SDHCI_GLI_9750_PLL_LDIV   GENMASK(9, 0)
+#define   SDHCI_GLI_9750_PLL_PDIV   GENMASK(14, 12)
+#define   SDHCI_GLI_9750_PLL_DIRBIT(15)
 #define   SDHCI_GLI_9750_PLL_TX2_INVBIT(23)
 #define   SDHCI_GLI_9750_PLL_TX2_DLYGENMASK(22, 20)
 #define   GLI_9750_PLL_TX2_INV_VALUE0x1
 #define   GLI_9750_PLL_TX2_DLY_VALUE0x0
+#define   SDHCI_GLI_9750_PLLSSC_STEPGENMASK(28, 24)
+#define   SDHCI_GLI_9750_PLLSSC_EN  BIT(31)
+
+#define SDHCI_GLI_9750_PLLSSC0x86C
+#define   SDHCI_GLI_9750_PLLSSC_PPMGENMASK(31, 16)
 
 #define SDHCI_GLI_9750_SW_CTRL  0x874
 #define   SDHCI_GLI_9750_SW_CTRL_4GENMASK(7, 6)
@@ -76,6 +84,21 @@
 #define PCIE_GLI_9763E_SCR  0x8E0
 #define   GLI_9763E_SCR_AXI_REQ   BIT(9)
 
+#define PCI_GLI_9755_WT   0x800
+#define   PCI_GLI_9755_WT_ENBIT(0)
+#define   GLI_9755_WT_EN_ON 0x1
+#define   GLI_9755_WT_EN_OFF0x0
+
+#define PCI_GLI_9755_PLL0x64
+#define   PCI_GLI_9755_PLL_LDIV   GENMASK(9, 0)
+#define   PCI_GLI_9755_PLL_PDIV   GENMASK(14, 12)
+#define   PCI_GLI_9755_PLL_DIRBIT(15)
+#define   PCI_GLI_9755_PLLSSC_STEPGENMASK(28, 24)
+#define   PCI_GLI_9755_PLLSSC_EN  BIT(31)
+
+#define PCI_GLI_9755_PLLSSC0x68
+#define   PCI_GLI_9755_PLLSSC_PPMGENMASK(15, 0)
+
 #define GLI_MAX_TUNING_LOOP 40
 
 /* Genesys Logic chipset */
@@ -280,6 +303,84 @@ static int gl9750_execute_tuning(struct sdhci_host *host, 
u32 opcode)
return 0;
 }
 
+static void gl9750_disable_ssc_pll(struct sdhci_host *host)
+{
+   u32 pll;
+
+   gl9750_wt_on(host);
+   pll = sdhci_readl(host, SDHCI_GLI_9750_PLL);
+   pll &= ~(SDHCI_GLI_9750_PLL_DIR | SDHCI_GLI_9750_PLLSSC_EN);
+   sdhci_writel(host, pll, SDHCI_GLI_9750_PLL);
+   gl9750_wt_off(host);
+}
+
+static void gl9750_set_pll(struct sdhci_host *host, u8 dir, u16 ldiv, u8 pdiv)
+{
+   u32 pll;
+
+   gl9750_wt_on(host);
+   pll = sdhci_readl(host, SDHCI_GLI_9750_PLL);
+   pll &= ~(SDHCI_GLI_9750_PLL_LDIV |
+SDHCI_GLI_9750_PLL_PDIV |
+SDHCI_GLI_9750_PLL_DIR);
+   pll |= FIELD_PREP(SDHCI_GLI_9750_PLL_LDIV, ldiv) |
+  FIELD_PREP(SDHCI_GLI_9750_PLL_PDIV, pdiv) |
+  FIELD_PREP(SDHCI_GLI_9750_PLL_DIR, dir);
+   sdhci_writel(host, pll, SDHCI_GLI_9750_PLL);
+   gl9750_wt_off(host);
+
+   /* wait for pll stable */
+   mdelay(1);
+}
+
+static void gl9750_set_ssc(struct sdhci_host *host, u8 enable, u8 step, u16 
ppm)
+{
+   u32 pll;
+   u32 ssc;
+
+   gl9750_wt_on(host);
+   pll = sdhci_readl(host, SDHCI_GLI_9750_PLL);
+   ssc = sdhci_readl(host, SDHCI_GLI_9750_PLLSSC);
+   pll &= ~(SDHCI_GLI_9750_PLLSSC_STEP |
+SDHCI_GLI_9750_PLLSSC_EN);
+   ssc &= ~SDHCI_GLI_9750_PLLSSC_PPM;
+   pll |= FIELD_PREP(SDHCI_GLI_9750_PLLSSC_STEP, step) |
+  FIELD_PREP(SDHCI_GLI_9750_PLLSSC_EN, enable);
+   ssc |= FIELD_PREP(SDHCI_GLI_9750_PLLSSC_PPM, ppm);
+   sdhci_writel(host, ssc, SDHCI_GLI_9750_PLLSSC);
+   sdhci_writel(host, pll, SDHCI_GLI_9750_PLL);
+   gl9750_wt_off(host);
+}
+
+static void gl9750_set_ssc_pll_205mhz(struct sdhci_host *host)
+{
+   /* set pll to 205MHz and enable ssc */
+   gl9750_set_ssc(host, 0x1, 0x1F, 0xFFE7);
+   gl9750_set_pll(host, 0x1, 0x246, 0x0);
+}
+
+static void sdhci_gl9750_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+   struct mmc_ios *ios = >mmc->ios;
+   u16 clk;
+
+   host->mmc->actual_clock = 0;
+
+   gl9750_disable_ssc_pll(host);
+   sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
+
+   if (clock == 0)
+   return;
+
+   clk = sdhci_calc_clk(host, clock, >mmc->actual_clock);
+   if (clock == 2 && ios->timing == MMC_TIMING_UHS_SDR104) {
+   host->mmc->actual_clock = 20500;
+   gl9750_set_ssc_pll_205mhz(host);
+   }
+
+   sdhci_enable_clk(host, clk);
+}
+
 static void gli_pcie_enable_msi(struct sdhci_pci_slot *slot)
 {
int ret;
@@ -295,6 +396,121 @@ static void gli_pcie_enable_msi(struct sdhci_pci_slot 
*slot)
slot->host->irq = pci_irq_vector(slot->chip->pdev, 0);
 }
 
+static inline void gl9755_wt_on(struct pci_dev *pdev)
+{
+   u32 wt_value;
+   u32 wt_enable;
+
+   pci_read

[PATCH] mmc: cqhci: Fix a print format for the task descriptor

2020-07-15 Thread Ben Chuang
The format string of the task descriptor should be "%016llx".

Signed-off-by: Ben Chuang 
---
 drivers/mmc/host/cqhci.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mmc/host/cqhci.c b/drivers/mmc/host/cqhci.c
index 75934f3c117e..280d64d0b809 100644
--- a/drivers/mmc/host/cqhci.c
+++ b/drivers/mmc/host/cqhci.c
@@ -422,7 +422,7 @@ static void cqhci_prep_task_desc(struct mmc_request *mrq,
CQHCI_BLK_COUNT(mrq->data->blocks) |
CQHCI_BLK_ADDR((u64)mrq->data->blk_addr);
 
-   pr_debug("%s: cqhci: tag %d task descriptor 0x016%llx\n",
+   pr_debug("%s: cqhci: tag %d task descriptor 0x%016llx\n",
 mmc_hostname(mrq->host), mrq->tag, (unsigned long long)*data);
 }
 
-- 
2.27.0



[RFC PATCH V3 21/21] mmc: sdhci-pci-gli: enable UHS-II mode for GL9755

2020-07-10 Thread Ben Chuang
From: Ben Chuang 

Changes are:
* Disable GL9755 overcurrent interrupt when power on/off on UHS-II.
* Enable the internal clock when do reset on UHS-II mode.
* Set ZC to 0x0 for Sandisk cards and set ZC to 0xB for others.
* Increase timeout value before detecting UHS-II interface.
* Add vendor settings fro UHS-II mode.

Signed-off-by: Ben Chuang 
---
 drivers/mmc/host/Kconfig |   1 +
 drivers/mmc/host/sdhci-pci-gli.c | 361 ++-
 2 files changed, 361 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index ffeef38264c0..88e27d3a032b 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -102,6 +102,7 @@ config MMC_SDHCI_PCI
tristate "SDHCI support on PCI bus"
depends on MMC_SDHCI && PCI
select MMC_CQHCI
+   select MMC_SDHCI_UHS2
select IOSF_MBI if X86
select MMC_SDHCI_IO_ACCESSORS
help
diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c
index ca0166d9bf82..16be8e47bf15 100644
--- a/drivers/mmc/host/sdhci-pci-gli.c
+++ b/drivers/mmc/host/sdhci-pci-gli.c
@@ -14,6 +14,7 @@
 #include 
 #include "sdhci.h"
 #include "sdhci-pci.h"
+#include "sdhci-uhs2.h"
 
 /*  Genesys Logic extra registers */
 #define SDHCI_GLI_9750_WT 0x800
@@ -63,6 +64,42 @@
 #define   SDHCI_GLI_9750_TUNING_PARAMETERS_RX_DLYGENMASK(2, 0)
 #define   GLI_9750_TUNING_PARAMETERS_RX_DLY_VALUE0x1
 
+#define PCI_GLI_9755_WT   0x800
+#define   PCI_GLI_9755_WT_ENBIT(0)
+#define   GLI_9755_WT_EN_ON0x1
+#define   GLI_9755_WT_EN_OFF0x0
+
+#define PCI_GLI_9755_PLLSSC 0x68
+#define   PCI_GLI_9755_PLLSSC_RTL BIT(24)
+#define   GLI_9755_PLLSSC_RTL_VALUE   0x1
+#define   PCI_GLI_9755_PLLSSC_TRANS_PASS  BIT(27)
+#define   GLI_9755_PLLSSC_TRANS_PASS_VALUE0x1
+#define   PCI_GLI_9755_PLLSSC_RECVGENMASK(29, 28)
+#define   GLI_9755_PLLSSC_RECV_VALUE  0x3
+#define   PCI_GLI_9755_PLLSSC_TRANGENMASK(31, 30)
+#define   GLI_9755_PLLSSC_TRAN_VALUE  0x3
+
+#define PCI_GLI_9755_UHS2_PLL0x6C
+#define   PCI_GLI_9755_UHS2_PLL_SSCGENMASK(9, 8)
+#define   GLI_9755_UHS2_PLL_SSC_VALUE  0x0
+#define   PCI_GLI_9755_UHS2_PLL_DELAY  BIT(18)
+#define   GLI_9755_UHS2_PLL_DELAY_VALUE0x1
+#define   PCI_GLI_9755_UHS2_PLL_PDRST  BIT(27)
+#define   GLI_9755_UHS2_PLL_PDRST_VALUE0x1
+
+#define PCI_GLI_9755_UHS2_SERDES   0x70
+#define   PCI_GLI_9755_UHS2_SERDES_INTR   GENMASK(2, 0)
+#define   GLI_9755_UHS2_SERDES_INTR_VALUE 0x3
+#define   PCI_GLI_9755_UHS2_SERDES_ZC1BIT(3)
+#define   GLI_9755_UHS2_SERDES_ZC1_VALUE  0x0
+#define   PCI_GLI_9755_UHS2_SERDES_ZC2GENMASK(7, 4)
+#define   GLI_9755_UHS2_SERDES_ZC2_DEFAULT0xB
+#define   GLI_9755_UHS2_SERDES_ZC2_SANDISK0x0
+#define   PCI_GLI_9755_UHS2_SERDES_TRAN   GENMASK(27, 24)
+#define   GLI_9755_UHS2_SERDES_TRAN_VALUE 0xC
+#define   PCI_GLI_9755_UHS2_SERDES_RECV   GENMASK(31, 28)
+#define   GLI_9755_UHS2_SERDES_RECV_VALUE 0xF
+
 #define SDHCI_GLI_9763E_CTRL_HS400  0x7
 
 #define SDHCI_GLI_9763E_HS400_ES_REG  0x52C
@@ -295,6 +332,324 @@ static void gli_pcie_enable_msi(struct sdhci_pci_slot 
*slot)
slot->host->irq = pci_irq_vector(slot->chip->pdev, 0);
 }
 
+static inline void gl9755_wt_on(struct pci_dev *pdev)
+{
+   u32 wt_value;
+   u32 wt_enable;
+
+   pci_read_config_dword(pdev, PCI_GLI_9755_WT, _value);
+   wt_enable = FIELD_GET(PCI_GLI_9755_WT_EN, wt_value);
+
+   if (wt_enable == GLI_9755_WT_EN_ON)
+   return;
+
+   wt_value &= ~PCI_GLI_9755_WT_EN;
+   wt_value |= FIELD_PREP(PCI_GLI_9755_WT_EN, GLI_9755_WT_EN_ON);
+
+   pci_write_config_dword(pdev, PCI_GLI_9755_WT, wt_value);
+}
+
+static inline void gl9755_wt_off(struct pci_dev *pdev)
+{
+   u32 wt_value;
+   u32 wt_enable;
+
+   pci_read_config_dword(pdev, PCI_GLI_9755_WT, _value);
+   wt_enable = FIELD_GET(PCI_GLI_9755_WT_EN, wt_value);
+
+   if (wt_enable == GLI_9755_WT_EN_OFF)
+   return;
+
+   wt_value &= ~PCI_GLI_9755_WT_EN;
+   wt_value |= FIELD_PREP(PCI_GLI_9755_WT_EN, GLI_9755_WT_EN_OFF);
+
+   pci_write_config_dword(pdev, PCI_GLI_9755_WT, wt_value);
+}
+
+static void gl9755_vendor_init(struct sdhci_host *host)
+{
+   struct sdhci_pci_slot *slot = sdhci_priv(host);
+   struct pci_dev *pdev = slot->chip->pdev;
+   u32 serdes;
+   u32 pllssc;
+   u32 uhs2_pll;
+
+   gl9755_wt_on(pdev);
+
+   pci_read_config_dword(pdev, PCI_GLI_9755_UHS2_SERDES, );
+   serdes &= ~PCI_GLI_9755_UHS2_SERDES_TRAN;
+   serdes |= FIELD_PREP(PCI_GLI_9755_UHS2_SERDES_TRAN,
+GLI_9755_UHS2_SERDES_TRAN_VALUE);
+   serdes &= ~PCI_GLI

[RFC PATCH V3 19/21] mmc: core: add post-mmc_attach_sd hook

2020-07-10 Thread Ben Chuang
From: AKASHI Takahiro 

This "post" hook for mmc_attach_sd() will be required to enable UHS-II
support, at least, on GL9755.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/core/sd.c| 6 ++
 include/linux/mmc/host.h | 1 +
 2 files changed, 7 insertions(+)

diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index c5b071bd98b3..fd4cae4ed747 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1381,6 +1381,12 @@ int mmc_attach_sd(struct mmc_host *host)
goto remove_card;
 
mmc_claim_host(host);
+
+   /* TODO: Is this the right place? */
+   if ((host->flags & MMC_UHS2_INITIALIZED) &&
+   host->ops->uhs2_post_attach_sd)
+   host->ops->uhs2_post_attach_sd(host);
+
return 0;
 
 remove_card:
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 56bdb153ef16..e61e0ae62cff 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -180,6 +180,7 @@ struct mmc_host_ops {
int (*uhs2_set_reg)(struct mmc_host *host, enum uhs2_act act);
void(*uhs2_disable_clk)(struct mmc_host *host);
void(*uhs2_enable_clk)(struct mmc_host *host);
+   void(*uhs2_post_attach_sd)(struct mmc_host *host);
 };
 
 struct mmc_cqe_ops {
-- 
2.27.0



[RFC PATCH V3 20/21] mmc: sdhci-uhs2: add post-mmc_attach_sd hook

2020-07-10 Thread Ben Chuang
From: Ben Chuang 

This "post" hook for mmc_attach_sd(), uhs2_post_attach_sd, will be required
to enable UHS-II support, at least, on GL9755.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/host/sdhci.c | 9 +
 drivers/mmc/host/sdhci.h | 1 +
 2 files changed, 10 insertions(+)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 5d84e61f6ad9..a2cc5f758547 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -3155,6 +3155,14 @@ static void sdhci_uhs2_enable_clk(struct mmc_host *mmc)
udelay(10);
}
 }
+
+static void sdhci_uhs2_post_attach_sd(struct mmc_host *mmc)
+{
+   struct sdhci_host *host = mmc_priv(mmc);
+
+   if (host->ops && host->ops->uhs2_post_attach_sd)
+   host->ops->uhs2_post_attach_sd(host);
+}
 #endif /* CONFIG_MMC_SDHCI_UHS2 */
 
 static const struct mmc_host_ops sdhci_ops = {
@@ -3177,6 +3185,7 @@ static const struct mmc_host_ops sdhci_ops = {
.uhs2_set_reg   = sdhci_uhs2_set_reg,
.uhs2_disable_clk   = sdhci_uhs2_disable_clk,
.uhs2_enable_clk= sdhci_uhs2_enable_clk,
+   .uhs2_post_attach_sd= sdhci_uhs2_post_attach_sd,
 #endif /* CONFIG_MMC_SDHCI_UHS2 */
 };
 
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index c825a8130bc1..d613ff8daaf6 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -723,6 +723,7 @@ struct sdhci_ops {
void(*dump_vendor_regs)(struct sdhci_host *host);
/* UHS-2 support */
void(*uhs2_pre_detect_init)(struct sdhci_host *host);
+   void(*uhs2_post_attach_sd)(struct sdhci_host *host);
 };
 
 struct sdhci_uhs2_ops {
-- 
2.27.0



[RFC PATCH V3 16/21] mmc: sdhci: UHS-II support, export helper functions to a module

2020-07-10 Thread Ben Chuang
From: AKASHI Takahiro 

Those exported functions will be utilized in the following commit
to implement UHS-II support as a kernel module.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/host/sdhci.c | 14 --
 drivers/mmc/host/sdhci.h | 10 ++
 2 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index ca3d4a506e01..5d84e61f6ad9 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -57,8 +57,6 @@ EXPORT_SYMBOL_GPL(sdhci_uhs2_ops);
 static unsigned int debug_quirks = 0;
 static unsigned int debug_quirks2;
 
-static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
-
 static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command 
*cmd);
 
 void sdhci_dumpregs(struct sdhci_host *host)
@@ -225,13 +223,14 @@ static void sdhci_runtime_pm_bus_on(struct sdhci_host 
*host)
pm_runtime_get_noresume(host->mmc->parent);
 }
 
-static void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
+void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
 {
if (!host->bus_on)
return;
host->bus_on = false;
pm_runtime_put_noidle(host->mmc->parent);
 }
+EXPORT_SYMBOL_GPL(sdhci_runtime_pm_bus_off);
 
 void sdhci_reset(struct sdhci_host *host, u8 mask)
 {
@@ -1560,12 +1559,13 @@ static void __sdhci_finish_mrq(struct sdhci_host *host, 
struct mmc_request *mrq)
sdhci_led_deactivate(host);
 }
 
-static void sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
+void sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
 {
__sdhci_finish_mrq(host, mrq);
 
queue_work(host->complete_wq, >complete_work);
 }
+EXPORT_SYMBOL_GPL(sdhci_finish_mrq);
 
 static void __sdhci_finish_data(struct sdhci_host *host, bool sw_data_timeout)
 {
@@ -1644,10 +1644,11 @@ static void __sdhci_finish_data(struct sdhci_host 
*host, bool sw_data_timeout)
}
 }
 
-static void sdhci_finish_data(struct sdhci_host *host)
+void sdhci_finish_data(struct sdhci_host *host)
 {
__sdhci_finish_data(host, false);
 }
+EXPORT_SYMBOL_GPL(sdhci_finish_data);
 
 static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command 
*cmd)
 {
@@ -2991,7 +2992,7 @@ int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
 }
 EXPORT_SYMBOL_GPL(sdhci_execute_tuning);
 
-static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable)
+void sdhci_enable_preset_value(struct sdhci_host *host, bool enable)
 {
/* Host Controller v3.00 defines preset value registers */
if (host->version < SDHCI_SPEC_300)
@@ -3019,6 +3020,7 @@ static void sdhci_enable_preset_value(struct sdhci_host 
*host, bool enable)
host->preset_enabled = enable;
}
 }
+EXPORT_SYMBOL_GPL(sdhci_enable_preset_value);
 
 static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
int err)
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index f6732f33f29f..927aaba28932 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -893,4 +893,14 @@ void sdhci_switch_external_dma(struct sdhci_host *host, 
bool en);
 void sdhci_set_data_timeout_irq(struct sdhci_host *host, bool enable);
 void __sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd);
 
+/* sdhci_uhs2.c needed */
+void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
+void sdhci_finish_data(struct sdhci_host *host);
+void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
+unsigned short vdd, unsigned short vdd2);
+void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode,
+  unsigned short vdd, unsigned short vdd2);
+void sdhci_runtime_pm_bus_off(struct sdhci_host *host);
+void sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq);
+
 #endif /* __SDHCI_HW_H */
-- 
2.27.0



[RFC PATCH V3 17/21] mmc: sdhci: UHS-II support, implement operations as a module

2020-07-10 Thread Ben Chuang
From: AKASHI Takahiro 

All the UHS-II operations in struct sdhci_uhs2_ops are implemented here
and exported as a kernel module.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/host/Makefile |   1 +
 drivers/mmc/host/sdhci-uhs2.c | 794 ++
 2 files changed, 795 insertions(+)
 create mode 100644 drivers/mmc/host/sdhci-uhs2.c

diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 4d5bcb0144a0..e51430d8f85d 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_MMC_PXA) += pxamci.o
 obj-$(CONFIG_MMC_MXC)  += mxcmmc.o
 obj-$(CONFIG_MMC_MXS)  += mxs-mmc.o
 obj-$(CONFIG_MMC_SDHCI)+= sdhci.o
+obj-$(CONFIG_MMC_SDHCI_UHS2)   += sdhci-uhs2.o
 obj-$(CONFIG_MMC_SDHCI_PCI)+= sdhci-pci.o
 sdhci-pci-y+= sdhci-pci-core.o sdhci-pci-o2micro.o 
sdhci-pci-arasan.o \
   sdhci-pci-dwc-mshc.o sdhci-pci-gli.o
diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
new file mode 100644
index ..3cb13071dd9d
--- /dev/null
+++ b/drivers/mmc/host/sdhci-uhs2.c
@@ -0,0 +1,794 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  linux/drivers/mmc/host/sdhci_uhs2.c - Secure Digital Host Controller
+ *  Interface driver
+ *
+ *  Copyright (C) 2014 Intel Corp, All Rights Reserved.
+ *  Copyright (C) 2020 Genesys Logic, Inc.
+ *  Authors: Ben Chuang 
+ *  Copyright (C) 2020 Linaro Limited
+ *  Author: AKASHI Takahiro 
+ */
+
+#include 
+#include 
+#include 
+
+#include 
+
+#include "sdhci.h"
+#include "sdhci-uhs2.h"
+
+#define DRIVER_NAME "sdhci_uhs2"
+#define DBG(f, x...) \
+   pr_debug(DRIVER_NAME " [%s()]: " f, __func__, ## x)
+
+static void sdhci_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set)
+{
+   u32 ier;
+
+   ier = sdhci_readl(host, SDHCI_INT_ENABLE);
+   ier &= ~clear;
+   ier |= set;
+   sdhci_writel(host, ier, SDHCI_INT_ENABLE);
+   sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE);
+}
+
+/**
+ * sdhci_uhs2_clear_set_irqs - set Error Interrupt Status Enable register
+ * @host:  SDHCI host
+ * @clear: bit-wise clear mask
+ * @set:   bit-wise set mask
+ *
+ * Set/unset bits in UHS-II Error Interrupt Status Enable register
+ */
+void sdhci_uhs2_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set)
+{
+   u32 ier;
+
+   ier = sdhci_readl(host, SDHCI_UHS2_ERR_INT_STATUS_EN);
+   ier &= ~clear;
+   ier |= set;
+   sdhci_writel(host, ier, SDHCI_UHS2_ERR_INT_STATUS_EN);
+   sdhci_writel(host, ier, SDHCI_UHS2_ERR_INT_SIG_EN);
+}
+EXPORT_SYMBOL_GPL(sdhci_uhs2_clear_set_irqs);
+
+/**
+ * sdhci_uhs2_reset - invoke SW reset
+ * @host: SDHCI host
+ * @mask: Control mask
+ *
+ * Invoke SW reset, depending on a bit in @mask and wait for completion.
+ */
+void sdhci_uhs2_reset(struct sdhci_host *host, u16 mask)
+{
+   unsigned long timeout;
+
+   if (!(host->mmc->caps & MMC_CAP_UHS2))
+   return;
+
+   sdhci_writew(host, mask, SDHCI_UHS2_SW_RESET);
+
+   if (mask & SDHCI_UHS2_SW_RESET_FULL) {
+   host->clock = 0;
+   /* Reset-all turns off SD Bus Power */
+   if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
+   sdhci_runtime_pm_bus_off(host);
+   }
+
+   /* Wait max 100 ms */
+   timeout = 1;
+
+   /* hw clears the bit when it's done */
+   while (sdhci_readw(host, SDHCI_UHS2_SW_RESET) & mask) {
+   if (timeout == 0) {
+   pr_err("%s: %s: Reset 0x%x never completed.\n",
+  __func__, mmc_hostname(host->mmc), (int)mask);
+   pr_err("%s: clean reset bit\n",
+  mmc_hostname(host->mmc));
+   sdhci_writeb(host, 0, SDHCI_UHS2_SW_RESET);
+   return;
+   }
+   timeout--;
+   udelay(10);
+   }
+}
+EXPORT_SYMBOL_GPL(sdhci_uhs2_reset);
+
+static u8 sdhci_calc_timeout_uhs2(struct sdhci_host *host, u8 *cmd_res,
+ u8 *dead_lock)
+{
+   u8 count;
+   unsigned int cmd_res_timeout, dead_lock_timeout, current_timeout;
+
+   /*
+* If the host controller provides us with an incorrect timeout
+* value, just skip the check and use 0xE.  The hardware may take
+* longer to time out, but that's much better than having a too-short
+* timeout value.
+*/
+   if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL) {
+   *cmd_res = 0xE;
+   *dead_lock = 0xE;
+   return 0xE;
+   }
+
+   /* timeout in us */
+   cmd_res_timeout = 5 * 1000;
+   dead_lock_timeout = 1 * 1000 * 1000;
+
+   /*
+* Figur

[RFC PATCH V3 18/21] mmc: sdhci-uhs2: add pre-detect_init hook

2020-07-10 Thread Ben Chuang
From: Ben Chuang 

This "pre" hook for detect_init(), uhs2_pre_detect_init, will be required
to enable UHS-II support, at least, on GL9755.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/host/sdhci-uhs2.c | 3 +++
 drivers/mmc/host/sdhci.h  | 2 ++
 2 files changed, 5 insertions(+)

diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
index 3cb13071dd9d..3f7ebf5d18c5 100644
--- a/drivers/mmc/host/sdhci-uhs2.c
+++ b/drivers/mmc/host/sdhci-uhs2.c
@@ -525,6 +525,9 @@ static int sdhci_uhs2_do_detect_init(struct sdhci_host 
*host)
DBG("%s: begin UHS2 init.\n", __func__);
spin_lock_irqsave(>lock, flags);
 
+   if (host->ops && host->ops->uhs2_pre_detect_init)
+   host->ops->uhs2_pre_detect_init(host);
+
if (sdhci_uhs2_interface_detect(host)) {
pr_warn("%s: cannot detect UHS2 interface.\n",
mmc_hostname(host->mmc));
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 927aaba28932..c825a8130bc1 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -721,6 +721,8 @@ struct sdhci_ops {
void(*request_done)(struct sdhci_host *host,
struct mmc_request *mrq);
void(*dump_vendor_regs)(struct sdhci_host *host);
+   /* UHS-2 support */
+   void(*uhs2_pre_detect_init)(struct sdhci_host *host);
 };
 
 struct sdhci_uhs2_ops {
-- 
2.27.0



[RFC PATCH V3 15/21] mmc: sdhci: UHS-II support, modify set_power() to handle vdd2

2020-07-10 Thread Ben Chuang
From: AKASHI Takahiro 

VDD2 is used for powering UHS-II interface.
Modify sdhci_set_power_and_bus_voltage(), sdhci_set_power_noreg()
and sdhci_set_power_noreg() to handle VDD2.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/host/sdhci-omap.c |  2 +-
 drivers/mmc/host/sdhci-pci-core.c |  4 +--
 drivers/mmc/host/sdhci-pxav3.c|  4 +--
 drivers/mmc/host/sdhci-xenon.c|  4 +--
 drivers/mmc/host/sdhci.c  | 42 ---
 drivers/mmc/host/sdhci.h  |  9 +++
 6 files changed, 43 insertions(+), 22 deletions(-)

diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c
index 1ec74c2d5c17..1926585debe5 100644
--- a/drivers/mmc/host/sdhci-omap.c
+++ b/drivers/mmc/host/sdhci-omap.c
@@ -678,7 +678,7 @@ static void sdhci_omap_set_clock(struct sdhci_host *host, 
unsigned int clock)
 }
 
 static void sdhci_omap_set_power(struct sdhci_host *host, unsigned char mode,
- unsigned short vdd)
+ unsigned short vdd, unsigned short vdd2)
 {
struct mmc_host *mmc = host->mmc;
 
diff --git a/drivers/mmc/host/sdhci-pci-core.c 
b/drivers/mmc/host/sdhci-pci-core.c
index bb6802448b2f..40f5a24a8982 100644
--- a/drivers/mmc/host/sdhci-pci-core.c
+++ b/drivers/mmc/host/sdhci-pci-core.c
@@ -629,12 +629,12 @@ static int bxt_get_cd(struct mmc_host *mmc)
 #define SDHCI_INTEL_PWR_TIMEOUT_UDELAY 100
 
 static void sdhci_intel_set_power(struct sdhci_host *host, unsigned char mode,
- unsigned short vdd)
+ unsigned short vdd, unsigned short vdd2)
 {
int cntr;
u8 reg;
 
-   sdhci_set_power(host, mode, vdd);
+   sdhci_set_power(host, mode, vdd, -1);
 
if (mode == MMC_POWER_OFF)
return;
diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c
index e55037ceda73..457e9425339a 100644
--- a/drivers/mmc/host/sdhci-pxav3.c
+++ b/drivers/mmc/host/sdhci-pxav3.c
@@ -298,12 +298,12 @@ static void pxav3_set_uhs_signaling(struct sdhci_host 
*host, unsigned int uhs)
 }
 
 static void pxav3_set_power(struct sdhci_host *host, unsigned char mode,
-   unsigned short vdd)
+   unsigned short vdd, unsigned short vdd2)
 {
struct mmc_host *mmc = host->mmc;
u8 pwr = host->pwr;
 
-   sdhci_set_power_noreg(host, mode, vdd);
+   sdhci_set_power_noreg(host, mode, vdd, -1);
 
if (host->pwr == pwr)
return;
diff --git a/drivers/mmc/host/sdhci-xenon.c b/drivers/mmc/host/sdhci-xenon.c
index 4703cd540c7f..2b0ebb91895a 100644
--- a/drivers/mmc/host/sdhci-xenon.c
+++ b/drivers/mmc/host/sdhci-xenon.c
@@ -214,12 +214,12 @@ static void xenon_set_uhs_signaling(struct sdhci_host 
*host,
 }
 
 static void xenon_set_power(struct sdhci_host *host, unsigned char mode,
-   unsigned short vdd)
+   unsigned short vdd, unsigned short vdd2)
 {
struct mmc_host *mmc = host->mmc;
u8 pwr = host->pwr;
 
-   sdhci_set_power_noreg(host, mode, vdd);
+   sdhci_set_power_noreg(host, mode, vdd, -1);
 
if (host->pwr == pwr)
return;
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index d38d734ec83f..ca3d4a506e01 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2089,12 +2089,15 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned 
int clock)
 EXPORT_SYMBOL_GPL(sdhci_set_clock);
 
 static void sdhci_set_power_reg(struct sdhci_host *host, unsigned char mode,
-   unsigned short vdd)
+   unsigned short vdd, unsigned short vdd2)
 {
struct mmc_host *mmc = host->mmc;
 
mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
 
+   if (mmc->caps & MMC_CAP_UHS2 && !IS_ERR(mmc->supply.vmmc2))
+   mmc_regulator_set_ocr(mmc, mmc->supply.vmmc2, vdd2);
+
if (mode != MMC_POWER_OFF)
sdhci_writeb(host, SDHCI_POWER_ON, SDHCI_POWER_CONTROL);
else
@@ -2102,7 +2105,7 @@ static void sdhci_set_power_reg(struct sdhci_host *host, 
unsigned char mode,
 }
 
 void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode,
-  unsigned short vdd)
+  unsigned short vdd, unsigned short vdd2)
 {
u8 pwr = 0;
 
@@ -2133,6 +2136,20 @@ void sdhci_set_power_noreg(struct sdhci_host *host, 
unsigned char mode,
}
}
 
+   if (mode != MMC_POWER_OFF) {
+   if (vdd2 != (unsigned short)-1) {
+   switch (1 << vdd2) {
+   case MMC_VDD2_165_195:
+   pwr |= SDHCI_VDD2_POWER_180;
+   break;
+   default:
+   WARN(1, "%s: Invalid vdd2 %#x\n",
+ 

[RFC PATCH V3 14/21] mmc: sdhci: UHS-II support, handle vdd2 in case of power-off

2020-07-10 Thread Ben Chuang
From: AKASHI Takahiro 

Configure a regulator for VDD2 in case of power-off.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/host/sdhci.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 7f2537648a08..d38d734ec83f 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2333,6 +2333,11 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios 
*ios)
if (!IS_ERR(mmc->supply.vmmc) &&
ios->power_mode == MMC_POWER_OFF)
mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
+   if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
+   host->mmc->caps & MMC_CAP_UHS2 &&
+   !IS_ERR(mmc->supply.vmmc2) &&
+   ios->power_mode == MMC_POWER_OFF)
+   mmc_regulator_set_ocr(mmc, mmc->supply.vmmc2, 0);
return;
}
 
-- 
2.27.0



[RFC PATCH V3 13/21] mmc: sdhci: UHS-II support, skip signal_voltage_switch()

2020-07-10 Thread Ben Chuang
From: AKASHI Takahiro 

sdhci_start_signal_voltage_switch() should be called only in UHS-I mode,
and not for UHS-II mode.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/host/sdhci.c | 7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 5511649946b9..7f2537648a08 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2623,8 +2623,13 @@ int sdhci_start_signal_voltage_switch(struct mmc_host 
*mmc,
/*
 * Signal Voltage Switching is only applicable for Host Controllers
 * v3.00 and above.
+* But for UHS2, the signal voltage is supplied by vdd2 which is
+* already 1.8v so no voltage switch required.
 */
-   if (host->version < SDHCI_SPEC_300)
+   if (host->version < SDHCI_SPEC_300 ||
+   (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
+host->version >= SDHCI_SPEC_400 &&
+host->mmc->flags & MMC_UHS2_SUPPORT))
return 0;
 
ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
-- 
2.27.0



[RFC PATCH V3 12/21] mmc: sdhci: UHS-II support, add hooks for additional operations

2020-07-10 Thread Ben Chuang
From: Ben Chuang 

In this commit, UHS-II related operations will be called via a function
pointer array, sdhci_uhs2_ops, in order to make UHS-II support as
a kernel module.
This array will be initialized only if CONFIG_MMC_SDHCI_UHS2 is enabled
and when the UHS-II module is loaded. Otherwise, all the functions
stay void.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/host/sdhci.c | 152 ++-
 1 file changed, 136 insertions(+), 16 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index aaf41954511a..5511649946b9 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -32,8 +32,12 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 
 #include "sdhci.h"
+#include "sdhci-uhs2.h"
+#include "sdhci-pci.h"
 
 #define DRIVER_NAME "sdhci"
 
@@ -45,6 +49,11 @@
 
 #define MAX_TUNING_LOOP 40
 
+#if IS_ENABLED(CONFIG_MMC_SDHCI_UHS2)
+struct sdhci_uhs2_ops sdhci_uhs2_ops;
+EXPORT_SYMBOL_GPL(sdhci_uhs2_ops);
+#endif
+
 static unsigned int debug_quirks = 0;
 static unsigned int debug_quirks2;
 
@@ -1041,8 +1050,11 @@ EXPORT_SYMBOL_GPL(sdhci_set_data_timeout_irq);
 
 void __sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
 {
+   u8 count;
+
bool too_big = false;
-   u8 count = sdhci_calc_timeout(host, cmd, _big);
+
+   count = sdhci_calc_timeout(host, cmd, _big);
 
if (too_big &&
host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT) {
@@ -1053,6 +1065,11 @@ void __sdhci_set_timeout(struct sdhci_host *host, struct 
mmc_command *cmd)
}
 
sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL);
+
+   if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
+   host->mmc->flags & MMC_UHS2_SUPPORT &&
+   sdhci_uhs2_ops.set_timeout)
+   sdhci_uhs2_ops.set_timeout(host);
 }
 EXPORT_SYMBOL_GPL(__sdhci_set_timeout);
 
@@ -1191,7 +1208,14 @@ static void sdhci_prepare_data(struct sdhci_host *host, 
struct mmc_command *cmd)
 
sdhci_set_transfer_irqs(host);
 
-   sdhci_set_block_info(host, data);
+   if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
+   host->mmc->flags & MMC_UHS2_SUPPORT &&
+   host->mmc->flags & MMC_UHS2_INITIALIZED) {
+   sdhci_writew(host, data->blksz, SDHCI_UHS2_BLOCK_SIZE);
+   sdhci_writew(host, data->blocks, SDHCI_UHS2_BLOCK_COUNT);
+   } else {
+   sdhci_set_block_info(host, data);
+   }
 }
 
 #if IS_ENABLED(CONFIG_MMC_SDHCI_EXTERNAL_DMA)
@@ -1439,6 +1463,13 @@ static void sdhci_set_transfer_mode(struct sdhci_host 
*host,
u16 mode = 0;
struct mmc_data *data = cmd->data;
 
+   if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
+   host->mmc->flags & MMC_UHS2_SUPPORT) {
+   if (sdhci_uhs2_ops.set_transfer_mode)
+   sdhci_uhs2_ops.set_transfer_mode(host, cmd);
+   return;
+   }
+
if (data == NULL) {
if (host->quirks2 &
SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD) {
@@ -1570,6 +1601,12 @@ static void __sdhci_finish_data(struct sdhci_host *host, 
bool sw_data_timeout)
else
data->bytes_xfered = data->blksz * data->blocks;
 
+   if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
+   host->mmc->flags & MMC_UHS2_INITIALIZED) {
+   __sdhci_finish_mrq(host, data->mrq);
+   return;
+   }
+
/*
 * Need to send CMD12 if -
 * a) open-ended multiblock transfer not using auto CMD12 (no CMD23)
@@ -1654,7 +1691,8 @@ static bool sdhci_send_command(struct sdhci_host *host, 
struct mmc_command *cmd)
sdhci_prepare_data(host, cmd);
}
 
-   sdhci_writel(host, cmd->arg, SDHCI_ARGUMENT);
+   if (!IS_ENABLED(CONFIG_MMC_SDHCI_UHS2))
+   sdhci_writel(host, cmd->arg, SDHCI_ARGUMENT);
 
sdhci_set_transfer_mode(host, cmd);
 
@@ -1699,6 +1737,17 @@ static bool sdhci_send_command(struct sdhci_host *host, 
struct mmc_command *cmd)
if (host->use_external_dma)
sdhci_external_dma_pre_transfer(host, cmd);
 
+   if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
+   (host->mmc->flags & MMC_UHS2_SUPPORT)) {
+   if (sdhci_uhs2_ops.send_command)
+   sdhci_uhs2_ops.send_command(host, cmd);
+
+   return true;
+   }
+
+   if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2))
+   sdhci_writel(host, cmd->arg, SDHCI_ARGUMENT);
+
sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
 
return true;
@@ -1780,13 +1829,20 @@ static void sdhci_finish_command(struct sdhci_host 
*host)
 {

[RFC PATCH V3 10/21] mmc: sdhci: UHS-II support, dump UHS-II registers

2020-07-10 Thread Ben Chuang
From: AKASHI Takahiro 

Dump UHS-II specific registers, if available, in sdhci_dumpregs()
for informative/debugging use.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/host/sdhci.c | 24 
 1 file changed, 24 insertions(+)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 37b1158c1c0c..c2f6923d296c 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -111,6 +111,30 @@ void sdhci_dumpregs(struct sdhci_host *host)
}
}
 
+   if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
+   host->mmc && host->mmc->flags & MMC_UHS2_SUPPORT) {
+   SDHCI_DUMP(" UHS2 ==\n");
+   SDHCI_DUMP("Blk Size:  0x%08x | Blk Cnt:  0x%08x\n",
+  sdhci_readw(host, SDHCI_UHS2_BLOCK_SIZE),
+  sdhci_readl(host, SDHCI_UHS2_BLOCK_COUNT));
+   SDHCI_DUMP("Cmd:   0x%08x | Trn mode: 0x%08x\n",
+  sdhci_readw(host, SDHCI_UHS2_COMMAND),
+  sdhci_readw(host, SDHCI_UHS2_TRANS_MODE));
+   SDHCI_DUMP("Int Stat:  0x%08x | Dev Sel : 0x%08x\n",
+  sdhci_readw(host, SDHCI_UHS2_DEV_INT_STATUS),
+  sdhci_readb(host, SDHCI_UHS2_DEV_SELECT));
+   SDHCI_DUMP("Dev Int Code:  0x%08x\n",
+  sdhci_readb(host, SDHCI_UHS2_DEV_INT_CODE));
+   SDHCI_DUMP("Reset: 0x%08x | Timer:0x%08x\n",
+  sdhci_readw(host, SDHCI_UHS2_SW_RESET),
+  sdhci_readw(host, SDHCI_UHS2_TIMER_CTRL));
+   SDHCI_DUMP("ErrInt:0x%08x | ErrIntEn: 0x%08x\n",
+  sdhci_readl(host, SDHCI_UHS2_ERR_INT_STATUS),
+  sdhci_readl(host, SDHCI_UHS2_ERR_INT_STATUS_EN));
+   SDHCI_DUMP("ErrSigEn:  0x%08x\n",
+  sdhci_readl(host, SDHCI_UHS2_ERR_INT_SIG_EN));
+   }
+
if (host->ops->dump_vendor_regs)
host->ops->dump_vendor_regs(host);
 
-- 
2.27.0



[RFC PATCH V3 09/21] mmc: sdhci: add UHS-II related definitions in headers

2020-07-10 Thread Ben Chuang
From: AKASHI Takahiro 

Add UHS-II related definitions in shdci.h and sdhci-uhs2.h.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/host/sdhci-uhs2.h | 215 ++
 drivers/mmc/host/sdhci.h  |  91 +-
 2 files changed, 305 insertions(+), 1 deletion(-)
 create mode 100644 drivers/mmc/host/sdhci-uhs2.h

diff --git a/drivers/mmc/host/sdhci-uhs2.h b/drivers/mmc/host/sdhci-uhs2.h
new file mode 100644
index ..a7f53f95d69a
--- /dev/null
+++ b/drivers/mmc/host/sdhci-uhs2.h
@@ -0,0 +1,215 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ *  linux/drivers/mmc/host/sdhci-uhs2.h - Secure Digital Host Controller
+ *  Interface driver
+ *
+ * Header file for Host Controller UHS2 related registers and I/O accessors.
+ *
+ *  Copyright (C) 2014 Intel Corp, All Rights Reserved.
+ */
+#ifndef __SDHCI_UHS2_H
+#define __SDHCI_UHS2_H
+
+#include 
+#include 
+#include 
+
+/*
+ * UHS-II Controller registers
+ * 0x74 preset in sdhci.h
+ * 0x80
+ * 0x84-0xB4
+ * 0xB8-0xCF
+ * 0xE0-0xE7
+ */
+/* UHS2 */
+#define SDHCI_UHS2_BLOCK_SIZE  0x80
+#define  SDHCI_UHS2_MAKE_BLKSZ(dma, blksz) \
+   dma) & 0x7) << 12) | ((blksz) & 0xFFF))
+
+#define SDHCI_UHS2_BLOCK_COUNT 0x84
+
+#define SDHCI_UHS2_CMD_PACKET  0x88
+#define  SDHCI_UHS2_CMD_PACK_MAX_LEN   20
+
+#define SDHCI_UHS2_TRANS_MODE  0x9C
+#define  SDHCI_UHS2_TRNS_DMA   0x0001
+#define  SDHCI_UHS2_TRNS_BLK_CNT_EN0x0002
+#define  SDHCI_UHS2_TRNS_DATA_TRNS_WRT 0x0010
+#define  SDHCI_UHS2_TRNS_BLK_BYTE_MODE 0x0020
+#define  SDHCI_UHS2_TRNS_RES_R50x0040
+#define  SDHCI_UHS2_TRNS_RES_ERR_CHECK_EN  0x0080
+#define  SDHCI_UHS2_TRNS_RES_INT_DIS   0x0100
+#define  SDHCI_UHS2_TRNS_WAIT_EBSY 0x4000
+#define  SDHCI_UHS2_TRNS_2L_HD 0x8000
+
+#define SDHCI_UHS2_COMMAND 0x9E
+#define  SDHCI_UHS2_COMMAND_SUB_CMD0x0004
+#define  SDHCI_UHS2_COMMAND_DATA   0x0020
+#define  SDHCI_UHS2_COMMAND_TRNS_ABORT 0x0040
+#define  SDHCI_UHS2_COMMAND_CMD12  0x0080
+#define  SDHCI_UHS2_COMMAND_DORMANT0x00C0
+#define  SDHCI_UHS2_COMMAND_PACK_LEN_MASK  0x1F00
+#define  SDHCI_UHS2_COMMAND_PACK_LEN_SHIFT 8
+
+#define SDHCI_UHS2_RESPONSE0xA0
+#define  SDHCI_UHS2_RESPONSE_MAX_LEN   20
+
+#define SDHCI_UHS2_MSG_SELECT  0xB4
+#define SDHCI_UHS2_MSG_SELECT_CURR 0x0
+#define SDHCI_UHS2_MSG_SELECT_ONE  0x1
+#define SDHCI_UHS2_MSG_SELECT_TWO  0x2
+#define SDHCI_UHS2_MSG_SELECT_THREE0x3
+
+#define SDHCI_UHS2_MSG 0xB8
+
+#define SDHCI_UHS2_DEV_INT_STATUS  0xBC
+
+#define SDHCI_UHS2_DEV_SELECT  0xBE
+#define SDHCI_UHS2_DEV_SELECT_DEV_SEL_MASK 0x0F
+#define SDHCI_UHS2_DEV_SELECT_INT_MSG_EN   0x80
+
+#define SDHCI_UHS2_DEV_INT_CODE0xBF
+
+#define SDHCI_UHS2_SW_RESET0xC0
+#define SDHCI_UHS2_SW_RESET_FULL   0x0001
+#define SDHCI_UHS2_SW_RESET_SD 0x0002
+
+#define SDHCI_UHS2_TIMER_CTRL  0xC2
+#define SDHCI_UHS2_TIMER_CTRL_DEADLOCK_SHIFT   4
+
+#define SDHCI_UHS2_ERR_INT_STATUS  0xC4
+#define SDHCI_UHS2_ERR_INT_STATUS_EN   0xC8
+#define SDHCI_UHS2_ERR_INT_SIG_EN  0xCC
+#define SDHCI_UHS2_ERR_INT_STATUS_HEADER   0x0001
+#define SDHCI_UHS2_ERR_INT_STATUS_RES  0x0002
+#define SDHCI_UHS2_ERR_INT_STATUS_RETRY_EXP0x0004
+#define SDHCI_UHS2_ERR_INT_STATUS_CRC  0x0008
+#define SDHCI_UHS2_ERR_INT_STATUS_FRAME0x0010
+#define SDHCI_UHS2_ERR_INT_STATUS_TID  0x0020
+#define SDHCI_UHS2_ERR_INT_STATUS_UNRECOVER0x0080
+#define SDHCI_UHS2_ERR_INT_STATUS_EBUSY0x0100
+#define SDHCI_UHS2_ERR_INT_STATUS_ADMA 0x8000
+#define SDHCI_UHS2_ERR_INT_STATUS_RES_TIMEOUT  0x0001
+#define SDHCI_UHS2_ERR_INT_STATUS_DEADLOCK_TIMEOUT 0x0002
+#define SDHCI_UHS2_ERR_INT_STATUS_VENDOR   0x0800
+#define SDHCI_UHS2_ERR_INT_STATUS_MASK \
+   (SDHCI_UHS2_ERR_INT_STATUS_HEADER | \
+   SDHCI_UHS2_ERR_INT_STATUS_RES | \
+   SDHCI_UHS2_ERR_INT_STATUS_RETRY_EXP |   \
+   SDHCI_UHS2_ERR_INT_STATUS_CRC | \
+   SDHCI_UHS2_ERR_INT_STATUS_FRAME |   \
+   SDHCI_UHS2_ERR_INT_STATUS_TID | \
+   SDHCI_UHS2_ERR_INT_STATUS_UNRECOVER |   \
+   SDHCI_UHS2_ERR_INT_STATUS_EBUSY |   \
+   SDHCI_UHS2_ERR_INT_STATUS_ADMA |\
+   SDHCI_UHS2_ERR_INT_STATUS_RES_TIMEOUT | \
+   SDHCI_UHS2_ERR_INT_STATUS_DEADLOCK_TIMEOUT)
+#define SDHCI_UHS2_ERR_INT_STATUS_CMD_MASK \
+   (SDHCI_UHS2_ERR_INT_STATUS_HEADER | \
+   SDHCI_UHS2_ERR_INT_STATUS_RES | \
+   SDHCI_UHS2_ERR_INT_STATUS_FRAME |   \
+   SDHCI_UHS2_ERR_INT_STATUS_TID | \
+   SDHCI_UHS2_ERR_INT_STATUS_RES_TIMEOUT)
+/* CRC Error occurs during a packet receivi

[RFC PATCH V3 11/21] mmc: sdhci: UHS-II support, export host operations to core

2020-07-10 Thread Ben Chuang
From: AKASHI Takahiro 

Export sdhci-specific UHS-II operations to core.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/host/sdhci.c | 70 
 1 file changed, 70 insertions(+)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index c2f6923d296c..aaf41954511a 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2977,6 +2977,70 @@ static void sdhci_card_event(struct mmc_host *mmc)
spin_unlock_irqrestore(>lock, flags);
 }
 
+#if IS_ENABLED(CONFIG_MMC_SDHCI_UHS2)
+static int sdhci_uhs2_detect_init(struct mmc_host *mmc)
+{
+   struct sdhci_host *host = mmc_priv(mmc);
+   int ret;
+
+   if (sdhci_uhs2_ops.do_detect_init)
+   ret = sdhci_uhs2_ops.do_detect_init(host);
+   else
+   return 0;
+
+   return ret;
+}
+
+static int sdhci_uhs2_set_reg(struct mmc_host *mmc, enum uhs2_act act)
+{
+   struct sdhci_host *host = mmc_priv(mmc);
+   int ret;
+
+   if (sdhci_uhs2_ops.do_set_reg)
+   ret = sdhci_uhs2_ops.do_set_reg(host, act);
+   else
+   ret = 0;
+
+   return ret;
+}
+
+static void sdhci_uhs2_disable_clk(struct mmc_host *mmc)
+{
+   struct sdhci_host *host = mmc_priv(mmc);
+   u16 clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+
+   clk &= ~SDHCI_CLOCK_CARD_EN;
+   sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+}
+
+static void sdhci_uhs2_enable_clk(struct mmc_host *mmc)
+{
+   struct sdhci_host *host = mmc_priv(mmc);
+   u16 clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+   ktime_t timeout;
+
+   clk |= SDHCI_CLOCK_CARD_EN;
+   sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+   /* Wait max 20 ms */
+   timeout = ktime_add_ms(ktime_get(), 20);
+   while (1) {
+   bool timedout = ktime_after(ktime_get(), timeout);
+
+   clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+   if (clk & SDHCI_CLOCK_INT_STABLE)
+   break;
+   if (timedout) {
+   pr_err("%s: Internal clock never stabilised.\n",
+  mmc_hostname(host->mmc));
+   sdhci_dumpregs(host);
+   return;
+   }
+   udelay(10);
+   }
+}
+#endif /* CONFIG_MMC_SDHCI_UHS2 */
+
 static const struct mmc_host_ops sdhci_ops = {
.request= sdhci_request,
.post_req   = sdhci_post_req,
@@ -2992,6 +3056,12 @@ static const struct mmc_host_ops sdhci_ops = {
.execute_tuning = sdhci_execute_tuning,
.card_event = sdhci_card_event,
.card_busy  = sdhci_card_busy,
+#if IS_ENABLED(CONFIG_MMC_SDHCI_UHS2)
+   .uhs2_detect_init   = sdhci_uhs2_detect_init,
+   .uhs2_set_reg   = sdhci_uhs2_set_reg,
+   .uhs2_disable_clk   = sdhci_uhs2_disable_clk,
+   .uhs2_enable_clk= sdhci_uhs2_enable_clk,
+#endif /* CONFIG_MMC_SDHCI_UHS2 */
 };
 
 /*\
-- 
2.27.0



[RFC PATCH V3 08/21] mmc: sdhci: add a kernel configuration for enabling UHS-II support

2020-07-10 Thread Ben Chuang
From: AKASHI Takahiro 

This kernel configuration, CONFIG_MMC_SDHCI_UHS2, will be used
in the following commits to indicate UHS-II specific code in sdhci
controllers.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/host/Kconfig | 9 +
 1 file changed, 9 insertions(+)

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 3b706af35ec3..ffeef38264c0 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -89,6 +89,15 @@ config MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
 
  This is the case for the Nintendo Wii SDHCI.
 
+config MMC_SDHCI_UHS2
+   tristate "UHS2 support on SDHCI controller"
+   depends on MMC_SDHCI
+   help
+ This option is selected by SDHCI controller drivers that want to
+ support UHS2-capable devices.
+
+ If you have a controller with this feature, say Y or M here.
+
 config MMC_SDHCI_PCI
tristate "SDHCI support on PCI bus"
depends on MMC_SDHCI && PCI
-- 
2.27.0



[RFC PATCH V3 07/21] mmc: core: UHS-II support, set APP_CMD bit if necessary

2020-07-10 Thread Ben Chuang
From: AKASHI Takahiro 

In UHS-II mode, MMC_APP_CMD command need not to be sent.
Instead, APP_CMD bit in a packet should be set.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/core/sd_ops.c | 9 +
 drivers/mmc/core/uhs2.c   | 4 
 2 files changed, 13 insertions(+)

diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c
index f58bb50872f6..9dc296356928 100644
--- a/drivers/mmc/core/sd_ops.c
+++ b/drivers/mmc/core/sd_ops.c
@@ -26,6 +26,15 @@ int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
if (WARN_ON(card && card->host != host))
return -EINVAL;
 
+   /* UHS2 packet has APP bit so only set APP_CMD flag here.
+* Will set the APP bit when assembling UHS2 packet.
+*/
+   if (host->flags &  MMC_UHS2_SUPPORT &&
+   host->flags & MMC_UHS2_INITIALIZED) {
+   host->flags |= MMC_UHS2_APP_CMD;
+   return 0;
+   }
+
cmd.opcode = MMC_APP_CMD;
 
if (card) {
diff --git a/drivers/mmc/core/uhs2.c b/drivers/mmc/core/uhs2.c
index 6e26de429726..2fbd7b6d9dea 100644
--- a/drivers/mmc/core/uhs2.c
+++ b/drivers/mmc/core/uhs2.c
@@ -826,6 +826,10 @@ int uhs2_prepare_sd_cmd(struct mmc_host *host, struct 
mmc_request *mrq)
header |= UHS2_PACKET_TYPE_CCMD;
 
arg = cmd->opcode << UHS2_SD_CMD_INDEX_POS;
+   if (host->flags & MMC_UHS2_APP_CMD) {
+   arg |= UHS2_SD_CMD_APP;
+   host->flags &= ~MMC_UHS2_APP_CMD;
+   }
 
uhs2_cmd = cmd->uhs2_cmd;
payload = uhs2_cmd->payload;
-- 
2.27.0



[RFC PATCH V3 06/21] mmc: core: UHS-II support, generate UHS-II SD command packet

2020-07-10 Thread Ben Chuang
From: AKASHI Takahiro 

In SD-TRAN protocol, legacy SD commands should be "encapsulated" in SD
packets as described in SD specification.
Please see section 7.1 and 7.2.1 in "UHS-II Simplified Addendum."

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/core/core.c | 18 +++
 drivers/mmc/core/uhs2.c | 70 +
 drivers/mmc/core/uhs2.h |  1 +
 3 files changed, 89 insertions(+)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index e2534f3446ce..dfe3a6df7645 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -337,6 +337,8 @@ static int mmc_mrq_prep(struct mmc_host *host, struct 
mmc_request *mrq)
 
 int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
 {
+   struct uhs2_command uhs2_cmd;
+   u32 payload[4]; /* for maximum size */
int err;
 
init_completion(>cmd_completion);
@@ -354,6 +356,13 @@ int mmc_start_request(struct mmc_host *host, struct 
mmc_request *mrq)
if (err)
return err;
 
+   if (host->flags & MMC_UHS2_SUPPORT &&
+   host->flags & MMC_UHS2_INITIALIZED) {
+   uhs2_cmd.payload = payload;
+   mrq->cmd->uhs2_cmd = _cmd;
+   uhs2_prepare_sd_cmd(host, mrq);
+   }
+
led_trigger_event(host->led, LED_FULL);
__mmc_start_request(host, mrq);
 
@@ -433,6 +442,8 @@ EXPORT_SYMBOL(mmc_wait_for_req_done);
  */
 int mmc_cqe_start_req(struct mmc_host *host, struct mmc_request *mrq)
 {
+   struct uhs2_command uhs2_cmd;
+   u32 payload[4]; /* for maximum size */
int err;
 
/*
@@ -453,6 +464,13 @@ int mmc_cqe_start_req(struct mmc_host *host, struct 
mmc_request *mrq)
if (err)
goto out_err;
 
+   if (host->flags & MMC_UHS2_SUPPORT &&
+   host->flags & MMC_UHS2_INITIALIZED) {
+   uhs2_cmd.payload = payload;
+   mrq->cmd->uhs2_cmd = _cmd;
+   uhs2_prepare_sd_cmd(host, mrq);
+   }
+
err = host->cqe_ops->cqe_request(host, mrq);
if (err)
goto out_err;
diff --git a/drivers/mmc/core/uhs2.c b/drivers/mmc/core/uhs2.c
index a3b20ac6f315..6e26de429726 100644
--- a/drivers/mmc/core/uhs2.c
+++ b/drivers/mmc/core/uhs2.c
@@ -798,3 +798,73 @@ int mmc_uhs2_rescan_try_freq(struct mmc_host *host, 
unsigned int freq)
return err;
 }
 EXPORT_SYMBOL_GPL(mmc_uhs2_rescan_try_freq);
+
+/**
+ * uhs2_prepare_sd_cmd - prepare for SD command packet
+ * @host:  MMC host
+ * @mrq:   MMC request
+ *
+ * Initialize and fill in a header and a payload of SD command packet.
+ * The caller should allocate uhs2_command in host->cmd->uhs2_cmd in
+ * advance.
+ *
+ * Return: 0 on success, non-zero error on failure
+ */
+int uhs2_prepare_sd_cmd(struct mmc_host *host, struct mmc_request *mrq)
+{
+   struct mmc_command *cmd;
+   struct uhs2_command *uhs2_cmd;
+   u16 header = 0, arg = 0;
+   u32 *payload;
+   u8 plen = 0;
+
+   cmd = mrq->cmd;
+   header = host->uhs2_dev_prop.node_id;
+   if ((cmd->flags & MMC_CMD_MASK) == MMC_CMD_ADTC)
+   header |= UHS2_PACKET_TYPE_DCMD;
+   else
+   header |= UHS2_PACKET_TYPE_CCMD;
+
+   arg = cmd->opcode << UHS2_SD_CMD_INDEX_POS;
+
+   uhs2_cmd = cmd->uhs2_cmd;
+   payload = uhs2_cmd->payload;
+   plen = 2; /* at the maximum */
+
+   if ((cmd->flags & MMC_CMD_MASK) == MMC_CMD_ADTC &&
+   !cmd->uhs2_tmode0_flag) {
+   if (host->flags & MMC_UHS2_2L_HD)
+   arg |= UHS2_DCMD_2L_HD_MODE;
+
+   arg |= UHS2_DCMD_LM_TLEN_EXIST;
+
+   if (cmd->data->blocks == 1 &&
+   cmd->data->blksz != 512 &&
+   cmd->opcode != MMC_READ_SINGLE_BLOCK &&
+   cmd->opcode != MMC_WRITE_BLOCK) {
+   arg |= UHS2_DCMD_TLUM_BYTE_MODE;
+   payload[1] = uhs2_dcmd_convert_msb(cmd->data->blksz);
+   } else {
+   payload[1] = uhs2_dcmd_convert_msb(cmd->data->blocks);
+   }
+
+   if (cmd->opcode == SD_IO_RW_EXTENDED) {
+   arg &= ~(UHS2_DCMD_LM_TLEN_EXIST |
+   UHS2_DCMD_TLUM_BYTE_MODE |
+   UHS2_NATIVE_DCMD_DAM_IO);
+   payload[1] = 0;
+   plen = 1;
+   }
+   } else {
+   plen = 1;
+   }
+
+   payload[0] = uhs2_dcmd_convert_msb(cmd->arg);
+   pr_debug("%s: %s: sd_cmd->arg = 0x%x, payload[0]= 0x%x.\n",
+mmc_hostname(host), __func__, cmd->arg, payload[0]);
+
+   uhs2_cmd_assemble(cmd, uhs2_cmd, header,

[RFC PATCH V3 03/21] mmc: core: UHS-II support, skip set_chip_select()

2020-07-10 Thread Ben Chuang
From: AKASHI Takahiro 

mmc_set_chip_select() should be called only in UHS-I mode,
and not for UHS-II mode.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/core/core.c | 6 --
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 85c83c82ad0c..c6540d56646b 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -898,8 +898,10 @@ static inline void mmc_set_ios(struct mmc_host *host)
  */
 void mmc_set_chip_select(struct mmc_host *host, int mode)
 {
-   host->ios.chip_select = mode;
-   mmc_set_ios(host);
+   if (!(host->flags & MMC_UHS2_INITIALIZED)) {
+   host->ios.chip_select = mode;
+   mmc_set_ios(host);
+   }
 }
 
 /*
-- 
2.27.0



[RFC PATCH V3 05/21] mmc: core: UHS-II support, skip TMODE setup in some cases

2020-07-10 Thread Ben Chuang
From: AKASHI Takahiro 

UHS-II's data command packet has TMODE fields in which parameters for
data transaction, like Duplex Mode(DM) and Length Mode(LM), are specified.
In some cases, we don't need to initialize them and so set uhs2_tmode0_flag
to 1 in order to skip them in generating a packet.
(The code will be added in the next commit.)

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/core/block.c  | 7 ++-
 drivers/mmc/core/sd_ops.c | 3 +++
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
index 7896952de1ac..212f872d60bc 100644
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -56,6 +56,7 @@
 #include "mmc_ops.h"
 #include "quirks.h"
 #include "sd_ops.h"
+#include "uhs2.h"
 
 MODULE_ALIAS("mmc:block");
 #ifdef MODULE_PARAM_PREFIX
@@ -1526,6 +1527,9 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
struct request *req = mmc_queue_req_to_req(mqrq);
struct mmc_blk_data *md = mq->blkdata;
bool do_rel_wr, do_data_tag;
+   bool do_multi;
+
+   do_multi = (card->host->flags & MMC_UHS2_INITIALIZED) ? true : false;
 
mmc_blk_data_prep(mq, mqrq, disable_multi, _rel_wr, _data_tag);
 
@@ -1536,7 +1540,7 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
brq->cmd.arg <<= 9;
brq->cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
 
-   if (brq->data.blocks > 1 || do_rel_wr) {
+   if (brq->data.blocks > 1 || do_rel_wr || do_multi) {
/* SPI multiblock writes terminate using a special
 * token, not a STOP_TRANSMISSION request.
 */
@@ -1549,6 +1553,7 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
brq->mrq.stop = NULL;
readcmd = MMC_READ_SINGLE_BLOCK;
writecmd = MMC_WRITE_BLOCK;
+   brq->cmd.uhs2_tmode0_flag = 1;
}
brq->cmd.opcode = rq_data_dir(req) == READ ? readcmd : writecmd;
 
diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c
index 22bf528294b9..f58bb50872f6 100644
--- a/drivers/mmc/core/sd_ops.c
+++ b/drivers/mmc/core/sd_ops.c
@@ -235,6 +235,7 @@ int mmc_app_send_scr(struct mmc_card *card)
cmd.opcode = SD_APP_SEND_SCR;
cmd.arg = 0;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+   cmd.uhs2_tmode0_flag = 1;
 
data.blksz = 8;
data.blocks = 1;
@@ -282,6 +283,7 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int 
group,
cmd.arg &= ~(0xF << (group * 4));
cmd.arg |= value << (group * 4);
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+   cmd.uhs2_tmode0_flag = 1;
 
data.blksz = 64;
data.blocks = 1;
@@ -323,6 +325,7 @@ int mmc_app_sd_status(struct mmc_card *card, void *ssr)
cmd.opcode = SD_APP_SD_STATUS;
cmd.arg = 0;
cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_ADTC;
+   cmd.uhs2_tmode0_flag = 1;
 
data.blksz = 64;
data.blocks = 1;
-- 
2.27.0



[RFC PATCH V3 04/21] mmc: core: UHS-II support, try to select UHS-II interface

2020-07-10 Thread Ben Chuang
From: Ben Chuang 

The flow of "interface selection and initialization" was a bit modified
for UHS-II card. This commit follows the sequence defined in SD
specification (Part 1).
See section 7.2.3 in "UHS-II Simplified Addendum."

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/core/Makefile |   2 +-
 drivers/mmc/core/bus.c|   5 +-
 drivers/mmc/core/core.c   |  33 +-
 drivers/mmc/core/sd.c |  26 ++
 drivers/mmc/core/uhs2.c   | 800 ++
 drivers/mmc/core/uhs2.h   |  20 +
 6 files changed, 882 insertions(+), 4 deletions(-)
 create mode 100644 drivers/mmc/core/uhs2.c
 create mode 100644 drivers/mmc/core/uhs2.h

diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile
index 95ffe008ebdf..e2a90dc98afc 100644
--- a/drivers/mmc/core/Makefile
+++ b/drivers/mmc/core/Makefile
@@ -8,7 +8,7 @@ mmc_core-y  := core.o bus.o host.o \
   mmc.o mmc_ops.o sd.o sd_ops.o \
   sdio.o sdio_ops.o sdio_bus.o \
   sdio_cis.o sdio_io.o sdio_irq.o \
-  slot-gpio.o regulator.o
+  slot-gpio.o regulator.o uhs2.o
 mmc_core-$(CONFIG_OF)  += pwrseq.o
 obj-$(CONFIG_PWRSEQ_SIMPLE)+= pwrseq_simple.o
 obj-$(CONFIG_PWRSEQ_SD8787)+= pwrseq_sd8787.o
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 70207f11a654..66d3e942f3fc 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -350,8 +350,9 @@ int mmc_add_card(struct mmc_card *card)
} else {
pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
mmc_hostname(card->host),
-   mmc_card_uhs(card) ? "ultra high speed " :
-   (mmc_card_hs(card) ? "high speed " : ""),
+   mmc_card_uhs2(card) ? "ultra high speed 2 " :
+   (mmc_card_uhs(card) ? "ultra high speed 1 " :
+   (mmc_card_hs(card) ? "high speed " : "")),
mmc_card_hs400(card) ? "HS400 " :
(mmc_card_hs200(card) ? "HS200 " : ""),
mmc_card_hs400es(card) ? "Enhanced strobe " : "",
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index c6540d56646b..e2534f3446ce 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -31,6 +31,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #define CREATE_TRACE_POINTS
 #include 
@@ -41,6 +42,7 @@
 #include "host.h"
 #include "sdio_bus.h"
 #include "pwrseq.h"
+#include "uhs2.h"
 
 #include "mmc_ops.h"
 #include "sd_ops.h"
@@ -51,6 +53,7 @@
 #define SD_DISCARD_TIMEOUT_MS  (250)
 
 static const unsigned freqs[] = { 40, 30, 20, 10 };
+static const unsigned int uhs2_freqs[] = { 5200, 2600 };
 
 /*
  * Enabling software CRCs on the data blocks can be a significant (30%)
@@ -2165,9 +2168,10 @@ static int mmc_rescan_try_freq(struct mmc_host *host, 
unsigned freq)
if (!mmc_attach_sdio(host))
return 0;
 
-   if (!(host->caps2 & MMC_CAP2_NO_SD))
+   if (!(host->caps2 & MMC_CAP2_NO_SD)) {
if (!mmc_attach_sd(host))
return 0;
+   }
 
if (!(host->caps2 & MMC_CAP2_NO_MMC))
if (!mmc_attach_mmc(host))
@@ -2300,6 +2304,33 @@ void mmc_rescan(struct work_struct *work)
goto out;
}
 
+   if (host->caps & MMC_CAP_UHS2) {
+   /*
+* Start to try UHS-II initialization from 52MHz to 26MHz
+* (RCLK range) per spec.
+*/
+   for (i = 0; i < ARRAY_SIZE(uhs2_freqs); i++) {
+   unsigned int freq = uhs2_freqs[i];
+   int err;
+
+   err = mmc_uhs2_rescan_try_freq(host,
+  max(freq, host->f_min));
+   if (!err) {
+   mmc_release_host(host);
+   goto out;
+   }
+
+   if (err == UHS2_PHY_INIT_ERR)
+   /* UHS2 IF detect or Lane Sync error.
+* Try legacy interface.
+*/
+   break;
+
+   if (freq <= host->f_min)
+   break;
+   }
+   }
+
for (i = 0; i < ARRAY_SIZE(freqs); i++) {
unsigned int freq = freqs[i];
if (freq > host->f_max) {
diff --git a/drivers/mmc/

[RFC PATCH V3 00/21] Add support UHS-II for GL9755

2020-07-10 Thread Ben Chuang
Summary
===
These patches[1] support UHS-II and fix GL9755 UHS-II compatibility.

About UHS-II, roughly deal with the following three parts:
1) A UHS-II detection and initialization:
- Host setup to support UHS-II (Section 3.13.1 Host Controller Setup Sequence
  [2]).
- Detect a UHS-II I/F (Section 3.13.2 Card Interface Detection Sequence[2]).
- In step(9) of Section 3.13.2 in [2], UHS-II initialization is include Section
  3.13.3 UHS-II Card Initialization and Section 3.13.4 UHS-II Setting Register
  Setup Sequence.

2) Send Legacy SD command through SD-TRAN
- Encapsulated SD packets are defined in SD-TRAN in order to ensure Legacy SD
  compatibility and preserve Legacy SD infrastructures (Section 7.1.1 Packet
  Types and Format Overview[3]).
- Host issue a UHS-II CCMD packet or a UHS-II DCMD (Section 3.13.5 UHS-II
  CCMD Packet issuing and Section 3.13.6 UHS-II DCMD Packet issuing[2]).

3) UHS-II Interrupt
- Except for UHS-II error interrupts, most interrupts share the original 
  interrupt registers.

Patch structure
===
patch#1-#7: for core
patch#8-#17: for sdhci
patch#18-#21: for GL9755

Tests
=
Ran 'dd' command to evaluate the performance:
(SanDisk UHS-II card on GL9755 controller)
 ReadWrite
UHS-II disabled (UHS-I): 88.3MB/s 60.7MB/s
UHS-II enabled :  206MB/s   80MB/s

TODO

- replace some define with BIT macro

Reference
=
[1] https://gitlab.com/ben.chuang/linux-uhs2-gl9755.git
[2] SD Host Controller Simplified Specification 4.20
[3] UHS-II Simplified Addendum 1.02

Changes in v3 (Jul. 10, 2020)
* rebased to v5.8-rc4
* add copyright notice
* reorganize the patch set and split some commits into smaller ones
* separate uhs-2 headers from others
* correct wrong spellings
* fix most of checkpatch warnings/errors
* remove all k[cz]alloc() from the code
* guard sdhci-uhs2 specific code with
  'if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2))'
* make sdhci-uhs2.c as a module
* trivial changes, including
  - rename back sdhci-core.c to sdhci.c
  - allow vendor code to disable uhs2 if v4_mode == 0
  in __sdhci_add_host()
  - merge uhs2_power_up() into mmc_power_up()
  - remove flag_uhs2 from mmc_attach_sd()
  - add function descriptions to EXPORT'ed functions
  - other minor code optimization

Changes in v2 (Jan. 9, 2020)
* rebased to v5.5-rc5

AKASHI Takahiro (15):
  mmc: core: UHS-II support, modify power-up sequence
  mmc: core: UHS-II support, skip set_chip_select()
  mmc: core: UHS-II support, skip TMODE setup in some cases
  mmc: core: UHS-II support, generate UHS-II SD command packet
  mmc: core: UHS-II support, set APP_CMD bit if necessary
  mmc: sdhci: add a kernel configuration for enabling UHS-II support
  mmc: sdhci: add UHS-II related definitions in headers
  mmc: sdhci: UHS-II support, dump UHS-II registers
  mmc: sdhci: UHS-II support, export host operations to core
  mmc: sdhci: UHS-II support, skip signal_voltage_switch()
  mmc: sdhci: UHS-II support, handle vdd2 in case of power-off
  mmc: sdhci: UHS-II support, modify set_power() to handle vdd2
  mmc: sdhci: UHS-II support, export helper functions to a module
  mmc: sdhci: UHS-II support, implement operations as a module
  mmc: core: add post-mmc_attach_sd hook

Ben Chuang (6):
  mmc: add UHS-II related definitions in public headers
  mmc: core: UHS-II support, try to select UHS-II interface
  mmc: sdhci: UHS-II support, add hooks for additional operations
  mmc: sdhci-uhs2: add pre-detect_init hook
  mmc: sdhci-uhs2: add post-mmc_attach_sd hook
  mmc: sdhci-pci-gli: enable UHS-II mode for GL9755

 drivers/mmc/core/Makefile |   2 +-
 drivers/mmc/core/block.c  |   7 +-
 drivers/mmc/core/bus.c|   5 +-
 drivers/mmc/core/core.c   | 119 +++-
 drivers/mmc/core/regulator.c  |  14 +
 drivers/mmc/core/sd.c |  32 ++
 drivers/mmc/core/sd_ops.c |  12 +
 drivers/mmc/core/uhs2.c   | 874 ++
 drivers/mmc/core/uhs2.h   |  21 +
 drivers/mmc/host/Kconfig  |  10 +
 drivers/mmc/host/Makefile |   1 +
 drivers/mmc/host/sdhci-omap.c |   2 +-
 drivers/mmc/host/sdhci-pci-core.c |   4 +-
 drivers/mmc/host/sdhci-pci-gli.c  | 361 +++-
 drivers/mmc/host/sdhci-pxav3.c|   4 +-
 drivers/mmc/host/sdhci-uhs2.c | 797 +++
 drivers/mmc/host/sdhci-uhs2.h | 215 
 drivers/mmc/host/sdhci-xenon.c|   4 +-
 drivers/mmc/host/sdhci.c  | 321 +--
 drivers/mmc/host/sdhci.h  | 113 +++-
 include/linux/mmc/card.h  |   1 +
 include/linux/mmc/core.h  |   6 +
 include/linux/mmc/host.h  |  31 ++
 include/linux/mmc/uhs2.h  | 268 +
 24 files changed, 3151 insertions(+), 73 deletions(-)
 create mode 100644 drivers/mmc/core/uhs2.c
 create mode 100644 drivers/mmc/core/uhs2.h
 create mode 100644 drivers/mmc/host/sdhci-uhs2.c
 create mode 100644 drivers/mmc/host/sdhci-uhs2.h
 create mode

[RFC PATCH V3 02/21] mmc: core: UHS-II support, modify power-up sequence

2020-07-10 Thread Ben Chuang
From: AKASHI Takahiro 

According to Fig. 3-35 in "SD Host Controller Simplified Spec. Ver4.20":
- Prepare vdd1, vdd2 and ios.timing for using after/in step (2)
- chip_select is not used in UHS-II, used to return to the legacy flow

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/core/core.c  | 62 
 drivers/mmc/core/regulator.c | 14 
 2 files changed, 56 insertions(+), 20 deletions(-)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 8d2b808e9b58..85c83c82ad0c 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1315,33 +1315,51 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
if (host->ios.power_mode == MMC_POWER_ON)
return;
 
-   mmc_pwrseq_pre_power_on(host);
+   if (host->flags & MMC_UHS2_SUPPORT) {
+   /* TODO: handle 'ocr' parameter */
+   host->ios.vdd = fls(host->ocr_avail) - 1;
+   host->ios.vdd2 = fls(host->ocr_avail_uhs2) - 1;
+   if (mmc_host_is_spi(host))
+   host->ios.chip_select = MMC_CS_HIGH;
+   else
+   host->ios.chip_select = MMC_CS_DONTCARE;
+   host->ios.timing = MMC_TIMING_UHS2;
+   } else {
+   mmc_pwrseq_pre_power_on(host);
 
-   host->ios.vdd = fls(ocr) - 1;
-   host->ios.power_mode = MMC_POWER_UP;
-   /* Set initial state and call mmc_set_ios */
-   mmc_set_initial_state(host);
+   host->ios.vdd = fls(ocr) - 1;
+   host->ios.power_mode = MMC_POWER_UP;
+   /* Set initial state and call mmc_set_ios */
+   mmc_set_initial_state(host);
 
-   mmc_set_initial_signal_voltage(host);
+   mmc_set_initial_signal_voltage(host);
 
-   /*
-* This delay should be sufficient to allow the power supply
-* to reach the minimum voltage.
-*/
-   mmc_delay(host->ios.power_delay_ms);
-
-   mmc_pwrseq_post_power_on(host);
+   /*
+* This delay should be sufficient to allow the power supply
+* to reach the minimum voltage.
+*/
+   mmc_delay(host->ios.power_delay_ms);
 
+   mmc_pwrseq_post_power_on(host);
+   }
host->ios.clock = host->f_init;
-
host->ios.power_mode = MMC_POWER_ON;
+
mmc_set_ios(host);
 
-   /*
-* This delay must be at least 74 clock sizes, or 1 ms, or the
-* time required to reach a stable voltage.
-*/
-   mmc_delay(host->ios.power_delay_ms);
+   if (host->flags & MMC_UHS2_SUPPORT)
+   /*
+* This delay should be sufficient to allow the power supply
+* to reach the minimum voltage.
+*/
+   /*  TODO: avoid an immediate value */
+   mmc_delay(10);
+   else
+   /*
+* This delay must be at least 74 clock sizes, or 1 ms, or the
+* time required to reach a stable voltage.
+*/
+   mmc_delay(host->ios.power_delay_ms);
 }
 
 void mmc_power_off(struct mmc_host *host)
@@ -2307,7 +2325,11 @@ void mmc_start_host(struct mmc_host *host)
 
if (!(host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP)) {
mmc_claim_host(host);
-   mmc_power_up(host, host->ocr_avail);
+
+   /* Power up here will make UHS2 init ugly. */
+   if (!(host->caps & MMC_CAP_UHS2))
+   mmc_power_up(host, host->ocr_avail);
+
mmc_release_host(host);
}
 
diff --git a/drivers/mmc/core/regulator.c b/drivers/mmc/core/regulator.c
index 96b1d15045d6..05556225d9ac 100644
--- a/drivers/mmc/core/regulator.c
+++ b/drivers/mmc/core/regulator.c
@@ -247,6 +247,7 @@ int mmc_regulator_get_supply(struct mmc_host *mmc)
 
mmc->supply.vmmc = devm_regulator_get_optional(dev, "vmmc");
mmc->supply.vqmmc = devm_regulator_get_optional(dev, "vqmmc");
+   mmc->supply.vmmc2 = devm_regulator_get_optional(dev, "vmmc2");
 
if (IS_ERR(mmc->supply.vmmc)) {
if (PTR_ERR(mmc->supply.vmmc) == -EPROBE_DEFER)
@@ -266,6 +267,19 @@ int mmc_regulator_get_supply(struct mmc_host *mmc)
dev_dbg(dev, "No vqmmc regulator found\n");
}
 
+   if (IS_ERR(mmc->supply.vmmc2)) {
+   if (PTR_ERR(mmc->supply.vmmc2) == -EPROBE_DEFER)
+   return -EPROBE_DEFER;
+   dev_dbg(dev, "No vmmc2 regulator found\n");
+   } else {
+   ret = mmc_regulator_get_ocrmask(mmc->supply.vmmc2);
+   if (ret > 0)
+   mmc->ocr_avail_uhs2 = ret;
+   else
+   dev_warn(dev, "Failed getting UHS2 OCR mask: %d\n",
+ret);
+   }
+
return 0;
 }
 EXPORT_SYMBOL_GPL(mmc_regulator_get_supply);
-- 
2.27.0



[RFC PATCH V3 01/21] mmc: add UHS-II related definitions in public headers

2020-07-10 Thread Ben Chuang
From: Ben Chuang 

Add UHS-II support in public headers

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 include/linux/mmc/card.h |   1 +
 include/linux/mmc/core.h |   6 +
 include/linux/mmc/host.h |  30 +
 include/linux/mmc/uhs2.h | 268 +++
 4 files changed, 305 insertions(+)
 create mode 100644 include/linux/mmc/uhs2.h

diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 7d46411ffaa2..b7a7ce928155 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -181,6 +181,7 @@ struct sd_switch_caps {
 #define SD_SET_CURRENT_LIMIT_400   1
 #define SD_SET_CURRENT_LIMIT_600   2
 #define SD_SET_CURRENT_LIMIT_800   3
+#define SD_SET_CURRENT_LIMIT_1000   4
 #define SD_SET_CURRENT_NO_CHANGE   (-1)
 
 #define SD_MAX_CURRENT_200 (1 << SD_SET_CURRENT_LIMIT_200)
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 29aa50711626..52cb628d03fd 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -7,6 +7,7 @@
 
 #include 
 #include 
+#include 
 
 struct mmc_data;
 struct mmc_request;
@@ -109,6 +110,11 @@ struct mmc_command {
unsigned intbusy_timeout;   /* busy detect timeout in ms */
struct mmc_data *data;  /* data segment associated with 
cmd */
struct mmc_request  *mrq;   /* associated request */
+
+   struct uhs2_command *uhs2_cmd;  /* UHS2 command */
+   u8  *uhs2_resp; /* UHS2 native cmd resp */
+   u8  uhs2_resp_len;  /* UHS2 native cmd resp len */
+   u8  uhs2_tmode0_flag; /* UHS2 transfer mode flag */
 };
 
 struct mmc_data {
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 7149bab555d7..56bdb153ef16 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -15,10 +15,12 @@
 #include 
 #include 
 #include 
+#include 
 
 struct mmc_ios {
unsigned intclock;  /* clock rate */
unsigned short  vdd;
+   unsigned short  vdd2;   /* UHS2 VDD2 power supply */
unsigned intpower_delay_ms; /* waiting for stable power */
 
 /* vdd stores the bit number of the selected voltage range from below. */
@@ -60,6 +62,7 @@ struct mmc_ios {
 #define MMC_TIMING_MMC_DDR52   8
 #define MMC_TIMING_MMC_HS200   9
 #define MMC_TIMING_MMC_HS400   10
+#define MMC_TIMING_UHS211
 
unsigned char   signal_voltage; /* signalling voltage (1.8V or 
3.3V) */
 
@@ -172,6 +175,11 @@ struct mmc_host_ops {
 */
int (*multi_io_quirk)(struct mmc_card *card,
  unsigned int direction, int blk_size);
+   /* UHS2 interfaces */
+   int (*uhs2_detect_init)(struct mmc_host *host);
+   int (*uhs2_set_reg)(struct mmc_host *host, enum uhs2_act act);
+   void(*uhs2_disable_clk)(struct mmc_host *host);
+   void(*uhs2_enable_clk)(struct mmc_host *host);
 };
 
 struct mmc_cqe_ops {
@@ -264,6 +272,7 @@ struct mmc_pwrseq;
 
 struct mmc_supply {
struct regulator *vmmc; /* Card power supply */
+   struct regulator *vmmc2;/* UHS2 VDD2 power supply */
struct regulator *vqmmc;/* Optional Vccq supply */
 };
 
@@ -284,12 +293,14 @@ struct mmc_host {
u32 ocr_avail_sdio; /* SDIO-specific OCR */
u32 ocr_avail_sd;   /* SD-specific OCR */
u32 ocr_avail_mmc;  /* MMC-specific OCR */
+   u32 ocr_avail_uhs2; /* UHS2-specific OCR */
 #ifdef CONFIG_PM_SLEEP
struct notifier_block   pm_notify;
 #endif
u32 max_current_330;
u32 max_current_300;
u32 max_current_180;
+   u32 max_current_180_vdd2; /* UHS2 vdd2 max curt. */
 
 #define MMC_VDD_165_1950x0080  /* VDD voltage 1.65 - 
1.95 */
 #define MMC_VDD_20_21  0x0100  /* VDD voltage 2.0 ~ 2.1 */
@@ -308,6 +319,7 @@ struct mmc_host {
 #define MMC_VDD_33_34  0x0020  /* VDD voltage 3.3 ~ 3.4 */
 #define MMC_VDD_34_35  0x0040  /* VDD voltage 3.4 ~ 3.5 */
 #define MMC_VDD_35_36  0x0080  /* VDD voltage 3.5 ~ 3.6 */
+#define MMC_VDD2_165_195   0x0080  /* UHS2 VDD2 1.65 ~ 1.95 */
 
u32 caps;   /* Host capabilities */
 
@@ -341,6 +353,7 @@ struct mmc_host {
 #define MMC_CAP_DRIVER_TYPE_A  (1 << 23)   /* Host supports Driver Type A 
*/
 #define MMC_CAP_DRIVER_TYPE_C  (1 << 24)   /* Host supports Driver Type C 
*/
 #define MMC_CAP_DRIVER_TYPE_D  (1 << 25)   /* Host supports Driver Type D 
*/
+#define MMC_CAP_UHS2   BIT(26) /* Host supports UHS2 mode */
 #define MMC_CAP_DONE_COMPLETE  (1 <

Re: [PATCH -next] mmc: sdhci-pci-gli: Make sdhci_pci_gli_resume static

2020-05-08 Thread Ben Chuang
>>On Thu, 7 May 2020 at 14:14, Samuel Zou  wrote:
>>
>> Fix the following sparse warning:
>>
>> drivers/mmc/host/sdhci-pci-gli.c:343:5: warning:
>> symbol 'sdhci_pci_gli_resume' was not declared. Should it be static?
>>
>> Reported-by: Hulk Robot 
>> Signed-off-by: Samuel Zou 
>
>This actually fixes a commit that I on my fixes branch, which is also
>targeted for stable.
>
>Therefore, I decided to squash this into the offending commit and
>adding your sob tag, with a note about what you fixed.
>
>Kind regards
>Uffe
>

Thanks Samuel for fixed this issue.
Thanks Ulf for your help.

PS.
I use this email to reply because the company's email will have a
confidentiality clause in the letter.

Best regards,
Ben Chuang

>> ---
>>  drivers/mmc/host/sdhci-pci-gli.c | 2 +-
>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/drivers/mmc/host/sdhci-pci-gli.c 
>> b/drivers/mmc/host/sdhci-pci-gli.c
>> index bdb6336..fd76aa6 100644
>> --- a/drivers/mmc/host/sdhci-pci-gli.c
>> +++ b/drivers/mmc/host/sdhci-pci-gli.c
>> @@ -340,7 +340,7 @@ static u32 sdhci_gl9750_readl(struct sdhci_host *host, 
>> int reg)
>>  }
>>
>>  #ifdef CONFIG_PM_SLEEP
>>-int sdhci_pci_gli_resume(struct sdhci_pci_chip *chip)
>> +static int sdhci_pci_gli_resume(struct sdhci_pci_chip *chip)
>>{
>>struct sdhci_pci_slot *slot = chip->slots[0];
>>
>>--
>>2.6.2
>>


[PATCH] mmc: sdhci-pci-gli: Add Genesys Logic GL9763E support

2020-05-08 Thread Ben Chuang
From: Ben Chuang 

GL9763E supports High Speed SDR, High Speed DDR, HS200, HS400, Enhanced
Strobe in HS400 mode, 1/4/8 bits data bus and 3.3/1.8V.

Signed-off-by: Ben Chuang 
---
 drivers/mmc/host/sdhci-pci-core.c |   1 +
 drivers/mmc/host/sdhci-pci-gli.c  | 106 ++
 drivers/mmc/host/sdhci-pci.h  |   2 +
 3 files changed, 109 insertions(+)

diff --git a/drivers/mmc/host/sdhci-pci-core.c 
b/drivers/mmc/host/sdhci-pci-core.c
index af736afb4b91..bb6802448b2f 100644
--- a/drivers/mmc/host/sdhci-pci-core.c
+++ b/drivers/mmc/host/sdhci-pci-core.c
@@ -1745,6 +1745,7 @@ static const struct pci_device_id pci_ids[] = {
SDHCI_PCI_DEVICE(SYNOPSYS, DWC_MSHC, snps),
SDHCI_PCI_DEVICE(GLI, 9750, gl9750),
SDHCI_PCI_DEVICE(GLI, 9755, gl9755),
+   SDHCI_PCI_DEVICE(GLI, 9763E, gl9763e),
SDHCI_PCI_DEVICE_CLASS(AMD, SYSTEM_SDHCI, PCI_CLASS_MASK, amd),
/* Generic SD host controller */
{PCI_DEVICE_CLASS(SYSTEM_SDHCI, PCI_CLASS_MASK)},
diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c
index fd76aa672e02..ca0166d9bf82 100644
--- a/drivers/mmc/host/sdhci-pci-gli.c
+++ b/drivers/mmc/host/sdhci-pci-gli.c
@@ -63,6 +63,19 @@
 #define   SDHCI_GLI_9750_TUNING_PARAMETERS_RX_DLYGENMASK(2, 0)
 #define   GLI_9750_TUNING_PARAMETERS_RX_DLY_VALUE0x1
 
+#define SDHCI_GLI_9763E_CTRL_HS400  0x7
+
+#define SDHCI_GLI_9763E_HS400_ES_REG  0x52C
+#define   SDHCI_GLI_9763E_HS400_ES_BIT  BIT(8)
+
+#define PCIE_GLI_9763E_VHS  0x884
+#define   GLI_9763E_VHS_REV   GENMASK(19, 16)
+#define   GLI_9763E_VHS_REV_R  0x0
+#define   GLI_9763E_VHS_REV_M  0x1
+#define   GLI_9763E_VHS_REV_W  0x2
+#define PCIE_GLI_9763E_SCR  0x8E0
+#define   GLI_9763E_SCR_AXI_REQ   BIT(9)
+
 #define GLI_MAX_TUNING_LOOP 40
 
 /* Genesys Logic chipset */
@@ -351,6 +364,81 @@ static int sdhci_pci_gli_resume(struct sdhci_pci_chip 
*chip)
 }
 #endif
 
+static void gl9763e_hs400_enhanced_strobe(struct mmc_host *mmc,
+ struct mmc_ios *ios)
+{
+   struct sdhci_host *host = mmc_priv(mmc);
+   u32 val;
+
+   val = sdhci_readl(host, SDHCI_GLI_9763E_HS400_ES_REG);
+   if (ios->enhanced_strobe)
+   val |= SDHCI_GLI_9763E_HS400_ES_BIT;
+   else
+   val &= ~SDHCI_GLI_9763E_HS400_ES_BIT;
+
+   sdhci_writel(host, val, SDHCI_GLI_9763E_HS400_ES_REG);
+}
+
+static void sdhci_set_gl9763e_signaling(struct sdhci_host *host,
+   unsigned int timing)
+{
+   u16 ctrl_2;
+
+   ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+   ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
+   if (timing == MMC_TIMING_MMC_HS200)
+   ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
+   else if (timing == MMC_TIMING_MMC_HS)
+   ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
+   else if (timing == MMC_TIMING_MMC_DDR52)
+   ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
+   else if (timing == MMC_TIMING_MMC_HS400)
+   ctrl_2 |= SDHCI_GLI_9763E_CTRL_HS400;
+
+   sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+}
+
+static void gli_set_gl9763e(struct sdhci_pci_slot *slot)
+{
+   struct pci_dev *pdev = slot->chip->pdev;
+   u32 value;
+
+   pci_read_config_dword(pdev, PCIE_GLI_9763E_VHS, );
+   value &= ~GLI_9763E_VHS_REV;
+   value |= FIELD_PREP(GLI_9763E_VHS_REV, GLI_9763E_VHS_REV_W);
+   pci_write_config_dword(pdev, PCIE_GLI_9763E_VHS, value);
+
+   pci_read_config_dword(pdev, PCIE_GLI_9763E_SCR, );
+   value |= GLI_9763E_SCR_AXI_REQ;
+   pci_write_config_dword(pdev, PCIE_GLI_9763E_SCR, value);
+
+   pci_read_config_dword(pdev, PCIE_GLI_9763E_VHS, );
+   value &= ~GLI_9763E_VHS_REV;
+   value |= FIELD_PREP(GLI_9763E_VHS_REV, GLI_9763E_VHS_REV_R);
+   pci_write_config_dword(pdev, PCIE_GLI_9763E_VHS, value);
+}
+
+static int gli_probe_slot_gl9763e(struct sdhci_pci_slot *slot)
+{
+   struct sdhci_host *host = slot->host;
+
+   host->mmc->caps |= MMC_CAP_8_BIT_DATA |
+  MMC_CAP_1_8V_DDR |
+  MMC_CAP_NONREMOVABLE;
+   host->mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR |
+   MMC_CAP2_HS400_1_8V |
+   MMC_CAP2_HS400_ES |
+   MMC_CAP2_NO_SDIO |
+   MMC_CAP2_NO_SD;
+   gli_pcie_enable_msi(slot);
+   host->mmc_host_ops.hs400_enhanced_strobe =
+   gl9763e_hs400_enhanced_strobe;
+   gli_set_gl9763e(slot);
+   sdhci_enable_v4_mode(host);
+
+   return 0;
+}
+
 static const struct sdhci_ops sdhci_gl9755_ops = {
.set_clock  = sdhci_set_clock,
.enable_dma = sdhci_pci_enable_dma,
@@ -390,3 +478,21 @@ const struct sdhci_pci_fixes sdhci_gl9750 = {
.resume = sdhci_pci_gli_resume,
 #endif
 };
+
+stat

[PATCH] mmc: sdhci-pci-gli: Fix can not access GL9750 after reboot from Windows 10

2020-05-04 Thread Ben Chuang
From: Ben Chuang 

Need to clear some bits in a vendor-defined register after reboot from
Windows 10.

Fixes: e51df6ce668a ("mmc: host: sdhci-pci: Add Genesys Logic GL975x support")
Reported-by: Grzegorz Kowal 
Signed-off-by: Ben Chuang 
---
 drivers/mmc/host/sdhci-pci-gli.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c
index ce15a05f23d4..8170b659f2af 100644
--- a/drivers/mmc/host/sdhci-pci-gli.c
+++ b/drivers/mmc/host/sdhci-pci-gli.c
@@ -26,6 +26,9 @@
 #define   SDHCI_GLI_9750_DRIVING_2GENMASK(27, 26)
 #define   GLI_9750_DRIVING_1_VALUE0xFFF
 #define   GLI_9750_DRIVING_2_VALUE0x3
+#define   SDHCI_GLI_9750_SEL_1BIT(29)
+#define   SDHCI_GLI_9750_SEL_2BIT(31)
+#define   SDHCI_GLI_9750_ALL_RST  (BIT(24)|BIT(25)|BIT(28)|BIT(30))
 
 #define SDHCI_GLI_9750_PLL   0x864
 #define   SDHCI_GLI_9750_PLL_TX2_INVBIT(23)
@@ -122,6 +125,8 @@ static void gli_set_9750(struct sdhci_host *host)
GLI_9750_DRIVING_1_VALUE);
driving_value |= FIELD_PREP(SDHCI_GLI_9750_DRIVING_2,
GLI_9750_DRIVING_2_VALUE);
+   driving_value &= 
~(SDHCI_GLI_9750_SEL_1|SDHCI_GLI_9750_SEL_2|SDHCI_GLI_9750_ALL_RST);
+   driving_value |= SDHCI_GLI_9750_SEL_2;
sdhci_writel(host, driving_value, SDHCI_GLI_9750_DRIVING);
 
sw_ctrl_value &= ~SDHCI_GLI_9750_SW_CTRL_4;
-- 
2.26.2



Re: [PATCH V9 5/5] mmc: host: sdhci-pci: Add Genesys Logic GL975x support

2019-09-18 Thread Ben Chuang
On Wed, Sep 18, 2019 at 7:09 PM Adrian Hunter  wrote:
>
> On 18/09/19 1:47 PM, Michael K. Johnson wrote:
> > I see that the first four patches made it into Linus's kernel
> > yesterday. Is there any chance of this final patch that actually
> > enables the hardware making it into another pull request still
> > intended for 5.4?  Waiting on additional acked-by on Ben's work
> > addressing all the review comments?
> >
> > Thanks.
> >
> > On Wed, Sep 11, 2019 at 03:23:44PM +0800, Ben Chuang wrote:
> >> From: Ben Chuang 
> >>
> >> Add support for the GL9750 and GL9755 chipsets.
> >>
> >> Enable v4 mode and wait 5ms after set 1.8V signal enable for GL9750/
> >> GL9755. Fix the value of SDHCI_MAX_CURRENT register and use the vendor
> >> tuning flow for GL9750.
> >
>
> It is OK by me:
>
> Acked-by: Adrian Hunter 

Thank you. Also thanks to other people who have given me their comments.
Ben


[PATCH V9 5/5] mmc: host: sdhci-pci: Add Genesys Logic GL975x support

2019-09-11 Thread Ben Chuang
From: Ben Chuang 

Add support for the GL9750 and GL9755 chipsets.

Enable v4 mode and wait 5ms after set 1.8V signal enable for GL9750/
GL9755. Fix the value of SDHCI_MAX_CURRENT register and use the vendor
tuning flow for GL9750.

Co-developed-by: Michael K Johnson 
Signed-off-by: Michael K Johnson 
Signed-off-by: Ben Chuang 
---
 drivers/mmc/host/Kconfig  |   1 +
 drivers/mmc/host/Makefile |   2 +-
 drivers/mmc/host/sdhci-pci-core.c |   2 +
 drivers/mmc/host/sdhci-pci-gli.c  | 353 ++
 drivers/mmc/host/sdhci-pci.h  |   5 +
 5 files changed, 362 insertions(+), 1 deletion(-)
 create mode 100644 drivers/mmc/host/sdhci-pci-gli.c

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 931770f17087..9fbfff514d6c 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -94,6 +94,7 @@ config MMC_SDHCI_PCI
depends on MMC_SDHCI && PCI
select MMC_CQHCI
select IOSF_MBI if X86
+   select MMC_SDHCI_IO_ACCESSORS
help
  This selects the PCI Secure Digital Host Controller Interface.
  Most controllers found today are PCI devices.
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 73578718f119..661445415090 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -13,7 +13,7 @@ obj-$(CONFIG_MMC_MXS) += mxs-mmc.o
 obj-$(CONFIG_MMC_SDHCI)+= sdhci.o
 obj-$(CONFIG_MMC_SDHCI_PCI)+= sdhci-pci.o
 sdhci-pci-y+= sdhci-pci-core.o sdhci-pci-o2micro.o 
sdhci-pci-arasan.o \
-  sdhci-pci-dwc-mshc.o
+  sdhci-pci-dwc-mshc.o sdhci-pci-gli.o
 obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI))   += sdhci-pci-data.o
 obj-$(CONFIG_MMC_SDHCI_ACPI)   += sdhci-acpi.o
 obj-$(CONFIG_MMC_SDHCI_PXAV3)  += sdhci-pxav3.o
diff --git a/drivers/mmc/host/sdhci-pci-core.c 
b/drivers/mmc/host/sdhci-pci-core.c
index 4154ee11b47d..e5835fbf73bc 100644
--- a/drivers/mmc/host/sdhci-pci-core.c
+++ b/drivers/mmc/host/sdhci-pci-core.c
@@ -1682,6 +1682,8 @@ static const struct pci_device_id pci_ids[] = {
SDHCI_PCI_DEVICE(O2, SEABIRD1, o2),
SDHCI_PCI_DEVICE(ARASAN, PHY_EMMC, arasan),
SDHCI_PCI_DEVICE(SYNOPSYS, DWC_MSHC, snps),
+   SDHCI_PCI_DEVICE(GLI, 9750, gl9750),
+   SDHCI_PCI_DEVICE(GLI, 9755, gl9755),
SDHCI_PCI_DEVICE_CLASS(AMD, SYSTEM_SDHCI, PCI_CLASS_MASK, amd),
/* Generic SD host controller */
{PCI_DEVICE_CLASS(SYSTEM_SDHCI, PCI_CLASS_MASK)},
diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c
new file mode 100644
index ..041261bf9f7e
--- /dev/null
+++ b/drivers/mmc/host/sdhci-pci-gli.c
@@ -0,0 +1,353 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Genesys Logic, Inc.
+ *
+ * Authors: Ben Chuang 
+ *
+ * Version: v0.9.0 (2019-08-08)
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "sdhci.h"
+#include "sdhci-pci.h"
+
+/*  Genesys Logic extra registers */
+#define SDHCI_GLI_9750_WT 0x800
+#define   SDHCI_GLI_9750_WT_EN  BIT(0)
+#define   GLI_9750_WT_EN_ON0x1
+#define   GLI_9750_WT_EN_OFF   0x0
+
+#define SDHCI_GLI_9750_DRIVING  0x860
+#define   SDHCI_GLI_9750_DRIVING_1GENMASK(11, 0)
+#define   SDHCI_GLI_9750_DRIVING_2GENMASK(27, 26)
+#define   GLI_9750_DRIVING_1_VALUE0xFFF
+#define   GLI_9750_DRIVING_2_VALUE0x3
+
+#define SDHCI_GLI_9750_PLL   0x864
+#define   SDHCI_GLI_9750_PLL_TX2_INVBIT(23)
+#define   SDHCI_GLI_9750_PLL_TX2_DLYGENMASK(22, 20)
+#define   GLI_9750_PLL_TX2_INV_VALUE0x1
+#define   GLI_9750_PLL_TX2_DLY_VALUE0x0
+
+#define SDHCI_GLI_9750_SW_CTRL  0x874
+#define   SDHCI_GLI_9750_SW_CTRL_4GENMASK(7, 6)
+#define   GLI_9750_SW_CTRL_4_VALUE0x3
+
+#define SDHCI_GLI_9750_MISC0x878
+#define   SDHCI_GLI_9750_MISC_TX1_INVBIT(2)
+#define   SDHCI_GLI_9750_MISC_RX_INV BIT(3)
+#define   SDHCI_GLI_9750_MISC_TX1_DLYGENMASK(6, 4)
+#define   GLI_9750_MISC_TX1_INV_VALUE0x0
+#define   GLI_9750_MISC_RX_INV_ON0x1
+#define   GLI_9750_MISC_RX_INV_OFF   0x0
+#define   GLI_9750_MISC_RX_INV_VALUE GLI_9750_MISC_RX_INV_OFF
+#define   GLI_9750_MISC_TX1_DLY_VALUE0x5
+
+#define SDHCI_GLI_9750_TUNING_CONTROL0x540
+#define   SDHCI_GLI_9750_TUNING_CONTROL_EN  BIT(4)
+#define   GLI_9750_TUNING_CONTROL_EN_ON 0x1
+#define   GLI_9750_TUNING_CONTROL_EN_OFF0x0
+#define   SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_1BIT(16)
+#define   SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_2GENMASK(20, 19)
+#define   GLI_9750_TUNING_CONTROL_GLITCH_1_VALUE0x1
+#define   GLI_9750_TUNING_CONTROL_GLITCH_2_VALUE0x2
+
+#define SDHCI_GLI_9750_TUNING_PARAMETERS   0x544
+#define   SDHCI_GLI_9750_TUNING_PARAMETERS_RX_DLYGENMASK(2, 0)
+#define   GLI_9750_TUNING_PARAMETERS_RX

[PATCH V9 3/5] PCI: Add Genesys Logic, Inc. Vendor ID

2019-09-11 Thread Ben Chuang
From: Ben Chuang 

Add the Genesys Logic, Inc. vendor ID to pci_ids.h.

Signed-off-by: Ben Chuang 
Co-developed-by: Michael K Johnson 
Signed-off-by: Michael K Johnson 
Acked-by: Adrian Hunter 
---
 include/linux/pci_ids.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 70e86148cb1e..4f7e12772a14 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -2403,6 +2403,8 @@
 #define PCI_DEVICE_ID_RDC_R60610x6061
 #define PCI_DEVICE_ID_RDC_D10100x1010
 
+#define PCI_VENDOR_ID_GLI  0x17a0
+
 #define PCI_VENDOR_ID_LENOVO   0x17aa
 
 #define PCI_VENDOR_ID_QCOM 0x17cb
-- 
2.23.0



[PATCH V9 4/5] mmc: sdhci: Export sdhci_abort_tuning function symbol

2019-09-11 Thread Ben Chuang
From: Ben Chuang 

Export sdhci_abort_tuning() function symbols which are used by other SD Host
controller driver modules.

Signed-off-by: Ben Chuang 
Co-developed-by: Michael K Johnson 
Signed-off-by: Michael K Johnson 
Acked-by: Adrian Hunter 
---
 drivers/mmc/host/sdhci.c | 3 ++-
 drivers/mmc/host/sdhci.h | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 9106ebc7a422..0f2f110534db 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2328,7 +2328,7 @@ void sdhci_reset_tuning(struct sdhci_host *host)
 }
 EXPORT_SYMBOL_GPL(sdhci_reset_tuning);
 
-static void sdhci_abort_tuning(struct sdhci_host *host, u32 opcode)
+void sdhci_abort_tuning(struct sdhci_host *host, u32 opcode)
 {
sdhci_reset_tuning(host);
 
@@ -2339,6 +2339,7 @@ static void sdhci_abort_tuning(struct sdhci_host *host, 
u32 opcode)
 
mmc_abort_tuning(host->mmc, opcode);
 }
+EXPORT_SYMBOL_GPL(sdhci_abort_tuning);
 
 /*
  * We use sdhci_send_tuning() because mmc_send_tuning() is not a good fit. 
SDHCI
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 72601a4d2e95..437bab3af195 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -797,5 +797,6 @@ void sdhci_start_tuning(struct sdhci_host *host);
 void sdhci_end_tuning(struct sdhci_host *host);
 void sdhci_reset_tuning(struct sdhci_host *host);
 void sdhci_send_tuning(struct sdhci_host *host, u32 opcode);
+void sdhci_abort_tuning(struct sdhci_host *host, u32 opcode);
 
 #endif /* __SDHCI_HW_H */
-- 
2.23.0



[PATCH V9 2/5] mmc: sdhci: Add PLL Enable support to internal clock setup

2019-09-11 Thread Ben Chuang
From: Ben Chuang 

The GL9750 and GL9755 chipsets, and possibly others, require PLL Enable
setup as part of the internal clock setup as described in 3.2.1 Internal
Clock Setup Sequence of SD Host Controller Simplified Specification
Version 4.20.

Signed-off-by: Ben Chuang 
Co-developed-by: Michael K Johnson 
Signed-off-by: Michael K Johnson 
Acked-by: Adrian Hunter 
---
 drivers/mmc/host/sdhci.c | 23 +++
 drivers/mmc/host/sdhci.h |  1 +
 2 files changed, 24 insertions(+)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index bed0760a6c2a..9106ebc7a422 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1653,6 +1653,29 @@ void sdhci_enable_clk(struct sdhci_host *host, u16 clk)
udelay(10);
}
 
+   if (host->version >= SDHCI_SPEC_410 && host->v4_mode) {
+   clk |= SDHCI_CLOCK_PLL_EN;
+   clk &= ~SDHCI_CLOCK_INT_STABLE;
+   sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+   /* Wait max 150 ms */
+   timeout = ktime_add_ms(ktime_get(), 150);
+   while (1) {
+   bool timedout = ktime_after(ktime_get(), timeout);
+
+   clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+   if (clk & SDHCI_CLOCK_INT_STABLE)
+   break;
+   if (timedout) {
+   pr_err("%s: PLL clock never stabilised.\n",
+  mmc_hostname(host->mmc));
+   sdhci_dumpregs(host);
+   return;
+   }
+   udelay(10);
+   }
+   }
+
clk |= SDHCI_CLOCK_CARD_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
 }
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 199712e7adbb..72601a4d2e95 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -114,6 +114,7 @@
 #define  SDHCI_DIV_HI_MASK 0x300
 #define  SDHCI_PROG_CLOCK_MODE 0x0020
 #define  SDHCI_CLOCK_CARD_EN   0x0004
+#define  SDHCI_CLOCK_PLL_EN0x0008
 #define  SDHCI_CLOCK_INT_STABLE0x0002
 #define  SDHCI_CLOCK_INT_EN0x0001
 
-- 
2.23.0



[PATCH V9 1/5] mmc: sdhci: Change timeout of loop for checking internal clock stable

2019-09-11 Thread Ben Chuang
From: Ben Chuang 

According to section 3.2.1 internal clock setup in SD Host Controller
Simplified Specifications 4.20, the timeout of loop for checking
internal clock stable is defined as 150ms.

Signed-off-by: Ben Chuang 
Co-developed-by: Michael K Johnson 
Signed-off-by: Michael K Johnson 
Acked-by: Adrian Hunter 
---
 drivers/mmc/host/sdhci.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 59acf8e3331e..bed0760a6c2a 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1636,8 +1636,8 @@ void sdhci_enable_clk(struct sdhci_host *host, u16 clk)
clk |= SDHCI_CLOCK_INT_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
 
-   /* Wait max 20 ms */
-   timeout = ktime_add_ms(ktime_get(), 20);
+   /* Wait max 150 ms */
+   timeout = ktime_add_ms(ktime_get(), 150);
while (1) {
bool timedout = ktime_after(ktime_get(), timeout);
 
-- 
2.23.0



[PATCH V9 0/5] Add Genesys Logic GL975x support

2019-09-11 Thread Ben Chuang
From: Ben Chuang 

The patches modify internal clock setup to match SD Host Controller
Simplified Specifications 4.20 and support Genesys Logic GL9750/GL9755
chipsets.

v9:
 - refine gli_set_9750_rx_inv()
 - modify comments in sdhci_gli_voltage_switch()

v8:
 refine codes in sdhci-gli-pci.c
 - remove duplicate assignment 
 - remove redundant delay
 - use '!!'(not not) logical operator to refine the true/false condition
 - check end condition after outter loop
 - add comments for delay 5ms in sdhci_gli_voltage_switch()
 - merge two logical conditions to one line

v7:
 - remove condition define CONFIG_MMC_SDHCI_IO_ACCESSORS from sdhci-pci-gli.c
 - making the accessors(MMC_SDHCI_IO_ACCESSORS) always available when selecting
   MMC_SDHCI_PCI in Kconfig

V6:
 - export sdhci_abot_tuning() function symbol
 - use C-style comments
 - use BIT, FIELD_{GET,PREP} and GENMASK to define bit fields of register
 - use host->ops->platform_execute_tuning instead of mmc->ops->execute_tuning
 - call sdhci_reset() instead of duplicating the code in sdhci_gl9750_reset
 - remove .hw_reset 
 - use condition define CONFIG_MMC_SDHCI_IO_ACCESSORS for read_l

V5:
 - add "change timeout of loop .." to a patch
 - fix typo "verndor" to "vendor"

V4:
 - change name from sdhci_gli_reset to sdhci_gl9750_reset
 - fix sdhci_reset to sdhci_gl9750_reset in sdhci_gl9750_ops
 - fix sdhci_gli_reset to sdhci_reset in sdhci_gl9755_ops
 
V3:
 - change usleep_range to udelay
 - add Genesys Logic PCI Vendor ID to a patch
 - separate the Genesys Logic specific part to a patch

V2:
 - change udelay to usleep_range

Ben Chuang (5):
  mmc: sdhci: Change timeout of loop for checking internal clock stable
  mmc: sdhci: Add PLL Enable support to internal clock setup
  PCI: Add Genesys Logic, Inc. Vendor ID
  mmc: sdhci: Export sdhci_abort_tuning function symbol
  mmc: host: sdhci-pci: Add Genesys Logic GL975x support

 drivers/mmc/host/Kconfig  |   1 +
 drivers/mmc/host/Makefile |   2 +-
 drivers/mmc/host/sdhci-pci-core.c |   2 +
 drivers/mmc/host/sdhci-pci-gli.c  | 353 ++
 drivers/mmc/host/sdhci-pci.h  |   5 +
 drivers/mmc/host/sdhci.c  |  30 ++-
 drivers/mmc/host/sdhci.h  |   2 +
 include/linux/pci_ids.h   |   2 +
 8 files changed, 393 insertions(+), 4 deletions(-)
 create mode 100644 drivers/mmc/host/sdhci-pci-gli.c

-- 
2.23.0



Re: [PATCH V8 5/5] mmc: host: sdhci-pci: Add Genesys Logic GL975x support

2019-09-10 Thread Ben Chuang
On Wed, Sep 11, 2019 at 12:42 PM Guenter Roeck  wrote:
>
> On Fri, Sep 06, 2019 at 10:33:26AM +0800, Ben Chuang wrote:
> > From: Ben Chuang 
> >
> > Add support for the GL9750 and GL9755 chipsets.
> >
> > Enable v4 mode and wait 5ms after set 1.8V signal enable for GL9750/
> > GL9755. Fix the value of SDHCI_MAX_CURRENT register and use the vendor
> > tuning flow for GL9750.
> >
> > Co-developed-by: Michael K Johnson 
> > Signed-off-by: Michael K Johnson 
> > Signed-off-by: Ben Chuang 
> > ---
> >  drivers/mmc/host/Kconfig  |   1 +
> >  drivers/mmc/host/Makefile |   2 +-
> >  drivers/mmc/host/sdhci-pci-core.c |   2 +
> >  drivers/mmc/host/sdhci-pci-gli.c  | 355 ++
> >  drivers/mmc/host/sdhci-pci.h  |   5 +
> >  5 files changed, 364 insertions(+), 1 deletion(-)
> >  create mode 100644 drivers/mmc/host/sdhci-pci-gli.c
> >
> > diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
> > index 931770f17087..9fbfff514d6c 100644
> > --- a/drivers/mmc/host/Kconfig
> > +++ b/drivers/mmc/host/Kconfig
> > @@ -94,6 +94,7 @@ config MMC_SDHCI_PCI
> >   depends on MMC_SDHCI && PCI
> >   select MMC_CQHCI
> >   select IOSF_MBI if X86
> > + select MMC_SDHCI_IO_ACCESSORS
> >   help
> > This selects the PCI Secure Digital Host Controller Interface.
> > Most controllers found today are PCI devices.
> > diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
> > index 73578718f119..661445415090 100644
> > --- a/drivers/mmc/host/Makefile
> > +++ b/drivers/mmc/host/Makefile
> > @@ -13,7 +13,7 @@ obj-$(CONFIG_MMC_MXS)   += mxs-mmc.o
> >  obj-$(CONFIG_MMC_SDHCI)  += sdhci.o
> >  obj-$(CONFIG_MMC_SDHCI_PCI)  += sdhci-pci.o
> >  sdhci-pci-y  += sdhci-pci-core.o sdhci-pci-o2micro.o 
> > sdhci-pci-arasan.o \
> > -sdhci-pci-dwc-mshc.o
> > +sdhci-pci-dwc-mshc.o sdhci-pci-gli.o
> >  obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI)) += sdhci-pci-data.o
> >  obj-$(CONFIG_MMC_SDHCI_ACPI) += sdhci-acpi.o
> >  obj-$(CONFIG_MMC_SDHCI_PXAV3)+= sdhci-pxav3.o
> > diff --git a/drivers/mmc/host/sdhci-pci-core.c 
> > b/drivers/mmc/host/sdhci-pci-core.c
> > index 4154ee11b47d..e5835fbf73bc 100644
> > --- a/drivers/mmc/host/sdhci-pci-core.c
> > +++ b/drivers/mmc/host/sdhci-pci-core.c
> > @@ -1682,6 +1682,8 @@ static const struct pci_device_id pci_ids[] = {
> >   SDHCI_PCI_DEVICE(O2, SEABIRD1, o2),
> >   SDHCI_PCI_DEVICE(ARASAN, PHY_EMMC, arasan),
> >   SDHCI_PCI_DEVICE(SYNOPSYS, DWC_MSHC, snps),
> > + SDHCI_PCI_DEVICE(GLI, 9750, gl9750),
> > + SDHCI_PCI_DEVICE(GLI, 9755, gl9755),
> >   SDHCI_PCI_DEVICE_CLASS(AMD, SYSTEM_SDHCI, PCI_CLASS_MASK, amd),
> >   /* Generic SD host controller */
> >   {PCI_DEVICE_CLASS(SYSTEM_SDHCI, PCI_CLASS_MASK)},
> > diff --git a/drivers/mmc/host/sdhci-pci-gli.c 
> > b/drivers/mmc/host/sdhci-pci-gli.c
> > new file mode 100644
> > index ..94462b94abec
> > --- /dev/null
> > +++ b/drivers/mmc/host/sdhci-pci-gli.c
> > @@ -0,0 +1,355 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Copyright (C) 2019 Genesys Logic, Inc.
> > + *
> > + * Authors: Ben Chuang 
> > + *
> > + * Version: v0.9.0 (2019-08-08)
> > + */
> > +
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include "sdhci.h"
> > +#include "sdhci-pci.h"
> > +
> > +/*  Genesys Logic extra registers */
> > +#define SDHCI_GLI_9750_WT 0x800
> > +#define   SDHCI_GLI_9750_WT_EN  BIT(0)
> > +#define   GLI_9750_WT_EN_ON  0x1
> > +#define   GLI_9750_WT_EN_OFF 0x0
> > +
> > +#define SDHCI_GLI_9750_DRIVING  0x860
> > +#define   SDHCI_GLI_9750_DRIVING_1GENMASK(11, 0)
> > +#define   SDHCI_GLI_9750_DRIVING_2GENMASK(27, 26)
> > +#define   GLI_9750_DRIVING_1_VALUE0xFFF
> > +#define   GLI_9750_DRIVING_2_VALUE0x3
> > +
> > +#define SDHCI_GLI_9750_PLL 0x864
> > +#define   SDHCI_GLI_9750_PLL_TX2_INVBIT(23)
> > +#define   SDHCI_GLI_9750_PLL_TX2_DLYGENMASK(22, 20)
> > +#define   GLI_9750_PLL_TX2_INV_VALUE0x1
> > +#define   GLI_9750_PLL_TX2_DLY_VALUE0x0
> > +
> > +#define SDHCI_GLI_9750_SW_CTRL  0x874
> > +#define   SDHCI_GLI_9750_SW_CTRL_4GENMASK(7, 6)
> > +#define   GLI_9750_

[PATCH V8 5/5] mmc: host: sdhci-pci: Add Genesys Logic GL975x support

2019-09-05 Thread Ben Chuang
From: Ben Chuang 

Add support for the GL9750 and GL9755 chipsets.

Enable v4 mode and wait 5ms after set 1.8V signal enable for GL9750/
GL9755. Fix the value of SDHCI_MAX_CURRENT register and use the vendor
tuning flow for GL9750.

Co-developed-by: Michael K Johnson 
Signed-off-by: Michael K Johnson 
Signed-off-by: Ben Chuang 
---
 drivers/mmc/host/Kconfig  |   1 +
 drivers/mmc/host/Makefile |   2 +-
 drivers/mmc/host/sdhci-pci-core.c |   2 +
 drivers/mmc/host/sdhci-pci-gli.c  | 355 ++
 drivers/mmc/host/sdhci-pci.h  |   5 +
 5 files changed, 364 insertions(+), 1 deletion(-)
 create mode 100644 drivers/mmc/host/sdhci-pci-gli.c

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 931770f17087..9fbfff514d6c 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -94,6 +94,7 @@ config MMC_SDHCI_PCI
depends on MMC_SDHCI && PCI
select MMC_CQHCI
select IOSF_MBI if X86
+   select MMC_SDHCI_IO_ACCESSORS
help
  This selects the PCI Secure Digital Host Controller Interface.
  Most controllers found today are PCI devices.
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 73578718f119..661445415090 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -13,7 +13,7 @@ obj-$(CONFIG_MMC_MXS) += mxs-mmc.o
 obj-$(CONFIG_MMC_SDHCI)+= sdhci.o
 obj-$(CONFIG_MMC_SDHCI_PCI)+= sdhci-pci.o
 sdhci-pci-y+= sdhci-pci-core.o sdhci-pci-o2micro.o 
sdhci-pci-arasan.o \
-  sdhci-pci-dwc-mshc.o
+  sdhci-pci-dwc-mshc.o sdhci-pci-gli.o
 obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI))   += sdhci-pci-data.o
 obj-$(CONFIG_MMC_SDHCI_ACPI)   += sdhci-acpi.o
 obj-$(CONFIG_MMC_SDHCI_PXAV3)  += sdhci-pxav3.o
diff --git a/drivers/mmc/host/sdhci-pci-core.c 
b/drivers/mmc/host/sdhci-pci-core.c
index 4154ee11b47d..e5835fbf73bc 100644
--- a/drivers/mmc/host/sdhci-pci-core.c
+++ b/drivers/mmc/host/sdhci-pci-core.c
@@ -1682,6 +1682,8 @@ static const struct pci_device_id pci_ids[] = {
SDHCI_PCI_DEVICE(O2, SEABIRD1, o2),
SDHCI_PCI_DEVICE(ARASAN, PHY_EMMC, arasan),
SDHCI_PCI_DEVICE(SYNOPSYS, DWC_MSHC, snps),
+   SDHCI_PCI_DEVICE(GLI, 9750, gl9750),
+   SDHCI_PCI_DEVICE(GLI, 9755, gl9755),
SDHCI_PCI_DEVICE_CLASS(AMD, SYSTEM_SDHCI, PCI_CLASS_MASK, amd),
/* Generic SD host controller */
{PCI_DEVICE_CLASS(SYSTEM_SDHCI, PCI_CLASS_MASK)},
diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c
new file mode 100644
index ..94462b94abec
--- /dev/null
+++ b/drivers/mmc/host/sdhci-pci-gli.c
@@ -0,0 +1,355 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Genesys Logic, Inc.
+ *
+ * Authors: Ben Chuang 
+ *
+ * Version: v0.9.0 (2019-08-08)
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "sdhci.h"
+#include "sdhci-pci.h"
+
+/*  Genesys Logic extra registers */
+#define SDHCI_GLI_9750_WT 0x800
+#define   SDHCI_GLI_9750_WT_EN  BIT(0)
+#define   GLI_9750_WT_EN_ON0x1
+#define   GLI_9750_WT_EN_OFF   0x0
+
+#define SDHCI_GLI_9750_DRIVING  0x860
+#define   SDHCI_GLI_9750_DRIVING_1GENMASK(11, 0)
+#define   SDHCI_GLI_9750_DRIVING_2GENMASK(27, 26)
+#define   GLI_9750_DRIVING_1_VALUE0xFFF
+#define   GLI_9750_DRIVING_2_VALUE0x3
+
+#define SDHCI_GLI_9750_PLL   0x864
+#define   SDHCI_GLI_9750_PLL_TX2_INVBIT(23)
+#define   SDHCI_GLI_9750_PLL_TX2_DLYGENMASK(22, 20)
+#define   GLI_9750_PLL_TX2_INV_VALUE0x1
+#define   GLI_9750_PLL_TX2_DLY_VALUE0x0
+
+#define SDHCI_GLI_9750_SW_CTRL  0x874
+#define   SDHCI_GLI_9750_SW_CTRL_4GENMASK(7, 6)
+#define   GLI_9750_SW_CTRL_4_VALUE0x3
+
+#define SDHCI_GLI_9750_MISC0x878
+#define   SDHCI_GLI_9750_MISC_TX1_INVBIT(2)
+#define   SDHCI_GLI_9750_MISC_RX_INV BIT(3)
+#define   SDHCI_GLI_9750_MISC_TX1_DLYGENMASK(6, 4)
+#define   GLI_9750_MISC_TX1_INV_VALUE0x0
+#define   GLI_9750_MISC_RX_INV_ON0x1
+#define   GLI_9750_MISC_RX_INV_OFF   0x0
+#define   GLI_9750_MISC_RX_INV_VALUE GLI_9750_MISC_RX_INV_OFF
+#define   GLI_9750_MISC_TX1_DLY_VALUE0x5
+
+#define SDHCI_GLI_9750_TUNING_CONTROL0x540
+#define   SDHCI_GLI_9750_TUNING_CONTROL_EN  BIT(4)
+#define   GLI_9750_TUNING_CONTROL_EN_ON 0x1
+#define   GLI_9750_TUNING_CONTROL_EN_OFF0x0
+#define   SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_1BIT(16)
+#define   SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_2GENMASK(20, 19)
+#define   GLI_9750_TUNING_CONTROL_GLITCH_1_VALUE0x1
+#define   GLI_9750_TUNING_CONTROL_GLITCH_2_VALUE0x2
+
+#define SDHCI_GLI_9750_TUNING_PARAMETERS   0x544
+#define   SDHCI_GLI_9750_TUNING_PARAMETERS_RX_DLYGENMASK(2, 0)
+#define   GLI_9750_TUNING_PARAMETERS_RX

[PATCH V8 4/5] mmc: sdhci: Export sdhci_abort_tuning function symbol

2019-09-05 Thread Ben Chuang
From: Ben Chuang 

Export sdhci_abort_tuning() function symbols which are used by other SD Host
controller driver modules.

Signed-off-by: Ben Chuang 
Co-developed-by: Michael K Johnson 
Signed-off-by: Michael K Johnson 
Acked-by: Adrian Hunter 
---
 drivers/mmc/host/sdhci.c | 3 ++-
 drivers/mmc/host/sdhci.h | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 9106ebc7a422..0f2f110534db 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2328,7 +2328,7 @@ void sdhci_reset_tuning(struct sdhci_host *host)
 }
 EXPORT_SYMBOL_GPL(sdhci_reset_tuning);
 
-static void sdhci_abort_tuning(struct sdhci_host *host, u32 opcode)
+void sdhci_abort_tuning(struct sdhci_host *host, u32 opcode)
 {
sdhci_reset_tuning(host);
 
@@ -2339,6 +2339,7 @@ static void sdhci_abort_tuning(struct sdhci_host *host, 
u32 opcode)
 
mmc_abort_tuning(host->mmc, opcode);
 }
+EXPORT_SYMBOL_GPL(sdhci_abort_tuning);
 
 /*
  * We use sdhci_send_tuning() because mmc_send_tuning() is not a good fit. 
SDHCI
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 72601a4d2e95..437bab3af195 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -797,5 +797,6 @@ void sdhci_start_tuning(struct sdhci_host *host);
 void sdhci_end_tuning(struct sdhci_host *host);
 void sdhci_reset_tuning(struct sdhci_host *host);
 void sdhci_send_tuning(struct sdhci_host *host, u32 opcode);
+void sdhci_abort_tuning(struct sdhci_host *host, u32 opcode);
 
 #endif /* __SDHCI_HW_H */
-- 
2.23.0



[PATCH V8 3/5] PCI: Add Genesys Logic, Inc. Vendor ID

2019-09-05 Thread Ben Chuang
From: Ben Chuang 

Add the Genesys Logic, Inc. vendor ID to pci_ids.h.

Signed-off-by: Ben Chuang 
Co-developed-by: Michael K Johnson 
Signed-off-by: Michael K Johnson 
Acked-by: Adrian Hunter 
---
 include/linux/pci_ids.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 70e86148cb1e..4f7e12772a14 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -2403,6 +2403,8 @@
 #define PCI_DEVICE_ID_RDC_R60610x6061
 #define PCI_DEVICE_ID_RDC_D10100x1010
 
+#define PCI_VENDOR_ID_GLI  0x17a0
+
 #define PCI_VENDOR_ID_LENOVO   0x17aa
 
 #define PCI_VENDOR_ID_QCOM 0x17cb
-- 
2.23.0



[PATCH V8 2/5] mmc: sdhci: Add PLL Enable support to internal clock setup

2019-09-05 Thread Ben Chuang
From: Ben Chuang 

The GL9750 and GL9755 chipsets, and possibly others, require PLL Enable
setup as part of the internal clock setup as described in 3.2.1 Internal
Clock Setup Sequence of SD Host Controller Simplified Specification
Version 4.20.

Signed-off-by: Ben Chuang 
Co-developed-by: Michael K Johnson 
Signed-off-by: Michael K Johnson 
Acked-by: Adrian Hunter 
---
 drivers/mmc/host/sdhci.c | 23 +++
 drivers/mmc/host/sdhci.h |  1 +
 2 files changed, 24 insertions(+)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index bed0760a6c2a..9106ebc7a422 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1653,6 +1653,29 @@ void sdhci_enable_clk(struct sdhci_host *host, u16 clk)
udelay(10);
}
 
+   if (host->version >= SDHCI_SPEC_410 && host->v4_mode) {
+   clk |= SDHCI_CLOCK_PLL_EN;
+   clk &= ~SDHCI_CLOCK_INT_STABLE;
+   sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+   /* Wait max 150 ms */
+   timeout = ktime_add_ms(ktime_get(), 150);
+   while (1) {
+   bool timedout = ktime_after(ktime_get(), timeout);
+
+   clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+   if (clk & SDHCI_CLOCK_INT_STABLE)
+   break;
+   if (timedout) {
+   pr_err("%s: PLL clock never stabilised.\n",
+  mmc_hostname(host->mmc));
+   sdhci_dumpregs(host);
+   return;
+   }
+   udelay(10);
+   }
+   }
+
clk |= SDHCI_CLOCK_CARD_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
 }
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 199712e7adbb..72601a4d2e95 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -114,6 +114,7 @@
 #define  SDHCI_DIV_HI_MASK 0x300
 #define  SDHCI_PROG_CLOCK_MODE 0x0020
 #define  SDHCI_CLOCK_CARD_EN   0x0004
+#define  SDHCI_CLOCK_PLL_EN0x0008
 #define  SDHCI_CLOCK_INT_STABLE0x0002
 #define  SDHCI_CLOCK_INT_EN0x0001
 
-- 
2.23.0



[PATCH V8 1/5] mmc: sdhci: Change timeout of loop for checking internal clock stable

2019-09-05 Thread Ben Chuang
From: Ben Chuang 

According to section 3.2.1 internal clock setup in SD Host Controller
Simplified Specifications 4.20, the timeout of loop for checking
internal clock stable is defined as 150ms.

Signed-off-by: Ben Chuang 
Co-developed-by: Michael K Johnson 
Signed-off-by: Michael K Johnson 
Acked-by: Adrian Hunter 
---
 drivers/mmc/host/sdhci.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 59acf8e3331e..bed0760a6c2a 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1636,8 +1636,8 @@ void sdhci_enable_clk(struct sdhci_host *host, u16 clk)
clk |= SDHCI_CLOCK_INT_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
 
-   /* Wait max 20 ms */
-   timeout = ktime_add_ms(ktime_get(), 20);
+   /* Wait max 150 ms */
+   timeout = ktime_add_ms(ktime_get(), 150);
while (1) {
bool timedout = ktime_after(ktime_get(), timeout);
 
-- 
2.23.0



[PATCH V8 0/5] Add Genesys Logic GL975x support

2019-09-05 Thread Ben Chuang
From: Ben Chuang 

The patches modify internal clock setup to match SD Host Controller
Simplified Specifications 4.20 and support Genesys Logic GL9750/GL9755
chipsets.

v8:
 refine codes in sdhci-gli-pci.c
 - remove duplicate assignment 
 - remove redundant delay
 - use '!!'(not not) logical operator to refine the true/false condition
 - check end condition after outter loop
 - add comments for delay 5ms in sdhci_gli_voltage_switch()
 - merge two logical conditions to one line

v7:
 - remove condition define CONFIG_MMC_SDHCI_IO_ACCESSORS from sdhci-pci-gli.c
 - making the accessors(MMC_SDHCI_IO_ACCESSORS) always available when selecting
   MMC_SDHCI_PCI in Kconfig

V6:
 - export sdhci_abot_tuning() function symbol
 - use C-style comments
 - use BIT, FIELD_{GET,PREP} and GENMASK to define bit fields of register
 - use host->ops->platform_execute_tuning instead of mmc->ops->execute_tuning
 - call sdhci_reset() instead of duplicating the code in sdhci_gl9750_reset
 - remove .hw_reset 
 - use condition define CONFIG_MMC_SDHCI_IO_ACCESSORS for read_l

V5:
 - add "change timeout of loop .." to a patch
 - fix typo "verndor" to "vendor"

V4:
 - change name from sdhci_gli_reset to sdhci_gl9750_reset
 - fix sdhci_reset to sdhci_gl9750_reset in sdhci_gl9750_ops
 - fix sdhci_gli_reset to sdhci_reset in sdhci_gl9755_ops
 
V3:
 - change usleep_range to udelay
 - add Genesys Logic PCI Vendor ID to a patch
 - separate the Genesys Logic specific part to a patch

V2:
 - change udelay to usleep_range

Ben Chuang (5):
  mmc: sdhci: Change timeout of loop for checking internal clock stable
  mmc: sdhci: Add PLL Enable support to internal clock setup
  PCI: Add Genesys Logic, Inc. Vendor ID
  mmc: sdhci: Export sdhci_abort_tuning function symbol
  mmc: host: sdhci-pci: Add Genesys Logic GL975x support

 drivers/mmc/host/Kconfig  |   1 +
 drivers/mmc/host/Makefile |   2 +-
 drivers/mmc/host/sdhci-pci-core.c |   2 +
 drivers/mmc/host/sdhci-pci-gli.c  | 355 ++
 drivers/mmc/host/sdhci-pci.h  |   5 +
 drivers/mmc/host/sdhci.c  |  30 ++-
 drivers/mmc/host/sdhci.h  |   2 +
 include/linux/pci_ids.h   |   2 +
 8 files changed, 395 insertions(+), 4 deletions(-)
 create mode 100644 drivers/mmc/host/sdhci-pci-gli.c

-- 
2.23.0



Re: [PATCH V7 5/5] mmc: host: sdhci-pci: Add Genesys Logic GL975x support

2019-09-04 Thread Ben Chuang
On Wed, Sep 4, 2019 at 5:54 PM Adrian Hunter  wrote:
>
> On 4/09/19 3:58 AM, Ben Chuang wrote:
> > On Tue, Sep 3, 2019 at 6:05 AM Andy Shevchenko
> >  wrote:
> >>
> >> On Fri, Aug 30, 2019 at 5:28 AM Ben Chuang  wrote:
> >>>
> >>> From: Ben Chuang 
> >>>
> >>> Add support for the GL9750 and GL9755 chipsets.
> >>>
> >>> Enable v4 mode and wait 5ms after set 1.8V signal enable for GL9750/
> >>> GL9755. Fix the value of SDHCI_MAX_CURRENT register and use the vendor
> >>> tuning flow for GL9750.
> >>>
> >>
> >>> Signed-off-by: Ben Chuang 
> >>
> >> Usually last one for latest developer / submitter goes on.
> >>
> >>> Co-developed-by: Michael K Johnson 
> >>> Signed-off-by: Michael K Johnson 
> >>
> >>
> >>> +#define GLI_MAX_TUNING_LOOP 40
> >>
> >>
> >>> +static void gli_set_9750(struct sdhci_host *host)
> >>> +{
> >>> +   u32 driving_value = 0;
> >>> +   u32 pll_value = 0;
> >>> +   u32 sw_ctrl_value = 0;
> >>> +   u32 misc_value = 0;
> >>> +   u32 parameter_value = 0;
> >>> +   u32 control_value = 0;
> >>
> >>> +
> >>
> >> Redundant blank line.
> >>
> >>> +   u16 ctrl2 = 0;
> >>
> >> Do you need these all assignments above?
> >>
> >>> +   driving_value = sdhci_readl(host, SDHCI_GLI_9750_DRIVING);
> >>> +   pll_value = sdhci_readl(host, SDHCI_GLI_9750_PLL);
> >>> +   sw_ctrl_value = sdhci_readl(host, SDHCI_GLI_9750_SW_CTRL);
> >>> +   misc_value = sdhci_readl(host, SDHCI_GLI_9750_MISC);
> >>> +   parameter_value = sdhci_readl(host, 
> >>> SDHCI_GLI_9750_TUNING_PARAMETERS);
> >>> +   control_value = sdhci_readl(host, SDHCI_GLI_9750_TUNING_CONTROL);
> >>
> >>
> >>
> >>> +
> >>> +   udelay(1);
> >>
> >> This misses the answer to question why. Why this is needed and why
> >> timeout is this long?
> >>
> >>> +
> >>> +   gl9750_wt_off(host);
> >>> +}
> >>
> >>> +static int __sdhci_execute_tuning_9750(struct sdhci_host *host, u32 
> >>> opcode)
> >>> +{
> >>> +   int i;
> >>
> >>> +   int rx_inv = 0;
> >>
> >> Duplicate assignment.
> >>
> >>> +
> >>> +   for (rx_inv = 0; rx_inv < 2; rx_inv++) {
> >>
> >>> +   if (rx_inv & 0x1)
> >>> +   gli_set_9750_rx_inv(host, true);
> >>> +   else
> >>> +   gli_set_9750_rx_inv(host, false);
> >>
> >> gli_set_...(host, !!rx_inv);
> >>
> >>> +
> >>> +   sdhci_start_tuning(host);
> >>> +
> >>> +   for (i = 0; i < GLI_MAX_TUNING_LOOP; i++) {
> >>> +   u16 ctrl;
> >>> +
> >>> +   sdhci_send_tuning(host, opcode);
> >>> +
> >>> +   if (!host->tuning_done) {
> >>
> >>> +   if (rx_inv == 1) {
> >>
> >> It's an invariant to the loop. So, you may do this check after outter loop.
> >>
> >>> +   pr_info("%s: Tuning timeout, 
> >>> falling back to fixed sampling clock\n",
> >>> +   mmc_hostname(host->mmc));
> >>
> >>> +   sdhci_abort_tuning(host, opcode);
> >>
> >> It will also de-duplicates this call.
> >>
> >>> +   return -ETIMEDOUT;
> >>> +   }
> >>> +   sdhci_abort_tuning(host, opcode);
> >>> +   break;
> >>> +   }
> >>
> >>> +   }
> >>> +   }
> >>> +
> >>> +   pr_info("%s: Tuning failed, falling back to fixed sampling 
> >>> clock\n",
> >>> +   mmc_hostname(host->mmc));
> >>> +   sdhci_reset_tuning(host);
> >>> +   return -EAGAIN;
> >>> +}
> >>
> >>> +static void sdhci_gli_voltage_switch(struct sdhci_host *host)
> >>> +{
> >>
> >> Any comment why?
> >>
> >>> +   usleep_range(5000, 5500);
> >>> +}
> >>
> >>> +static u32 sdhci_gl9750_readl(struct sdhci_host *host, int reg)
> >>> +{
> >>> +   u32 value;
> >>> +
> >>> +   value = readl(host->ioaddr + reg);
> >>
> >>> +   if (unlikely(reg == SDHCI_MAX_CURRENT)) {
> >>> +   if (!(value & 0xff))
> >>> +   value |= 0xc8;
> >>> +   }
> >>
> >> if (a) {
> >>  if (b) {
> >>...
> >>  }
> >> }
> >>
> >> is the same as
> >>
> >> if (a && b) {
> >>  ...
> >> }
> >>
> >>> +   return value;
> >>> +}
> >>
> >>> +#define PCI_DEVICE_ID_GLI_9755 0x9755
> >>> +#define PCI_DEVICE_ID_GLI_9750 0x9750
> >>
> >> --
> >> With Best Regards,
> >> Andy Shevchenko
> >
> > Hi, Andy,
> >
> > Thank you for your comments to make the code better.
> > Waiting to see if Adrian has any other comments.
>
> Nope! :-)
>
> Please go ahead and address Andy's comments.

OK, refine the code and let it better.


Re: [PATCH V7 5/5] mmc: host: sdhci-pci: Add Genesys Logic GL975x support

2019-09-03 Thread Ben Chuang
On Tue, Sep 3, 2019 at 6:05 AM Andy Shevchenko
 wrote:
>
> On Fri, Aug 30, 2019 at 5:28 AM Ben Chuang  wrote:
> >
> > From: Ben Chuang 
> >
> > Add support for the GL9750 and GL9755 chipsets.
> >
> > Enable v4 mode and wait 5ms after set 1.8V signal enable for GL9750/
> > GL9755. Fix the value of SDHCI_MAX_CURRENT register and use the vendor
> > tuning flow for GL9750.
> >
>
> > Signed-off-by: Ben Chuang 
>
> Usually last one for latest developer / submitter goes on.
>
> > Co-developed-by: Michael K Johnson 
> > Signed-off-by: Michael K Johnson 
>
>
> > +#define GLI_MAX_TUNING_LOOP 40
>
>
> > +static void gli_set_9750(struct sdhci_host *host)
> > +{
> > +   u32 driving_value = 0;
> > +   u32 pll_value = 0;
> > +   u32 sw_ctrl_value = 0;
> > +   u32 misc_value = 0;
> > +   u32 parameter_value = 0;
> > +   u32 control_value = 0;
>
> > +
>
> Redundant blank line.
>
> > +   u16 ctrl2 = 0;
>
> Do you need these all assignments above?
>
> > +   driving_value = sdhci_readl(host, SDHCI_GLI_9750_DRIVING);
> > +   pll_value = sdhci_readl(host, SDHCI_GLI_9750_PLL);
> > +   sw_ctrl_value = sdhci_readl(host, SDHCI_GLI_9750_SW_CTRL);
> > +   misc_value = sdhci_readl(host, SDHCI_GLI_9750_MISC);
> > +   parameter_value = sdhci_readl(host, 
> > SDHCI_GLI_9750_TUNING_PARAMETERS);
> > +   control_value = sdhci_readl(host, SDHCI_GLI_9750_TUNING_CONTROL);
>
>
>
> > +
> > +   udelay(1);
>
> This misses the answer to question why. Why this is needed and why
> timeout is this long?
>
> > +
> > +   gl9750_wt_off(host);
> > +}
>
> > +static int __sdhci_execute_tuning_9750(struct sdhci_host *host, u32 opcode)
> > +{
> > +   int i;
>
> > +   int rx_inv = 0;
>
> Duplicate assignment.
>
> > +
> > +   for (rx_inv = 0; rx_inv < 2; rx_inv++) {
>
> > +   if (rx_inv & 0x1)
> > +   gli_set_9750_rx_inv(host, true);
> > +   else
> > +   gli_set_9750_rx_inv(host, false);
>
> gli_set_...(host, !!rx_inv);
>
> > +
> > +   sdhci_start_tuning(host);
> > +
> > +   for (i = 0; i < GLI_MAX_TUNING_LOOP; i++) {
> > +   u16 ctrl;
> > +
> > +   sdhci_send_tuning(host, opcode);
> > +
> > +   if (!host->tuning_done) {
>
> > +   if (rx_inv == 1) {
>
> It's an invariant to the loop. So, you may do this check after outter loop.
>
> > +   pr_info("%s: Tuning timeout, 
> > falling back to fixed sampling clock\n",
> > +   mmc_hostname(host->mmc));
>
> > +   sdhci_abort_tuning(host, opcode);
>
> It will also de-duplicates this call.
>
> > +   return -ETIMEDOUT;
> > +   }
> > +   sdhci_abort_tuning(host, opcode);
> > +   break;
> > +   }
>
> > +   }
> > +   }
> > +
> > +   pr_info("%s: Tuning failed, falling back to fixed sampling clock\n",
> > +   mmc_hostname(host->mmc));
> > +   sdhci_reset_tuning(host);
> > +   return -EAGAIN;
> > +}
>
> > +static void sdhci_gli_voltage_switch(struct sdhci_host *host)
> > +{
>
> Any comment why?
>
> > +   usleep_range(5000, 5500);
> > +}
>
> > +static u32 sdhci_gl9750_readl(struct sdhci_host *host, int reg)
> > +{
> > +   u32 value;
> > +
> > +   value = readl(host->ioaddr + reg);
>
> > +   if (unlikely(reg == SDHCI_MAX_CURRENT)) {
> > +   if (!(value & 0xff))
> > +   value |= 0xc8;
> > +   }
>
> if (a) {
>  if (b) {
>...
>  }
> }
>
> is the same as
>
> if (a && b) {
>  ...
> }
>
> > +   return value;
> > +}
>
> > +#define PCI_DEVICE_ID_GLI_9755 0x9755
> > +#define PCI_DEVICE_ID_GLI_9750 0x9750
>
> --
> With Best Regards,
> Andy Shevchenko

Hi, Andy,

Thank you for your comments to make the code better.
Waiting to see if Adrian has any other comments.

Best Regards,
Ben Chuang


[PATCH V7 5/5] mmc: host: sdhci-pci: Add Genesys Logic GL975x support

2019-08-29 Thread Ben Chuang
From: Ben Chuang 

Add support for the GL9750 and GL9755 chipsets.

Enable v4 mode and wait 5ms after set 1.8V signal enable for GL9750/
GL9755. Fix the value of SDHCI_MAX_CURRENT register and use the vendor
tuning flow for GL9750.

Signed-off-by: Ben Chuang 
Co-developed-by: Michael K Johnson 
Signed-off-by: Michael K Johnson 
---
 drivers/mmc/host/Kconfig  |   1 +
 drivers/mmc/host/Makefile |   2 +-
 drivers/mmc/host/sdhci-pci-core.c |   2 +
 drivers/mmc/host/sdhci-pci-gli.c  | 350 ++
 drivers/mmc/host/sdhci-pci.h  |   5 +
 5 files changed, 359 insertions(+), 1 deletion(-)
 create mode 100644 drivers/mmc/host/sdhci-pci-gli.c

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 931770f17087..9fbfff514d6c 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -94,6 +94,7 @@ config MMC_SDHCI_PCI
depends on MMC_SDHCI && PCI
select MMC_CQHCI
select IOSF_MBI if X86
+   select MMC_SDHCI_IO_ACCESSORS
help
  This selects the PCI Secure Digital Host Controller Interface.
  Most controllers found today are PCI devices.
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 73578718f119..661445415090 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -13,7 +13,7 @@ obj-$(CONFIG_MMC_MXS) += mxs-mmc.o
 obj-$(CONFIG_MMC_SDHCI)+= sdhci.o
 obj-$(CONFIG_MMC_SDHCI_PCI)+= sdhci-pci.o
 sdhci-pci-y+= sdhci-pci-core.o sdhci-pci-o2micro.o 
sdhci-pci-arasan.o \
-  sdhci-pci-dwc-mshc.o
+  sdhci-pci-dwc-mshc.o sdhci-pci-gli.o
 obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI))   += sdhci-pci-data.o
 obj-$(CONFIG_MMC_SDHCI_ACPI)   += sdhci-acpi.o
 obj-$(CONFIG_MMC_SDHCI_PXAV3)  += sdhci-pxav3.o
diff --git a/drivers/mmc/host/sdhci-pci-core.c 
b/drivers/mmc/host/sdhci-pci-core.c
index 4154ee11b47d..e5835fbf73bc 100644
--- a/drivers/mmc/host/sdhci-pci-core.c
+++ b/drivers/mmc/host/sdhci-pci-core.c
@@ -1682,6 +1682,8 @@ static const struct pci_device_id pci_ids[] = {
SDHCI_PCI_DEVICE(O2, SEABIRD1, o2),
SDHCI_PCI_DEVICE(ARASAN, PHY_EMMC, arasan),
SDHCI_PCI_DEVICE(SYNOPSYS, DWC_MSHC, snps),
+   SDHCI_PCI_DEVICE(GLI, 9750, gl9750),
+   SDHCI_PCI_DEVICE(GLI, 9755, gl9755),
SDHCI_PCI_DEVICE_CLASS(AMD, SYSTEM_SDHCI, PCI_CLASS_MASK, amd),
/* Generic SD host controller */
{PCI_DEVICE_CLASS(SYSTEM_SDHCI, PCI_CLASS_MASK)},
diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c
new file mode 100644
index ..ed87a32b4470
--- /dev/null
+++ b/drivers/mmc/host/sdhci-pci-gli.c
@@ -0,0 +1,350 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Genesys Logic, Inc.
+ *
+ * Authors: Ben Chuang 
+ *
+ * Version: v0.9.0 (2019-08-08)
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "sdhci.h"
+#include "sdhci-pci.h"
+
+/*  Genesys Logic extra registers */
+#define SDHCI_GLI_9750_WT 0x800
+#define   SDHCI_GLI_9750_WT_EN  BIT(0)
+#define   GLI_9750_WT_EN_ON0x1
+#define   GLI_9750_WT_EN_OFF   0x0
+
+#define SDHCI_GLI_9750_DRIVING  0x860
+#define   SDHCI_GLI_9750_DRIVING_1GENMASK(11, 0)
+#define   SDHCI_GLI_9750_DRIVING_2GENMASK(27, 26)
+#define   GLI_9750_DRIVING_1_VALUE0xFFF
+#define   GLI_9750_DRIVING_2_VALUE0x3
+
+#define SDHCI_GLI_9750_PLL   0x864
+#define   SDHCI_GLI_9750_PLL_TX2_INVBIT(23)
+#define   SDHCI_GLI_9750_PLL_TX2_DLYGENMASK(22, 20)
+#define   GLI_9750_PLL_TX2_INV_VALUE0x1
+#define   GLI_9750_PLL_TX2_DLY_VALUE0x0
+
+#define SDHCI_GLI_9750_SW_CTRL  0x874
+#define   SDHCI_GLI_9750_SW_CTRL_4GENMASK(7, 6)
+#define   GLI_9750_SW_CTRL_4_VALUE0x3
+
+#define SDHCI_GLI_9750_MISC0x878
+#define   SDHCI_GLI_9750_MISC_TX1_INVBIT(2)
+#define   SDHCI_GLI_9750_MISC_RX_INV BIT(3)
+#define   SDHCI_GLI_9750_MISC_TX1_DLYGENMASK(6, 4)
+#define   GLI_9750_MISC_TX1_INV_VALUE0x0
+#define   GLI_9750_MISC_RX_INV_ON0x1
+#define   GLI_9750_MISC_RX_INV_OFF   0x0
+#define   GLI_9750_MISC_RX_INV_VALUE GLI_9750_MISC_RX_INV_OFF
+#define   GLI_9750_MISC_TX1_DLY_VALUE0x5
+
+#define SDHCI_GLI_9750_TUNING_CONTROL0x540
+#define   SDHCI_GLI_9750_TUNING_CONTROL_EN  BIT(4)
+#define   GLI_9750_TUNING_CONTROL_EN_ON 0x1
+#define   GLI_9750_TUNING_CONTROL_EN_OFF0x0
+#define   SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_1BIT(16)
+#define   SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_2GENMASK(20, 19)
+#define   GLI_9750_TUNING_CONTROL_GLITCH_1_VALUE0x1
+#define   GLI_9750_TUNING_CONTROL_GLITCH_2_VALUE0x2
+
+#define SDHCI_GLI_9750_TUNING_PARAMETERS   0x544
+#define   SDHCI_GLI_9750_TUNING_PARAMETERS_RX_DLYGENMASK(2, 0)
+#define   GLI_9750_TUNING_PARAMETERS_RX

[PATCH V7 3/5] PCI: Add Genesys Logic, Inc. Vendor ID

2019-08-29 Thread Ben Chuang
From: Ben Chuang 

Add the Genesys Logic, Inc. vendor ID to pci_ids.h.

Signed-off-by: Ben Chuang 
Co-developed-by: Michael K Johnson 
Signed-off-by: Michael K Johnson 
Acked-by: Adrian Hunter 
---
 include/linux/pci_ids.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 70e86148cb1e..4f7e12772a14 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -2403,6 +2403,8 @@
 #define PCI_DEVICE_ID_RDC_R60610x6061
 #define PCI_DEVICE_ID_RDC_D10100x1010
 
+#define PCI_VENDOR_ID_GLI  0x17a0
+
 #define PCI_VENDOR_ID_LENOVO   0x17aa
 
 #define PCI_VENDOR_ID_QCOM 0x17cb
-- 
2.22.1



[PATCH V7 4/5] mmc: sdhci: Export sdhci_abort_tuning function symbol

2019-08-29 Thread Ben Chuang
From: Ben Chuang 

Export sdhci_abort_tuning() function symbols which are used by other SD Host
controller driver modules.

Signed-off-by: Ben Chuang 
Co-developed-by: Michael K Johnson 
Signed-off-by: Michael K Johnson 
Acked-by: Adrian Hunter 
---
 drivers/mmc/host/sdhci.c | 3 ++-
 drivers/mmc/host/sdhci.h | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 9106ebc7a422..0f2f110534db 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2328,7 +2328,7 @@ void sdhci_reset_tuning(struct sdhci_host *host)
 }
 EXPORT_SYMBOL_GPL(sdhci_reset_tuning);
 
-static void sdhci_abort_tuning(struct sdhci_host *host, u32 opcode)
+void sdhci_abort_tuning(struct sdhci_host *host, u32 opcode)
 {
sdhci_reset_tuning(host);
 
@@ -2339,6 +2339,7 @@ static void sdhci_abort_tuning(struct sdhci_host *host, 
u32 opcode)
 
mmc_abort_tuning(host->mmc, opcode);
 }
+EXPORT_SYMBOL_GPL(sdhci_abort_tuning);
 
 /*
  * We use sdhci_send_tuning() because mmc_send_tuning() is not a good fit. 
SDHCI
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 72601a4d2e95..437bab3af195 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -797,5 +797,6 @@ void sdhci_start_tuning(struct sdhci_host *host);
 void sdhci_end_tuning(struct sdhci_host *host);
 void sdhci_reset_tuning(struct sdhci_host *host);
 void sdhci_send_tuning(struct sdhci_host *host, u32 opcode);
+void sdhci_abort_tuning(struct sdhci_host *host, u32 opcode);
 
 #endif /* __SDHCI_HW_H */
-- 
2.22.1



[PATCH V7 2/5] mmc: sdhci: Add PLL Enable support to internal clock setup

2019-08-29 Thread Ben Chuang
From: Ben Chuang 

The GL9750 and GL9755 chipsets, and possibly others, require PLL Enable
setup as part of the internal clock setup as described in 3.2.1 Internal
Clock Setup Sequence of SD Host Controller Simplified Specification
Version 4.20.

Signed-off-by: Ben Chuang 
Co-developed-by: Michael K Johnson 
Signed-off-by: Michael K Johnson 
Acked-by: Adrian Hunter 
---
 drivers/mmc/host/sdhci.c | 23 +++
 drivers/mmc/host/sdhci.h |  1 +
 2 files changed, 24 insertions(+)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index bed0760a6c2a..9106ebc7a422 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1653,6 +1653,29 @@ void sdhci_enable_clk(struct sdhci_host *host, u16 clk)
udelay(10);
}
 
+   if (host->version >= SDHCI_SPEC_410 && host->v4_mode) {
+   clk |= SDHCI_CLOCK_PLL_EN;
+   clk &= ~SDHCI_CLOCK_INT_STABLE;
+   sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+   /* Wait max 150 ms */
+   timeout = ktime_add_ms(ktime_get(), 150);
+   while (1) {
+   bool timedout = ktime_after(ktime_get(), timeout);
+
+   clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+   if (clk & SDHCI_CLOCK_INT_STABLE)
+   break;
+   if (timedout) {
+   pr_err("%s: PLL clock never stabilised.\n",
+  mmc_hostname(host->mmc));
+   sdhci_dumpregs(host);
+   return;
+   }
+   udelay(10);
+   }
+   }
+
clk |= SDHCI_CLOCK_CARD_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
 }
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 199712e7adbb..72601a4d2e95 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -114,6 +114,7 @@
 #define  SDHCI_DIV_HI_MASK 0x300
 #define  SDHCI_PROG_CLOCK_MODE 0x0020
 #define  SDHCI_CLOCK_CARD_EN   0x0004
+#define  SDHCI_CLOCK_PLL_EN0x0008
 #define  SDHCI_CLOCK_INT_STABLE0x0002
 #define  SDHCI_CLOCK_INT_EN0x0001
 
-- 
2.22.1



[PATCH V7 1/5] mmc: sdhci: Change timeout of loop for checking internal clock stable

2019-08-29 Thread Ben Chuang
From: Ben Chuang 

According to section 3.2.1 internal clock setup in SD Host Controller
Simplified Specifications 4.20, the timeout of loop for checking
internal clock stable is defined as 150ms.

Signed-off-by: Ben Chuang 
Co-developed-by: Michael K Johnson 
Signed-off-by: Michael K Johnson 
Acked-by: Adrian Hunter 
---
 drivers/mmc/host/sdhci.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 59acf8e3331e..bed0760a6c2a 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1636,8 +1636,8 @@ void sdhci_enable_clk(struct sdhci_host *host, u16 clk)
clk |= SDHCI_CLOCK_INT_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
 
-   /* Wait max 20 ms */
-   timeout = ktime_add_ms(ktime_get(), 20);
+   /* Wait max 150 ms */
+   timeout = ktime_add_ms(ktime_get(), 150);
while (1) {
bool timedout = ktime_after(ktime_get(), timeout);
 
-- 
2.22.1



[PATCH V7 0/5] Add Genesys Logic GL975x support

2019-08-29 Thread Ben Chuang
From: Ben Chuang 

The patches modify internal clock setup to match SD Host Controller
Simplified Specifications 4.20 and support Genesys Logic GL9750/GL9755 chipsets.

v7:
 - remove condition define CONFIG_MMC_SDHCI_IO_ACCESSORS from sdhci-pci-gli.c
 - making the accessors(MMC_SDHCI_IO_ACCESSORS) always available when selecting
   MMC_SDHCI_PCI in Kconfig

V6:
 - export sdhci_abot_tuning() function symbol
 - use C-style comments
 - use BIT, FIELD_{GET,PREP} and GENMASK to define bit fields of register
 - use host->ops->platform_execute_tuning instead of mmc->ops->execute_tuning
 - call sdhci_reset() instead of duplicating the code in sdhci_gl9750_reset
 - remove .hw_reset 
 - use condition define CONFIG_MMC_SDHCI_IO_ACCESSORS for read_l

V5:
 - add "change timeout of loop .." to a patch
 - fix typo "verndor" to "vendor"

V4:
 - change name from sdhci_gli_reset to sdhci_gl9750_reset
 - fix sdhci_reset to sdhci_gl9750_reset in sdhci_gl9750_ops
 - fix sdhci_gli_reset to sdhci_reset in sdhci_gl9755_ops
 
V3:
 - change usleep_range to udelay
 - add Genesys Logic PCI Vendor ID to a patch
 - separate the Genesys Logic specific part to a patch

V2:
 - change udelay to usleep_range

Ben Chuang (5):
  mmc: sdhci: Change timeout of loop for checking internal clock stable
  mmc: sdhci: Add PLL Enable support to internal clock setup
  PCI: Add Genesys Logic, Inc. Vendor ID
  mmc: sdhci: Export sdhci_abort_tuning function symbol
  mmc: host: sdhci-pci: Add Genesys Logic GL975x support

 drivers/mmc/host/Kconfig  |   1 +
 drivers/mmc/host/Makefile |   2 +-
 drivers/mmc/host/sdhci-pci-core.c |   2 +
 drivers/mmc/host/sdhci-pci-gli.c  | 350 ++
 drivers/mmc/host/sdhci-pci.h  |   5 +
 drivers/mmc/host/sdhci.c  |  30 ++-
 drivers/mmc/host/sdhci.h  |   2 +
 include/linux/pci_ids.h   |   2 +
 8 files changed, 390 insertions(+), 4 deletions(-)
 create mode 100644 drivers/mmc/host/sdhci-pci-gli.c

-- 
2.22.1



Re: [PATCH V6 0/5] Add Genesys Logic GL975x support

2019-08-29 Thread Ben Chuang
On Thu, Aug 29, 2019 at 9:34 PM Ulf Hansson  wrote:
>
> On Tue, 27 Aug 2019 at 02:32, Ben Chuang  wrote:
> >
> > From: Ben Chuang 
> >
> > The patches modify internal clock setup to match SD Host Controller
> > Simplified Specifications 4.20 and support Genesys Logic GL9750/GL9755 
> > chipsets.
> >
> > V6:
> >  - export sdhci_abot_tuning() function symbol
> >  - use C-style comments
> >  - use BIT, FIELD_{GET,PREP} and GENMASK to define bit fields of register
> >  - use host->ops->platform_execute_tuning instead of 
> > mmc->ops->execute_tuning
> >  - call sdhci_reset() instead of duplicating the code in sdhci_gl9750_reset
> >  - remove .hw_reset
> >  - use condition define CONFIG_MMC_SDHCI_IO_ACCESSORS for read_l
>
> Applied patch 1-4, deferring patch5 for another version to fix Adrian's 
> comment.
>
> Kind regards
> Uffe

Hi, Uffe,

So happy to get the good news.
 Thank you and Adrian for reviewing and helping.

Sincerely yours,
Ben Chuang


Re: [PATCH V6 5/5] mmc: host: sdhci-pci: Add Genesys Logic GL975x support

2019-08-29 Thread Ben Chuang
On Thu, Aug 29, 2019 at 9:22 PM Adrian Hunter  wrote:
>
> On 28/08/19 4:47 PM, Michael K. Johnson wrote:
> > On Wed, Aug 28, 2019 at 04:13:03PM +0300, Adrian Hunter wrote:
> >> On 27/08/19 3:33 AM, Ben Chuang wrote:
> >> Looks good, one minor comment
> > ...
> >>> +#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
> >>
> >> Arguably CONFIG_MMC_SDHCI_IO_ACCESSORS needs to be removed altogether. i.e.
> >> making the accessors always available.  So for now, I'd prefer to select
> >> MMC_SDHCI_IO_ACCESSORS:
> >>
> >> diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
> >> index 14d89a108edd..c3bd967d8a1a 100644
> >> --- a/drivers/mmc/host/Kconfig
> >> +++ b/drivers/mmc/host/Kconfig
> >> @@ -94,6 +94,7 @@ config MMC_SDHCI_PCI
> >>  depends on MMC_SDHCI && PCI
> >>  select MMC_CQHCI
> >>  select IOSF_MBI if X86
> >> +select MMC_SDHCI_IO_ACCESSORS
> >>  help
> >>This selects the PCI Secure Digital Host Controller Interface.
> >>Most controllers found today are PCI devices.
> >
> > Unless I'm missing something, this seems like a separate patch;
> > are you asking for it first, as a predecessor to the GLI patch?
> >
>
> No, it is fine with this patch.

I will remove CONFIG_MMC_SDHCI_IO_ACCESSORS from sdhci-pci-gli.c and
add add `select MMC_SDHCI_IO_ACCESSORS` in Kconfig.
Thank you.


[PATCH V6 4/5] mmc: sdhci: Export sdhci_abort_tuning function symbol

2019-08-26 Thread Ben Chuang
From: Ben Chuang 

Export sdhci_abort_tuning() function symbols which are used by other SD Host
controller driver modules.

Signed-off-by: Ben Chuang 
Co-developed-by: Michael K Johnson 
Signed-off-by: Michael K Johnson 
---
 drivers/mmc/host/sdhci.c | 3 ++-
 drivers/mmc/host/sdhci.h | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 9106ebc7a422..0f2f110534db 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2328,7 +2328,7 @@ void sdhci_reset_tuning(struct sdhci_host *host)
 }
 EXPORT_SYMBOL_GPL(sdhci_reset_tuning);
 
-static void sdhci_abort_tuning(struct sdhci_host *host, u32 opcode)
+void sdhci_abort_tuning(struct sdhci_host *host, u32 opcode)
 {
sdhci_reset_tuning(host);
 
@@ -2339,6 +2339,7 @@ static void sdhci_abort_tuning(struct sdhci_host *host, 
u32 opcode)
 
mmc_abort_tuning(host->mmc, opcode);
 }
+EXPORT_SYMBOL_GPL(sdhci_abort_tuning);
 
 /*
  * We use sdhci_send_tuning() because mmc_send_tuning() is not a good fit. 
SDHCI
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 72601a4d2e95..437bab3af195 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -797,5 +797,6 @@ void sdhci_start_tuning(struct sdhci_host *host);
 void sdhci_end_tuning(struct sdhci_host *host);
 void sdhci_reset_tuning(struct sdhci_host *host);
 void sdhci_send_tuning(struct sdhci_host *host, u32 opcode);
+void sdhci_abort_tuning(struct sdhci_host *host, u32 opcode);
 
 #endif /* __SDHCI_HW_H */
-- 
2.22.1



[PATCH V6 5/5] mmc: host: sdhci-pci: Add Genesys Logic GL975x support

2019-08-26 Thread Ben Chuang
From: Ben Chuang 

Add support for the GL9750 and GL9755 chipsets.

Enable v4 mode and wait 5ms after set 1.8V signal enable for GL9750/
GL9755. Fix the value of SDHCI_MAX_CURRENT register and use the vendor
tuning flow for GL9750.

Signed-off-by: Ben Chuang 
Co-developed-by: Michael K Johnson 
Signed-off-by: Michael K Johnson 
---
 drivers/mmc/host/Makefile |   2 +-
 drivers/mmc/host/sdhci-pci-core.c |   2 +
 drivers/mmc/host/sdhci-pci-gli.c  | 354 ++
 drivers/mmc/host/sdhci-pci.h  |   5 +
 4 files changed, 362 insertions(+), 1 deletion(-)
 create mode 100644 drivers/mmc/host/sdhci-pci-gli.c

diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 73578718f119..661445415090 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -13,7 +13,7 @@ obj-$(CONFIG_MMC_MXS) += mxs-mmc.o
 obj-$(CONFIG_MMC_SDHCI)+= sdhci.o
 obj-$(CONFIG_MMC_SDHCI_PCI)+= sdhci-pci.o
 sdhci-pci-y+= sdhci-pci-core.o sdhci-pci-o2micro.o 
sdhci-pci-arasan.o \
-  sdhci-pci-dwc-mshc.o
+  sdhci-pci-dwc-mshc.o sdhci-pci-gli.o
 obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI))   += sdhci-pci-data.o
 obj-$(CONFIG_MMC_SDHCI_ACPI)   += sdhci-acpi.o
 obj-$(CONFIG_MMC_SDHCI_PXAV3)  += sdhci-pxav3.o
diff --git a/drivers/mmc/host/sdhci-pci-core.c 
b/drivers/mmc/host/sdhci-pci-core.c
index 4154ee11b47d..e5835fbf73bc 100644
--- a/drivers/mmc/host/sdhci-pci-core.c
+++ b/drivers/mmc/host/sdhci-pci-core.c
@@ -1682,6 +1682,8 @@ static const struct pci_device_id pci_ids[] = {
SDHCI_PCI_DEVICE(O2, SEABIRD1, o2),
SDHCI_PCI_DEVICE(ARASAN, PHY_EMMC, arasan),
SDHCI_PCI_DEVICE(SYNOPSYS, DWC_MSHC, snps),
+   SDHCI_PCI_DEVICE(GLI, 9750, gl9750),
+   SDHCI_PCI_DEVICE(GLI, 9755, gl9755),
SDHCI_PCI_DEVICE_CLASS(AMD, SYSTEM_SDHCI, PCI_CLASS_MASK, amd),
/* Generic SD host controller */
{PCI_DEVICE_CLASS(SYSTEM_SDHCI, PCI_CLASS_MASK)},
diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c
new file mode 100644
index ..d0ca3c60f8de
--- /dev/null
+++ b/drivers/mmc/host/sdhci-pci-gli.c
@@ -0,0 +1,354 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Genesys Logic, Inc.
+ *
+ * Authors: Ben Chuang 
+ *
+ * Version: v0.9.0 (2019-08-08)
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "sdhci.h"
+#include "sdhci-pci.h"
+
+/*  Genesys Logic extra registers */
+#define SDHCI_GLI_9750_WT 0x800
+#define   SDHCI_GLI_9750_WT_EN  BIT(0)
+#define   GLI_9750_WT_EN_ON0x1
+#define   GLI_9750_WT_EN_OFF   0x0
+
+#define SDHCI_GLI_9750_DRIVING  0x860
+#define   SDHCI_GLI_9750_DRIVING_1GENMASK(11, 0)
+#define   SDHCI_GLI_9750_DRIVING_2GENMASK(27, 26)
+#define   GLI_9750_DRIVING_1_VALUE0xFFF
+#define   GLI_9750_DRIVING_2_VALUE0x3
+
+#define SDHCI_GLI_9750_PLL   0x864
+#define   SDHCI_GLI_9750_PLL_TX2_INVBIT(23)
+#define   SDHCI_GLI_9750_PLL_TX2_DLYGENMASK(22, 20)
+#define   GLI_9750_PLL_TX2_INV_VALUE0x1
+#define   GLI_9750_PLL_TX2_DLY_VALUE0x0
+
+#define SDHCI_GLI_9750_SW_CTRL  0x874
+#define   SDHCI_GLI_9750_SW_CTRL_4GENMASK(7, 6)
+#define   GLI_9750_SW_CTRL_4_VALUE0x3
+
+#define SDHCI_GLI_9750_MISC0x878
+#define   SDHCI_GLI_9750_MISC_TX1_INVBIT(2)
+#define   SDHCI_GLI_9750_MISC_RX_INV BIT(3)
+#define   SDHCI_GLI_9750_MISC_TX1_DLYGENMASK(6, 4)
+#define   GLI_9750_MISC_TX1_INV_VALUE0x0
+#define   GLI_9750_MISC_RX_INV_ON0x1
+#define   GLI_9750_MISC_RX_INV_OFF   0x0
+#define   GLI_9750_MISC_RX_INV_VALUE GLI_9750_MISC_RX_INV_OFF
+#define   GLI_9750_MISC_TX1_DLY_VALUE0x5
+
+#define SDHCI_GLI_9750_TUNING_CONTROL0x540
+#define   SDHCI_GLI_9750_TUNING_CONTROL_EN  BIT(4)
+#define   GLI_9750_TUNING_CONTROL_EN_ON 0x1
+#define   GLI_9750_TUNING_CONTROL_EN_OFF0x0
+#define   SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_1BIT(16)
+#define   SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_2GENMASK(20, 19)
+#define   GLI_9750_TUNING_CONTROL_GLITCH_1_VALUE0x1
+#define   GLI_9750_TUNING_CONTROL_GLITCH_2_VALUE0x2
+
+#define SDHCI_GLI_9750_TUNING_PARAMETERS   0x544
+#define   SDHCI_GLI_9750_TUNING_PARAMETERS_RX_DLYGENMASK(2, 0)
+#define   GLI_9750_TUNING_PARAMETERS_RX_DLY_VALUE0x1
+
+#define GLI_MAX_TUNING_LOOP 40
+
+/* Genesys Logic chipset */
+static inline void gl9750_wt_on(struct sdhci_host *host)
+{
+   u32 wt_value = 0;
+   u32 wt_enable = 0;
+
+   wt_value = sdhci_readl(host, SDHCI_GLI_9750_WT);
+   wt_enable = FIELD_GET(SDHCI_GLI_9750_WT_EN, wt_value);
+
+   if (wt_enable == GLI_9750_WT_EN_ON)
+   return;
+
+   wt_value &= ~SDHCI_GLI_9750_WT_EN;
+   wt_value |= FIELD_PREP(SDHCI_GLI_9750_WT_EN, GLI_9750_WT_EN_ON);
+
+   sdhci_writel(host, wt_

[PATCH V6 3/5] PCI: Add Genesys Logic, Inc. Vendor ID

2019-08-26 Thread Ben Chuang
From: Ben Chuang 

Add the Genesys Logic, Inc. vendor ID to pci_ids.h.

Signed-off-by: Ben Chuang 
Co-developed-by: Michael K Johnson 
Signed-off-by: Michael K Johnson 
Acked-by: Adrian Hunter 
---
 include/linux/pci_ids.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 70e86148cb1e..4f7e12772a14 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -2403,6 +2403,8 @@
 #define PCI_DEVICE_ID_RDC_R60610x6061
 #define PCI_DEVICE_ID_RDC_D10100x1010
 
+#define PCI_VENDOR_ID_GLI  0x17a0
+
 #define PCI_VENDOR_ID_LENOVO   0x17aa
 
 #define PCI_VENDOR_ID_QCOM 0x17cb
-- 
2.22.1



[PATCH V6 2/5] mmc: sdhci: Add PLL Enable support to internal clock setup

2019-08-26 Thread Ben Chuang
From: Ben Chuang 

The GL9750 and GL9755 chipsets, and possibly others, require PLL Enable
setup as part of the internal clock setup as described in 3.2.1 Internal
Clock Setup Sequence of SD Host Controller Simplified Specification
Version 4.20.

Signed-off-by: Ben Chuang 
Co-developed-by: Michael K Johnson 
Signed-off-by: Michael K Johnson 
Acked-by: Adrian Hunter 
---
 drivers/mmc/host/sdhci.c | 23 +++
 drivers/mmc/host/sdhci.h |  1 +
 2 files changed, 24 insertions(+)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index bed0760a6c2a..9106ebc7a422 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1653,6 +1653,29 @@ void sdhci_enable_clk(struct sdhci_host *host, u16 clk)
udelay(10);
}
 
+   if (host->version >= SDHCI_SPEC_410 && host->v4_mode) {
+   clk |= SDHCI_CLOCK_PLL_EN;
+   clk &= ~SDHCI_CLOCK_INT_STABLE;
+   sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+   /* Wait max 150 ms */
+   timeout = ktime_add_ms(ktime_get(), 150);
+   while (1) {
+   bool timedout = ktime_after(ktime_get(), timeout);
+
+   clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+   if (clk & SDHCI_CLOCK_INT_STABLE)
+   break;
+   if (timedout) {
+   pr_err("%s: PLL clock never stabilised.\n",
+  mmc_hostname(host->mmc));
+   sdhci_dumpregs(host);
+   return;
+   }
+   udelay(10);
+   }
+   }
+
clk |= SDHCI_CLOCK_CARD_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
 }
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 199712e7adbb..72601a4d2e95 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -114,6 +114,7 @@
 #define  SDHCI_DIV_HI_MASK 0x300
 #define  SDHCI_PROG_CLOCK_MODE 0x0020
 #define  SDHCI_CLOCK_CARD_EN   0x0004
+#define  SDHCI_CLOCK_PLL_EN0x0008
 #define  SDHCI_CLOCK_INT_STABLE0x0002
 #define  SDHCI_CLOCK_INT_EN0x0001
 
-- 
2.22.1



[PATCH V6 0/5] Add Genesys Logic GL975x support

2019-08-26 Thread Ben Chuang
From: Ben Chuang 

The patches modify internal clock setup to match SD Host Controller
Simplified Specifications 4.20 and support Genesys Logic GL9750/GL9755 chipsets.

V6:
 - export sdhci_abot_tuning() function symbol
 - use C-style comments
 - use BIT, FIELD_{GET,PREP} and GENMASK to define bit fields of register
 - use host->ops->platform_execute_tuning instead of mmc->ops->execute_tuning
 - call sdhci_reset() instead of duplicating the code in sdhci_gl9750_reset
 - remove .hw_reset 
 - use condition define CONFIG_MMC_SDHCI_IO_ACCESSORS for read_l

V5:
 - add "change timeout of loop .." to a patch
 - fix typo "verndor" to "vendor"

V4:
 - change name from sdhci_gli_reset to sdhci_gl9750_reset
 - fix sdhci_reset to sdhci_gl9750_reset in sdhci_gl9750_ops
 - fix sdhci_gli_reset to sdhci_reset in sdhci_gl9755_ops
 
V3:
 - change usleep_range to udelay
 - add Genesys Logic PCI Vendor ID to a patch
 - separate the Genesys Logic specific part to a patch

V2:
 - change udelay to usleep_range

Ben Chuang (5):
  mmc: sdhci: Change timeout of loop for checking internal clock stable
  mmc: sdhci: Add PLL Enable support to internal clock setup
  PCI: Add Genesys Logic, Inc. Vendor ID
  mmc: sdhci: Export sdhci_abort_tuning function symbol
  mmc: host: sdhci-pci: Add Genesys Logic GL975x support

 drivers/mmc/host/Makefile |   2 +-
 drivers/mmc/host/sdhci-pci-core.c |   2 +
 drivers/mmc/host/sdhci-pci-gli.c  | 354 ++
 drivers/mmc/host/sdhci-pci.h  |   5 +
 drivers/mmc/host/sdhci.c  |  30 ++-
 drivers/mmc/host/sdhci.h  |   2 +
 include/linux/pci_ids.h   |   2 +
 7 files changed, 393 insertions(+), 4 deletions(-)
 create mode 100644 drivers/mmc/host/sdhci-pci-gli.c

-- 
2.22.1



[PATCH V6 1/5] mmc: sdhci: Change timeout of loop for checking internal clock stable

2019-08-26 Thread Ben Chuang
From: Ben Chuang 

According to section 3.2.1 internal clock setup in SD Host Controller
Simplified Specifications 4.20, the timeout of loop for checking
internal clock stable is defined as 150ms.

Signed-off-by: Ben Chuang 
Co-developed-by: Michael K Johnson 
Signed-off-by: Michael K Johnson 
Acked-by: Adrian Hunter 
---
 drivers/mmc/host/sdhci.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 59acf8e3331e..bed0760a6c2a 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1636,8 +1636,8 @@ void sdhci_enable_clk(struct sdhci_host *host, u16 clk)
clk |= SDHCI_CLOCK_INT_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
 
-   /* Wait max 20 ms */
-   timeout = ktime_add_ms(ktime_get(), 20);
+   /* Wait max 150 ms */
+   timeout = ktime_add_ms(ktime_get(), 150);
while (1) {
bool timedout = ktime_after(ktime_get(), timeout);
 
-- 
2.22.1



Re: [PATCH V5 4/4] mmc: host: sdhci-pci: Add Genesys Logic GL975x support

2019-08-21 Thread Ben Chuang
Sorry to resend the email because of non-plain text issues.

On Wed, Aug 21, 2019 at 8:30 PM Adrian Hunter  wrote:
>
> On 20/08/19 5:07 AM, Ben Chuang wrote:
> > From: Ben Chuang 
> >
> > Add support for the GL9750 and GL9755 chipsets.
> >
> > The patches enable v4 mode and wait 5ms after set 1.8V signal enable for
> > GL9750/GL9755. It fixed the value of SDHCI_MAX_CURRENT register and uses
> > the vendor tuning flow for GL9750.
> >
> > Signed-off-by: Ben Chuang 
> > Co-developed-by: Michael K Johnson 
> > Signed-off-by: Michael K Johnson 
> > ---
> >  drivers/mmc/host/Makefile |   2 +-
> >  drivers/mmc/host/sdhci-pci-core.c |   2 +
> >  drivers/mmc/host/sdhci-pci-gli.c  | 381 ++
> >  drivers/mmc/host/sdhci-pci.h  |   5 +
> >  4 files changed, 389 insertions(+), 1 deletion(-)
> >  create mode 100644 drivers/mmc/host/sdhci-pci-gli.c
> >
> > diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
> > index 73578718f119..661445415090 100644
> > --- a/drivers/mmc/host/Makefile
> > +++ b/drivers/mmc/host/Makefile
> > @@ -13,7 +13,7 @@ obj-$(CONFIG_MMC_MXS)   += mxs-mmc.o
> >  obj-$(CONFIG_MMC_SDHCI)  += sdhci.o
> >  obj-$(CONFIG_MMC_SDHCI_PCI)  += sdhci-pci.o
> >  sdhci-pci-y  += sdhci-pci-core.o sdhci-pci-o2micro.o 
> > sdhci-pci-arasan.o \
> > -sdhci-pci-dwc-mshc.o
> > +sdhci-pci-dwc-mshc.o sdhci-pci-gli.o
> >  obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI)) += sdhci-pci-data.o
> >  obj-$(CONFIG_MMC_SDHCI_ACPI) += sdhci-acpi.o
> >  obj-$(CONFIG_MMC_SDHCI_PXAV3)+= sdhci-pxav3.o
> > diff --git a/drivers/mmc/host/sdhci-pci-core.c 
> > b/drivers/mmc/host/sdhci-pci-core.c
> > index 4154ee11b47d..e5835fbf73bc 100644
> > --- a/drivers/mmc/host/sdhci-pci-core.c
> > +++ b/drivers/mmc/host/sdhci-pci-core.c
> > @@ -1682,6 +1682,8 @@ static const struct pci_device_id pci_ids[] = {
> >   SDHCI_PCI_DEVICE(O2, SEABIRD1, o2),
> >   SDHCI_PCI_DEVICE(ARASAN, PHY_EMMC, arasan),
> >   SDHCI_PCI_DEVICE(SYNOPSYS, DWC_MSHC, snps),
> > + SDHCI_PCI_DEVICE(GLI, 9750, gl9750),
> > + SDHCI_PCI_DEVICE(GLI, 9755, gl9755),
> >   SDHCI_PCI_DEVICE_CLASS(AMD, SYSTEM_SDHCI, PCI_CLASS_MASK, amd),
> >   /* Generic SD host controller */
> >   {PCI_DEVICE_CLASS(SYSTEM_SDHCI, PCI_CLASS_MASK)},
> > diff --git a/drivers/mmc/host/sdhci-pci-gli.c 
> > b/drivers/mmc/host/sdhci-pci-gli.c
> > new file mode 100644
> > index ..99abb7830e62
> > --- /dev/null
> > +++ b/drivers/mmc/host/sdhci-pci-gli.c
> > @@ -0,0 +1,381 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Copyright (C) 2019 Genesys Logic, Inc.
> > + *
> > + * Authors: Ben Chuang 
> > + *
> > + * Version: v0.9.0 (2019-08-08)
> > + */
> > +
> > +#include 
> > +#include 
> > +#include 
> > +#include "sdhci.h"
> > +#include "sdhci-pci.h"
> > +
> > +/*  Genesys Logic extra registers */
> > +#define SDHCI_GLI_9750_WT 0x800
> > +#define SDHCI_GLI_9750_DRIVING0x860
> > +#define SDHCI_GLI_9750_PLL0x864
> > +#define SDHCI_GLI_9750_SW_CTRL0x874
> > +#define SDHCI_GLI_9750_MISC   0x878
> > +
> > +#define SDHCI_GLI_9750_TUNING_CONTROL0x540
> > +#define SDHCI_GLI_9750_TUNING_PARAMETERS 0x544
> > +
> > +#define GLI_MAX_TUNING_LOOP 40
> > +
> > +/* Genesys Logic chipset */
> > +static void gli_set_9750(struct sdhci_host *host)
> > +{
> > + u32 wt_value = 0;
> > + u32 driving_value = 0;
> > + u32 pll_value = 0;
> > + u32 sw_ctrl_value = 0;
> > + u32 misc_value = 0;
> > + u32 parameter_value = 0;
> > + u32 control_value = 0;
> > +
> > + u16 ctrl2 = 0;
> > +
> > + wt_value = sdhci_readl(host, SDHCI_GLI_9750_WT);
> > + if ((wt_value & 0x1) == 0) {
> > + wt_value |= 0x1;
> > + sdhci_writel(host, wt_value, SDHCI_GLI_9750_WT);
> > + }
> > +
> > + driving_value = sdhci_readl(host, SDHCI_GLI_9750_DRIVING);
> > + pll_value = sdhci_readl(host, SDHCI_GLI_9750_PLL);
> > + sw_ctrl_value = sdhci_readl(host, SDHCI_GLI_9750_SW_CTRL);
> > + misc_value = sdhci_readl(host, SDHCI_GLI_9750_MISC);
> > + parameter_value = sdhci_readl(host, SDHCI_GLI_9750_TUNING_PARAMETERS);
> > + control_value = sdhci_readl(host, SDHCI_GLI_9750_

[PATCH V5 4/4] mmc: host: sdhci-pci: Add Genesys Logic GL975x support

2019-08-19 Thread Ben Chuang
From: Ben Chuang 

Add support for the GL9750 and GL9755 chipsets.

The patches enable v4 mode and wait 5ms after set 1.8V signal enable for
GL9750/GL9755. It fixed the value of SDHCI_MAX_CURRENT register and uses
the vendor tuning flow for GL9750.

Signed-off-by: Ben Chuang 
Co-developed-by: Michael K Johnson 
Signed-off-by: Michael K Johnson 
---
 drivers/mmc/host/Makefile |   2 +-
 drivers/mmc/host/sdhci-pci-core.c |   2 +
 drivers/mmc/host/sdhci-pci-gli.c  | 381 ++
 drivers/mmc/host/sdhci-pci.h  |   5 +
 4 files changed, 389 insertions(+), 1 deletion(-)
 create mode 100644 drivers/mmc/host/sdhci-pci-gli.c

diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 73578718f119..661445415090 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -13,7 +13,7 @@ obj-$(CONFIG_MMC_MXS) += mxs-mmc.o
 obj-$(CONFIG_MMC_SDHCI)+= sdhci.o
 obj-$(CONFIG_MMC_SDHCI_PCI)+= sdhci-pci.o
 sdhci-pci-y+= sdhci-pci-core.o sdhci-pci-o2micro.o 
sdhci-pci-arasan.o \
-  sdhci-pci-dwc-mshc.o
+  sdhci-pci-dwc-mshc.o sdhci-pci-gli.o
 obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI))   += sdhci-pci-data.o
 obj-$(CONFIG_MMC_SDHCI_ACPI)   += sdhci-acpi.o
 obj-$(CONFIG_MMC_SDHCI_PXAV3)  += sdhci-pxav3.o
diff --git a/drivers/mmc/host/sdhci-pci-core.c 
b/drivers/mmc/host/sdhci-pci-core.c
index 4154ee11b47d..e5835fbf73bc 100644
--- a/drivers/mmc/host/sdhci-pci-core.c
+++ b/drivers/mmc/host/sdhci-pci-core.c
@@ -1682,6 +1682,8 @@ static const struct pci_device_id pci_ids[] = {
SDHCI_PCI_DEVICE(O2, SEABIRD1, o2),
SDHCI_PCI_DEVICE(ARASAN, PHY_EMMC, arasan),
SDHCI_PCI_DEVICE(SYNOPSYS, DWC_MSHC, snps),
+   SDHCI_PCI_DEVICE(GLI, 9750, gl9750),
+   SDHCI_PCI_DEVICE(GLI, 9755, gl9755),
SDHCI_PCI_DEVICE_CLASS(AMD, SYSTEM_SDHCI, PCI_CLASS_MASK, amd),
/* Generic SD host controller */
{PCI_DEVICE_CLASS(SYSTEM_SDHCI, PCI_CLASS_MASK)},
diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c
new file mode 100644
index ..99abb7830e62
--- /dev/null
+++ b/drivers/mmc/host/sdhci-pci-gli.c
@@ -0,0 +1,381 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Genesys Logic, Inc.
+ *
+ * Authors: Ben Chuang 
+ *
+ * Version: v0.9.0 (2019-08-08)
+ */
+
+#include 
+#include 
+#include 
+#include "sdhci.h"
+#include "sdhci-pci.h"
+
+/*  Genesys Logic extra registers */
+#define SDHCI_GLI_9750_WT 0x800
+#define SDHCI_GLI_9750_DRIVING0x860
+#define SDHCI_GLI_9750_PLL0x864
+#define SDHCI_GLI_9750_SW_CTRL0x874
+#define SDHCI_GLI_9750_MISC   0x878
+
+#define SDHCI_GLI_9750_TUNING_CONTROL  0x540
+#define SDHCI_GLI_9750_TUNING_PARAMETERS   0x544
+
+#define GLI_MAX_TUNING_LOOP 40
+
+/* Genesys Logic chipset */
+static void gli_set_9750(struct sdhci_host *host)
+{
+   u32 wt_value = 0;
+   u32 driving_value = 0;
+   u32 pll_value = 0;
+   u32 sw_ctrl_value = 0;
+   u32 misc_value = 0;
+   u32 parameter_value = 0;
+   u32 control_value = 0;
+
+   u16 ctrl2 = 0;
+
+   wt_value = sdhci_readl(host, SDHCI_GLI_9750_WT);
+   if ((wt_value & 0x1) == 0) {
+   wt_value |= 0x1;
+   sdhci_writel(host, wt_value, SDHCI_GLI_9750_WT);
+   }
+
+   driving_value = sdhci_readl(host, SDHCI_GLI_9750_DRIVING);
+   pll_value = sdhci_readl(host, SDHCI_GLI_9750_PLL);
+   sw_ctrl_value = sdhci_readl(host, SDHCI_GLI_9750_SW_CTRL);
+   misc_value = sdhci_readl(host, SDHCI_GLI_9750_MISC);
+   parameter_value = sdhci_readl(host, SDHCI_GLI_9750_TUNING_PARAMETERS);
+   control_value = sdhci_readl(host, SDHCI_GLI_9750_TUNING_CONTROL);
+
+   driving_value &= ~(0x0C000FFF);
+   driving_value |= 0x0C000FFF;
+   sdhci_writel(host, driving_value, SDHCI_GLI_9750_DRIVING);
+
+   sw_ctrl_value |= 0xc0;
+   sdhci_writel(host, sw_ctrl_value, SDHCI_GLI_9750_SW_CTRL);
+
+   // reset the tuning flow after reinit and before starting tuning
+   pll_value |= 0x80; // bit23-1
+   pll_value &= ~(0x0070); // bit22:20-0
+
+   misc_value &= ~(0x8); // bit3-0
+   misc_value &= ~(0x4); // bit2-0
+
+   misc_value &= ~(0x70); // bit6:4-0
+   misc_value |= 0x50; // bit6:4-5
+
+   parameter_value &= ~(0x7); // bit2:0-0
+   parameter_value |= 0x1; // bit2:0-1
+
+   control_value &= ~(0x19); // bit20:19-0, bit16-0
+   control_value |=   0x11; // bit20:19-b10, bit16-1
+
+   sdhci_writel(host, pll_value, SDHCI_GLI_9750_PLL);
+   sdhci_writel(host, misc_value, SDHCI_GLI_9750_MISC);
+
+   // disable tuned clk
+   ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+   ctrl2 &= ~SDHCI_CTRL_TUNED_CLK;
+   sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2);
+
+   // 54

[PATCH V5 3/4] PCI: Add Genesys Logic, Inc. Vendor ID

2019-08-19 Thread Ben Chuang
From: Ben Chuang 

Add the Genesys Logic, Inc. vendor ID to pci_ids.h.

Signed-off-by: Ben Chuang 
Co-developed-by: Michael K Johnson 
Signed-off-by: Michael K Johnson 
---
 include/linux/pci_ids.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 70e86148cb1e..4f7e12772a14 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -2403,6 +2403,8 @@
 #define PCI_DEVICE_ID_RDC_R60610x6061
 #define PCI_DEVICE_ID_RDC_D10100x1010
 
+#define PCI_VENDOR_ID_GLI  0x17a0
+
 #define PCI_VENDOR_ID_LENOVO   0x17aa
 
 #define PCI_VENDOR_ID_QCOM 0x17cb
-- 
2.22.1



[PATCH V5 2/4] mmc: sdhci: Add PLL Enable support to internal clock setup

2019-08-19 Thread Ben Chuang
From: Ben Chuang 

The GL9750 and GL9755 chipsets, and possibly others, require PLL Enable
setup as part of the internal clock setup as described in 3.2.1 Internal
Clock Setup Sequence of SD Host Controller Simplified Specification
Version 4.20.

Signed-off-by: Ben Chuang 
Co-developed-by: Michael K Johnson 
Signed-off-by: Michael K Johnson 
---
 drivers/mmc/host/sdhci.c | 23 +++
 drivers/mmc/host/sdhci.h |  1 +
 2 files changed, 24 insertions(+)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index bed0760a6c2a..9106ebc7a422 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1653,6 +1653,29 @@ void sdhci_enable_clk(struct sdhci_host *host, u16 clk)
udelay(10);
}
 
+   if (host->version >= SDHCI_SPEC_410 && host->v4_mode) {
+   clk |= SDHCI_CLOCK_PLL_EN;
+   clk &= ~SDHCI_CLOCK_INT_STABLE;
+   sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+   /* Wait max 150 ms */
+   timeout = ktime_add_ms(ktime_get(), 150);
+   while (1) {
+   bool timedout = ktime_after(ktime_get(), timeout);
+
+   clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+   if (clk & SDHCI_CLOCK_INT_STABLE)
+   break;
+   if (timedout) {
+   pr_err("%s: PLL clock never stabilised.\n",
+  mmc_hostname(host->mmc));
+   sdhci_dumpregs(host);
+   return;
+   }
+   udelay(10);
+   }
+   }
+
clk |= SDHCI_CLOCK_CARD_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
 }
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 199712e7adbb..72601a4d2e95 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -114,6 +114,7 @@
 #define  SDHCI_DIV_HI_MASK 0x300
 #define  SDHCI_PROG_CLOCK_MODE 0x0020
 #define  SDHCI_CLOCK_CARD_EN   0x0004
+#define  SDHCI_CLOCK_PLL_EN0x0008
 #define  SDHCI_CLOCK_INT_STABLE0x0002
 #define  SDHCI_CLOCK_INT_EN0x0001
 
-- 
2.22.1



[PATCH V5 1/4] mmc: sdhci: Change timeout of loop for checking internal clock stable

2019-08-19 Thread Ben Chuang
From: Ben Chuang 

According to section 3.2.1 internal clock setup in SD Host Controller
Simplified Specifications 4.20, the timeout of loop for checking
internal clock stable is defined as 150ms.

Signed-off-by: Ben Chuang 
Co-developed-by: Michael K Johnson 
Signed-off-by: Michael K Johnson 
---
 drivers/mmc/host/sdhci.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 59acf8e3331e..bed0760a6c2a 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1636,8 +1636,8 @@ void sdhci_enable_clk(struct sdhci_host *host, u16 clk)
clk |= SDHCI_CLOCK_INT_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
 
-   /* Wait max 20 ms */
-   timeout = ktime_add_ms(ktime_get(), 20);
+   /* Wait max 150 ms */
+   timeout = ktime_add_ms(ktime_get(), 150);
while (1) {
bool timedout = ktime_after(ktime_get(), timeout);
 
-- 
2.22.1



[PATCH V5 0/4] Add Genesys Logic GL975x support

2019-08-19 Thread Ben Chuang
From: Ben Chuang 

The patches modify internal clock setup to match SD Host Controller
Simplified Specifications 4.20 and support Genesys Logic GL9750/
GL9755 support.

V5:
 - add "change timeout of loop .." to a patch
 - fix typo "verndor" to "vendor"

V4:
 - change name from sdhci_gli_reset to sdhci_gl9750_reset
 - fix sdhci_reset to sdhci_gl9750_reset in sdhci_gl9750_ops
 - fix sdhci_gli_reset to sdhci_reset in sdhci_gl9755_ops
 
V3:
 - change usleep_range to udelay
 - add Genesys Logic PCI Vendor ID to a patch
 - separate the Genesys Logic specific part to a patch

V2:
 - change udelay to usleep_range

Ben Chuang (4):
  mmc: sdhci: Change timeout of loop for checking internal clock stable
  mmc: sdhci: Add PLL Enable support to internal clock setup
  PCI: Add Genesys Logic, Inc. Vendor ID
  mmc: host: sdhci-pci: Add Genesys Logic GL975x support

 drivers/mmc/host/Makefile |   2 +-
 drivers/mmc/host/sdhci-pci-core.c |   2 +
 drivers/mmc/host/sdhci-pci-gli.c  | 381 ++
 drivers/mmc/host/sdhci-pci.h  |   5 +
 drivers/mmc/host/sdhci.c  |  27 ++-
 drivers/mmc/host/sdhci.h  |   1 +
 include/linux/pci_ids.h   |   2 +
 7 files changed, 417 insertions(+), 3 deletions(-)
 create mode 100644 drivers/mmc/host/sdhci-pci-gli.c

-- 
2.22.1



Re: [PATCH v2 2/2] mmc: sdhci: sdhci-pci-core: Add Genesis Logic GL975x support

2019-08-11 Thread Ben Chuang

On 8/7/19 8:25 PM, Adrian Hunter wrote:

On 26/07/19 5:07 AM, Michael K. Johnson wrote:

Add support for the GL9750 and GL9755 chipsets.

Signed-off-by: Ben Chuang 
Co-developed-by: Michael K Johnson 
Signed-off-by: Michael K Johnson 

diff --git a/drivers/mmc/host/sdhci-gli.h b/drivers/mmc/host/sdhci-gli.h

I suggest creating sdhci-pci-gli.c and putting definitions there.  Have a
look at sdhci-pci-arasan.c, sdhci-pci-dwc-mshc.c or sdhci-pci-o2micro.c


Hi, Adrian,

Thanks for the review.

I will break the patch apart as you suggested and create sdhci-pci-gli.c.

Then move vendor specific changes to sdhci-pci-gli.c.


new file mode 100644
index ..0acd35b6d3e2
--- /dev/null
+++ b/drivers/mmc/host/sdhci-gli.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+#ifndef __SDHCI_GLI_H
+#define __SDHCI_GLI_H
+
+/* the define PCI_VENDOR_ID_GLI may put in kernel/include/linux/pci_ids.h */
+#ifndef PCI_VENDOR_ID_GLI
+#define PCI_VENDOR_ID_GLI   0x17a0
+#endif

If it is in include/linux/pci_ids.h then this code should be removed


+
+/*  Genesys Logic extra registers */
+#define SDHCI_GLI_9750_WT 0x800
+#define SDHCI_GLI_9750_DRIVING0x860
+#define SDHCI_GLI_9750_PLL0x864
+#define SDHCI_GLI_9750_SW_CTRL0x874
+#define SDHCI_GLI_9750_MISC   0x878
+
+#define SDHCI_GLI_9750_TUNING_CONTROL   0x540
+#define SDHCI_GLI_9750_TUNING_PARAMETERS0x544
+
+#define GLI_9755_DRIVER_VER  "Genesys Logic (GL9755 v0.9.0-y190703)"
+#define GLI_9750_DRIVER_VER  "Genesys Logic (GL9750 v0.9.0-y190703)"
+
+#define GLI_MAX_TUNING_LOOP 40
+
+void gli_set_9750(struct sdhci_host *host);
+
+#endif /* __SDHCI_GLI_H */
diff --git a/drivers/mmc/host/sdhci-pci-core.c 
b/drivers/mmc/host/sdhci-pci-core.c
index 4154ee11b47d..b5c28df39de1 100644
--- a/drivers/mmc/host/sdhci-pci-core.c
+++ b/drivers/mmc/host/sdhci-pci-core.c
@@ -35,6 +35,7 @@

  #include "sdhci.h"
  #include "sdhci-pci.h"
+#include "sdhci-gli.h"

  static void sdhci_pci_hw_reset(struct sdhci_host *host);

@@ -1453,6 +1454,223 @@ static const struct sdhci_pci_fixes sdhci_rtsx = {
 .probe_slot = rtsx_probe_slot,
  };

+/* Genesys Logic chipset */
+static int gli_probe_slot_gl9755(struct sdhci_pci_slot *slot)
+{
+struct sdhci_host *host = slot->host;
+
+slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO;
+dev_info(>chip->pdev->dev, "%s\n", GLI_9755_DRIVER_VER);
+sdhci_enable_v4_mode(host);
+
+return 0;
+}
+
+static void gli_set_9750_rx_inv(struct sdhci_host *host, bool b)
+{
+u32 wt_value = sdhci_readl(host, SDHCI_GLI_9750_WT);
+u32 misc_value = sdhci_readl(host, SDHCI_GLI_9750_MISC);
+
+if ((wt_value & 0x1) == 0) {
+wt_value |= 0x1;
+sdhci_writel(host, wt_value, SDHCI_GLI_9750_WT);
+}
+
+misc_value = sdhci_readl(host, SDHCI_GLI_9750_MISC);
+if (b) {
+misc_value |= 0x8;
+sdhci_writel(host, misc_value, SDHCI_GLI_9750_MISC);
+} else {
+misc_value &= ~0x8;
+sdhci_writel(host, misc_value, SDHCI_GLI_9750_MISC);
+}
+
+wt_value = sdhci_readl(host, SDHCI_GLI_9750_WT);
+wt_value &= ~0x1;
+sdhci_writel(host, wt_value, SDHCI_GLI_9750_WT);
+}
+
+static int __sdhci_execute_tuning_9750(struct sdhci_host *host, u32 opcode)
+{
+int i;
+int rx_inv = 0;
+
+for (rx_inv = 0; rx_inv < 2; rx_inv++) {
+if (rx_inv & 0x1)
+gli_set_9750_rx_inv(host, true);
+else
+gli_set_9750_rx_inv(host, false);
+
+sdhci_start_tuning(host);
+
+for (i = 0; i < GLI_MAX_TUNING_LOOP; i++) {
+u16 ctrl;
+
+sdhci_send_tuning(host, opcode);
+
+if (!host->tuning_done) {
+if (rx_inv == 1) {
+pr_info("%s: Tuning timeout, falling back to 
fixed sampling clock\n",
+mmc_hostname(host->mmc));
+sdhci_abort_tuning(host, opcode);
+return -ETIMEDOUT;
+}
+pr_info("%s: Tuning timeout, try next tuning\n",
+mmc_hostname(host->mmc));
+sdhci_abort_tuning(host, opcode);
+break;
+}
+
+ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+if (!(ctrl & SDHCI_CTRL_EXEC_TUNING)) {
+if (ctrl & SDHCI_CTRL_TUNED_CLK) {
+pr_info("%s: Tuning successful\n",
+mmc_hostname(host->mmc));
+return 0; /* Success! */
+   

[PATCH 2/2] mmc: sdhci: sdhci-pci-core: Add Genesis Logic GL975x support

2019-07-16 Thread Ben Chuang
Add support for the GL9750 and GL9755 chipsets.

Signed-off-by: Ben Chuang 
Co-developed-by: Michael K Johnson 
Signed-off-by: Michael K Johnson 
---
 drivers/mmc/host/sdhci-gli.h  |  27 
 drivers/mmc/host/sdhci-pci-core.c | 220 ++
 drivers/mmc/host/sdhci-pci.h  |   3 +
 drivers/mmc/host/sdhci.c  | 142 +--
 drivers/mmc/host/sdhci.h  |   2 +
 include/linux/pci_ids.h   |   1 +
 6 files changed, 385 insertions(+), 10 deletions(-)
 create mode 100644 drivers/mmc/host/sdhci-gli.h

diff --git a/drivers/mmc/host/sdhci-gli.h b/drivers/mmc/host/sdhci-gli.h
new file mode 100644
index ..0acd35b6d3e2
--- /dev/null
+++ b/drivers/mmc/host/sdhci-gli.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+#ifndef __SDHCI_GLI_H
+#define __SDHCI_GLI_H
+
+/* the define PCI_VENDOR_ID_GLI may put in kernel/include/linux/pci_ids.h */
+#ifndef PCI_VENDOR_ID_GLI
+#define PCI_VENDOR_ID_GLI  0x17a0
+#endif
+
+/*  Genesys Logic extra registers */
+#define SDHCI_GLI_9750_WT 0x800
+#define SDHCI_GLI_9750_DRIVING0x860
+#define SDHCI_GLI_9750_PLL0x864
+#define SDHCI_GLI_9750_SW_CTRL0x874
+#define SDHCI_GLI_9750_MISC   0x878
+
+#define SDHCI_GLI_9750_TUNING_CONTROL  0x540
+#define SDHCI_GLI_9750_TUNING_PARAMETERS   0x544
+
+#define GLI_9755_DRIVER_VER  "Genesys Logic (GL9755 v0.9.0-y190703)"
+#define GLI_9750_DRIVER_VER  "Genesys Logic (GL9750 v0.9.0-y190703)"
+
+#define GLI_MAX_TUNING_LOOP 40
+
+void gli_set_9750(struct sdhci_host *host);
+
+#endif /* __SDHCI_GLI_H */
diff --git a/drivers/mmc/host/sdhci-pci-core.c 
b/drivers/mmc/host/sdhci-pci-core.c
index 4154ee11b47d..b5c28df39de1 100644
--- a/drivers/mmc/host/sdhci-pci-core.c
+++ b/drivers/mmc/host/sdhci-pci-core.c
@@ -35,6 +35,7 @@

 #include "sdhci.h"
 #include "sdhci-pci.h"
+#include "sdhci-gli.h"

 static void sdhci_pci_hw_reset(struct sdhci_host *host);

@@ -1453,6 +1454,223 @@ static const struct sdhci_pci_fixes sdhci_rtsx = {
.probe_slot = rtsx_probe_slot,
 };

+/* Genesys Logic chipset */
+static int gli_probe_slot_gl9755(struct sdhci_pci_slot *slot)
+{
+   struct sdhci_host *host = slot->host;
+
+   slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO;
+   dev_info(>chip->pdev->dev, "%s\n", GLI_9755_DRIVER_VER);
+   sdhci_enable_v4_mode(host);
+
+   return 0;
+}
+
+static void gli_set_9750_rx_inv(struct sdhci_host *host, bool b)
+{
+   u32 wt_value = sdhci_readl(host, SDHCI_GLI_9750_WT);
+   u32 misc_value = sdhci_readl(host, SDHCI_GLI_9750_MISC);
+
+   if ((wt_value & 0x1) == 0) {
+   wt_value |= 0x1;
+   sdhci_writel(host, wt_value, SDHCI_GLI_9750_WT);
+   }
+
+   misc_value = sdhci_readl(host, SDHCI_GLI_9750_MISC);
+   if (b) {
+   misc_value |= 0x8;
+   sdhci_writel(host, misc_value, SDHCI_GLI_9750_MISC);
+   } else {
+   misc_value &= ~0x8;
+   sdhci_writel(host, misc_value, SDHCI_GLI_9750_MISC);
+   }
+
+   wt_value = sdhci_readl(host, SDHCI_GLI_9750_WT);
+   wt_value &= ~0x1;
+   sdhci_writel(host, wt_value, SDHCI_GLI_9750_WT);
+}
+
+static int __sdhci_execute_tuning_9750(struct sdhci_host *host, u32 opcode)
+{
+   int i;
+   int rx_inv = 0;
+
+   for (rx_inv = 0; rx_inv < 2; rx_inv++) {
+   if (rx_inv & 0x1)
+   gli_set_9750_rx_inv(host, true);
+   else
+   gli_set_9750_rx_inv(host, false);
+
+   sdhci_start_tuning(host);
+
+   for (i = 0; i < GLI_MAX_TUNING_LOOP; i++) {
+   u16 ctrl;
+
+   sdhci_send_tuning(host, opcode);
+
+   if (!host->tuning_done) {
+   if (rx_inv == 1) {
+   pr_info("%s: Tuning timeout, falling 
back to fixed sampling clock\n",
+   mmc_hostname(host->mmc));
+   sdhci_abort_tuning(host, opcode);
+   return -ETIMEDOUT;
+   }
+   pr_info("%s: Tuning timeout, try next tuning\n",
+   mmc_hostname(host->mmc));
+   sdhci_abort_tuning(host, opcode);
+   break;
+   }
+
+   ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+   if (!(ctrl & SDHCI_CTRL_EXEC_TUNING)) {
+   if (ctrl & SDHCI_CTRL_TUNED_CLK) {
+   pr_info("%s: Tuning successful\n",
+   mmc_hostname

[PATCH 1/2] mmc: sdhci: Add PLL Enable support to internal clock setup

2019-07-16 Thread Ben Chuang
The GL9750 and GL9755 chipsets, and possibly others, require PLL Enable
setup as part of the internal clock setup as described in 3.2.1 Internal
Clock Setup Sequence of SD Host Controller Simplified Specification
Version 4.20.  This changes the timeouts to the new specification of
150ms for each step and is documented as safe for "prior versions which
do not support PLL Enable."

Signed-off-by: Ben Chuang 
Co-developed-by: Michael K Johnson 
Signed-off-by: Michael K Johnson 
---
 drivers/mmc/host/sdhci.c | 33 -
 1 file changed, 24 insertions(+), 9 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 59acf8e3331e..fd684d7a5f15 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1636,15 +1636,11 @@ void sdhci_enable_clk(struct sdhci_host *host, u16 clk)
clk |= SDHCI_CLOCK_INT_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);

-   /* Wait max 20 ms */
-   timeout = ktime_add_ms(ktime_get(), 20);
-   while (1) {
-   bool timedout = ktime_after(ktime_get(), timeout);
-
-   clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
-   if (clk & SDHCI_CLOCK_INT_STABLE)
-   break;
-   if (timedout) {
+   /* Wait max 150 ms */
+   timeout = ktime_add_ms(ktime_get(), 150);
+   while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
+   & SDHCI_CLOCK_INT_STABLE)) {
+   if (ktime_after(ktime_get(), timeout)) {
pr_err("%s: Internal clock never stabilised.\n",
   mmc_hostname(host->mmc));
sdhci_dumpregs(host);
@@ -1653,8 +1649,27 @@ void sdhci_enable_clk(struct sdhci_host *host, u16 clk)
udelay(10);
}

+   clk |= SDHCI_CLOCK_PLL_EN;
+   clk &= ~SDHCI_CLOCK_INT_STABLE;
+   sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+   /* Wait max 150 ms */
+   timeout = ktime_add_ms(ktime_get(), 150);
+   while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
+   & SDHCI_CLOCK_INT_STABLE)) {
+   if (ktime_after(ktime_get(), timeout)) {
+   pr_err("%s: PLL clock never stabilised.\n",
+  mmc_hostname(host->mmc));
+   sdhci_dumpregs(host);
+   return;
+   }
+   udelay(10);
+   }
+
clk |= SDHCI_CLOCK_CARD_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+   mdelay(1);
 }
 EXPORT_SYMBOL_GPL(sdhci_enable_clk);

--
2.22.0



Genesys Logic Email Confidentiality Notice:
This mail and any attachments may contain information that is confidential, 
proprietary, privileged or otherwise protected by law. The mail is intended 
solely for the named addressee (or a person responsible for delivering it to 
the addressee). If you are not the intended recipient of this mail, you are not 
authorized to read, print, copy or disseminate this mail.

If you have received this email in error, please notify us immediately by reply 
email and immediately delete this message and any attachments from your system. 
Please be noted that any unauthorized use, dissemination, distribution or 
copying of this email is strictly prohibited.