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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

> +               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
>




[Index of Archives]     [Linux Memonry Technology]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux