On 30/05/23 12:53, Victor Shih wrote: > From: Victor Shih <victor.shih@xxxxxxxxxxxxxxxxxxx> > > 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@xxxxxxxxxxxxxxxxxxx> > Signed-off-by: Victor Shih <victor.shih@xxxxxxxxxxxxxxxxxxx> Acked-by: Adrian Hunter <adrian.hunter@xxxxxxxxx> > --- > 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;