11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * linux/arch/arm/mach-sa1100/cpu-sa1110.c 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2001 Russell King 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License version 2 as 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * published by the Free Software Foundation. 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note: there are two erratas that apply to the SA1110 here: 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 7 - SDRAM auto-power-up failure (rev A0) 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 13 - Corruption of internal register reads/writes following 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SDRAM reads (rev A0, B0, B1) 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We ignore rev. A0 and B0 devices; I don't think they're worth supporting. 16ba53201180e267bd1f0792e6c375ced7c100738eRussell King * 17ba53201180e267bd1f0792e6c375ced7c100738eRussell King * The SDRAM type can be passed on the command line as cpu_sa1110.sdram=type 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/cpufreq.h> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 223169663ac5902f2228ea0eb8cc34eb52cbd4b283Russell King#include <linux/io.h> 239f15d2caca102c4b79e34562296bcbf982665cb2Marcelo Roberto Jimenez#include <linux/kernel.h> 249f15d2caca102c4b79e34562296bcbf982665cb2Marcelo Roberto Jimenez#include <linux/moduleparam.h> 259f15d2caca102c4b79e34562296bcbf982665cb2Marcelo Roberto Jimenez#include <linux/types.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 270ba8b9b273c45dd23f60ff700e265a0069b33758Russell King#include <asm/cputype.h> 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/mach-types.h> 299f15d2caca102c4b79e34562296bcbf982665cb2Marcelo Roberto Jimenez 3059a2e613d07fbd592ff711c87458eabcf9c98902Viresh Kumar#include <mach/generic.h> 319f15d2caca102c4b79e34562296bcbf982665cb2Marcelo Roberto Jimenez#include <mach/hardware.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef DEBUG 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct sdram_params { 369f15d2caca102c4b79e34562296bcbf982665cb2Marcelo Roberto Jimenez const char name[20]; 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char rows; /* bits */ 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char cas_latency; /* cycles */ 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char tck; /* clock cycle time (ns) */ 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char trcd; /* activate to r/w (ns) */ 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char trp; /* precharge to activate (ns) */ 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char twr; /* write recovery time (ns) */ 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_short refresh; /* refresh time for array (us) */ 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct sdram_info { 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int mdcnfg; 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int mdrefr; 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int mdcas[3]; 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 52ba53201180e267bd1f0792e6c375ced7c100738eRussell Kingstatic struct sdram_params sdram_tbl[] __initdata = { 53ba53201180e267bd1f0792e6c375ced7c100738eRussell King { /* Toshiba TC59SM716 CL2 */ 54ba53201180e267bd1f0792e6c375ced7c100738eRussell King .name = "TC59SM716-CL2", 55ba53201180e267bd1f0792e6c375ced7c100738eRussell King .rows = 12, 56ba53201180e267bd1f0792e6c375ced7c100738eRussell King .tck = 10, 57ba53201180e267bd1f0792e6c375ced7c100738eRussell King .trcd = 20, 58ba53201180e267bd1f0792e6c375ced7c100738eRussell King .trp = 20, 59ba53201180e267bd1f0792e6c375ced7c100738eRussell King .twr = 10, 60ba53201180e267bd1f0792e6c375ced7c100738eRussell King .refresh = 64000, 61ba53201180e267bd1f0792e6c375ced7c100738eRussell King .cas_latency = 2, 62ba53201180e267bd1f0792e6c375ced7c100738eRussell King }, { /* Toshiba TC59SM716 CL3 */ 63ba53201180e267bd1f0792e6c375ced7c100738eRussell King .name = "TC59SM716-CL3", 64ba53201180e267bd1f0792e6c375ced7c100738eRussell King .rows = 12, 65ba53201180e267bd1f0792e6c375ced7c100738eRussell King .tck = 8, 66ba53201180e267bd1f0792e6c375ced7c100738eRussell King .trcd = 20, 67ba53201180e267bd1f0792e6c375ced7c100738eRussell King .trp = 20, 68ba53201180e267bd1f0792e6c375ced7c100738eRussell King .twr = 8, 69ba53201180e267bd1f0792e6c375ced7c100738eRussell King .refresh = 64000, 70ba53201180e267bd1f0792e6c375ced7c100738eRussell King .cas_latency = 3, 71ba53201180e267bd1f0792e6c375ced7c100738eRussell King }, { /* Samsung K4S641632D TC75 */ 72ba53201180e267bd1f0792e6c375ced7c100738eRussell King .name = "K4S641632D", 73ba53201180e267bd1f0792e6c375ced7c100738eRussell King .rows = 14, 74ba53201180e267bd1f0792e6c375ced7c100738eRussell King .tck = 9, 75ba53201180e267bd1f0792e6c375ced7c100738eRussell King .trcd = 27, 76ba53201180e267bd1f0792e6c375ced7c100738eRussell King .trp = 20, 77ba53201180e267bd1f0792e6c375ced7c100738eRussell King .twr = 9, 78ba53201180e267bd1f0792e6c375ced7c100738eRussell King .refresh = 64000, 79ba53201180e267bd1f0792e6c375ced7c100738eRussell King .cas_latency = 3, 8093982535a201399c0023c1166a7f16a335134d5aKristoffer Ericson }, { /* Samsung K4S281632B-1H */ 8193982535a201399c0023c1166a7f16a335134d5aKristoffer Ericson .name = "K4S281632B-1H", 8293982535a201399c0023c1166a7f16a335134d5aKristoffer Ericson .rows = 12, 8393982535a201399c0023c1166a7f16a335134d5aKristoffer Ericson .tck = 10, 8493982535a201399c0023c1166a7f16a335134d5aKristoffer Ericson .trp = 20, 8593982535a201399c0023c1166a7f16a335134d5aKristoffer Ericson .twr = 10, 8693982535a201399c0023c1166a7f16a335134d5aKristoffer Ericson .refresh = 64000, 8793982535a201399c0023c1166a7f16a335134d5aKristoffer Ericson .cas_latency = 3, 88ba53201180e267bd1f0792e6c375ced7c100738eRussell King }, { /* Samsung KM416S4030CT */ 89ba53201180e267bd1f0792e6c375ced7c100738eRussell King .name = "KM416S4030CT", 90ba53201180e267bd1f0792e6c375ced7c100738eRussell King .rows = 13, 91ba53201180e267bd1f0792e6c375ced7c100738eRussell King .tck = 8, 92ba53201180e267bd1f0792e6c375ced7c100738eRussell King .trcd = 24, /* 3 CLKs */ 93ba53201180e267bd1f0792e6c375ced7c100738eRussell King .trp = 24, /* 3 CLKs */ 94ba53201180e267bd1f0792e6c375ced7c100738eRussell King .twr = 16, /* Trdl: 2 CLKs */ 95ba53201180e267bd1f0792e6c375ced7c100738eRussell King .refresh = 64000, 96ba53201180e267bd1f0792e6c375ced7c100738eRussell King .cas_latency = 3, 97ba53201180e267bd1f0792e6c375ced7c100738eRussell King }, { /* Winbond W982516AH75L CL3 */ 98ba53201180e267bd1f0792e6c375ced7c100738eRussell King .name = "W982516AH75L", 99ba53201180e267bd1f0792e6c375ced7c100738eRussell King .rows = 16, 100ba53201180e267bd1f0792e6c375ced7c100738eRussell King .tck = 8, 101ba53201180e267bd1f0792e6c375ced7c100738eRussell King .trcd = 20, 102ba53201180e267bd1f0792e6c375ced7c100738eRussell King .trp = 20, 103ba53201180e267bd1f0792e6c375ced7c100738eRussell King .twr = 8, 104ba53201180e267bd1f0792e6c375ced7c100738eRussell King .refresh = 64000, 105ba53201180e267bd1f0792e6c375ced7c100738eRussell King .cas_latency = 3, 1069f15d2caca102c4b79e34562296bcbf982665cb2Marcelo Roberto Jimenez }, { /* Micron MT48LC8M16A2TG-75 */ 1079f15d2caca102c4b79e34562296bcbf982665cb2Marcelo Roberto Jimenez .name = "MT48LC8M16A2TG-75", 1089f15d2caca102c4b79e34562296bcbf982665cb2Marcelo Roberto Jimenez .rows = 12, 1099f15d2caca102c4b79e34562296bcbf982665cb2Marcelo Roberto Jimenez .tck = 8, 1109f15d2caca102c4b79e34562296bcbf982665cb2Marcelo Roberto Jimenez .trcd = 20, 1119f15d2caca102c4b79e34562296bcbf982665cb2Marcelo Roberto Jimenez .trp = 20, 1129f15d2caca102c4b79e34562296bcbf982665cb2Marcelo Roberto Jimenez .twr = 8, 1139f15d2caca102c4b79e34562296bcbf982665cb2Marcelo Roberto Jimenez .refresh = 64000, 1149f15d2caca102c4b79e34562296bcbf982665cb2Marcelo Roberto Jimenez .cas_latency = 3, 115ba53201180e267bd1f0792e6c375ced7c100738eRussell King }, 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sdram_params sdram_params; 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Given a period in ns and frequency in khz, calculate the number of 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cycles of frequency in period. Note that we round up to the next 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cycle, even if we are only slightly over. 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u_int ns_to_cycles(u_int ns, u_int khz) 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (ns * khz + 999999) / 1000000; 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Create the MDCAS register bit pattern. 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void set_mdcas(u_int *mdcas, int delayed, u_int rcd) 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int shift; 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rcd = 2 * rcd - 1; 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds shift = delayed + 1 + rcd; 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mdcas[0] = (1 << rcd) - 1; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mdcas[0] |= 0x55555555 << shift; 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mdcas[1] = mdcas[2] = 0x55555555 << (shift & 1); 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssdram_calculate_timing(struct sdram_info *sd, u_int cpu_khz, 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sdram_params *sdram) 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int mem_khz, sd_khz, trp, twr; 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mem_khz = cpu_khz / 2; 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sd_khz = mem_khz; 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If SDCLK would invalidate the SDRAM timings, 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * run SDCLK at half speed. 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * CPU steppings prior to B2 must either run the memory at 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * half speed or use delayed read latching (errata 13). 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ns_to_cycles(sdram->tck, sd_khz) > 1) || 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (CPU_REVISION < CPU_SA1110_B2 && sd_khz < 62000)) 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sd_khz /= 2; 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sd->mdcnfg = MDCNFG & 0x007f007f; 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds twr = ns_to_cycles(sdram->twr, mem_khz); 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* trp should always be >1 */ 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds trp = ns_to_cycles(sdram->trp, mem_khz) - 1; 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (trp < 1) 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds trp = 1; 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sd->mdcnfg |= trp << 8; 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sd->mdcnfg |= trp << 24; 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sd->mdcnfg |= sdram->cas_latency << 12; 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sd->mdcnfg |= sdram->cas_latency << 28; 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sd->mdcnfg |= twr << 14; 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sd->mdcnfg |= twr << 30; 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sd->mdrefr = MDREFR & 0xffbffff0; 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sd->mdrefr |= 7; 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sd_khz != mem_khz) 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sd->mdrefr |= MDREFR_K1DB2; 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* initial number of '1's in MDCAS + 1 */ 18847bb3b31ab2c95e275b850a291794a29aaaa31cdMarcelo Roberto Jimenez set_mdcas(sd->mdcas, sd_khz >= 62000, 18947bb3b31ab2c95e275b850a291794a29aaaa31cdMarcelo Roberto Jimenez ns_to_cycles(sdram->trcd, mem_khz)); 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG 19247bb3b31ab2c95e275b850a291794a29aaaa31cdMarcelo Roberto Jimenez printk(KERN_DEBUG "MDCNFG: %08x MDREFR: %08x MDCAS0: %08x MDCAS1: %08x MDCAS2: %08x\n", 19347bb3b31ab2c95e275b850a291794a29aaaa31cdMarcelo Roberto Jimenez sd->mdcnfg, sd->mdrefr, sd->mdcas[0], sd->mdcas[1], 19447bb3b31ab2c95e275b850a291794a29aaaa31cdMarcelo Roberto Jimenez sd->mdcas[2]); 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set the SDRAM refresh rate. 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void sdram_set_refresh(u_int dri) 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MDREFR = (MDREFR & 0xffff000f) | (dri << 4); 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void) MDREFR; 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Update the refresh period. We do this such that we always refresh 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the SDRAMs within their permissible period. The refresh period is 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * always a multiple of the memory clock (fixed at cpu_clock / 2). 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * FIXME: we don't currently take account of burst accesses here, 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but neither do Intels DM nor Angel. 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssdram_update_refresh(u_int cpu_khz, struct sdram_params *sdram) 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int ns_row = (sdram->refresh * 1000) >> sdram->rows; 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int dri = ns_to_cycles(ns_row, cpu_khz / 2) / 32; 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mdelay(250); 22347bb3b31ab2c95e275b850a291794a29aaaa31cdMarcelo Roberto Jimenez printk(KERN_DEBUG "new dri value = %d\n", dri); 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sdram_set_refresh(dri); 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 23093982535a201399c0023c1166a7f16a335134d5aKristoffer Ericson * Ok, set the CPU frequency. 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2329c0ebcf78fde0ffa348a95a544c6d3f2dac5af65Viresh Kumarstatic int sa1110_target(struct cpufreq_policy *policy, unsigned int ppcr) 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sdram_params *sdram = &sdram_params; 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sdram_info sd; 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 2379c0ebcf78fde0ffa348a95a544c6d3f2dac5af65Viresh Kumar unsigned int unused; 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 239d4019f0a92ab802f385cc9c8ad3ab7b5449712cbViresh Kumar sdram_calculate_timing(&sd, sa11x0_freq_table[ppcr].frequency, sdram); 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * These values are wrong according to the SA1110 documentation 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and errata, but they seem to work. Need to get a storage 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * scope on to the SDRAM signals to work out why. 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (policy->max < 147500) { 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sd.mdrefr |= MDREFR_K1DB2; 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sd.mdcas[0] = 0xaaaaaa7f; 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sd.mdrefr &= ~MDREFR_K1DB2; 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sd.mdcas[0] = 0xaaaaaa9f; 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sd.mdcas[1] = 0xaaaaaaaa; 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sd.mdcas[2] = 0xaaaaaaaa; 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The clock could be going away for some time. Set the SDRAMs 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to refresh rapidly (every 64 memory clock cycles). To get 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * through the whole array, we need to wait 262144 mclk cycles. 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We wait 20ms to be safe. 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sdram_set_refresh(2); 26547bb3b31ab2c95e275b850a291794a29aaaa31cdMarcelo Roberto Jimenez if (!irqs_disabled()) 266db5795547694cf68388aaf8f59723e850f7466f6Nishanth Aravamudan msleep(20); 26747bb3b31ab2c95e275b850a291794a29aaaa31cdMarcelo Roberto Jimenez else 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mdelay(20); 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Reprogram the DRAM timings with interrupts disabled, and 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ensure that we are doing this within a complete cache line. 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This means that we won't access SDRAM for the duration of 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the programming. 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_save(flags); 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds asm("mcr p15, 0, %0, c7, c10, 4" : : "r" (0)); 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(10); 27947bb3b31ab2c95e275b850a291794a29aaaa31cdMarcelo Roberto Jimenez __asm__ __volatile__("\n\ 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b 2f \n\ 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .align 5 \n\ 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds1: str %3, [%1, #0] @ MDCNFG \n\ 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds str %4, [%1, #28] @ MDREFR \n\ 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds str %5, [%1, #4] @ MDCAS0 \n\ 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds str %6, [%1, #8] @ MDCAS1 \n\ 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds str %7, [%1, #12] @ MDCAS2 \n\ 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds str %8, [%2, #0] @ PPCR \n\ 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ldr %0, [%1, #0] \n\ 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b 3f \n\ 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds2: b 1b \n\ 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds3: nop \n\ 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nop" 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds : "=&r" (unused) 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds : "r" (&MDCNFG), "r" (&PPCR), "0" (sd.mdcnfg), 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "r" (sd.mdrefr), "r" (sd.mdcas[0]), 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "r" (sd.mdcas[1]), "r" (sd.mdcas[2]), "r" (ppcr)); 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Now, return the SDRAM refresh back to normal. 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 302d4019f0a92ab802f385cc9c8ad3ab7b5449712cbViresh Kumar sdram_update_refresh(sa11x0_freq_table[ppcr].frequency, sdram); 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init sa1110_cpu_init(struct cpufreq_policy *policy) 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3099b30367bbf3353a7dfc34ed800b7ff03cb35252bViresh Kumar return cpufreq_generic_init(policy, sa11x0_freq_table, CPUFREQ_ETERNAL); 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3129f15d2caca102c4b79e34562296bcbf982665cb2Marcelo Roberto Jimenez/* sa1110_driver needs __refdata because it must remain after init registers 3139f15d2caca102c4b79e34562296bcbf982665cb2Marcelo Roberto Jimenez * it with cpufreq_register_driver() */ 3149f15d2caca102c4b79e34562296bcbf982665cb2Marcelo Roberto Jimenezstatic struct cpufreq_driver sa1110_driver __refdata = { 315ae6b427132ba39d023e332e7d920e9931ff05313Viresh Kumar .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK, 316dd9f263956727320a2bcba8ffae7e9ab4a5be8a6Viresh Kumar .verify = cpufreq_generic_frequency_table_verify, 3179c0ebcf78fde0ffa348a95a544c6d3f2dac5af65Viresh Kumar .target_index = sa1110_target, 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .get = sa11x0_getspeed, 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .init = sa1110_cpu_init, 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "sa1110", 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 323ba53201180e267bd1f0792e6c375ced7c100738eRussell Kingstatic struct sdram_params *sa1110_find_sdram(const char *name) 324ba53201180e267bd1f0792e6c375ced7c100738eRussell King{ 325ba53201180e267bd1f0792e6c375ced7c100738eRussell King struct sdram_params *sdram; 326ba53201180e267bd1f0792e6c375ced7c100738eRussell King 32747bb3b31ab2c95e275b850a291794a29aaaa31cdMarcelo Roberto Jimenez for (sdram = sdram_tbl; sdram < sdram_tbl + ARRAY_SIZE(sdram_tbl); 32847bb3b31ab2c95e275b850a291794a29aaaa31cdMarcelo Roberto Jimenez sdram++) 329ba53201180e267bd1f0792e6c375ced7c100738eRussell King if (strcmp(name, sdram->name) == 0) 330ba53201180e267bd1f0792e6c375ced7c100738eRussell King return sdram; 331ba53201180e267bd1f0792e6c375ced7c100738eRussell King 332ba53201180e267bd1f0792e6c375ced7c100738eRussell King return NULL; 333ba53201180e267bd1f0792e6c375ced7c100738eRussell King} 334ba53201180e267bd1f0792e6c375ced7c100738eRussell King 335ba53201180e267bd1f0792e6c375ced7c100738eRussell Kingstatic char sdram_name[16]; 336ba53201180e267bd1f0792e6c375ced7c100738eRussell King 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init sa1110_clk_init(void) 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 339ba53201180e267bd1f0792e6c375ced7c100738eRussell King struct sdram_params *sdram; 340ba53201180e267bd1f0792e6c375ced7c100738eRussell King const char *name = sdram_name; 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 342e5992c05ffaa405cd291aa9fbca042ad47d53632Dmitry Artamonow if (!cpu_is_sa1110()) 343e5992c05ffaa405cd291aa9fbca042ad47d53632Dmitry Artamonow return -ENODEV; 344e5992c05ffaa405cd291aa9fbca042ad47d53632Dmitry Artamonow 345ba53201180e267bd1f0792e6c375ced7c100738eRussell King if (!name[0]) { 346ba53201180e267bd1f0792e6c375ced7c100738eRussell King if (machine_is_assabet()) 347ba53201180e267bd1f0792e6c375ced7c100738eRussell King name = "TC59SM716-CL3"; 348ba53201180e267bd1f0792e6c375ced7c100738eRussell King if (machine_is_pt_system3()) 349ba53201180e267bd1f0792e6c375ced7c100738eRussell King name = "K4S641632D"; 350ba53201180e267bd1f0792e6c375ced7c100738eRussell King if (machine_is_h3100()) 351ba53201180e267bd1f0792e6c375ced7c100738eRussell King name = "KM416S4030CT"; 35297d496bf1a7934c77f8bb0de9b773dd759def616Linus Walleij if (machine_is_jornada720() || machine_is_h3600()) 35347bb3b31ab2c95e275b850a291794a29aaaa31cdMarcelo Roberto Jimenez name = "K4S281632B-1H"; 3549f15d2caca102c4b79e34562296bcbf982665cb2Marcelo Roberto Jimenez if (machine_is_nanoengine()) 3559f15d2caca102c4b79e34562296bcbf982665cb2Marcelo Roberto Jimenez name = "MT48LC8M16A2TG-75"; 356ba53201180e267bd1f0792e6c375ced7c100738eRussell King } 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 358ba53201180e267bd1f0792e6c375ced7c100738eRussell King sdram = sa1110_find_sdram(name); 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sdram) { 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG "SDRAM: tck: %d trcd: %d trp: %d" 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds " twr: %d refresh: %d cas_latency: %d\n", 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sdram->tck, sdram->trcd, sdram->trp, 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sdram->twr, sdram->refresh, sdram->cas_latency); 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(&sdram_params, sdram, sizeof(sdram_params)); 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return cpufreq_register_driver(&sa1110_driver); 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 373ba53201180e267bd1f0792e6c375ced7c100738eRussell Kingmodule_param_string(sdram, sdram_name, sizeof(sdram_name), 0); 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsarch_initcall(sa1110_clk_init); 375