|
@@ -295,3 +295,114 @@ static int sa1110_target(struct cpufreq_policy *policy,
|
|
|
|
|
|
/*
|
|
|
* Reprogram the DRAM timings with interrupts disabled, and
|
|
|
+ * ensure that we are doing this within a complete cache line.
|
|
|
+ * This means that we won't access SDRAM for the duration of
|
|
|
+ * the programming.
|
|
|
+ */
|
|
|
+ local_irq_save(flags);
|
|
|
+ asm("mcr p15, 0, %0, c7, c10, 4" : : "r" (0));
|
|
|
+ udelay(10);
|
|
|
+ __asm__ __volatile__("\n\
|
|
|
+ b 2f \n\
|
|
|
+ .align 5 \n\
|
|
|
+1: str %3, [%1, #0] @ MDCNFG \n\
|
|
|
+ str %4, [%1, #28] @ MDREFR \n\
|
|
|
+ str %5, [%1, #4] @ MDCAS0 \n\
|
|
|
+ str %6, [%1, #8] @ MDCAS1 \n\
|
|
|
+ str %7, [%1, #12] @ MDCAS2 \n\
|
|
|
+ str %8, [%2, #0] @ PPCR \n\
|
|
|
+ ldr %0, [%1, #0] \n\
|
|
|
+ b 3f \n\
|
|
|
+2: b 1b \n\
|
|
|
+3: nop \n\
|
|
|
+ nop"
|
|
|
+ : "=&r" (unused)
|
|
|
+ : "r" (&MDCNFG), "r" (&PPCR), "0" (sd.mdcnfg),
|
|
|
+ "r" (sd.mdrefr), "r" (sd.mdcas[0]),
|
|
|
+ "r" (sd.mdcas[1]), "r" (sd.mdcas[2]), "r" (ppcr));
|
|
|
+ local_irq_restore(flags);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Now, return the SDRAM refresh back to normal.
|
|
|
+ */
|
|
|
+ sdram_update_refresh(freqs.new, sdram);
|
|
|
+
|
|
|
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int __init sa1110_cpu_init(struct cpufreq_policy *policy)
|
|
|
+{
|
|
|
+ if (policy->cpu != 0)
|
|
|
+ return -EINVAL;
|
|
|
+ policy->cur = policy->min = policy->max = sa11x0_getspeed(0);
|
|
|
+ policy->cpuinfo.min_freq = 59000;
|
|
|
+ policy->cpuinfo.max_freq = 287000;
|
|
|
+ policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/* sa1110_driver needs __refdata because it must remain after init registers
|
|
|
+ * it with cpufreq_register_driver() */
|
|
|
+static struct cpufreq_driver sa1110_driver __refdata = {
|
|
|
+ .flags = CPUFREQ_STICKY,
|
|
|
+ .verify = sa11x0_verify_speed,
|
|
|
+ .target = sa1110_target,
|
|
|
+ .get = sa11x0_getspeed,
|
|
|
+ .init = sa1110_cpu_init,
|
|
|
+ .name = "sa1110",
|
|
|
+};
|
|
|
+
|
|
|
+static struct sdram_params *sa1110_find_sdram(const char *name)
|
|
|
+{
|
|
|
+ struct sdram_params *sdram;
|
|
|
+
|
|
|
+ for (sdram = sdram_tbl; sdram < sdram_tbl + ARRAY_SIZE(sdram_tbl);
|
|
|
+ sdram++)
|
|
|
+ if (strcmp(name, sdram->name) == 0)
|
|
|
+ return sdram;
|
|
|
+
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+static char sdram_name[16];
|
|
|
+
|
|
|
+static int __init sa1110_clk_init(void)
|
|
|
+{
|
|
|
+ struct sdram_params *sdram;
|
|
|
+ const char *name = sdram_name;
|
|
|
+
|
|
|
+ if (!cpu_is_sa1110())
|
|
|
+ return -ENODEV;
|
|
|
+
|
|
|
+ if (!name[0]) {
|
|
|
+ if (machine_is_assabet())
|
|
|
+ name = "TC59SM716-CL3";
|
|
|
+ if (machine_is_pt_system3())
|
|
|
+ name = "K4S641632D";
|
|
|
+ if (machine_is_h3100())
|
|
|
+ name = "KM416S4030CT";
|
|
|
+ if (machine_is_jornada720())
|
|
|
+ name = "K4S281632B-1H";
|
|
|
+ if (machine_is_nanoengine())
|
|
|
+ name = "MT48LC8M16A2TG-75";
|
|
|
+ }
|
|
|
+
|
|
|
+ sdram = sa1110_find_sdram(name);
|
|
|
+ if (sdram) {
|
|
|
+ printk(KERN_DEBUG "SDRAM: tck: %d trcd: %d trp: %d"
|
|
|
+ " twr: %d refresh: %d cas_latency: %d\n",
|
|
|
+ sdram->tck, sdram->trcd, sdram->trp,
|
|
|
+ sdram->twr, sdram->refresh, sdram->cas_latency);
|
|
|
+
|
|
|
+ memcpy(&sdram_params, sdram, sizeof(sdram_params));
|
|
|
+
|
|
|
+ return cpufreq_register_driver(&sa1110_driver);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+module_param_string(sdram, sdram_name, sizeof(sdram_name), 0);
|
|
|
+arch_initcall(sa1110_clk_init);
|