[PATCH v4 05/38] mmc: dw_mmc: Extract divider update to a separate function
Sam Protsenko
semen.protsenko at linaro.org
Thu Jul 25 22:44:47 CEST 2024
Extract the clock divider update into dwmci_update_div() function. It's
a procedure recommended in TRM, so it's better to keep it in a dedicated
function to make the code clearer.
While at it also extract the clock control code into a separate routine
to avoid code duplication in dwmci_setup_bus().
No functional change.
Signed-off-by: Sam Protsenko <semen.protsenko at linaro.org>
---
Changes in v4:
- (none)
Changes in v3:
- (none)
Changes in v2:
- Moved CLKSRC after disabling the clock as recommended in TRM, to
avoid possible glitch
- Extracted div update into a separate function with corresponding
comment
- Changed the patch subject and reworked the commit message
drivers/mmc/dw_mmc.c | 81 +++++++++++++++++++++++++++-----------------
1 file changed, 50 insertions(+), 31 deletions(-)
diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c
index 4a9e57165fbb..b9c14fe6857b 100644
--- a/drivers/mmc/dw_mmc.c
+++ b/drivers/mmc/dw_mmc.c
@@ -410,11 +410,56 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
return ret;
}
-static int dwmci_setup_bus(struct dwmci_host *host, u32 freq)
+static int dwmci_control_clken(struct dwmci_host *host, bool on)
{
- u32 div, status;
+ const u32 val = on ? DWMCI_CLKEN_ENABLE | DWMCI_CLKEN_LOW_PWR : 0;
+ const u32 cmd_only_clk = DWMCI_CMD_PRV_DAT_WAIT | DWMCI_CMD_UPD_CLK;
int timeout = 10000;
+ u32 status;
+
+ dwmci_writel(host, DWMCI_CLKENA, val);
+
+ /* Inform CIU */
+ dwmci_writel(host, DWMCI_CMD, DWMCI_CMD_START | cmd_only_clk);
+ do {
+ status = dwmci_readl(host, DWMCI_CMD);
+ if (timeout-- < 0) {
+ debug("%s: Timeout!\n", __func__);
+ return -ETIMEDOUT;
+ }
+ } while (status & DWMCI_CMD_START);
+
+ return 0;
+}
+
+/*
+ * Update the clock divider.
+ *
+ * To prevent a clock glitch keep the clock stopped during the update of
+ * clock divider and clock source.
+ */
+static int dwmci_update_div(struct dwmci_host *host, u32 div)
+{
+ int ret;
+
+ /* Disable clock */
+ ret = dwmci_control_clken(host, false);
+ if (ret)
+ return ret;
+
+ /* Set clock to desired speed */
+ dwmci_writel(host, DWMCI_CLKDIV, div);
+ dwmci_writel(host, DWMCI_CLKSRC, 0);
+
+ /* Enable clock */
+ return dwmci_control_clken(host, true);
+}
+
+static int dwmci_setup_bus(struct dwmci_host *host, u32 freq)
+{
+ u32 div;
unsigned long sclk;
+ int ret;
if ((freq == host->clock) || (freq == 0))
return 0;
@@ -437,35 +482,9 @@ static int dwmci_setup_bus(struct dwmci_host *host, u32 freq)
else
div = DIV_ROUND_UP(sclk, 2 * freq);
- dwmci_writel(host, DWMCI_CLKENA, 0);
- dwmci_writel(host, DWMCI_CLKSRC, 0);
-
- dwmci_writel(host, DWMCI_CLKDIV, div);
- dwmci_writel(host, DWMCI_CMD, DWMCI_CMD_PRV_DAT_WAIT |
- DWMCI_CMD_UPD_CLK | DWMCI_CMD_START);
-
- do {
- status = dwmci_readl(host, DWMCI_CMD);
- if (timeout-- < 0) {
- debug("%s: Timeout!\n", __func__);
- return -ETIMEDOUT;
- }
- } while (status & DWMCI_CMD_START);
-
- dwmci_writel(host, DWMCI_CLKENA, DWMCI_CLKEN_ENABLE |
- DWMCI_CLKEN_LOW_PWR);
-
- dwmci_writel(host, DWMCI_CMD, DWMCI_CMD_PRV_DAT_WAIT |
- DWMCI_CMD_UPD_CLK | DWMCI_CMD_START);
-
- timeout = 10000;
- do {
- status = dwmci_readl(host, DWMCI_CMD);
- if (timeout-- < 0) {
- debug("%s: Timeout!\n", __func__);
- return -ETIMEDOUT;
- }
- } while (status & DWMCI_CMD_START);
+ ret = dwmci_update_div(host, div);
+ if (ret)
+ return ret;
host->clock = freq;
--
2.39.2
More information about the U-Boot
mailing list