Message ID | 20230531111518.396868-5-victorshihgli@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Add Genesys Logic GL9767 support | expand |
On 31/05/23 14:15, 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 | 113 +++++++++++++++++++++++++++++++ > 1 file changed, 113 insertions(+) > > diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c > index 392a106cea18..e47236e3b89a 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,9 @@ > #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_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) > @@ -191,6 +198,23 @@ > #define PCIE_GLI_9767_SD_PLL_CTL2 0x93C > #define PCIE_GLI_9767_SD_PLL_CTL2_PLLSSC_PPM GENMASK(31, 16) > > +#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 GLI_MAX_TUNING_LOOP 40 > > /* Genesys Logic chipset */ > @@ -935,6 +959,93 @@ 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_VDD2_POWER_180 | SDHCI_VDD2_POWER_ON); > + 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) { > + 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); > + > + value = sdhci_readb(host, SDHCI_POWER_CONTROL); > + value &= ~(SDHCI_VDD2_POWER_180 | SDHCI_VDD2_POWER_ON); > + sdhci_writeb(host, value, SDHCI_POWER_CONTROL); > + > + value = sdhci_readw(host, SDHCI_CLOCK_CONTROL); > + value |= (SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_PLL_EN); > + sdhci_writew(host, value, SDHCI_CLOCK_CONTROL); > + } > + > + 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 +1078,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;
diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c index 392a106cea18..e47236e3b89a 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,9 @@ #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_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) @@ -191,6 +198,23 @@ #define PCIE_GLI_9767_SD_PLL_CTL2 0x93C #define PCIE_GLI_9767_SD_PLL_CTL2_PLLSSC_PPM GENMASK(31, 16) +#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 GLI_MAX_TUNING_LOOP 40 /* Genesys Logic chipset */ @@ -935,6 +959,93 @@ 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_VDD2_POWER_180 | SDHCI_VDD2_POWER_ON); + 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) { + 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); + + value = sdhci_readb(host, SDHCI_POWER_CONTROL); + value &= ~(SDHCI_VDD2_POWER_180 | SDHCI_VDD2_POWER_ON); + sdhci_writeb(host, value, SDHCI_POWER_CONTROL); + + value = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + value |= (SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_PLL_EN); + sdhci_writew(host, value, SDHCI_CLOCK_CONTROL); + } + + 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 +1078,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;