2023-05-12 10:58:43

by Victor Shih

[permalink] [raw]
Subject: [PATCH V1 3/3] mmc: sdhci-pci-gli: Add support SD Express card for GL9767

Add support SD Express card for GL9767. The workflow of the
SD Express card in GL9767 is as below.
1. GL9767 operates in SD mode and set MMC_CAP2_SD_EXP flag.
2. If card is inserted, Host send CMD8 to ask the capabilities
of the card.
3. If the card has PCIe capability and write protect is not
enable, then init_sd_express() will be invoked.
4. GL9767 switch from SD mode to PCIe/NVMe mode and mmc driver
handover control to NVMe driver.
5. If card is removed, GL9767 will return to SD mode.

Signed-off-by: Ben Chuang <[email protected]>
Signed-off-by: Victor Shih <[email protected]>
---
drivers/mmc/host/sdhci-pci-gli.c | 115 +++++++++++++++++++++++++++++++
1 file changed, 115 insertions(+)

diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c
index 300512740cb0..a0f9c24439be 100644
--- a/drivers/mmc/host/sdhci-pci-gli.c
+++ b/drivers/mmc/host/sdhci-pci-gli.c
@@ -158,6 +158,13 @@
#define GLI_9767_VHS_REV_M 0x1
#define GLI_9767_VHS_REV_W 0x2

+#define PCIE_GLI_9767_CFG 0x8A0
+#define PCIE_GLI_9767_CFG_LOW_PWR_OFF BIT(12)
+
+#define PCIE_GLI_9767_COMBO_MUX_CTL 0x8C8
+#define PCIE_GLI_9767_COMBO_MUX_CTL_RST_EN BIT(6)
+#define PCIE_GLI_9767_COMBO_MUX_CTL_WAIT_PERST_EN BIT(10)
+
#define PCIE_GLI_9767_PWR_MACRO_CTL 0x8D0
#define PCIE_GLI_9767_PWR_MACRO_CTL_LOW_VOLTAGE GENMASK(3, 0)
#define PCIE_GLI_9767_PWR_MACRO_CTL_LD0_LOW_OUTPUT_VOLTAGE GENMASK(15, 12)
@@ -175,6 +182,27 @@
#define PCIE_GLI_9767_SCR_CORE_PWR_D3_OFF BIT(21)
#define PCIE_GLI_9767_SCR_CFG_RST_DATA_LINK_DOWN BIT(30)

+#define PCIE_GLI_9767_SDHC_CAP 0x91C
+#define PCIE_GLI_9767_SDHC_CAP_SDEI_RESULT BIT(5)
+
+#define PCIE_GLI_9767_SD_EXPRESS_CTL 0x940
+#define PCIE_GLI_9767_SD_EXPRESS_CTL_SDEI_EXE BIT(0)
+#define PCIE_GLI_9767_SD_EXPRESS_CTL_SD_EXPRESS_MODE BIT(1)
+
+#define PCIE_GLI_9767_SD_DATA_MULTI_CTL 0x944
+#define PCIE_GLI_9767_SD_DATA_MULTI_CTL_DISCONNECT_TIME GENMASK(23, 16)
+#define PCIE_GLI_9767_SD_DATA_MULTI_CTL_DISCONNECT_TIME_VALUE 0x64
+
+#define PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2 0x950
+#define PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2_SDEI_COMPLETE BIT(0)
+#define PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2_SDEI_GEN_TIMER GENMASK(1, 0)
+
+#define PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_EN_REG2 0x954
+#define PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_EN_REG2_SDEI_COMPLETE_STATUS_EN GENMASK(1, 0)
+
+#define PCIE_GLI_9767_NORMAL_ERR_INT_SIGNAL_EN_REG2 0x958
+#define PCIE_GLI_9767_NORMAL_ERR_INT_SIGNAL_EN_REG2_SDEI_COMPLETE_SIGNAL_EN GENMASK(1, 0)
+
#define GLI_MAX_TUNING_LOOP 40

/* Genesys Logic chipset */
@@ -774,6 +802,91 @@ static void sdhci_gl9767_reset(struct sdhci_host *host, u8 mask)
gli_set_9767(host);
}

+static int gl9767_init_sd_express(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ struct sdhci_pci_slot *slot = sdhci_priv(host);
+ struct pci_dev *pdev;
+ u32 value;
+ int i;
+
+ pdev = slot->chip->pdev;
+
+ if (sdhci_check_ro(host)) {
+ mmc->ios.timing &= ~(MMC_TIMING_SD_EXP | MMC_TIMING_SD_EXP_1_2V);
+ return 0;
+ }
+
+ pci_read_config_dword(pdev, PCIE_GLI_9767_VHS, &value);
+ value &= ~GLI_9767_VHS_REV;
+ value |= FIELD_PREP(GLI_9767_VHS_REV, GLI_9767_VHS_REV_W);
+ pci_write_config_dword(pdev, PCIE_GLI_9767_VHS, value);
+
+ pci_read_config_dword(pdev, PCIE_GLI_9767_COMBO_MUX_CTL, &value);
+ value &= ~(PCIE_GLI_9767_COMBO_MUX_CTL_RST_EN | PCIE_GLI_9767_COMBO_MUX_CTL_WAIT_PERST_EN);
+ pci_write_config_dword(pdev, PCIE_GLI_9767_COMBO_MUX_CTL, value);
+
+ pci_read_config_dword(pdev, PCIE_GLI_9767_SD_DATA_MULTI_CTL, &value);
+ value &= ~PCIE_GLI_9767_SD_DATA_MULTI_CTL_DISCONNECT_TIME;
+ value |= FIELD_PREP(PCIE_GLI_9767_SD_DATA_MULTI_CTL_DISCONNECT_TIME,
+ PCIE_GLI_9767_SD_DATA_MULTI_CTL_DISCONNECT_TIME_VALUE);
+ pci_write_config_dword(pdev, PCIE_GLI_9767_SD_DATA_MULTI_CTL, value);
+
+ pci_read_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2, &value);
+ value |= PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2_SDEI_GEN_TIMER;
+ pci_write_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2, value);
+
+ pci_read_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_EN_REG2, &value);
+ value |= PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_EN_REG2_SDEI_COMPLETE_STATUS_EN;
+ pci_write_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_EN_REG2, value);
+
+ pci_read_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_SIGNAL_EN_REG2, &value);
+ value |= PCIE_GLI_9767_NORMAL_ERR_INT_SIGNAL_EN_REG2_SDEI_COMPLETE_SIGNAL_EN;
+ pci_write_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_SIGNAL_EN_REG2, value);
+
+ pci_read_config_dword(pdev, PCIE_GLI_9767_CFG, &value);
+ value |= PCIE_GLI_9767_CFG_LOW_PWR_OFF;
+ pci_write_config_dword(pdev, PCIE_GLI_9767_CFG, value);
+
+ value = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+ value &= ~(SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_PLL_EN);
+ sdhci_writew(host, value, SDHCI_CLOCK_CONTROL);
+
+ value = sdhci_readb(host, SDHCI_POWER_CONTROL);
+ value |= ((SDHCI_POWER_180 | SDHCI_POWER_ON) << 4);
+ sdhci_writeb(host, value, SDHCI_POWER_CONTROL);
+
+ pci_read_config_dword(pdev, PCIE_GLI_9767_SD_EXPRESS_CTL, &value);
+ value |= PCIE_GLI_9767_SD_EXPRESS_CTL_SDEI_EXE;
+ pci_write_config_dword(pdev, PCIE_GLI_9767_SD_EXPRESS_CTL, value);
+
+ for (i = 0; i < 10; i++) {
+ mdelay(10);
+ pci_read_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2, &value);
+ if (value & PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2_SDEI_COMPLETE) {
+ pci_write_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2,
+ value);
+ break;
+ }
+ }
+
+ pci_read_config_dword(pdev, PCIE_GLI_9767_SDHC_CAP, &value);
+ if ((value & PCIE_GLI_9767_SDHC_CAP_SDEI_RESULT) == PCIE_GLI_9767_SDHC_CAP_SDEI_RESULT) {
+ pci_read_config_dword(pdev, PCIE_GLI_9767_SD_EXPRESS_CTL, &value);
+ value |= PCIE_GLI_9767_SD_EXPRESS_CTL_SD_EXPRESS_MODE;
+ pci_write_config_dword(pdev, PCIE_GLI_9767_SD_EXPRESS_CTL, value);
+ } else {
+ mmc->ios.timing &= ~(MMC_TIMING_SD_EXP | MMC_TIMING_SD_EXP_1_2V);
+ }
+
+ pci_read_config_dword(pdev, PCIE_GLI_9767_VHS, &value);
+ value &= ~GLI_9767_VHS_REV;
+ value |= FIELD_PREP(GLI_9767_VHS_REV, GLI_9767_VHS_REV_R);
+ pci_write_config_dword(pdev, PCIE_GLI_9767_VHS, value);
+
+ return 0;
+}
+
static int gli_probe_slot_gl9750(struct sdhci_pci_slot *slot)
{
struct sdhci_host *host = slot->host;
@@ -806,6 +919,8 @@ static int gli_probe_slot_gl9767(struct sdhci_pci_slot *slot)
gl9767_hw_setting(slot);
gli_pcie_enable_msi(slot);
slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO;
+ host->mmc->caps2 |= MMC_CAP2_SD_EXP;
+ host->mmc_host_ops.init_sd_express = gl9767_init_sd_express;
sdhci_enable_v4_mode(host);

return 0;
--
2.25.1



2023-05-15 00:58:44

by Ben Chuang

[permalink] [raw]
Subject: Re: [PATCH V1 3/3] mmc: sdhci-pci-gli: Add support SD Express card for GL9767

Hi Victor,

On Fri, May 12, 2023 at 6:47 PM Victor Shih <[email protected]> wrote:
>
> Add support SD Express card for GL9767. The workflow of the
> SD Express card in GL9767 is as below.
> 1. GL9767 operates in SD mode and set MMC_CAP2_SD_EXP flag.
> 2. If card is inserted, Host send CMD8 to ask the capabilities
> of the card.
> 3. If the card has PCIe capability and write protect is not
> enable, then init_sd_express() will be invoked.
> 4. GL9767 switch from SD mode to PCIe/NVMe mode and mmc driver
> handover control to NVMe driver.
> 5. If card is removed, GL9767 will return to SD mode.
>
> Signed-off-by: Ben Chuang <[email protected]>
> Signed-off-by: Victor Shih <[email protected]>
> ---
> drivers/mmc/host/sdhci-pci-gli.c | 115 +++++++++++++++++++++++++++++++
> 1 file changed, 115 insertions(+)
>
> diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c
> index 300512740cb0..a0f9c24439be 100644
> --- a/drivers/mmc/host/sdhci-pci-gli.c
> +++ b/drivers/mmc/host/sdhci-pci-gli.c
> @@ -158,6 +158,13 @@
> #define GLI_9767_VHS_REV_M 0x1
> #define GLI_9767_VHS_REV_W 0x2
>
> +#define PCIE_GLI_9767_CFG 0x8A0
> +#define PCIE_GLI_9767_CFG_LOW_PWR_OFF BIT(12)
> +
> +#define PCIE_GLI_9767_COMBO_MUX_CTL 0x8C8
> +#define PCIE_GLI_9767_COMBO_MUX_CTL_RST_EN BIT(6)
> +#define PCIE_GLI_9767_COMBO_MUX_CTL_WAIT_PERST_EN BIT(10)
> +
> #define PCIE_GLI_9767_PWR_MACRO_CTL 0x8D0
> #define PCIE_GLI_9767_PWR_MACRO_CTL_LOW_VOLTAGE GENMASK(3, 0)
> #define PCIE_GLI_9767_PWR_MACRO_CTL_LD0_LOW_OUTPUT_VOLTAGE GENMASK(15, 12)
> @@ -175,6 +182,27 @@
> #define PCIE_GLI_9767_SCR_CORE_PWR_D3_OFF BIT(21)
> #define PCIE_GLI_9767_SCR_CFG_RST_DATA_LINK_DOWN BIT(30)
>
> +#define PCIE_GLI_9767_SDHC_CAP 0x91C
> +#define PCIE_GLI_9767_SDHC_CAP_SDEI_RESULT BIT(5)
> +
> +#define PCIE_GLI_9767_SD_EXPRESS_CTL 0x940
> +#define PCIE_GLI_9767_SD_EXPRESS_CTL_SDEI_EXE BIT(0)
> +#define PCIE_GLI_9767_SD_EXPRESS_CTL_SD_EXPRESS_MODE BIT(1)
> +
> +#define PCIE_GLI_9767_SD_DATA_MULTI_CTL 0x944
> +#define PCIE_GLI_9767_SD_DATA_MULTI_CTL_DISCONNECT_TIME GENMASK(23, 16)
> +#define PCIE_GLI_9767_SD_DATA_MULTI_CTL_DISCONNECT_TIME_VALUE 0x64
> +
> +#define PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2 0x950
> +#define PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2_SDEI_COMPLETE BIT(0)
> +#define PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2_SDEI_GEN_TIMER GENMASK(1, 0)
> +
> +#define PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_EN_REG2 0x954
> +#define PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_EN_REG2_SDEI_COMPLETE_STATUS_EN GENMASK(1, 0)
> +
> +#define PCIE_GLI_9767_NORMAL_ERR_INT_SIGNAL_EN_REG2 0x958
> +#define PCIE_GLI_9767_NORMAL_ERR_INT_SIGNAL_EN_REG2_SDEI_COMPLETE_SIGNAL_EN GENMASK(1, 0)
> +
> #define GLI_MAX_TUNING_LOOP 40
>
> /* Genesys Logic chipset */
> @@ -774,6 +802,91 @@ static void sdhci_gl9767_reset(struct sdhci_host *host, u8 mask)
> gli_set_9767(host);
> }
>
> +static int gl9767_init_sd_express(struct mmc_host *mmc, struct mmc_ios *ios)
> +{
> + struct sdhci_host *host = mmc_priv(mmc);
> + struct sdhci_pci_slot *slot = sdhci_priv(host);
> + struct pci_dev *pdev;
> + u32 value;
> + int i;
> +
> + pdev = slot->chip->pdev;
> +
> + if (sdhci_check_ro(host)) {
> + mmc->ios.timing &= ~(MMC_TIMING_SD_EXP | MMC_TIMING_SD_EXP_1_2V);
> + return 0;
> + }
> +
> + pci_read_config_dword(pdev, PCIE_GLI_9767_VHS, &value);
> + value &= ~GLI_9767_VHS_REV;
> + value |= FIELD_PREP(GLI_9767_VHS_REV, GLI_9767_VHS_REV_W);
> + pci_write_config_dword(pdev, PCIE_GLI_9767_VHS, value);
> +
> + pci_read_config_dword(pdev, PCIE_GLI_9767_COMBO_MUX_CTL, &value);
> + value &= ~(PCIE_GLI_9767_COMBO_MUX_CTL_RST_EN | PCIE_GLI_9767_COMBO_MUX_CTL_WAIT_PERST_EN);
> + pci_write_config_dword(pdev, PCIE_GLI_9767_COMBO_MUX_CTL, value);
> +
> + pci_read_config_dword(pdev, PCIE_GLI_9767_SD_DATA_MULTI_CTL, &value);
> + value &= ~PCIE_GLI_9767_SD_DATA_MULTI_CTL_DISCONNECT_TIME;
> + value |= FIELD_PREP(PCIE_GLI_9767_SD_DATA_MULTI_CTL_DISCONNECT_TIME,
> + PCIE_GLI_9767_SD_DATA_MULTI_CTL_DISCONNECT_TIME_VALUE);
> + pci_write_config_dword(pdev, PCIE_GLI_9767_SD_DATA_MULTI_CTL, value);
> +
> + pci_read_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2, &value);
> + value |= PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2_SDEI_GEN_TIMER;
> + pci_write_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2, value);
> +
> + pci_read_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_EN_REG2, &value);
> + value |= PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_EN_REG2_SDEI_COMPLETE_STATUS_EN;
> + pci_write_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_EN_REG2, value);
> +
> + pci_read_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_SIGNAL_EN_REG2, &value);
> + value |= PCIE_GLI_9767_NORMAL_ERR_INT_SIGNAL_EN_REG2_SDEI_COMPLETE_SIGNAL_EN;
> + pci_write_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_SIGNAL_EN_REG2, value);
> +
> + pci_read_config_dword(pdev, PCIE_GLI_9767_CFG, &value);
> + value |= PCIE_GLI_9767_CFG_LOW_PWR_OFF;
> + pci_write_config_dword(pdev, PCIE_GLI_9767_CFG, value);
> +
> + value = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
> + value &= ~(SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_PLL_EN);
> + sdhci_writew(host, value, SDHCI_CLOCK_CONTROL);
> +
> + value = sdhci_readb(host, SDHCI_POWER_CONTROL);
> + value |= ((SDHCI_POWER_180 | SDHCI_POWER_ON) << 4);
> + sdhci_writeb(host, value, SDHCI_POWER_CONTROL);
> +
> + pci_read_config_dword(pdev, PCIE_GLI_9767_SD_EXPRESS_CTL, &value);
> + value |= PCIE_GLI_9767_SD_EXPRESS_CTL_SDEI_EXE;
> + pci_write_config_dword(pdev, PCIE_GLI_9767_SD_EXPRESS_CTL, value);
> +
> + for (i = 0; i < 10; i++) {
> + mdelay(10);

A little question.
Can you explain or comment on the reason for up to 10 loops (max. 100 ms wait),
For example "because of asic specs..." or "hardware measurements".

Best regards,
Ben

> + pci_read_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2, &value);
> + if (value & PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2_SDEI_COMPLETE) {
> + pci_write_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2,
> + value);
> + break;
> + }
> + }
> +
> + pci_read_config_dword(pdev, PCIE_GLI_9767_SDHC_CAP, &value);
> + if ((value & PCIE_GLI_9767_SDHC_CAP_SDEI_RESULT) == PCIE_GLI_9767_SDHC_CAP_SDEI_RESULT) {
> + pci_read_config_dword(pdev, PCIE_GLI_9767_SD_EXPRESS_CTL, &value);
> + value |= PCIE_GLI_9767_SD_EXPRESS_CTL_SD_EXPRESS_MODE;
> + pci_write_config_dword(pdev, PCIE_GLI_9767_SD_EXPRESS_CTL, value);
> + } else {
> + mmc->ios.timing &= ~(MMC_TIMING_SD_EXP | MMC_TIMING_SD_EXP_1_2V);
> + }
> +
> + pci_read_config_dword(pdev, PCIE_GLI_9767_VHS, &value);
> + value &= ~GLI_9767_VHS_REV;
> + value |= FIELD_PREP(GLI_9767_VHS_REV, GLI_9767_VHS_REV_R);
> + pci_write_config_dword(pdev, PCIE_GLI_9767_VHS, value);
> +
> + return 0;
> +}
> +
> static int gli_probe_slot_gl9750(struct sdhci_pci_slot *slot)
> {
> struct sdhci_host *host = slot->host;
> @@ -806,6 +919,8 @@ static int gli_probe_slot_gl9767(struct sdhci_pci_slot *slot)
> gl9767_hw_setting(slot);
> gli_pcie_enable_msi(slot);
> slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO;
> + host->mmc->caps2 |= MMC_CAP2_SD_EXP;
> + host->mmc_host_ops.init_sd_express = gl9767_init_sd_express;
> sdhci_enable_v4_mode(host);
>
> return 0;
> --
> 2.25.1
>

2023-05-29 09:45:20

by Adrian Hunter

[permalink] [raw]
Subject: Re: [PATCH V1 3/3] mmc: sdhci-pci-gli: Add support SD Express card for GL9767

On 12/05/23 13:45, Victor Shih wrote:
> Add support SD Express card for GL9767. The workflow of the
> SD Express card in GL9767 is as below.
> 1. GL9767 operates in SD mode and set MMC_CAP2_SD_EXP flag.
> 2. If card is inserted, Host send CMD8 to ask the capabilities
> of the card.
> 3. If the card has PCIe capability and write protect is not
> enable, then init_sd_express() will be invoked.

Could explain about why not write protect

> 4. GL9767 switch from SD mode to PCIe/NVMe mode and mmc driver
> handover control to NVMe driver.
> 5. If card is removed, GL9767 will return to SD mode.
>
> Signed-off-by: Ben Chuang <[email protected]>
> Signed-off-by: Victor Shih <[email protected]>

As Ben pointed out, please try to use the same email address
for From: and Signed-off-by:

> ---
> drivers/mmc/host/sdhci-pci-gli.c | 115 +++++++++++++++++++++++++++++++
> 1 file changed, 115 insertions(+)
>
> diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c
> index 300512740cb0..a0f9c24439be 100644
> --- a/drivers/mmc/host/sdhci-pci-gli.c
> +++ b/drivers/mmc/host/sdhci-pci-gli.c
> @@ -158,6 +158,13 @@
> #define GLI_9767_VHS_REV_M 0x1
> #define GLI_9767_VHS_REV_W 0x2
>
> +#define PCIE_GLI_9767_CFG 0x8A0
> +#define PCIE_GLI_9767_CFG_LOW_PWR_OFF BIT(12)
> +
> +#define PCIE_GLI_9767_COMBO_MUX_CTL 0x8C8
> +#define PCIE_GLI_9767_COMBO_MUX_CTL_RST_EN BIT(6)
> +#define PCIE_GLI_9767_COMBO_MUX_CTL_WAIT_PERST_EN BIT(10)
> +
> #define PCIE_GLI_9767_PWR_MACRO_CTL 0x8D0
> #define PCIE_GLI_9767_PWR_MACRO_CTL_LOW_VOLTAGE GENMASK(3, 0)
> #define PCIE_GLI_9767_PWR_MACRO_CTL_LD0_LOW_OUTPUT_VOLTAGE GENMASK(15, 12)
> @@ -175,6 +182,27 @@
> #define PCIE_GLI_9767_SCR_CORE_PWR_D3_OFF BIT(21)
> #define PCIE_GLI_9767_SCR_CFG_RST_DATA_LINK_DOWN BIT(30)
>
> +#define PCIE_GLI_9767_SDHC_CAP 0x91C
> +#define PCIE_GLI_9767_SDHC_CAP_SDEI_RESULT BIT(5)
> +
> +#define PCIE_GLI_9767_SD_EXPRESS_CTL 0x940
> +#define PCIE_GLI_9767_SD_EXPRESS_CTL_SDEI_EXE BIT(0)
> +#define PCIE_GLI_9767_SD_EXPRESS_CTL_SD_EXPRESS_MODE BIT(1)
> +
> +#define PCIE_GLI_9767_SD_DATA_MULTI_CTL 0x944
> +#define PCIE_GLI_9767_SD_DATA_MULTI_CTL_DISCONNECT_TIME GENMASK(23, 16)
> +#define PCIE_GLI_9767_SD_DATA_MULTI_CTL_DISCONNECT_TIME_VALUE 0x64
> +
> +#define PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2 0x950
> +#define PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2_SDEI_COMPLETE BIT(0)
> +#define PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2_SDEI_GEN_TIMER GENMASK(1, 0)
> +
> +#define PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_EN_REG2 0x954
> +#define PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_EN_REG2_SDEI_COMPLETE_STATUS_EN GENMASK(1, 0)
> +
> +#define PCIE_GLI_9767_NORMAL_ERR_INT_SIGNAL_EN_REG2 0x958
> +#define PCIE_GLI_9767_NORMAL_ERR_INT_SIGNAL_EN_REG2_SDEI_COMPLETE_SIGNAL_EN GENMASK(1, 0)
> +
> #define GLI_MAX_TUNING_LOOP 40
>
> /* Genesys Logic chipset */
> @@ -774,6 +802,91 @@ static void sdhci_gl9767_reset(struct sdhci_host *host, u8 mask)
> gli_set_9767(host);
> }
>
> +static int gl9767_init_sd_express(struct mmc_host *mmc, struct mmc_ios *ios)
> +{
> + struct sdhci_host *host = mmc_priv(mmc);
> + struct sdhci_pci_slot *slot = sdhci_priv(host);
> + struct pci_dev *pdev;
> + u32 value;
> + int i;
> +
> + pdev = slot->chip->pdev;
> +
> + if (sdhci_check_ro(host)) {

I think mmc->get_ro(mmc) would be fine here instead.

> + mmc->ios.timing &= ~(MMC_TIMING_SD_EXP | MMC_TIMING_SD_EXP_1_2V);
> + return 0;
> + }
> +
> + pci_read_config_dword(pdev, PCIE_GLI_9767_VHS, &value);
> + value &= ~GLI_9767_VHS_REV;
> + value |= FIELD_PREP(GLI_9767_VHS_REV, GLI_9767_VHS_REV_W);
> + pci_write_config_dword(pdev, PCIE_GLI_9767_VHS, value);
> +
> + pci_read_config_dword(pdev, PCIE_GLI_9767_COMBO_MUX_CTL, &value);
> + value &= ~(PCIE_GLI_9767_COMBO_MUX_CTL_RST_EN | PCIE_GLI_9767_COMBO_MUX_CTL_WAIT_PERST_EN);
> + pci_write_config_dword(pdev, PCIE_GLI_9767_COMBO_MUX_CTL, value);
> +
> + pci_read_config_dword(pdev, PCIE_GLI_9767_SD_DATA_MULTI_CTL, &value);
> + value &= ~PCIE_GLI_9767_SD_DATA_MULTI_CTL_DISCONNECT_TIME;
> + value |= FIELD_PREP(PCIE_GLI_9767_SD_DATA_MULTI_CTL_DISCONNECT_TIME,
> + PCIE_GLI_9767_SD_DATA_MULTI_CTL_DISCONNECT_TIME_VALUE);
> + pci_write_config_dword(pdev, PCIE_GLI_9767_SD_DATA_MULTI_CTL, value);
> +
> + pci_read_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2, &value);
> + value |= PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2_SDEI_GEN_TIMER;
> + pci_write_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2, value);
> +
> + pci_read_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_EN_REG2, &value);
> + value |= PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_EN_REG2_SDEI_COMPLETE_STATUS_EN;
> + pci_write_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_EN_REG2, value);
> +
> + pci_read_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_SIGNAL_EN_REG2, &value);
> + value |= PCIE_GLI_9767_NORMAL_ERR_INT_SIGNAL_EN_REG2_SDEI_COMPLETE_SIGNAL_EN;
> + pci_write_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_SIGNAL_EN_REG2, value);
> +
> + pci_read_config_dword(pdev, PCIE_GLI_9767_CFG, &value);
> + value |= PCIE_GLI_9767_CFG_LOW_PWR_OFF;
> + pci_write_config_dword(pdev, PCIE_GLI_9767_CFG, value);
> +
> + value = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
> + value &= ~(SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_PLL_EN);
> + sdhci_writew(host, value, SDHCI_CLOCK_CONTROL);
> +
> + value = sdhci_readb(host, SDHCI_POWER_CONTROL);
> + value |= ((SDHCI_POWER_180 | SDHCI_POWER_ON) << 4);
> + sdhci_writeb(host, value, SDHCI_POWER_CONTROL);
> +
> + pci_read_config_dword(pdev, PCIE_GLI_9767_SD_EXPRESS_CTL, &value);
> + value |= PCIE_GLI_9767_SD_EXPRESS_CTL_SDEI_EXE;
> + pci_write_config_dword(pdev, PCIE_GLI_9767_SD_EXPRESS_CTL, value);
> +
> + for (i = 0; i < 10; i++) {
> + mdelay(10);

This should be msleep() or usleep_range()

> + pci_read_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2, &value);
> + if (value & PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2_SDEI_COMPLETE) {
> + pci_write_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2,
> + value);
> + break;
> + }
> + }
> +
> + pci_read_config_dword(pdev, PCIE_GLI_9767_SDHC_CAP, &value);
> + if ((value & PCIE_GLI_9767_SDHC_CAP_SDEI_RESULT) == PCIE_GLI_9767_SDHC_CAP_SDEI_RESULT) {
> + pci_read_config_dword(pdev, PCIE_GLI_9767_SD_EXPRESS_CTL, &value);
> + value |= PCIE_GLI_9767_SD_EXPRESS_CTL_SD_EXPRESS_MODE;
> + pci_write_config_dword(pdev, PCIE_GLI_9767_SD_EXPRESS_CTL, value);
> + } else {
> + mmc->ios.timing &= ~(MMC_TIMING_SD_EXP | MMC_TIMING_SD_EXP_1_2V);
> + }
> +
> + pci_read_config_dword(pdev, PCIE_GLI_9767_VHS, &value);
> + value &= ~GLI_9767_VHS_REV;
> + value |= FIELD_PREP(GLI_9767_VHS_REV, GLI_9767_VHS_REV_R);
> + pci_write_config_dword(pdev, PCIE_GLI_9767_VHS, value);
> +
> + return 0;
> +}
> +
> static int gli_probe_slot_gl9750(struct sdhci_pci_slot *slot)
> {
> struct sdhci_host *host = slot->host;
> @@ -806,6 +919,8 @@ static int gli_probe_slot_gl9767(struct sdhci_pci_slot *slot)
> gl9767_hw_setting(slot);
> gli_pcie_enable_msi(slot);
> slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO;
> + host->mmc->caps2 |= MMC_CAP2_SD_EXP;
> + host->mmc_host_ops.init_sd_express = gl9767_init_sd_express;
> sdhci_enable_v4_mode(host);
>
> return 0;


2023-05-30 10:06:17

by Victor Shih

[permalink] [raw]
Subject: Re: [PATCH V1 3/3] mmc: sdhci-pci-gli: Add support SD Express card for GL9767

Hi, Ben

On Mon, May 15, 2023 at 8:15 AM Ben Chuang <[email protected]> wrote:
>
> Hi Victor,
>
> On Fri, May 12, 2023 at 6:47 PM Victor Shih <[email protected]> wrote:
> >
> > Add support SD Express card for GL9767. The workflow of the
> > SD Express card in GL9767 is as below.
> > 1. GL9767 operates in SD mode and set MMC_CAP2_SD_EXP flag.
> > 2. If card is inserted, Host send CMD8 to ask the capabilities
> > of the card.
> > 3. If the card has PCIe capability and write protect is not
> > enable, then init_sd_express() will be invoked.
> > 4. GL9767 switch from SD mode to PCIe/NVMe mode and mmc driver
> > handover control to NVMe driver.
> > 5. If card is removed, GL9767 will return to SD mode.
> >
> > Signed-off-by: Ben Chuang <[email protected]>
> > Signed-off-by: Victor Shih <[email protected]>
> > ---
> > drivers/mmc/host/sdhci-pci-gli.c | 115 +++++++++++++++++++++++++++++++
> > 1 file changed, 115 insertions(+)
> >
> > diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c
> > index 300512740cb0..a0f9c24439be 100644
> > --- a/drivers/mmc/host/sdhci-pci-gli.c
> > +++ b/drivers/mmc/host/sdhci-pci-gli.c
> > @@ -158,6 +158,13 @@
> > #define GLI_9767_VHS_REV_M 0x1
> > #define GLI_9767_VHS_REV_W 0x2
> >
> > +#define PCIE_GLI_9767_CFG 0x8A0
> > +#define PCIE_GLI_9767_CFG_LOW_PWR_OFF BIT(12)
> > +
> > +#define PCIE_GLI_9767_COMBO_MUX_CTL 0x8C8
> > +#define PCIE_GLI_9767_COMBO_MUX_CTL_RST_EN BIT(6)
> > +#define PCIE_GLI_9767_COMBO_MUX_CTL_WAIT_PERST_EN BIT(10)
> > +
> > #define PCIE_GLI_9767_PWR_MACRO_CTL 0x8D0
> > #define PCIE_GLI_9767_PWR_MACRO_CTL_LOW_VOLTAGE GENMASK(3, 0)
> > #define PCIE_GLI_9767_PWR_MACRO_CTL_LD0_LOW_OUTPUT_VOLTAGE GENMASK(15, 12)
> > @@ -175,6 +182,27 @@
> > #define PCIE_GLI_9767_SCR_CORE_PWR_D3_OFF BIT(21)
> > #define PCIE_GLI_9767_SCR_CFG_RST_DATA_LINK_DOWN BIT(30)
> >
> > +#define PCIE_GLI_9767_SDHC_CAP 0x91C
> > +#define PCIE_GLI_9767_SDHC_CAP_SDEI_RESULT BIT(5)
> > +
> > +#define PCIE_GLI_9767_SD_EXPRESS_CTL 0x940
> > +#define PCIE_GLI_9767_SD_EXPRESS_CTL_SDEI_EXE BIT(0)
> > +#define PCIE_GLI_9767_SD_EXPRESS_CTL_SD_EXPRESS_MODE BIT(1)
> > +
> > +#define PCIE_GLI_9767_SD_DATA_MULTI_CTL 0x944
> > +#define PCIE_GLI_9767_SD_DATA_MULTI_CTL_DISCONNECT_TIME GENMASK(23, 16)
> > +#define PCIE_GLI_9767_SD_DATA_MULTI_CTL_DISCONNECT_TIME_VALUE 0x64
> > +
> > +#define PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2 0x950
> > +#define PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2_SDEI_COMPLETE BIT(0)
> > +#define PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2_SDEI_GEN_TIMER GENMASK(1, 0)
> > +
> > +#define PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_EN_REG2 0x954
> > +#define PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_EN_REG2_SDEI_COMPLETE_STATUS_EN GENMASK(1, 0)
> > +
> > +#define PCIE_GLI_9767_NORMAL_ERR_INT_SIGNAL_EN_REG2 0x958
> > +#define PCIE_GLI_9767_NORMAL_ERR_INT_SIGNAL_EN_REG2_SDEI_COMPLETE_SIGNAL_EN GENMASK(1, 0)
> > +
> > #define GLI_MAX_TUNING_LOOP 40
> >
> > /* Genesys Logic chipset */
> > @@ -774,6 +802,91 @@ static void sdhci_gl9767_reset(struct sdhci_host *host, u8 mask)
> > gli_set_9767(host);
> > }
> >
> > +static int gl9767_init_sd_express(struct mmc_host *mmc, struct mmc_ios *ios)
> > +{
> > + struct sdhci_host *host = mmc_priv(mmc);
> > + struct sdhci_pci_slot *slot = sdhci_priv(host);
> > + struct pci_dev *pdev;
> > + u32 value;
> > + int i;
> > +
> > + pdev = slot->chip->pdev;
> > +
> > + if (sdhci_check_ro(host)) {
> > + mmc->ios.timing &= ~(MMC_TIMING_SD_EXP | MMC_TIMING_SD_EXP_1_2V);
> > + return 0;
> > + }
> > +
> > + pci_read_config_dword(pdev, PCIE_GLI_9767_VHS, &value);
> > + value &= ~GLI_9767_VHS_REV;
> > + value |= FIELD_PREP(GLI_9767_VHS_REV, GLI_9767_VHS_REV_W);
> > + pci_write_config_dword(pdev, PCIE_GLI_9767_VHS, value);
> > +
> > + pci_read_config_dword(pdev, PCIE_GLI_9767_COMBO_MUX_CTL, &value);
> > + value &= ~(PCIE_GLI_9767_COMBO_MUX_CTL_RST_EN | PCIE_GLI_9767_COMBO_MUX_CTL_WAIT_PERST_EN);
> > + pci_write_config_dword(pdev, PCIE_GLI_9767_COMBO_MUX_CTL, value);
> > +
> > + pci_read_config_dword(pdev, PCIE_GLI_9767_SD_DATA_MULTI_CTL, &value);
> > + value &= ~PCIE_GLI_9767_SD_DATA_MULTI_CTL_DISCONNECT_TIME;
> > + value |= FIELD_PREP(PCIE_GLI_9767_SD_DATA_MULTI_CTL_DISCONNECT_TIME,
> > + PCIE_GLI_9767_SD_DATA_MULTI_CTL_DISCONNECT_TIME_VALUE);
> > + pci_write_config_dword(pdev, PCIE_GLI_9767_SD_DATA_MULTI_CTL, value);
> > +
> > + pci_read_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2, &value);
> > + value |= PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2_SDEI_GEN_TIMER;
> > + pci_write_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2, value);
> > +
> > + pci_read_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_EN_REG2, &value);
> > + value |= PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_EN_REG2_SDEI_COMPLETE_STATUS_EN;
> > + pci_write_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_EN_REG2, value);
> > +
> > + pci_read_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_SIGNAL_EN_REG2, &value);
> > + value |= PCIE_GLI_9767_NORMAL_ERR_INT_SIGNAL_EN_REG2_SDEI_COMPLETE_SIGNAL_EN;
> > + pci_write_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_SIGNAL_EN_REG2, value);
> > +
> > + pci_read_config_dword(pdev, PCIE_GLI_9767_CFG, &value);
> > + value |= PCIE_GLI_9767_CFG_LOW_PWR_OFF;
> > + pci_write_config_dword(pdev, PCIE_GLI_9767_CFG, value);
> > +
> > + value = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
> > + value &= ~(SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_PLL_EN);
> > + sdhci_writew(host, value, SDHCI_CLOCK_CONTROL);
> > +
> > + value = sdhci_readb(host, SDHCI_POWER_CONTROL);
> > + value |= ((SDHCI_POWER_180 | SDHCI_POWER_ON) << 4);
> > + sdhci_writeb(host, value, SDHCI_POWER_CONTROL);
> > +
> > + pci_read_config_dword(pdev, PCIE_GLI_9767_SD_EXPRESS_CTL, &value);
> > + value |= PCIE_GLI_9767_SD_EXPRESS_CTL_SDEI_EXE;
> > + pci_write_config_dword(pdev, PCIE_GLI_9767_SD_EXPRESS_CTL, value);
> > +
> > + for (i = 0; i < 10; i++) {
> > + mdelay(10);
>
> A little question.
> Can you explain or comment on the reason for up to 10 loops (max. 100 ms wait),
> For example "because of asic specs..." or "hardware measurements".
>
> Best regards,
> Ben
>

Because specs define the time between Power valid to CLKREQ at most 1ms.
To be on the safe side I will update to 3 loops(max. 30 ms wait) in Patch v2.

> > + pci_read_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2, &value);
> > + if (value & PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2_SDEI_COMPLETE) {
> > + pci_write_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2,
> > + value);
> > + break;
> > + }
> > + }
> > +
> > + pci_read_config_dword(pdev, PCIE_GLI_9767_SDHC_CAP, &value);
> > + if ((value & PCIE_GLI_9767_SDHC_CAP_SDEI_RESULT) == PCIE_GLI_9767_SDHC_CAP_SDEI_RESULT) {
> > + pci_read_config_dword(pdev, PCIE_GLI_9767_SD_EXPRESS_CTL, &value);
> > + value |= PCIE_GLI_9767_SD_EXPRESS_CTL_SD_EXPRESS_MODE;
> > + pci_write_config_dword(pdev, PCIE_GLI_9767_SD_EXPRESS_CTL, value);
> > + } else {
> > + mmc->ios.timing &= ~(MMC_TIMING_SD_EXP | MMC_TIMING_SD_EXP_1_2V);
> > + }
> > +
> > + pci_read_config_dword(pdev, PCIE_GLI_9767_VHS, &value);
> > + value &= ~GLI_9767_VHS_REV;
> > + value |= FIELD_PREP(GLI_9767_VHS_REV, GLI_9767_VHS_REV_R);
> > + pci_write_config_dword(pdev, PCIE_GLI_9767_VHS, value);
> > +
> > + return 0;
> > +}
> > +
> > static int gli_probe_slot_gl9750(struct sdhci_pci_slot *slot)
> > {
> > struct sdhci_host *host = slot->host;
> > @@ -806,6 +919,8 @@ static int gli_probe_slot_gl9767(struct sdhci_pci_slot *slot)
> > gl9767_hw_setting(slot);
> > gli_pcie_enable_msi(slot);
> > slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO;
> > + host->mmc->caps2 |= MMC_CAP2_SD_EXP;
> > + host->mmc_host_ops.init_sd_express = gl9767_init_sd_express;
> > sdhci_enable_v4_mode(host);
> >
> > return 0;
> > --
> > 2.25.1
> >

Thanks, Victor Shih

2023-05-30 10:10:53

by Victor Shih

[permalink] [raw]
Subject: Re: [PATCH V1 3/3] mmc: sdhci-pci-gli: Add support SD Express card for GL9767

Hi, Adrian

On Mon, May 29, 2023 at 5:36 PM Adrian Hunter <[email protected]> wrote:
>
> On 12/05/23 13:45, Victor Shih wrote:
> > Add support SD Express card for GL9767. The workflow of the
> > SD Express card in GL9767 is as below.
> > 1. GL9767 operates in SD mode and set MMC_CAP2_SD_EXP flag.
> > 2. If card is inserted, Host send CMD8 to ask the capabilities
> > of the card.
> > 3. If the card has PCIe capability and write protect is not
> > enable, then init_sd_express() will be invoked.
>
> Could explain about why not write protect
>

I will update the commit message as below in Patch v2:
If the card has been put in write protect state then the SD features supported
by SD mode but not supported by PCIe mode, therefore GL9767 will switch
to SD mode.

> > 4. GL9767 switch from SD mode to PCIe/NVMe mode and mmc driver
> > handover control to NVMe driver.
> > 5. If card is removed, GL9767 will return to SD mode.
> >
> > Signed-off-by: Ben Chuang <[email protected]>
> > Signed-off-by: Victor Shih <[email protected]>
>
> As Ben pointed out, please try to use the same email address
> for From: and Signed-off-by:
>

I will be careful about this in the Patch v2.

> > ---
> > drivers/mmc/host/sdhci-pci-gli.c | 115 +++++++++++++++++++++++++++++++
> > 1 file changed, 115 insertions(+)
> >
> > diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c
> > index 300512740cb0..a0f9c24439be 100644
> > --- a/drivers/mmc/host/sdhci-pci-gli.c
> > +++ b/drivers/mmc/host/sdhci-pci-gli.c
> > @@ -158,6 +158,13 @@
> > #define GLI_9767_VHS_REV_M 0x1
> > #define GLI_9767_VHS_REV_W 0x2
> >
> > +#define PCIE_GLI_9767_CFG 0x8A0
> > +#define PCIE_GLI_9767_CFG_LOW_PWR_OFF BIT(12)
> > +
> > +#define PCIE_GLI_9767_COMBO_MUX_CTL 0x8C8
> > +#define PCIE_GLI_9767_COMBO_MUX_CTL_RST_EN BIT(6)
> > +#define PCIE_GLI_9767_COMBO_MUX_CTL_WAIT_PERST_EN BIT(10)
> > +
> > #define PCIE_GLI_9767_PWR_MACRO_CTL 0x8D0
> > #define PCIE_GLI_9767_PWR_MACRO_CTL_LOW_VOLTAGE GENMASK(3, 0)
> > #define PCIE_GLI_9767_PWR_MACRO_CTL_LD0_LOW_OUTPUT_VOLTAGE GENMASK(15, 12)
> > @@ -175,6 +182,27 @@
> > #define PCIE_GLI_9767_SCR_CORE_PWR_D3_OFF BIT(21)
> > #define PCIE_GLI_9767_SCR_CFG_RST_DATA_LINK_DOWN BIT(30)
> >
> > +#define PCIE_GLI_9767_SDHC_CAP 0x91C
> > +#define PCIE_GLI_9767_SDHC_CAP_SDEI_RESULT BIT(5)
> > +
> > +#define PCIE_GLI_9767_SD_EXPRESS_CTL 0x940
> > +#define PCIE_GLI_9767_SD_EXPRESS_CTL_SDEI_EXE BIT(0)
> > +#define PCIE_GLI_9767_SD_EXPRESS_CTL_SD_EXPRESS_MODE BIT(1)
> > +
> > +#define PCIE_GLI_9767_SD_DATA_MULTI_CTL 0x944
> > +#define PCIE_GLI_9767_SD_DATA_MULTI_CTL_DISCONNECT_TIME GENMASK(23, 16)
> > +#define PCIE_GLI_9767_SD_DATA_MULTI_CTL_DISCONNECT_TIME_VALUE 0x64
> > +
> > +#define PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2 0x950
> > +#define PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2_SDEI_COMPLETE BIT(0)
> > +#define PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2_SDEI_GEN_TIMER GENMASK(1, 0)
> > +
> > +#define PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_EN_REG2 0x954
> > +#define PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_EN_REG2_SDEI_COMPLETE_STATUS_EN GENMASK(1, 0)
> > +
> > +#define PCIE_GLI_9767_NORMAL_ERR_INT_SIGNAL_EN_REG2 0x958
> > +#define PCIE_GLI_9767_NORMAL_ERR_INT_SIGNAL_EN_REG2_SDEI_COMPLETE_SIGNAL_EN GENMASK(1, 0)
> > +
> > #define GLI_MAX_TUNING_LOOP 40
> >
> > /* Genesys Logic chipset */
> > @@ -774,6 +802,91 @@ static void sdhci_gl9767_reset(struct sdhci_host *host, u8 mask)
> > gli_set_9767(host);
> > }
> >
> > +static int gl9767_init_sd_express(struct mmc_host *mmc, struct mmc_ios *ios)
> > +{
> > + struct sdhci_host *host = mmc_priv(mmc);
> > + struct sdhci_pci_slot *slot = sdhci_priv(host);
> > + struct pci_dev *pdev;
> > + u32 value;
> > + int i;
> > +
> > + pdev = slot->chip->pdev;
> > +
> > + if (sdhci_check_ro(host)) {
>
> I think mmc->get_ro(mmc) would be fine here instead.
>

I will update it in Patch v2.

> > + mmc->ios.timing &= ~(MMC_TIMING_SD_EXP | MMC_TIMING_SD_EXP_1_2V);
> > + return 0;
> > + }
> > +
> > + pci_read_config_dword(pdev, PCIE_GLI_9767_VHS, &value);
> > + value &= ~GLI_9767_VHS_REV;
> > + value |= FIELD_PREP(GLI_9767_VHS_REV, GLI_9767_VHS_REV_W);
> > + pci_write_config_dword(pdev, PCIE_GLI_9767_VHS, value);
> > +
> > + pci_read_config_dword(pdev, PCIE_GLI_9767_COMBO_MUX_CTL, &value);
> > + value &= ~(PCIE_GLI_9767_COMBO_MUX_CTL_RST_EN | PCIE_GLI_9767_COMBO_MUX_CTL_WAIT_PERST_EN);
> > + pci_write_config_dword(pdev, PCIE_GLI_9767_COMBO_MUX_CTL, value);
> > +
> > + pci_read_config_dword(pdev, PCIE_GLI_9767_SD_DATA_MULTI_CTL, &value);
> > + value &= ~PCIE_GLI_9767_SD_DATA_MULTI_CTL_DISCONNECT_TIME;
> > + value |= FIELD_PREP(PCIE_GLI_9767_SD_DATA_MULTI_CTL_DISCONNECT_TIME,
> > + PCIE_GLI_9767_SD_DATA_MULTI_CTL_DISCONNECT_TIME_VALUE);
> > + pci_write_config_dword(pdev, PCIE_GLI_9767_SD_DATA_MULTI_CTL, value);
> > +
> > + pci_read_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2, &value);
> > + value |= PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2_SDEI_GEN_TIMER;
> > + pci_write_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2, value);
> > +
> > + pci_read_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_EN_REG2, &value);
> > + value |= PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_EN_REG2_SDEI_COMPLETE_STATUS_EN;
> > + pci_write_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_EN_REG2, value);
> > +
> > + pci_read_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_SIGNAL_EN_REG2, &value);
> > + value |= PCIE_GLI_9767_NORMAL_ERR_INT_SIGNAL_EN_REG2_SDEI_COMPLETE_SIGNAL_EN;
> > + pci_write_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_SIGNAL_EN_REG2, value);
> > +
> > + pci_read_config_dword(pdev, PCIE_GLI_9767_CFG, &value);
> > + value |= PCIE_GLI_9767_CFG_LOW_PWR_OFF;
> > + pci_write_config_dword(pdev, PCIE_GLI_9767_CFG, value);
> > +
> > + value = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
> > + value &= ~(SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_PLL_EN);
> > + sdhci_writew(host, value, SDHCI_CLOCK_CONTROL);
> > +
> > + value = sdhci_readb(host, SDHCI_POWER_CONTROL);
> > + value |= ((SDHCI_POWER_180 | SDHCI_POWER_ON) << 4);
> > + sdhci_writeb(host, value, SDHCI_POWER_CONTROL);
> > +
> > + pci_read_config_dword(pdev, PCIE_GLI_9767_SD_EXPRESS_CTL, &value);
> > + value |= PCIE_GLI_9767_SD_EXPRESS_CTL_SDEI_EXE;
> > + pci_write_config_dword(pdev, PCIE_GLI_9767_SD_EXPRESS_CTL, value);
> > +
> > + for (i = 0; i < 10; i++) {
> > + mdelay(10);
>
> This should be msleep() or usleep_range()
>

I will update this in Patch v2.

> > + pci_read_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2, &value);
> > + if (value & PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2_SDEI_COMPLETE) {
> > + pci_write_config_dword(pdev, PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2,
> > + value);
> > + break;
> > + }
> > + }
> > +
> > + pci_read_config_dword(pdev, PCIE_GLI_9767_SDHC_CAP, &value);
> > + if ((value & PCIE_GLI_9767_SDHC_CAP_SDEI_RESULT) == PCIE_GLI_9767_SDHC_CAP_SDEI_RESULT) {
> > + pci_read_config_dword(pdev, PCIE_GLI_9767_SD_EXPRESS_CTL, &value);
> > + value |= PCIE_GLI_9767_SD_EXPRESS_CTL_SD_EXPRESS_MODE;
> > + pci_write_config_dword(pdev, PCIE_GLI_9767_SD_EXPRESS_CTL, value);
> > + } else {
> > + mmc->ios.timing &= ~(MMC_TIMING_SD_EXP | MMC_TIMING_SD_EXP_1_2V);
> > + }
> > +
> > + pci_read_config_dword(pdev, PCIE_GLI_9767_VHS, &value);
> > + value &= ~GLI_9767_VHS_REV;
> > + value |= FIELD_PREP(GLI_9767_VHS_REV, GLI_9767_VHS_REV_R);
> > + pci_write_config_dword(pdev, PCIE_GLI_9767_VHS, value);
> > +
> > + return 0;
> > +}
> > +
> > static int gli_probe_slot_gl9750(struct sdhci_pci_slot *slot)
> > {
> > struct sdhci_host *host = slot->host;
> > @@ -806,6 +919,8 @@ static int gli_probe_slot_gl9767(struct sdhci_pci_slot *slot)
> > gl9767_hw_setting(slot);
> > gli_pcie_enable_msi(slot);
> > slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO;
> > + host->mmc->caps2 |= MMC_CAP2_SD_EXP;
> > + host->mmc_host_ops.init_sd_express = gl9767_init_sd_express;
> > sdhci_enable_v4_mode(host);
> >
> > return 0;
>

Thanks, Victor Shih