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