Message ID | 20230530095308.8165-4-victorshihgli@gmail.com |
---|---|
State | Superseded |
Headers | show |
Series | Add Genesys Logic GL9767 support | expand |
On 30/05/23 12:53, Victor Shih wrote: > From: Victor Shih <victor.shih@genesyslogic.com.tw> > > 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, then init_sd_express() > will be invoked. > 4. 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 switch to SD mode. > 5. If the card has not been put in write protect state then > GL9767 switch from SD mode to PCIe/NVMe mode and mmc driver > handover control to NVMe driver. > 6. If card is removed, GL9767 will return to SD mode. > > Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw> > Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw> Acked-by: Adrian Hunter <adrian.hunter@intel.com> > --- > drivers/mmc/host/sdhci-pci-gli.c | 105 +++++++++++++++++++++++++++++++ > 1 file changed, 105 insertions(+) > > diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c > index 178253a7e86f..c7fa92fdadcd 100644 > --- a/drivers/mmc/host/sdhci-pci-gli.c > +++ b/drivers/mmc/host/sdhci-pci-gli.c > @@ -164,6 +164,10 @@ > #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) > @@ -181,6 +185,26 @@ > #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_EN_REG2 0x954 > +#define PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_EN_REG2_SDEI_COMPLETE_STATUS_EN BIT(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 BIT(0) > + > #define PCIE_GLI_9767_SD_PLL_CTL 0x938 > #define PCIE_GLI_9767_SD_PLL_CTL_PLL_LDIV GENMASK(9, 0) > #define PCIE_GLI_9767_SD_PLL_CTL_PLL_PDIV GENMASK(15, 12) > @@ -935,6 +959,85 @@ 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 (mmc->ops->get_ro(mmc)) { > + mmc->ios.timing &= ~(MMC_TIMING_SD_EXP | MMC_TIMING_SD_EXP_1_2V); > + return 0; > + } > + > + gl9767_vhs_write(pdev); > + > + 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_COMPLETE; > + 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 < 2; i++) { > + msleep(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); > + } > + > + gl9767_vhs_read(pdev); > + > + return 0; > +} > + > static int gli_probe_slot_gl9750(struct sdhci_pci_slot *slot) > { > struct sdhci_host *host = slot->host; > @@ -967,6 +1070,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;
Hi, Adrian On Wed, May 31, 2023 at 3:15 PM Adrian Hunter <adrian.hunter@intel.com> wrote: > > On 30/05/23 12:53, Victor Shih wrote: > > From: Victor Shih <victor.shih@genesyslogic.com.tw> > > > > 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, then init_sd_express() > > will be invoked. > > 4. 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 switch to SD mode. > > 5. If the card has not been put in write protect state then > > GL9767 switch from SD mode to PCIe/NVMe mode and mmc driver > > handover control to NVMe driver. > > 6. If card is removed, GL9767 will return to SD mode. > > > > Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw> > > Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw> > > Acked-by: Adrian Hunter <adrian.hunter@intel.com> > Excuse me, I will adjust the order of definitions and modify the if-else condition and content in gl9767_init_sd_express() function, please help to review it once, thank you. > > --- > > drivers/mmc/host/sdhci-pci-gli.c | 105 +++++++++++++++++++++++++++++++ > > 1 file changed, 105 insertions(+) > > > > diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c > > index 178253a7e86f..c7fa92fdadcd 100644 > > --- a/drivers/mmc/host/sdhci-pci-gli.c > > +++ b/drivers/mmc/host/sdhci-pci-gli.c > > @@ -164,6 +164,10 @@ > > #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) > > @@ -181,6 +185,26 @@ > > #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_EN_REG2 0x954 > > +#define PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_EN_REG2_SDEI_COMPLETE_STATUS_EN BIT(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 BIT(0) > > + > > #define PCIE_GLI_9767_SD_PLL_CTL 0x938 > > #define PCIE_GLI_9767_SD_PLL_CTL_PLL_LDIV GENMASK(9, 0) > > #define PCIE_GLI_9767_SD_PLL_CTL_PLL_PDIV GENMASK(15, 12) > > @@ -935,6 +959,85 @@ 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 (mmc->ops->get_ro(mmc)) { > > + mmc->ios.timing &= ~(MMC_TIMING_SD_EXP | MMC_TIMING_SD_EXP_1_2V); > > + return 0; > > + } > > + > > + gl9767_vhs_write(pdev); > > + > > + 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_COMPLETE; > > + 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 < 2; i++) { > > + msleep(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); > > + } > > + > > + gl9767_vhs_read(pdev); > > + > > + return 0; > > +} > > + > > static int gli_probe_slot_gl9750(struct sdhci_pci_slot *slot) > > { > > struct sdhci_host *host = slot->host; > > @@ -967,6 +1070,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
diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c index 178253a7e86f..c7fa92fdadcd 100644 --- a/drivers/mmc/host/sdhci-pci-gli.c +++ b/drivers/mmc/host/sdhci-pci-gli.c @@ -164,6 +164,10 @@ #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) @@ -181,6 +185,26 @@ #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_EN_REG2 0x954 +#define PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_EN_REG2_SDEI_COMPLETE_STATUS_EN BIT(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 BIT(0) + #define PCIE_GLI_9767_SD_PLL_CTL 0x938 #define PCIE_GLI_9767_SD_PLL_CTL_PLL_LDIV GENMASK(9, 0) #define PCIE_GLI_9767_SD_PLL_CTL_PLL_PDIV GENMASK(15, 12) @@ -935,6 +959,85 @@ 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 (mmc->ops->get_ro(mmc)) { + mmc->ios.timing &= ~(MMC_TIMING_SD_EXP | MMC_TIMING_SD_EXP_1_2V); + return 0; + } + + gl9767_vhs_write(pdev); + + 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_COMPLETE; + 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 < 2; i++) { + msleep(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); + } + + gl9767_vhs_read(pdev); + + return 0; +} + static int gli_probe_slot_gl9750(struct sdhci_pci_slot *slot) { struct sdhci_host *host = slot->host; @@ -967,6 +1070,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;