Hi, Ben On Mon, May 15, 2023 at 8:15 AM Ben Chuang <benchuanggli@xxxxxxxxx> wrote: > > Hi Victor, > > On Fri, May 12, 2023 at 6:47 PM Victor Shih <victorshihgli@xxxxxxxxx> 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 <ben.chuang@xxxxxxxxxxxxxxxxxxx> > > Signed-off-by: Victor Shih <victor.shih@xxxxxxxxxxxxxxxxxxx> > > --- > > 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