Blame view

arch/arm/mach-omap2/sdram-nokia.c 5.92 KB
2000655ee   Tero Kristo   omap3: rx51: Add ...
1
  /*
6c3bc4eb5   Aaro Koskinen   arm: omap: rename...
2
   * SDRC register values for Nokia boards
2000655ee   Tero Kristo   omap3: rx51: Add ...
3
   *
6c3bc4eb5   Aaro Koskinen   arm: omap: rename...
4
   * Copyright (C) 2008, 2010 Nokia Corporation
2000655ee   Tero Kristo   omap3: rx51: Add ...
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
   *
   * Lauri Leukkunen <lauri.leukkunen@nokia.com>
   *
   * Original code by Juha Yrjola <juha.yrjola@solidboot.com>
   *
   * 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.
   */
  
  #include <linux/kernel.h>
  #include <linux/clk.h>
  #include <linux/err.h>
  #include <linux/io.h>
  
  #include <plat/io.h>
  #include <plat/common.h>
  #include <plat/clock.h>
  #include <plat/sdrc.h>
fcd8d8463   Aaro Koskinen   arm: omap: add sd...
24
  #include "sdram-nokia.h"
2000655ee   Tero Kristo   omap3: rx51: Add ...
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
  
  /* In picoseconds, except for tREF (ns), tXP, tCKE, tWTR (clks) */
  struct sdram_timings {
  	u32 casl;
  	u32 tDAL;
  	u32 tDPL;
  	u32 tRRD;
  	u32 tRCD;
  	u32 tRP;
  	u32 tRAS;
  	u32 tRC;
  	u32 tRFC;
  	u32 tXSR;
  
  	u32 tREF; /* in ns */
  
  	u32 tXP;
  	u32 tCKE;
  	u32 tWTR;
  };
20dbeb108   Aaro Koskinen   arm: omap: sdram-...
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
  static const struct sdram_timings nokia_97dot6mhz_timings[] = {
  	{
  		.casl = 3,
  		.tDAL = 30725,
  		.tDPL = 15362,
  		.tRRD = 10241,
  		.tRCD = 20483,
  		.tRP = 15362,
  		.tRAS = 40967,
  		.tRC = 56330,
  		.tRFC = 138266,
  		.tXSR = 204839,
  
  		.tREF = 7798,
  
  		.tXP = 2,
  		.tCKE = 4,
  		.tWTR = 2,
  	},
  };
fbd208e97   Aaro Koskinen   arm: omap: sdram-...
65
  static const struct sdram_timings nokia_166mhz_timings[] = {
2000655ee   Tero Kristo   omap3: rx51: Add ...
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
  	{
  		.casl = 3,
  		.tDAL = 33000,
  		.tDPL = 15000,
  		.tRRD = 12000,
  		.tRCD = 22500,
  		.tRP = 18000,
  		.tRAS = 42000,
  		.tRC = 66000,
  		.tRFC = 138000,
  		.tXSR = 200000,
  
  		.tREF = 7800,
  
  		.tXP = 2,
  		.tCKE = 2,
  		.tWTR = 2
  	},
  };
20dbeb108   Aaro Koskinen   arm: omap: sdram-...
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
  static const struct sdram_timings nokia_195dot2mhz_timings[] = {
  	{
  		.casl = 3,
  		.tDAL = 30725,
  		.tDPL = 15362,
  		.tRRD = 10241,
  		.tRCD = 20483,
  		.tRP = 15362,
  		.tRAS = 40967,
  		.tRC = 56330,
  		.tRFC = 138266,
  		.tXSR = 204839,
  
  		.tREF = 7752,
  
  		.tXP = 2,
  		.tCKE = 4,
  		.tWTR = 2,
  	},
  };
e5f5b5422   Aaro Koskinen   arm: omap: sdram-...
105
106
107
108
  static const struct {
  	long rate;
  	struct sdram_timings const *data;
  } nokia_timings[] = {
e5f5b5422   Aaro Koskinen   arm: omap: sdram-...
109
  	{ 83000000, nokia_166mhz_timings },
20dbeb108   Aaro Koskinen   arm: omap: sdram-...
110
  	{ 97600000, nokia_97dot6mhz_timings },
e5f5b5422   Aaro Koskinen   arm: omap: sdram-...
111
  	{ 166000000, nokia_166mhz_timings },
20dbeb108   Aaro Koskinen   arm: omap: sdram-...
112
  	{ 195200000, nokia_195dot2mhz_timings },
e5f5b5422   Aaro Koskinen   arm: omap: sdram-...
113
114
  };
  static struct omap_sdrc_params nokia_sdrc_params[ARRAY_SIZE(nokia_timings) + 1];
2000655ee   Tero Kristo   omap3: rx51: Add ...
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
  static unsigned long sdrc_get_fclk_period(long rate)
  {
  	/* In picoseconds */
  	return 1000000000 / rate;
  }
  
  static unsigned int sdrc_ps_to_ticks(unsigned int time_ps, long rate)
  {
  	unsigned long tick_ps;
  
  	/* Calculate in picosecs to yield more exact results */
  	tick_ps = sdrc_get_fclk_period(rate);
  
  	return (time_ps + tick_ps - 1) / tick_ps;
  }
  #undef DEBUG
  #ifdef DEBUG
  static int set_sdrc_timing_regval(u32 *regval, int st_bit, int end_bit,
  				int ticks, long rate, const char *name)
  #else
  static int set_sdrc_timing_regval(u32 *regval, int st_bit, int end_bit,
  			       int ticks)
  #endif
  {
  	int mask, nr_bits;
  
  	nr_bits = end_bit - st_bit + 1;
  	if (ticks >= 1 << nr_bits)
  		return -1;
  	mask = (1 << nr_bits) - 1;
  	*regval &= ~(mask << st_bit);
  	*regval |= ticks << st_bit;
  #ifdef DEBUG
  	printk(KERN_INFO "SDRC %s: %i ticks %i ns
  ", name, ticks,
  			(unsigned int)sdrc_get_fclk_period(rate) * ticks /
  			1000);
  #endif
  
  	return 0;
  }
  
  #ifdef DEBUG
  #define SDRC_SET_ONE(reg, st, end, field, rate) \
  	if (set_sdrc_timing_regval((reg), (st), (end), \
6c3bc4eb5   Aaro Koskinen   arm: omap: rename...
160
  			memory_timings->field, (rate), #field) < 0) \
2000655ee   Tero Kristo   omap3: rx51: Add ...
161
162
163
164
  		err = -1;
  #else
  #define SDRC_SET_ONE(reg, st, end, field, rate) \
  	if (set_sdrc_timing_regval((reg), (st), (end), \
6c3bc4eb5   Aaro Koskinen   arm: omap: rename...
165
  			memory_timings->field) < 0) \
2000655ee   Tero Kristo   omap3: rx51: Add ...
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
  		err = -1;
  #endif
  
  #ifdef DEBUG
  static int set_sdrc_timing_regval_ps(u32 *regval, int st_bit, int end_bit,
  				int time, long rate, const char *name)
  #else
  static int set_sdrc_timing_regval_ps(u32 *regval, int st_bit, int end_bit,
  				int time, long rate)
  #endif
  {
  	int ticks, ret;
  	ret = 0;
  
  	if (time == 0)
  		ticks = 0;
  	else
  		ticks = sdrc_ps_to_ticks(time, rate);
  
  #ifdef DEBUG
  	ret = set_sdrc_timing_regval(regval, st_bit, end_bit, ticks,
  				     rate, name);
  #else
  	ret = set_sdrc_timing_regval(regval, st_bit, end_bit, ticks);
  #endif
  
  	return ret;
  }
  
  #ifdef DEBUG
  #define SDRC_SET_ONE_PS(reg, st, end, field, rate) \
  	if (set_sdrc_timing_regval_ps((reg), (st), (end), \
6c3bc4eb5   Aaro Koskinen   arm: omap: rename...
198
  			memory_timings->field, \
2000655ee   Tero Kristo   omap3: rx51: Add ...
199
200
201
202
203
204
  			(rate), #field) < 0) \
  		err = -1;
  
  #else
  #define SDRC_SET_ONE_PS(reg, st, end, field, rate) \
  	if (set_sdrc_timing_regval_ps((reg), (st), (end), \
6c3bc4eb5   Aaro Koskinen   arm: omap: rename...
205
  			memory_timings->field, (rate)) < 0) \
2000655ee   Tero Kristo   omap3: rx51: Add ...
206
207
  		err = -1;
  #endif
fbd208e97   Aaro Koskinen   arm: omap: sdram-...
208
209
  static int sdrc_timings(int id, long rate,
  			const struct sdram_timings *memory_timings)
2000655ee   Tero Kristo   omap3: rx51: Add ...
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
  {
  	u32 ticks_per_ms;
  	u32 rfr, l;
  	u32 actim_ctrla = 0, actim_ctrlb = 0;
  	u32 rfr_ctrl;
  	int err = 0;
  	long l3_rate = rate / 1000;
  
  	SDRC_SET_ONE_PS(&actim_ctrla,  0,  4, tDAL, l3_rate);
  	SDRC_SET_ONE_PS(&actim_ctrla,  6,  8, tDPL, l3_rate);
  	SDRC_SET_ONE_PS(&actim_ctrla,  9, 11, tRRD, l3_rate);
  	SDRC_SET_ONE_PS(&actim_ctrla, 12, 14, tRCD, l3_rate);
  	SDRC_SET_ONE_PS(&actim_ctrla, 15, 17, tRP, l3_rate);
  	SDRC_SET_ONE_PS(&actim_ctrla, 18, 21, tRAS, l3_rate);
  	SDRC_SET_ONE_PS(&actim_ctrla, 22, 26, tRC, l3_rate);
  	SDRC_SET_ONE_PS(&actim_ctrla, 27, 31, tRFC, l3_rate);
  
  	SDRC_SET_ONE_PS(&actim_ctrlb,  0,  7, tXSR, l3_rate);
  
  	SDRC_SET_ONE(&actim_ctrlb,  8, 10, tXP, l3_rate);
  	SDRC_SET_ONE(&actim_ctrlb, 12, 14, tCKE, l3_rate);
  	SDRC_SET_ONE(&actim_ctrlb, 16, 17, tWTR, l3_rate);
  
  	ticks_per_ms = l3_rate;
6c3bc4eb5   Aaro Koskinen   arm: omap: rename...
234
  	rfr = memory_timings[0].tREF * ticks_per_ms / 1000000;
2000655ee   Tero Kristo   omap3: rx51: Add ...
235
236
237
238
239
240
241
242
243
244
245
246
  	if (rfr > 65535 + 50)
  		rfr = 65535;
  	else
  		rfr -= 50;
  
  #ifdef DEBUG
  	printk(KERN_INFO "SDRC tREF: %i ticks
  ", rfr);
  #endif
  
  	l = rfr << 8;
  	rfr_ctrl = l | 0x1; /* autorefresh, reload counter with 1xARCV */
6c3bc4eb5   Aaro Koskinen   arm: omap: rename...
247
248
249
250
251
  	nokia_sdrc_params[id].rate = rate;
  	nokia_sdrc_params[id].actim_ctrla = actim_ctrla;
  	nokia_sdrc_params[id].actim_ctrlb = actim_ctrlb;
  	nokia_sdrc_params[id].rfr_ctrl = rfr_ctrl;
  	nokia_sdrc_params[id].mr = 0x32;
2000655ee   Tero Kristo   omap3: rx51: Add ...
252

6c3bc4eb5   Aaro Koskinen   arm: omap: rename...
253
  	nokia_sdrc_params[id + 1].rate = 0;
2000655ee   Tero Kristo   omap3: rx51: Add ...
254
255
256
  
  	return err;
  }
6c3bc4eb5   Aaro Koskinen   arm: omap: rename...
257
  struct omap_sdrc_params *nokia_get_sdram_timings(void)
2000655ee   Tero Kristo   omap3: rx51: Add ...
258
  {
e5f5b5422   Aaro Koskinen   arm: omap: sdram-...
259
260
  	int err = 0;
  	int i;
2000655ee   Tero Kristo   omap3: rx51: Add ...
261

2b1af87ac   Aaro Koskinen   arm: omap: sdram-...
262
  	for (i = 0; i < ARRAY_SIZE(nokia_timings); i++) {
e5f5b5422   Aaro Koskinen   arm: omap: sdram-...
263
264
  		err |= sdrc_timings(i, nokia_timings[i].rate,
  				       nokia_timings[i].data);
2b1af87ac   Aaro Koskinen   arm: omap: sdram-...
265
266
267
268
269
  		if (err)
  			pr_err("%s: error with rate %ld: %d
  ", __func__,
  			       nokia_timings[i].rate, err);
  	}
2000655ee   Tero Kristo   omap3: rx51: Add ...
270

2b1af87ac   Aaro Koskinen   arm: omap: sdram-...
271
  	return err ? NULL : nokia_sdrc_params;
2000655ee   Tero Kristo   omap3: rx51: Add ...
272
  }