mmc: sdhci-uhs2: add set_timeout()

This is a UHS-II version of sdhci's set_timeout() operation.
Use sdhci_uhs2_set_timeout() to set and calculate the timeout time.

Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Message-ID: <20241018105333.4569-8-victorshihgli@gmail.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
This commit is contained in:
Victor Shih 2024-10-18 18:53:24 +08:00 committed by Ulf Hansson
parent 6eb2c8e18f
commit 7e5b19f3a7
2 changed files with 74 additions and 0 deletions

View File

@ -13,6 +13,7 @@
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/iopoll.h>
#include <linux/bitfield.h>
#include "sdhci.h"
#include "sdhci-uhs2.h"
@ -135,6 +136,77 @@ void sdhci_uhs2_set_power(struct sdhci_host *host, unsigned char mode, unsigned
}
EXPORT_SYMBOL_GPL(sdhci_uhs2_set_power);
static u8 sdhci_calc_timeout_uhs2(struct sdhci_host *host, u8 *cmd_res, u8 *dead_lock)
{
/* timeout in us */
unsigned int dead_lock_timeout = 1 * 1000 * 1000;
unsigned int cmd_res_timeout = 5 * 1000;
unsigned int current_timeout;
u8 count;
/*
* Figure out needed cycles.
* We do this in steps in order to fit inside a 32 bit int.
* The first step is the minimum timeout, which will have a
* minimum resolution of 6 bits:
* (1) 2^13*1000 > 2^22,
* (2) host->timeout_clk < 2^16
* =>
* (1) / (2) > 2^6
*/
count = 0;
current_timeout = (1 << 13) * 1000 / host->timeout_clk;
while (current_timeout < cmd_res_timeout) {
count++;
current_timeout <<= 1;
if (count >= 0xF)
break;
}
if (count >= 0xF) {
DBG("%s: Too large timeout 0x%x requested for CMD_RES!\n",
mmc_hostname(host->mmc), count);
count = 0xE;
}
*cmd_res = count;
count = 0;
current_timeout = (1 << 13) * 1000 / host->timeout_clk;
while (current_timeout < dead_lock_timeout) {
count++;
current_timeout <<= 1;
if (count >= 0xF)
break;
}
if (count >= 0xF) {
DBG("%s: Too large timeout 0x%x requested for DEADLOCK!\n",
mmc_hostname(host->mmc), count);
count = 0xE;
}
*dead_lock = count;
return count;
}
static void __sdhci_uhs2_set_timeout(struct sdhci_host *host)
{
u8 cmd_res, dead_lock;
sdhci_calc_timeout_uhs2(host, &cmd_res, &dead_lock);
cmd_res |= FIELD_PREP(SDHCI_UHS2_TIMER_CTRL_DEADLOCK_MASK, dead_lock);
sdhci_writeb(host, cmd_res, SDHCI_UHS2_TIMER_CTRL);
}
void sdhci_uhs2_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
{
__sdhci_set_timeout(host, cmd);
if (mmc_card_uhs2(host->mmc))
__sdhci_uhs2_set_timeout(host);
}
EXPORT_SYMBOL_GPL(sdhci_uhs2_set_timeout);
/*****************************************************************************\
* *
* Driver init/exit *

View File

@ -173,9 +173,11 @@
#define SDHCI_UHS2_VENDOR_PTR 0xE8
struct sdhci_host;
struct mmc_command;
void sdhci_uhs2_dump_regs(struct sdhci_host *host);
void sdhci_uhs2_reset(struct sdhci_host *host, u16 mask);
void sdhci_uhs2_set_power(struct sdhci_host *host, unsigned char mode, unsigned short vdd);
void sdhci_uhs2_set_timeout(struct sdhci_host *host, struct mmc_command *cmd);
#endif /* __SDHCI_UHS2_H */