mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-06 13:23:18 +00:00
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:
parent
6eb2c8e18f
commit
7e5b19f3a7
@ -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 *
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user