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