mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 10:00:17 +00:00
Revert "bcm2835-sdhost: Precalc divisors and overclocks"
This reverts commit 2026046277.
This commit is contained in:
@@ -154,15 +154,12 @@ struct bcm2835_host {
|
|||||||
u32 pio_timeout; /* In jiffies */
|
u32 pio_timeout; /* In jiffies */
|
||||||
|
|
||||||
int clock; /* Current clock speed */
|
int clock; /* Current clock speed */
|
||||||
int clocks[2];
|
|
||||||
|
|
||||||
bool slow_card; /* Force 11-bit divisor */
|
bool slow_card; /* Force 11-bit divisor */
|
||||||
|
|
||||||
unsigned int max_clk; /* Max src clock freq */
|
unsigned int max_clk; /* Max src clock freq */
|
||||||
unsigned int src_clks[2]; /* Min/max src clock freqs */
|
unsigned int min_clk; /* Min src clock freq */
|
||||||
unsigned int cur_clk_idx; /* Index of current clock */
|
unsigned int cur_clk; /* Current src clock freq */
|
||||||
unsigned int next_clk_idx; /* Next clock index */
|
|
||||||
unsigned int cdivs[2];
|
|
||||||
|
|
||||||
struct tasklet_struct finish_tasklet; /* Tasklet structures */
|
struct tasklet_struct finish_tasklet; /* Tasklet structures */
|
||||||
|
|
||||||
@@ -216,7 +213,7 @@ struct bcm2835_host {
|
|||||||
u32 delay_after_stop; /* minimum time between stop and subsequent data transfer */
|
u32 delay_after_stop; /* minimum time between stop and subsequent data transfer */
|
||||||
u32 delay_after_this_stop; /* minimum time between this stop and subsequent data transfer */
|
u32 delay_after_this_stop; /* minimum time between this stop and subsequent data transfer */
|
||||||
u32 overclock_50; /* frequency to use when 50MHz is requested (in MHz) */
|
u32 overclock_50; /* frequency to use when 50MHz is requested (in MHz) */
|
||||||
u32 prev_overclock_50;
|
u32 overclock; /* Current frequency if overclocked, else zero */
|
||||||
u32 pio_limit; /* Maximum block count for PIO (0 = always DMA) */
|
u32 pio_limit; /* Maximum block count for PIO (0 = always DMA) */
|
||||||
|
|
||||||
u32 sectors; /* Cached card size in sectors */
|
u32 sectors; /* Cached card size in sectors */
|
||||||
@@ -1512,35 +1509,10 @@ static irqreturn_t bcm2835_sdhost_irq(int irq, void *dev_id)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bcm2835_sdhost_select_clock(struct bcm2835_host *host, int idx)
|
|
||||||
{
|
|
||||||
unsigned int clock = host->clocks[idx];
|
|
||||||
unsigned int cdiv = host->cdivs[idx];
|
|
||||||
|
|
||||||
host->mmc->actual_clock = clock;
|
|
||||||
host->ns_per_fifo_word = (1000000000/clock) *
|
|
||||||
((host->mmc->caps & MMC_CAP_4_BIT_DATA) ? 8 : 32);
|
|
||||||
|
|
||||||
host->cdiv = cdiv;
|
|
||||||
bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
|
|
||||||
|
|
||||||
/* Set the timeout to 500ms */
|
|
||||||
bcm2835_sdhost_write(host, clock/2, SDTOUT);
|
|
||||||
|
|
||||||
host->cur_clk_idx = host->next_clk_idx = idx;
|
|
||||||
|
|
||||||
if (host->debug)
|
|
||||||
pr_info("%s: clock=%d -> src_clk=%d, cdiv=%x (actual %d)\n",
|
|
||||||
mmc_hostname(host->mmc), host->clock,
|
|
||||||
host->src_clks[idx], host->cdiv,
|
|
||||||
host->mmc->actual_clock);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bcm2835_sdhost_set_clock(struct bcm2835_host *host)
|
void bcm2835_sdhost_set_clock(struct bcm2835_host *host)
|
||||||
{
|
{
|
||||||
int div = 0; /* Initialized for compiler warning */
|
int div = 0; /* Initialized for compiler warning */
|
||||||
unsigned int clock = host->clock;
|
unsigned int clock = host->clock;
|
||||||
int clk_idx;
|
|
||||||
|
|
||||||
if (host->debug)
|
if (host->debug)
|
||||||
pr_info("%s: set_clock(%d)\n", mmc_hostname(host->mmc), clock);
|
pr_info("%s: set_clock(%d)\n", mmc_hostname(host->mmc), clock);
|
||||||
@@ -1581,45 +1553,53 @@ void bcm2835_sdhost_set_clock(struct bcm2835_host *host)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calculate the clock divisors */
|
div = host->cur_clk / clock;
|
||||||
for (clk_idx = 0; clk_idx <= host->variable_clock; clk_idx++)
|
|
||||||
{
|
|
||||||
unsigned int cur_clk = host->src_clks[clk_idx];
|
|
||||||
unsigned int actual_clock;
|
|
||||||
|
|
||||||
div = cur_clk / clock;
|
|
||||||
if (div < 2)
|
if (div < 2)
|
||||||
div = 2;
|
div = 2;
|
||||||
if ((cur_clk / div) > clock)
|
if ((host->cur_clk / div) > clock)
|
||||||
div++;
|
div++;
|
||||||
div -= 2;
|
div -= 2;
|
||||||
|
|
||||||
if (div > SDCDIV_MAX_CDIV)
|
if (div > SDCDIV_MAX_CDIV)
|
||||||
div = SDCDIV_MAX_CDIV;
|
div = SDCDIV_MAX_CDIV;
|
||||||
actual_clock = cur_clk / (div + 2);
|
|
||||||
|
|
||||||
host->cdivs[clk_idx] = div;
|
clock = host->cur_clk / (div + 2);
|
||||||
host->clocks[clk_idx] = actual_clock;
|
host->mmc->actual_clock = clock;
|
||||||
|
|
||||||
if (host->overclock_50 != host->prev_overclock_50) {
|
/* Calibrate some delays */
|
||||||
const char *clk_name = "";
|
|
||||||
if (host->variable_clock)
|
host->ns_per_fifo_word = (1000000000/clock) *
|
||||||
clk_name = clk_idx ? " (turbo)" : " (normal)";
|
((host->mmc->caps & MMC_CAP_4_BIT_DATA) ? 8 : 32);
|
||||||
if (actual_clock > host->clock)
|
|
||||||
pr_info("%s: overclocking to %dHz%s\n",
|
if (clock > host->clock) {
|
||||||
mmc_hostname(host->mmc),
|
/* Save the closest value, to make it easier
|
||||||
actual_clock, clk_name);
|
to reduce in the event of error */
|
||||||
else if ((host->overclock_50 < 50) && (clk_idx == 0))
|
host->overclock_50 = (clock/MHZ);
|
||||||
pr_info("%s: cancelling overclock%s\n",
|
|
||||||
mmc_hostname(host->mmc),
|
if (clock != host->overclock) {
|
||||||
host->variable_clock ? "s" : "");
|
pr_warn("%s: overclocking to %dHz\n",
|
||||||
|
mmc_hostname(host->mmc), clock);
|
||||||
|
host->overclock = clock;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (host->overclock)
|
||||||
|
{
|
||||||
|
host->overclock = 0;
|
||||||
|
if (clock == 50 * MHZ)
|
||||||
|
pr_warn("%s: cancelling overclock\n",
|
||||||
|
mmc_hostname(host->mmc));
|
||||||
|
}
|
||||||
|
|
||||||
if (host->clock == 50*MHZ)
|
host->cdiv = div;
|
||||||
host->prev_overclock_50 = host->overclock_50;
|
bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
|
||||||
|
|
||||||
bcm2835_sdhost_select_clock(host, host->cur_clk_idx);
|
/* Set the timeout to 500ms */
|
||||||
|
bcm2835_sdhost_write(host, host->mmc->actual_clock/2, SDTOUT);
|
||||||
|
|
||||||
|
if (host->debug)
|
||||||
|
pr_info("%s: clock=%d -> cur_clk=%d, cdiv=%x (actual clock %d)\n",
|
||||||
|
mmc_hostname(host->mmc), host->clock,
|
||||||
|
host->cur_clk, host->cdiv, host->mmc->actual_clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bcm2835_sdhost_request(struct mmc_host *mmc, struct mmc_request *mrq)
|
static void bcm2835_sdhost_request(struct mmc_host *mmc, struct mmc_request *mrq)
|
||||||
@@ -1677,9 +1657,6 @@ static void bcm2835_sdhost_request(struct mmc_host *mmc, struct mmc_request *mrq
|
|||||||
|
|
||||||
spin_lock_irqsave(&host->lock, flags);
|
spin_lock_irqsave(&host->lock, flags);
|
||||||
|
|
||||||
if (host->next_clk_idx != host->cur_clk_idx)
|
|
||||||
bcm2835_sdhost_select_clock(host, host->next_clk_idx);
|
|
||||||
|
|
||||||
WARN_ON(host->mrq != NULL);
|
WARN_ON(host->mrq != NULL);
|
||||||
host->mrq = mrq;
|
host->mrq = mrq;
|
||||||
|
|
||||||
@@ -1742,7 +1719,11 @@ static int bcm2835_sdhost_cpufreq_callback(struct notifier_block *nb,
|
|||||||
return NOTIFY_BAD;
|
return NOTIFY_BAD;
|
||||||
break;
|
break;
|
||||||
case CPUFREQ_POSTCHANGE:
|
case CPUFREQ_POSTCHANGE:
|
||||||
host->next_clk_idx = (freq->new > freq->old);
|
if (freq->new > freq->old)
|
||||||
|
host->cur_clk = host->max_clk;
|
||||||
|
else
|
||||||
|
host->cur_clk = host->min_clk;
|
||||||
|
bcm2835_sdhost_set_clock(host);
|
||||||
up(&host->cpufreq_semaphore);
|
up(&host->cpufreq_semaphore);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -1782,11 +1763,8 @@ static void bcm2835_sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
|||||||
ios->clock, ios->power_mode, ios->bus_width,
|
ios->clock, ios->power_mode, ios->bus_width,
|
||||||
ios->timing, ios->signal_voltage, ios->drv_type);
|
ios->timing, ios->signal_voltage, ios->drv_type);
|
||||||
|
|
||||||
if (ios->clock && (host->cur_clk_idx == -1)) {
|
if (ios->clock && !host->cur_clk)
|
||||||
unsigned int cur_clk =
|
host->cur_clk = get_core_clock(RPI_FIRMWARE_GET_CLOCK_RATE);
|
||||||
get_core_clock(RPI_FIRMWARE_GET_CLOCK_RATE);
|
|
||||||
host->cur_clk_idx = (cur_clk == host->src_clks[0]) ? 0 : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_lock_irqsave(&host->lock, flags);
|
spin_lock_irqsave(&host->lock, flags);
|
||||||
|
|
||||||
@@ -1876,12 +1854,11 @@ static void bcm2835_sdhost_tasklet_finish(unsigned long param)
|
|||||||
|
|
||||||
/* Drop the overclock after any data corruption, or after any
|
/* Drop the overclock after any data corruption, or after any
|
||||||
error overclocked */
|
error overclocked */
|
||||||
if (host->clock > 50*MHZ) {
|
if (host->overclock) {
|
||||||
if ((mrq->cmd && mrq->cmd->error) ||
|
if ((mrq->cmd && mrq->cmd->error) ||
|
||||||
(mrq->data && mrq->data->error) ||
|
(mrq->data && mrq->data->error) ||
|
||||||
(mrq->stop && mrq->stop->error)) {
|
(mrq->stop && mrq->stop->error)) {
|
||||||
host->overclock_50 = (host->clock/MHZ) - 1;
|
host->overclock_50--;
|
||||||
|
|
||||||
pr_warn("%s: reducing overclock due to errors\n",
|
pr_warn("%s: reducing overclock due to errors\n",
|
||||||
mmc_hostname(host->mmc));
|
mmc_hostname(host->mmc));
|
||||||
bcm2835_sdhost_set_clock(host);
|
bcm2835_sdhost_set_clock(host);
|
||||||
@@ -2045,7 +2022,7 @@ static int bcm2835_sdhost_probe(struct platform_device *pdev)
|
|||||||
struct bcm2835_host *host;
|
struct bcm2835_host *host;
|
||||||
struct mmc_host *mmc;
|
struct mmc_host *mmc;
|
||||||
const __be32 *addr;
|
const __be32 *addr;
|
||||||
unsigned int max_clk, min_clk;
|
unsigned int max_clk;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
pr_debug("bcm2835_sdhost_probe\n");
|
pr_debug("bcm2835_sdhost_probe\n");
|
||||||
@@ -2151,8 +2128,12 @@ static int bcm2835_sdhost_probe(struct platform_device *pdev)
|
|||||||
else
|
else
|
||||||
mmc->caps |= MMC_CAP_4_BIT_DATA;
|
mmc->caps |= MMC_CAP_4_BIT_DATA;
|
||||||
|
|
||||||
|
ret = bcm2835_sdhost_add_host(host);
|
||||||
|
if (ret)
|
||||||
|
goto err;
|
||||||
|
|
||||||
/* Query the core clock frequencies */
|
/* Query the core clock frequencies */
|
||||||
min_clk = get_core_clock(RPI_FIRMWARE_GET_MIN_CLOCK_RATE);
|
host->min_clk = get_core_clock(RPI_FIRMWARE_GET_MIN_CLOCK_RATE);
|
||||||
max_clk = get_core_clock(RPI_FIRMWARE_GET_MAX_CLOCK_RATE);
|
max_clk = get_core_clock(RPI_FIRMWARE_GET_MAX_CLOCK_RATE);
|
||||||
if (max_clk != host->max_clk) {
|
if (max_clk != host->max_clk) {
|
||||||
pr_warn("%s: Expected max clock %d, found %d\n",
|
pr_warn("%s: Expected max clock %d, found %d\n",
|
||||||
@@ -2160,24 +2141,19 @@ static int bcm2835_sdhost_probe(struct platform_device *pdev)
|
|||||||
host->max_clk = max_clk;
|
host->max_clk = max_clk;
|
||||||
}
|
}
|
||||||
|
|
||||||
host->src_clks[0] = min_clk;
|
if (host->min_clk != host->max_clk) {
|
||||||
host->cur_clk_idx = -1;
|
|
||||||
if (max_clk != min_clk) {
|
|
||||||
host->src_clks[1] = max_clk;
|
|
||||||
host->cpufreq_nb.notifier_call =
|
host->cpufreq_nb.notifier_call =
|
||||||
bcm2835_sdhost_cpufreq_callback;
|
bcm2835_sdhost_cpufreq_callback;
|
||||||
sema_init(&host->cpufreq_semaphore, 1);
|
sema_init(&host->cpufreq_semaphore, 1);
|
||||||
cpufreq_register_notifier(&host->cpufreq_nb,
|
cpufreq_register_notifier(&host->cpufreq_nb,
|
||||||
CPUFREQ_TRANSITION_NOTIFIER);
|
CPUFREQ_TRANSITION_NOTIFIER);
|
||||||
host->variable_clock = 1;
|
host->variable_clock = 1;
|
||||||
|
host->cur_clk = 0; /* Get this later */
|
||||||
} else {
|
} else {
|
||||||
host->variable_clock = 0;
|
host->variable_clock = 0;
|
||||||
|
host->cur_clk = host->max_clk;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bcm2835_sdhost_add_host(host);
|
|
||||||
if (ret)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
platform_set_drvdata(pdev, host);
|
platform_set_drvdata(pdev, host);
|
||||||
|
|
||||||
pr_debug("bcm2835_sdhost_probe -> OK\n");
|
pr_debug("bcm2835_sdhost_probe -> OK\n");
|
||||||
|
|||||||
Reference in New Issue
Block a user