Commit | Line | Data |
---|---|---|
2000655e | 1 | /* |
6c3bc4eb | 2 | * SDRC register values for Nokia boards |
2000655e | 3 | * |
ef211dc6 | 4 | * Copyright (C) 2008, 2010-2011 Nokia Corporation |
2000655e TK |
5 | * |
6 | * Lauri Leukkunen <lauri.leukkunen@nokia.com> | |
7 | * | |
8 | * Original code by Juha Yrjola <juha.yrjola@solidboot.com> | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify | |
11 | * it under the terms of the GNU General Public License version 2 as | |
12 | * published by the Free Software Foundation. | |
13 | */ | |
14 | ||
15 | #include <linux/kernel.h> | |
16 | #include <linux/clk.h> | |
17 | #include <linux/err.h> | |
18 | #include <linux/io.h> | |
19 | ||
4e65331c | 20 | #include "common.h" |
2000655e TK |
21 | #include <plat/clock.h> |
22 | #include <plat/sdrc.h> | |
23 | ||
fcd8d846 | 24 | #include "sdram-nokia.h" |
2000655e TK |
25 | |
26 | /* In picoseconds, except for tREF (ns), tXP, tCKE, tWTR (clks) */ | |
27 | struct sdram_timings { | |
28 | u32 casl; | |
29 | u32 tDAL; | |
30 | u32 tDPL; | |
31 | u32 tRRD; | |
32 | u32 tRCD; | |
33 | u32 tRP; | |
34 | u32 tRAS; | |
35 | u32 tRC; | |
36 | u32 tRFC; | |
37 | u32 tXSR; | |
38 | ||
39 | u32 tREF; /* in ns */ | |
40 | ||
41 | u32 tXP; | |
42 | u32 tCKE; | |
43 | u32 tWTR; | |
44 | }; | |
45 | ||
20dbeb10 AK |
46 | static const struct sdram_timings nokia_97dot6mhz_timings[] = { |
47 | { | |
48 | .casl = 3, | |
49 | .tDAL = 30725, | |
50 | .tDPL = 15362, | |
51 | .tRRD = 10241, | |
52 | .tRCD = 20483, | |
53 | .tRP = 15362, | |
54 | .tRAS = 40967, | |
55 | .tRC = 56330, | |
56 | .tRFC = 138266, | |
57 | .tXSR = 204839, | |
58 | ||
59 | .tREF = 7798, | |
60 | ||
61 | .tXP = 2, | |
62 | .tCKE = 4, | |
63 | .tWTR = 2, | |
64 | }, | |
65 | }; | |
66 | ||
fbd208e9 | 67 | static const struct sdram_timings nokia_166mhz_timings[] = { |
2000655e TK |
68 | { |
69 | .casl = 3, | |
70 | .tDAL = 33000, | |
71 | .tDPL = 15000, | |
72 | .tRRD = 12000, | |
73 | .tRCD = 22500, | |
74 | .tRP = 18000, | |
75 | .tRAS = 42000, | |
76 | .tRC = 66000, | |
77 | .tRFC = 138000, | |
78 | .tXSR = 200000, | |
79 | ||
80 | .tREF = 7800, | |
81 | ||
82 | .tXP = 2, | |
83 | .tCKE = 2, | |
84 | .tWTR = 2 | |
85 | }, | |
86 | }; | |
87 | ||
20dbeb10 AK |
88 | static const struct sdram_timings nokia_195dot2mhz_timings[] = { |
89 | { | |
90 | .casl = 3, | |
91 | .tDAL = 30725, | |
92 | .tDPL = 15362, | |
93 | .tRRD = 10241, | |
94 | .tRCD = 20483, | |
95 | .tRP = 15362, | |
96 | .tRAS = 40967, | |
97 | .tRC = 56330, | |
98 | .tRFC = 138266, | |
99 | .tXSR = 204839, | |
100 | ||
101 | .tREF = 7752, | |
102 | ||
103 | .tXP = 2, | |
104 | .tCKE = 4, | |
105 | .tWTR = 2, | |
106 | }, | |
107 | }; | |
108 | ||
ef211dc6 ID |
109 | static const struct sdram_timings nokia_200mhz_timings[] = { |
110 | { | |
111 | .casl = 3, | |
112 | .tDAL = 30000, | |
113 | .tDPL = 15000, | |
114 | .tRRD = 10000, | |
115 | .tRCD = 20000, | |
116 | .tRP = 15000, | |
117 | .tRAS = 40000, | |
118 | .tRC = 55000, | |
119 | .tRFC = 140000, | |
120 | .tXSR = 200000, | |
121 | ||
122 | .tREF = 7800, | |
123 | ||
124 | .tXP = 2, | |
125 | .tCKE = 4, | |
126 | .tWTR = 2 | |
127 | }, | |
128 | }; | |
129 | ||
e5f5b542 AK |
130 | static const struct { |
131 | long rate; | |
132 | struct sdram_timings const *data; | |
133 | } nokia_timings[] = { | |
e5f5b542 | 134 | { 83000000, nokia_166mhz_timings }, |
20dbeb10 | 135 | { 97600000, nokia_97dot6mhz_timings }, |
ef211dc6 | 136 | { 100000000, nokia_200mhz_timings }, |
e5f5b542 | 137 | { 166000000, nokia_166mhz_timings }, |
20dbeb10 | 138 | { 195200000, nokia_195dot2mhz_timings }, |
ef211dc6 | 139 | { 200000000, nokia_200mhz_timings }, |
e5f5b542 AK |
140 | }; |
141 | static struct omap_sdrc_params nokia_sdrc_params[ARRAY_SIZE(nokia_timings) + 1]; | |
142 | ||
2000655e TK |
143 | static unsigned long sdrc_get_fclk_period(long rate) |
144 | { | |
145 | /* In picoseconds */ | |
146 | return 1000000000 / rate; | |
147 | } | |
148 | ||
149 | static unsigned int sdrc_ps_to_ticks(unsigned int time_ps, long rate) | |
150 | { | |
151 | unsigned long tick_ps; | |
152 | ||
153 | /* Calculate in picosecs to yield more exact results */ | |
154 | tick_ps = sdrc_get_fclk_period(rate); | |
155 | ||
156 | return (time_ps + tick_ps - 1) / tick_ps; | |
157 | } | |
158 | #undef DEBUG | |
159 | #ifdef DEBUG | |
160 | static int set_sdrc_timing_regval(u32 *regval, int st_bit, int end_bit, | |
161 | int ticks, long rate, const char *name) | |
162 | #else | |
163 | static int set_sdrc_timing_regval(u32 *regval, int st_bit, int end_bit, | |
164 | int ticks) | |
165 | #endif | |
166 | { | |
167 | int mask, nr_bits; | |
168 | ||
169 | nr_bits = end_bit - st_bit + 1; | |
170 | if (ticks >= 1 << nr_bits) | |
171 | return -1; | |
172 | mask = (1 << nr_bits) - 1; | |
173 | *regval &= ~(mask << st_bit); | |
174 | *regval |= ticks << st_bit; | |
175 | #ifdef DEBUG | |
176 | printk(KERN_INFO "SDRC %s: %i ticks %i ns\n", name, ticks, | |
177 | (unsigned int)sdrc_get_fclk_period(rate) * ticks / | |
178 | 1000); | |
179 | #endif | |
180 | ||
181 | return 0; | |
182 | } | |
183 | ||
184 | #ifdef DEBUG | |
185 | #define SDRC_SET_ONE(reg, st, end, field, rate) \ | |
186 | if (set_sdrc_timing_regval((reg), (st), (end), \ | |
6c3bc4eb | 187 | memory_timings->field, (rate), #field) < 0) \ |
2000655e TK |
188 | err = -1; |
189 | #else | |
190 | #define SDRC_SET_ONE(reg, st, end, field, rate) \ | |
191 | if (set_sdrc_timing_regval((reg), (st), (end), \ | |
6c3bc4eb | 192 | memory_timings->field) < 0) \ |
2000655e TK |
193 | err = -1; |
194 | #endif | |
195 | ||
196 | #ifdef DEBUG | |
197 | static int set_sdrc_timing_regval_ps(u32 *regval, int st_bit, int end_bit, | |
198 | int time, long rate, const char *name) | |
199 | #else | |
200 | static int set_sdrc_timing_regval_ps(u32 *regval, int st_bit, int end_bit, | |
201 | int time, long rate) | |
202 | #endif | |
203 | { | |
204 | int ticks, ret; | |
205 | ret = 0; | |
206 | ||
207 | if (time == 0) | |
208 | ticks = 0; | |
209 | else | |
210 | ticks = sdrc_ps_to_ticks(time, rate); | |
211 | ||
212 | #ifdef DEBUG | |
213 | ret = set_sdrc_timing_regval(regval, st_bit, end_bit, ticks, | |
214 | rate, name); | |
215 | #else | |
216 | ret = set_sdrc_timing_regval(regval, st_bit, end_bit, ticks); | |
217 | #endif | |
218 | ||
219 | return ret; | |
220 | } | |
221 | ||
222 | #ifdef DEBUG | |
223 | #define SDRC_SET_ONE_PS(reg, st, end, field, rate) \ | |
224 | if (set_sdrc_timing_regval_ps((reg), (st), (end), \ | |
6c3bc4eb | 225 | memory_timings->field, \ |
2000655e TK |
226 | (rate), #field) < 0) \ |
227 | err = -1; | |
228 | ||
229 | #else | |
230 | #define SDRC_SET_ONE_PS(reg, st, end, field, rate) \ | |
231 | if (set_sdrc_timing_regval_ps((reg), (st), (end), \ | |
6c3bc4eb | 232 | memory_timings->field, (rate)) < 0) \ |
2000655e TK |
233 | err = -1; |
234 | #endif | |
235 | ||
fbd208e9 AK |
236 | static int sdrc_timings(int id, long rate, |
237 | const struct sdram_timings *memory_timings) | |
2000655e TK |
238 | { |
239 | u32 ticks_per_ms; | |
240 | u32 rfr, l; | |
241 | u32 actim_ctrla = 0, actim_ctrlb = 0; | |
242 | u32 rfr_ctrl; | |
243 | int err = 0; | |
244 | long l3_rate = rate / 1000; | |
245 | ||
246 | SDRC_SET_ONE_PS(&actim_ctrla, 0, 4, tDAL, l3_rate); | |
247 | SDRC_SET_ONE_PS(&actim_ctrla, 6, 8, tDPL, l3_rate); | |
248 | SDRC_SET_ONE_PS(&actim_ctrla, 9, 11, tRRD, l3_rate); | |
249 | SDRC_SET_ONE_PS(&actim_ctrla, 12, 14, tRCD, l3_rate); | |
250 | SDRC_SET_ONE_PS(&actim_ctrla, 15, 17, tRP, l3_rate); | |
251 | SDRC_SET_ONE_PS(&actim_ctrla, 18, 21, tRAS, l3_rate); | |
252 | SDRC_SET_ONE_PS(&actim_ctrla, 22, 26, tRC, l3_rate); | |
253 | SDRC_SET_ONE_PS(&actim_ctrla, 27, 31, tRFC, l3_rate); | |
254 | ||
255 | SDRC_SET_ONE_PS(&actim_ctrlb, 0, 7, tXSR, l3_rate); | |
256 | ||
257 | SDRC_SET_ONE(&actim_ctrlb, 8, 10, tXP, l3_rate); | |
258 | SDRC_SET_ONE(&actim_ctrlb, 12, 14, tCKE, l3_rate); | |
259 | SDRC_SET_ONE(&actim_ctrlb, 16, 17, tWTR, l3_rate); | |
260 | ||
261 | ticks_per_ms = l3_rate; | |
6c3bc4eb | 262 | rfr = memory_timings[0].tREF * ticks_per_ms / 1000000; |
2000655e TK |
263 | if (rfr > 65535 + 50) |
264 | rfr = 65535; | |
265 | else | |
266 | rfr -= 50; | |
267 | ||
268 | #ifdef DEBUG | |
269 | printk(KERN_INFO "SDRC tREF: %i ticks\n", rfr); | |
270 | #endif | |
271 | ||
272 | l = rfr << 8; | |
273 | rfr_ctrl = l | 0x1; /* autorefresh, reload counter with 1xARCV */ | |
274 | ||
6c3bc4eb AK |
275 | nokia_sdrc_params[id].rate = rate; |
276 | nokia_sdrc_params[id].actim_ctrla = actim_ctrla; | |
277 | nokia_sdrc_params[id].actim_ctrlb = actim_ctrlb; | |
278 | nokia_sdrc_params[id].rfr_ctrl = rfr_ctrl; | |
279 | nokia_sdrc_params[id].mr = 0x32; | |
2000655e | 280 | |
6c3bc4eb | 281 | nokia_sdrc_params[id + 1].rate = 0; |
2000655e TK |
282 | |
283 | return err; | |
284 | } | |
285 | ||
6c3bc4eb | 286 | struct omap_sdrc_params *nokia_get_sdram_timings(void) |
2000655e | 287 | { |
e5f5b542 AK |
288 | int err = 0; |
289 | int i; | |
2000655e | 290 | |
2b1af87a | 291 | for (i = 0; i < ARRAY_SIZE(nokia_timings); i++) { |
e5f5b542 AK |
292 | err |= sdrc_timings(i, nokia_timings[i].rate, |
293 | nokia_timings[i].data); | |
2b1af87a AK |
294 | if (err) |
295 | pr_err("%s: error with rate %ld: %d\n", __func__, | |
296 | nokia_timings[i].rate, err); | |
297 | } | |
2000655e | 298 | |
2b1af87a | 299 | return err ? NULL : nokia_sdrc_params; |
2000655e TK |
300 | } |
301 |