Blackfin: decouple unrelated cache settings to get exact behavior
[linux-2.6.git] / arch / blackfin / mach-common / cpufreq.c
index ed81e00..85c6580 100644 (file)
@@ -62,15 +62,23 @@ static struct bfin_dpm_state {
        unsigned int tscale; /* change the divider on the core timer interrupt */
 } dpm_state_table[3];
 
+/*
+   normalized to maximum frequncy offset for CYCLES,
+   used in time-ts cycles clock source, but could be used
+   somewhere also.
+ */
+unsigned long long __bfin_cycles_off;
+unsigned int __bfin_cycles_mod;
+
 /**************************************************************************/
 
-static unsigned int bfin_getfreq(unsigned int cpu)
+static unsigned int bfin_getfreq_khz(unsigned int cpu)
 {
        /* The driver only support single cpu */
        if (cpu != 0)
                return -1;
 
-       return get_cclk();
+       return get_cclk() / 1000;
 }
 
 
@@ -80,6 +88,7 @@ static int bfin_target(struct cpufreq_policy *policy,
        unsigned int index, plldiv, tscale;
        unsigned long flags, cclk_hz;
        struct cpufreq_freqs freqs;
+       cycles_t cycles;
 
        if (cpufreq_frequency_table_target(policy, bfin_freq_table,
                 target_freq, relation, &index))
@@ -87,7 +96,7 @@ static int bfin_target(struct cpufreq_policy *policy,
 
        cclk_hz = bfin_freq_table[index].frequency;
 
-       freqs.old = bfin_getfreq(0);
+       freqs.old = bfin_getfreq_khz(0);
        freqs.new = cclk_hz;
        freqs.cpu = 0;
 
@@ -95,14 +104,20 @@ static int bfin_target(struct cpufreq_policy *policy,
                 cclk_hz, target_freq, freqs.old);
 
        cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
-       local_irq_save(flags);
+       local_irq_save_hw(flags);
                plldiv = (bfin_read_PLL_DIV() & SSEL) | dpm_state_table[index].csel;
                tscale = dpm_state_table[index].tscale;
                bfin_write_PLL_DIV(plldiv);
                /* we have to adjust the core timer, because it is using cclk */
                bfin_write_TSCALE(tscale);
+               cycles = get_cycles();
                SSYNC();
-       local_irq_restore(flags);
+       cycles += 10; /* ~10 cycles we lose after get_cycles() */
+       __bfin_cycles_off += (cycles << __bfin_cycles_mod) - (cycles << index);
+       __bfin_cycles_mod = index;
+       local_irq_restore_hw(flags);
+       /* TODO: just test case for cycles clock source, remove later */
+       pr_debug("cpufreq: done\n");
        cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 
        return 0;
@@ -119,22 +134,14 @@ static int __init __bfin_cpu_init(struct cpufreq_policy *policy)
        unsigned long cclk, sclk, csel, min_cclk;
        int index;
 
-#ifdef CONFIG_CYCLES_CLOCKSOURCE
-/*
- * Clocksource CYCLES is still CONTINUOUS but not longer MONOTONIC in case we enable
- * CPU frequency scaling, since CYCLES runs off Core Clock.
- */
-       printk(KERN_WARNING "CPU frequency scaling not supported: Clocksource not suitable\n"
-               return -ENODEV;
-#endif
-
        if (policy->cpu != 0)
                return -EINVAL;
 
-       cclk = get_cclk();
-       sclk = get_sclk();
+       cclk = get_cclk() / 1000;
+       sclk = get_sclk() / 1000;
 
-#if ANOMALY_05000273
+#if ANOMALY_05000273 || ANOMALY_05000274 || \
+       (!defined(CONFIG_BF54x) && defined(CONFIG_BFIN_EXTMEM_DCACHEABLE))
        min_cclk = sclk * 2;
 #else
        min_cclk = sclk;
@@ -146,14 +153,12 @@ static int __init __bfin_cpu_init(struct cpufreq_policy *policy)
                dpm_state_table[index].csel = csel << 4; /* Shift now into PLL_DIV bitpos */
                dpm_state_table[index].tscale =  (TIME_SCALE / (1 << csel)) - 1;
 
-               pr_debug("cpufreq: freq:%d csel:%d tscale:%d\n",
+               pr_debug("cpufreq: freq:%d csel:0x%x tscale:%d\n",
                                                 bfin_freq_table[index].frequency,
                                                 dpm_state_table[index].csel,
                                                 dpm_state_table[index].tscale);
        }
 
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-
        policy->cpuinfo.transition_latency = (bfin_read_PLL_LOCKCNT() / (sclk / 1000000)) * 1000;
        /*Now ,only support one cpu */
        policy->cur = cclk;
@@ -169,7 +174,7 @@ static struct freq_attr *bfin_freq_attr[] = {
 static struct cpufreq_driver bfin_driver = {
        .verify = bfin_verify_speed,
        .target = bfin_target,
-       .get = bfin_getfreq,
+       .get = bfin_getfreq_khz,
        .init = __bfin_cpu_init,
        .name = "bfin cpufreq",
        .owner = THIS_MODULE,