From 664ffae1f5e89a69f12f83717c2a7efccea008ca Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 4 Apr 2016 12:35:32 +0100 Subject: [PATCH] Revert "bcm2835-sdhost: Precalc divisors and overclocks" This reverts commit 20260462773366a5734e5268dae0a4c179a21a2d. --- drivers/mmc/host/bcm2835-sdhost.c | 152 ++++++++++++++++---------------------- 1 file changed, 64 insertions(+), 88 deletions(-) --- a/drivers/mmc/host/bcm2835-sdhost.c +++ b/drivers/mmc/host/bcm2835-sdhost.c @@ -154,15 +154,12 @@ struct bcm2835_host { u32 pio_timeout; /* In jiffies */ int clock; /* Current clock speed */ - int clocks[2]; bool slow_card; /* Force 11-bit divisor */ unsigned int max_clk; /* Max src clock freq */ - unsigned int src_clks[2]; /* Min/max src clock freqs */ - unsigned int cur_clk_idx; /* Index of current clock */ - unsigned int next_clk_idx; /* Next clock index */ - unsigned int cdivs[2]; + unsigned int min_clk; /* Min src clock freq */ + unsigned int cur_clk; /* Current src clock freq */ 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_this_stop; /* minimum time between this stop and subsequent data transfer */ 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 sectors; /* Cached card size in sectors */ @@ -1512,35 +1509,10 @@ static irqreturn_t bcm2835_sdhost_irq(in 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) { int div = 0; /* Initialized for compiler warning */ unsigned int clock = host->clock; - int clk_idx; if (host->debug) pr_info("%s: set_clock(%d)\n", mmc_hostname(host->mmc), clock); @@ -1581,45 +1553,53 @@ void bcm2835_sdhost_set_clock(struct bcm return; } - /* Calculate the clock divisors */ - 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 = host->cur_clk / clock; + if (div < 2) + div = 2; + if ((host->cur_clk / div) > clock) + div++; + div -= 2; + + if (div > SDCDIV_MAX_CDIV) + div = SDCDIV_MAX_CDIV; + + clock = host->cur_clk / (div + 2); + host->mmc->actual_clock = clock; + + /* Calibrate some delays */ + + host->ns_per_fifo_word = (1000000000/clock) * + ((host->mmc->caps & MMC_CAP_4_BIT_DATA) ? 8 : 32); - div = cur_clk / clock; - if (div < 2) - div = 2; - if ((cur_clk / div) > clock) - div++; - div -= 2; - - if (div > SDCDIV_MAX_CDIV) - div = SDCDIV_MAX_CDIV; - actual_clock = cur_clk / (div + 2); - - host->cdivs[clk_idx] = div; - host->clocks[clk_idx] = actual_clock; - - if (host->overclock_50 != host->prev_overclock_50) { - const char *clk_name = ""; - if (host->variable_clock) - clk_name = clk_idx ? " (turbo)" : " (normal)"; - if (actual_clock > host->clock) - pr_info("%s: overclocking to %dHz%s\n", - mmc_hostname(host->mmc), - actual_clock, clk_name); - else if ((host->overclock_50 < 50) && (clk_idx == 0)) - pr_info("%s: cancelling overclock%s\n", - mmc_hostname(host->mmc), - host->variable_clock ? "s" : ""); + if (clock > host->clock) { + /* Save the closest value, to make it easier + to reduce in the event of error */ + host->overclock_50 = (clock/MHZ); + + if (clock != host->overclock) { + 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->prev_overclock_50 = host->overclock_50; + host->cdiv = div; + 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) @@ -1677,9 +1657,6 @@ static void bcm2835_sdhost_request(struc 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); host->mrq = mrq; @@ -1742,7 +1719,11 @@ static int bcm2835_sdhost_cpufreq_callba return NOTIFY_BAD; break; 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); break; default: @@ -1782,11 +1763,8 @@ static void bcm2835_sdhost_set_ios(struc ios->clock, ios->power_mode, ios->bus_width, ios->timing, ios->signal_voltage, ios->drv_type); - if (ios->clock && (host->cur_clk_idx == -1)) { - unsigned int cur_clk = - get_core_clock(RPI_FIRMWARE_GET_CLOCK_RATE); - host->cur_clk_idx = (cur_clk == host->src_clks[0]) ? 0 : 1; - } + if (ios->clock && !host->cur_clk) + host->cur_clk = get_core_clock(RPI_FIRMWARE_GET_CLOCK_RATE); spin_lock_irqsave(&host->lock, flags); @@ -1876,12 +1854,11 @@ static void bcm2835_sdhost_tasklet_finis /* Drop the overclock after any data corruption, or after any error overclocked */ - if (host->clock > 50*MHZ) { + if (host->overclock) { if ((mrq->cmd && mrq->cmd->error) || (mrq->data && mrq->data->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", mmc_hostname(host->mmc)); bcm2835_sdhost_set_clock(host); @@ -2045,7 +2022,7 @@ static int bcm2835_sdhost_probe(struct p struct bcm2835_host *host; struct mmc_host *mmc; const __be32 *addr; - unsigned int max_clk, min_clk; + unsigned int max_clk; int ret; pr_debug("bcm2835_sdhost_probe\n"); @@ -2151,8 +2128,12 @@ static int bcm2835_sdhost_probe(struct p else mmc->caps |= MMC_CAP_4_BIT_DATA; + ret = bcm2835_sdhost_add_host(host); + if (ret) + goto err; + /* 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); if (max_clk != host->max_clk) { pr_warn("%s: Expected max clock %d, found %d\n", @@ -2160,24 +2141,19 @@ static int bcm2835_sdhost_probe(struct p host->max_clk = max_clk; } - host->src_clks[0] = min_clk; - host->cur_clk_idx = -1; - if (max_clk != min_clk) { - host->src_clks[1] = max_clk; + if (host->min_clk != host->max_clk) { host->cpufreq_nb.notifier_call = bcm2835_sdhost_cpufreq_callback; sema_init(&host->cpufreq_semaphore, 1); cpufreq_register_notifier(&host->cpufreq_nb, CPUFREQ_TRANSITION_NOTIFIER); host->variable_clock = 1; + host->cur_clk = 0; /* Get this later */ } else { 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); pr_debug("bcm2835_sdhost_probe -> OK\n");