0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016 #include <linux/cpufreq.h>
0017 #include <linux/delay.h>
0018 #include <linux/init.h>
0019 #include <linux/io.h>
0020 #include <linux/kernel.h>
0021 #include <linux/moduleparam.h>
0022 #include <linux/types.h>
0023
0024 #include <asm/cputype.h>
0025 #include <asm/mach-types.h>
0026
0027 #include <mach/generic.h>
0028 #include <mach/hardware.h>
0029
0030 #undef DEBUG
0031
0032 struct sdram_params {
0033 const char name[20];
0034 u_char rows;
0035 u_char cas_latency;
0036 u_char tck;
0037 u_char trcd;
0038 u_char trp;
0039 u_char twr;
0040 u_short refresh;
0041 };
0042
0043 struct sdram_info {
0044 u_int mdcnfg;
0045 u_int mdrefr;
0046 u_int mdcas[3];
0047 };
0048
0049 static struct sdram_params sdram_tbl[] __initdata = {
0050 {
0051 .name = "TC59SM716-CL2",
0052 .rows = 12,
0053 .tck = 10,
0054 .trcd = 20,
0055 .trp = 20,
0056 .twr = 10,
0057 .refresh = 64000,
0058 .cas_latency = 2,
0059 }, {
0060 .name = "TC59SM716-CL3",
0061 .rows = 12,
0062 .tck = 8,
0063 .trcd = 20,
0064 .trp = 20,
0065 .twr = 8,
0066 .refresh = 64000,
0067 .cas_latency = 3,
0068 }, {
0069 .name = "K4S641632D",
0070 .rows = 14,
0071 .tck = 9,
0072 .trcd = 27,
0073 .trp = 20,
0074 .twr = 9,
0075 .refresh = 64000,
0076 .cas_latency = 3,
0077 }, {
0078 .name = "K4S281632B-1H",
0079 .rows = 12,
0080 .tck = 10,
0081 .trp = 20,
0082 .twr = 10,
0083 .refresh = 64000,
0084 .cas_latency = 3,
0085 }, {
0086 .name = "KM416S4030CT",
0087 .rows = 13,
0088 .tck = 8,
0089 .trcd = 24,
0090 .trp = 24,
0091 .twr = 16,
0092 .refresh = 64000,
0093 .cas_latency = 3,
0094 }, {
0095 .name = "W982516AH75L",
0096 .rows = 16,
0097 .tck = 8,
0098 .trcd = 20,
0099 .trp = 20,
0100 .twr = 8,
0101 .refresh = 64000,
0102 .cas_latency = 3,
0103 }, {
0104 .name = "MT48LC8M16A2TG-75",
0105 .rows = 12,
0106 .tck = 8,
0107 .trcd = 20,
0108 .trp = 20,
0109 .twr = 8,
0110 .refresh = 64000,
0111 .cas_latency = 3,
0112 },
0113 };
0114
0115 static struct sdram_params sdram_params;
0116
0117
0118
0119
0120
0121
0122 static inline u_int ns_to_cycles(u_int ns, u_int khz)
0123 {
0124 return (ns * khz + 999999) / 1000000;
0125 }
0126
0127
0128
0129
0130 static inline void set_mdcas(u_int *mdcas, int delayed, u_int rcd)
0131 {
0132 u_int shift;
0133
0134 rcd = 2 * rcd - 1;
0135 shift = delayed + 1 + rcd;
0136
0137 mdcas[0] = (1 << rcd) - 1;
0138 mdcas[0] |= 0x55555555 << shift;
0139 mdcas[1] = mdcas[2] = 0x55555555 << (shift & 1);
0140 }
0141
0142 static void
0143 sdram_calculate_timing(struct sdram_info *sd, u_int cpu_khz,
0144 struct sdram_params *sdram)
0145 {
0146 u_int mem_khz, sd_khz, trp, twr;
0147
0148 mem_khz = cpu_khz / 2;
0149 sd_khz = mem_khz;
0150
0151
0152
0153
0154
0155
0156
0157
0158 if ((ns_to_cycles(sdram->tck, sd_khz) > 1) ||
0159 (read_cpuid_revision() < ARM_CPU_REV_SA1110_B2 && sd_khz < 62000))
0160 sd_khz /= 2;
0161
0162 sd->mdcnfg = MDCNFG & 0x007f007f;
0163
0164 twr = ns_to_cycles(sdram->twr, mem_khz);
0165
0166
0167 trp = ns_to_cycles(sdram->trp, mem_khz) - 1;
0168 if (trp < 1)
0169 trp = 1;
0170
0171 sd->mdcnfg |= trp << 8;
0172 sd->mdcnfg |= trp << 24;
0173 sd->mdcnfg |= sdram->cas_latency << 12;
0174 sd->mdcnfg |= sdram->cas_latency << 28;
0175 sd->mdcnfg |= twr << 14;
0176 sd->mdcnfg |= twr << 30;
0177
0178 sd->mdrefr = MDREFR & 0xffbffff0;
0179 sd->mdrefr |= 7;
0180
0181 if (sd_khz != mem_khz)
0182 sd->mdrefr |= MDREFR_K1DB2;
0183
0184
0185 set_mdcas(sd->mdcas, sd_khz >= 62000,
0186 ns_to_cycles(sdram->trcd, mem_khz));
0187
0188 #ifdef DEBUG
0189 printk(KERN_DEBUG "MDCNFG: %08x MDREFR: %08x MDCAS0: %08x MDCAS1: %08x MDCAS2: %08x\n",
0190 sd->mdcnfg, sd->mdrefr, sd->mdcas[0], sd->mdcas[1],
0191 sd->mdcas[2]);
0192 #endif
0193 }
0194
0195
0196
0197
0198 static inline void sdram_set_refresh(u_int dri)
0199 {
0200 MDREFR = (MDREFR & 0xffff000f) | (dri << 4);
0201 (void) MDREFR;
0202 }
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212 static void
0213 sdram_update_refresh(u_int cpu_khz, struct sdram_params *sdram)
0214 {
0215 u_int ns_row = (sdram->refresh * 1000) >> sdram->rows;
0216 u_int dri = ns_to_cycles(ns_row, cpu_khz / 2) / 32;
0217
0218 #ifdef DEBUG
0219 mdelay(250);
0220 printk(KERN_DEBUG "new dri value = %d\n", dri);
0221 #endif
0222
0223 sdram_set_refresh(dri);
0224 }
0225
0226
0227
0228
0229 static int sa1110_target(struct cpufreq_policy *policy, unsigned int ppcr)
0230 {
0231 struct sdram_params *sdram = &sdram_params;
0232 struct sdram_info sd;
0233 unsigned long flags;
0234 unsigned int unused;
0235
0236 sdram_calculate_timing(&sd, sa11x0_freq_table[ppcr].frequency, sdram);
0237
0238 #if 0
0239
0240
0241
0242
0243
0244 if (policy->max < 147500) {
0245 sd.mdrefr |= MDREFR_K1DB2;
0246 sd.mdcas[0] = 0xaaaaaa7f;
0247 } else {
0248 sd.mdrefr &= ~MDREFR_K1DB2;
0249 sd.mdcas[0] = 0xaaaaaa9f;
0250 }
0251 sd.mdcas[1] = 0xaaaaaaaa;
0252 sd.mdcas[2] = 0xaaaaaaaa;
0253 #endif
0254
0255
0256
0257
0258
0259
0260
0261 sdram_set_refresh(2);
0262 if (!irqs_disabled())
0263 msleep(20);
0264 else
0265 mdelay(20);
0266
0267
0268
0269
0270
0271
0272
0273 local_irq_save(flags);
0274 asm("mcr p15, 0, %0, c7, c10, 4" : : "r" (0));
0275 udelay(10);
0276 __asm__ __volatile__("\n\
0277 b 2f \n\
0278 .align 5 \n\
0279 1: str %3, [%1, #0] @ MDCNFG \n\
0280 str %4, [%1, #28] @ MDREFR \n\
0281 str %5, [%1, #4] @ MDCAS0 \n\
0282 str %6, [%1, #8] @ MDCAS1 \n\
0283 str %7, [%1, #12] @ MDCAS2 \n\
0284 str %8, [%2, #0] @ PPCR \n\
0285 ldr %0, [%1, #0] \n\
0286 b 3f \n\
0287 2: b 1b \n\
0288 3: nop \n\
0289 nop"
0290 : "=&r" (unused)
0291 : "r" (&MDCNFG), "r" (&PPCR), "0" (sd.mdcnfg),
0292 "r" (sd.mdrefr), "r" (sd.mdcas[0]),
0293 "r" (sd.mdcas[1]), "r" (sd.mdcas[2]), "r" (ppcr));
0294 local_irq_restore(flags);
0295
0296
0297
0298
0299 sdram_update_refresh(sa11x0_freq_table[ppcr].frequency, sdram);
0300
0301 return 0;
0302 }
0303
0304 static int __init sa1110_cpu_init(struct cpufreq_policy *policy)
0305 {
0306 cpufreq_generic_init(policy, sa11x0_freq_table, 0);
0307 return 0;
0308 }
0309
0310
0311
0312 static struct cpufreq_driver sa1110_driver __refdata = {
0313 .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK |
0314 CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING,
0315 .verify = cpufreq_generic_frequency_table_verify,
0316 .target_index = sa1110_target,
0317 .get = sa11x0_getspeed,
0318 .init = sa1110_cpu_init,
0319 .name = "sa1110",
0320 };
0321
0322 static struct sdram_params *sa1110_find_sdram(const char *name)
0323 {
0324 struct sdram_params *sdram;
0325
0326 for (sdram = sdram_tbl; sdram < sdram_tbl + ARRAY_SIZE(sdram_tbl);
0327 sdram++)
0328 if (strcmp(name, sdram->name) == 0)
0329 return sdram;
0330
0331 return NULL;
0332 }
0333
0334 static char sdram_name[16];
0335
0336 static int __init sa1110_clk_init(void)
0337 {
0338 struct sdram_params *sdram;
0339 const char *name = sdram_name;
0340
0341 if (!cpu_is_sa1110())
0342 return -ENODEV;
0343
0344 if (!name[0]) {
0345 if (machine_is_assabet())
0346 name = "TC59SM716-CL3";
0347 if (machine_is_pt_system3())
0348 name = "K4S641632D";
0349 if (machine_is_h3100())
0350 name = "KM416S4030CT";
0351 if (machine_is_jornada720() || machine_is_h3600())
0352 name = "K4S281632B-1H";
0353 if (machine_is_nanoengine())
0354 name = "MT48LC8M16A2TG-75";
0355 }
0356
0357 sdram = sa1110_find_sdram(name);
0358 if (sdram) {
0359 printk(KERN_DEBUG "SDRAM: tck: %d trcd: %d trp: %d"
0360 " twr: %d refresh: %d cas_latency: %d\n",
0361 sdram->tck, sdram->trcd, sdram->trp,
0362 sdram->twr, sdram->refresh, sdram->cas_latency);
0363
0364 memcpy(&sdram_params, sdram, sizeof(sdram_params));
0365
0366 return cpufreq_register_driver(&sa1110_driver);
0367 }
0368
0369 return 0;
0370 }
0371
0372 module_param_string(sdram, sdram_name, sizeof(sdram_name), 0);
0373 arch_initcall(sa1110_clk_init);