Message ID | 20241101-imx-emmc-reset-v3-1-184965eed476@solid-run.com |
---|---|
State | New |
Headers | show |
Series | mmc: host: sdhci-esdhc-imx: implement emmc hardware reset | expand |
> -----Original Message----- > From: Josua Mayer <josua@solid-run.com> > Sent: 2024年11月1日 19:42 > To: Adrian Hunter <adrian.hunter@intel.com>; Bough Chen > <haibo.chen@nxp.com>; Ulf Hansson <ulf.hansson@linaro.org>; Shawn Guo > <shawnguo@kernel.org>; Sascha Hauer <s.hauer@pengutronix.de>; > Pengutronix Kernel Team <kernel@pengutronix.de>; Fabio Estevam > <festevam@gmail.com> > Cc: Mikhail Anikin <mikhail.anikin@solid-run.com>; Jon Nettleton > <jon@solid-run.com>; yazan.shhady <yazan.shhady@solid-run.com>; Rabeeh > Khoury <rabeeh@solid-run.com>; imx@lists.linux.dev; > linux-mmc@vger.kernel.org; dl-S32 <S32@nxp.com>; > linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org; Josua > Mayer <josua@solid-run.com> > Subject: [PATCH v3 1/2] mmc: host: sdhci-esdhc-imx: implement emmc > hardware reset > > NXP ESDHC supports control of native emmc reset signal when pinmux is set > accordingly, using uSDHCx_SYS_CTRL register IPP_RST_N bit. > Documentation is available in NXP i.MX6Q Reference Manual. > > Implement the hw_reset function in sdhci_ops asserting reset for at least 1us > and waiting at least 200us after deassertion. > Lower bounds are based on: > JEDEC Standard No. 84-B51, 6.15.10 H/W Reset Operation, page 159. > Upper bounds are chosen allowing flexibility to the scheduler. > > Tested on SolidRun i.MX8DXL SoM with a scope, and confirmed that eMMC is > still accessible after boot: > - eMMC extcsd has RST_N_FUNCTION=0x01 > - sdhc node has cap-mmc-hw-reset > - pinmux set for EMMC0_RESET_B > - Linux v5.15 Reviewed-by: Haibo Chen <haibo.chen@nxp.com> Best Regards Haibo Chen > > Signed-off-by: Josua Mayer <josua@solid-run.com> > --- > drivers/mmc/host/sdhci-esdhc-imx.c | 13 +++++++++++++ > 1 file changed, 13 insertions(+) > > diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c > b/drivers/mmc/host/sdhci-esdhc-imx.c > index > 8f0bc6dca2b0402fd2a0695903cf261a5b4e19dc..f106e291c276d0c8063e9ac59 > a126acf5e9e239e 100644 > --- a/drivers/mmc/host/sdhci-esdhc-imx.c > +++ b/drivers/mmc/host/sdhci-esdhc-imx.c > @@ -31,6 +31,7 @@ > #include "cqhci.h" > > #define ESDHC_SYS_CTRL_DTOCV_MASK 0x0f > +#define ESDHC_SYS_CTRL_IPP_RST_N BIT(23) > #define ESDHC_CTRL_D3CD 0x08 > #define ESDHC_BURST_LEN_EN_INCR (1 << 27) > /* VENDOR SPEC register */ > @@ -1402,6 +1403,17 @@ static u32 esdhc_cqhci_irq(struct sdhci_host *host, > u32 intmask) > return 0; > } > > +static void esdhc_hw_reset(struct sdhci_host *host) { > + esdhc_clrset_le(host, ESDHC_SYS_CTRL_IPP_RST_N, 0, > ESDHC_SYSTEM_CONTROL); > + /* eMMC spec requires minimum 1us, here delay between 1-10us */ > + usleep_range(1, 10); > + esdhc_clrset_le(host, ESDHC_SYS_CTRL_IPP_RST_N, > + ESDHC_SYS_CTRL_IPP_RST_N, ESDHC_SYSTEM_CONTROL); > + /* eMMC spec requires minimum 200us, here delay between 200-300us */ > + usleep_range(200, 300); > +} > + > static struct sdhci_ops sdhci_esdhc_ops = { > .read_l = esdhc_readl_le, > .read_w = esdhc_readw_le, > @@ -1420,6 +1432,7 @@ static struct sdhci_ops sdhci_esdhc_ops = { > .reset = esdhc_reset, > .irq = esdhc_cqhci_irq, > .dump_vendor_regs = esdhc_dump_debug_regs, > + .hw_reset = esdhc_hw_reset, > }; > > static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { > > -- > 2.43.0
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 8f0bc6dca2b0402fd2a0695903cf261a5b4e19dc..f106e291c276d0c8063e9ac59a126acf5e9e239e 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -31,6 +31,7 @@ #include "cqhci.h" #define ESDHC_SYS_CTRL_DTOCV_MASK 0x0f +#define ESDHC_SYS_CTRL_IPP_RST_N BIT(23) #define ESDHC_CTRL_D3CD 0x08 #define ESDHC_BURST_LEN_EN_INCR (1 << 27) /* VENDOR SPEC register */ @@ -1402,6 +1403,17 @@ static u32 esdhc_cqhci_irq(struct sdhci_host *host, u32 intmask) return 0; } +static void esdhc_hw_reset(struct sdhci_host *host) +{ + esdhc_clrset_le(host, ESDHC_SYS_CTRL_IPP_RST_N, 0, ESDHC_SYSTEM_CONTROL); + /* eMMC spec requires minimum 1us, here delay between 1-10us */ + usleep_range(1, 10); + esdhc_clrset_le(host, ESDHC_SYS_CTRL_IPP_RST_N, + ESDHC_SYS_CTRL_IPP_RST_N, ESDHC_SYSTEM_CONTROL); + /* eMMC spec requires minimum 200us, here delay between 200-300us */ + usleep_range(200, 300); +} + static struct sdhci_ops sdhci_esdhc_ops = { .read_l = esdhc_readl_le, .read_w = esdhc_readw_le, @@ -1420,6 +1432,7 @@ static struct sdhci_ops sdhci_esdhc_ops = { .reset = esdhc_reset, .irq = esdhc_cqhci_irq, .dump_vendor_regs = esdhc_dump_debug_regs, + .hw_reset = esdhc_hw_reset, }; static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
NXP ESDHC supports control of native emmc reset signal when pinmux is set accordingly, using uSDHCx_SYS_CTRL register IPP_RST_N bit. Documentation is available in NXP i.MX6Q Reference Manual. Implement the hw_reset function in sdhci_ops asserting reset for at least 1us and waiting at least 200us after deassertion. Lower bounds are based on: JEDEC Standard No. 84-B51, 6.15.10 H/W Reset Operation, page 159. Upper bounds are chosen allowing flexibility to the scheduler. Tested on SolidRun i.MX8DXL SoM with a scope, and confirmed that eMMC is still accessible after boot: - eMMC extcsd has RST_N_FUNCTION=0x01 - sdhc node has cap-mmc-hw-reset - pinmux set for EMMC0_RESET_B - Linux v5.15 Signed-off-by: Josua Mayer <josua@solid-run.com> --- drivers/mmc/host/sdhci-esdhc-imx.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)