|
@@ -0,0 +1,130 @@
|
|
|
+/*
|
|
|
+ * linux/arch/arm/mach-sa1100/cpu-sa1110.c
|
|
|
+ *
|
|
|
+ * Copyright (C) 2001 Russell King
|
|
|
+ *
|
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
|
+ * it under the terms of the GNU General Public License version 2 as
|
|
|
+ * published by the Free Software Foundation.
|
|
|
+ *
|
|
|
+ * Note: there are two erratas that apply to the SA1110 here:
|
|
|
+ * 7 - SDRAM auto-power-up failure (rev A0)
|
|
|
+ * 13 - Corruption of internal register reads/writes following
|
|
|
+ * SDRAM reads (rev A0, B0, B1)
|
|
|
+ *
|
|
|
+ * We ignore rev. A0 and B0 devices; I don't think they're worth supporting.
|
|
|
+ *
|
|
|
+ * The SDRAM type can be passed on the command line as cpu_sa1110.sdram=type
|
|
|
+ */
|
|
|
+#include <linux/cpufreq.h>
|
|
|
+#include <linux/delay.h>
|
|
|
+#include <linux/init.h>
|
|
|
+#include <linux/io.h>
|
|
|
+#include <linux/kernel.h>
|
|
|
+#include <linux/moduleparam.h>
|
|
|
+#include <linux/types.h>
|
|
|
+
|
|
|
+#include <asm/cputype.h>
|
|
|
+#include <asm/mach-types.h>
|
|
|
+
|
|
|
+#include <mach/hardware.h>
|
|
|
+
|
|
|
+#include "generic.h"
|
|
|
+
|
|
|
+#undef DEBUG
|
|
|
+
|
|
|
+struct sdram_params {
|
|
|
+ const char name[20];
|
|
|
+ u_char rows; /* bits */
|
|
|
+ u_char cas_latency; /* cycles */
|
|
|
+ u_char tck; /* clock cycle time (ns) */
|
|
|
+ u_char trcd; /* activate to r/w (ns) */
|
|
|
+ u_char trp; /* precharge to activate (ns) */
|
|
|
+ u_char twr; /* write recovery time (ns) */
|
|
|
+ u_short refresh; /* refresh time for array (us) */
|
|
|
+};
|
|
|
+
|
|
|
+struct sdram_info {
|
|
|
+ u_int mdcnfg;
|
|
|
+ u_int mdrefr;
|
|
|
+ u_int mdcas[3];
|
|
|
+};
|
|
|
+
|
|
|
+static struct sdram_params sdram_tbl[] __initdata = {
|
|
|
+ { /* Toshiba TC59SM716 CL2 */
|
|
|
+ .name = "TC59SM716-CL2",
|
|
|
+ .rows = 12,
|
|
|
+ .tck = 10,
|
|
|
+ .trcd = 20,
|
|
|
+ .trp = 20,
|
|
|
+ .twr = 10,
|
|
|
+ .refresh = 64000,
|
|
|
+ .cas_latency = 2,
|
|
|
+ }, { /* Toshiba TC59SM716 CL3 */
|
|
|
+ .name = "TC59SM716-CL3",
|
|
|
+ .rows = 12,
|
|
|
+ .tck = 8,
|
|
|
+ .trcd = 20,
|
|
|
+ .trp = 20,
|
|
|
+ .twr = 8,
|
|
|
+ .refresh = 64000,
|
|
|
+ .cas_latency = 3,
|
|
|
+ }, { /* Samsung K4S641632D TC75 */
|
|
|
+ .name = "K4S641632D",
|
|
|
+ .rows = 14,
|
|
|
+ .tck = 9,
|
|
|
+ .trcd = 27,
|
|
|
+ .trp = 20,
|
|
|
+ .twr = 9,
|
|
|
+ .refresh = 64000,
|
|
|
+ .cas_latency = 3,
|
|
|
+ }, { /* Samsung K4S281632B-1H */
|
|
|
+ .name = "K4S281632B-1H",
|
|
|
+ .rows = 12,
|
|
|
+ .tck = 10,
|
|
|
+ .trp = 20,
|
|
|
+ .twr = 10,
|
|
|
+ .refresh = 64000,
|
|
|
+ .cas_latency = 3,
|
|
|
+ }, { /* Samsung KM416S4030CT */
|
|
|
+ .name = "KM416S4030CT",
|
|
|
+ .rows = 13,
|
|
|
+ .tck = 8,
|
|
|
+ .trcd = 24, /* 3 CLKs */
|
|
|
+ .trp = 24, /* 3 CLKs */
|
|
|
+ .twr = 16, /* Trdl: 2 CLKs */
|
|
|
+ .refresh = 64000,
|
|
|
+ .cas_latency = 3,
|
|
|
+ }, { /* Winbond W982516AH75L CL3 */
|
|
|
+ .name = "W982516AH75L",
|
|
|
+ .rows = 16,
|
|
|
+ .tck = 8,
|
|
|
+ .trcd = 20,
|
|
|
+ .trp = 20,
|
|
|
+ .twr = 8,
|
|
|
+ .refresh = 64000,
|
|
|
+ .cas_latency = 3,
|
|
|
+ }, { /* Micron MT48LC8M16A2TG-75 */
|
|
|
+ .name = "MT48LC8M16A2TG-75",
|
|
|
+ .rows = 12,
|
|
|
+ .tck = 8,
|
|
|
+ .trcd = 20,
|
|
|
+ .trp = 20,
|
|
|
+ .twr = 8,
|
|
|
+ .refresh = 64000,
|
|
|
+ .cas_latency = 3,
|
|
|
+ },
|
|
|
+};
|
|
|
+
|
|
|
+static struct sdram_params sdram_params;
|
|
|
+
|
|
|
+/*
|
|
|
+ * Given a period in ns and frequency in khz, calculate the number of
|
|
|
+ * cycles of frequency in period. Note that we round up to the next
|
|
|
+ * cycle, even if we are only slightly over.
|
|
|
+ */
|
|
|
+static inline u_int ns_to_cycles(u_int ns, u_int khz)
|
|
|
+{
|
|
|
+ return (ns * khz + 999999) / 1000000;
|
|
|
+}
|
|
|
+
|