[go: nahoru, domu]

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