[PATCH 06/42] mmc: dw_mmc: Extract clock on/off code into a separate routine
Quentin Schulz
quentin.schulz at cherry.de
Thu May 23 16:36:35 CEST 2024
Hi Sam,
On 5/23/24 1:30 AM, Sam Protsenko wrote:
> Extract clock control code into a separate routine to avoid code
> duplication in dwmci_setup_bus().
>
> No functional change.
>
There are some differences though.
> Signed-off-by: Sam Protsenko <semen.protsenko at linaro.org>
> ---
> drivers/mmc/dw_mmc.c | 60 ++++++++++++++++++++++++--------------------
> 1 file changed, 33 insertions(+), 27 deletions(-)
>
> diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c
> index cbfb8d3b8683..40b9b034f793 100644
> --- a/drivers/mmc/dw_mmc.c
> +++ b/drivers/mmc/dw_mmc.c
> @@ -412,11 +412,33 @@ 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;
> +}
> +
> +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;
> @@ -439,35 +461,19 @@ 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);
> + /* Disable clock */
> dwmci_writel(host, DWMCI_CLKSRC, 0);
> + ret = dwmci_control_clken(host, false);
Here, CLKENA and CLKSRC are swapped. The kernel still calls CLKENA
before CLKSRC, is this really safe? (I have no documentation so cannot
tell). E.g., we could have CLKSRC register be a way to select the clock
parent/source, 0 could be 24MHz crystal for example, so switching to
this new parent before disabling the clock output would likely result in
glitches?
> + if (ret)
> + return ret;
>
> + /* Set clock to desired speed */
> dwmci_writel(host, DWMCI_CLKDIV, div);
Same here, CLKDIV is set now after the CIU is informed, is this an
issue? We may want to set the clock speed before we enable the clock
again. Right now it's setting the desired speed while disabled, inform
the CIU, enable the clock, inform the CIU. This now does, disable the
clock, inform the CIU, set the desired speed, enable the clock, inform
the CIU. We may need to wait for the clock to stabilize before enabling
it? Again, just making guesses, no documentation for me here :/
> - 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);
> + /* Enable clock */
> + ret = dwmci_control_clken(host, true);
> + if (ret)
> + return ret;
>
> host->clock = freq;
>
Cheers,
Quentin
More information about the U-Boot
mailing list