]>
Commit | Line | Data |
---|---|---|
8ed96046 WD |
1 | /* |
2 | * (C) Copyright 2004 | |
3 | * Texas Instruments, <www.ti.com> | |
4 | * Richard Woodruff <r-woodruff2@ti.com> | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU General Public License as | |
8 | * published by the Free Software Foundation; either version 2 of | |
9 | * the License, or (at your option) any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program; if not, write to the Free Software | |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
19 | * MA 02111-1307 USA | |
20 | */ | |
21 | ||
22 | #include <common.h> | |
23 | #include <asm/arch/omap2420.h> | |
24 | #include <asm/io.h> | |
25 | #include <asm/arch/bits.h> | |
26 | #include <asm/arch/mux.h> | |
27 | #include <asm/arch/mem.h> | |
28 | #include <asm/arch/clocks.h> | |
29 | #include <asm/arch/sys_proto.h> | |
30 | #include <asm/arch/sys_info.h> | |
31 | ||
32 | /************************************************************ | |
33 | * sdelay() - simple spin loop. Will be constant time as | |
34 | * its generally used in 12MHz bypass conditions only. This | |
35 | * is necessary until timers are accessible. | |
36 | * | |
37 | * not inline to increase chances its in cache when called | |
38 | *************************************************************/ | |
39 | void sdelay (unsigned long loops) | |
40 | { | |
289f932c WD |
41 | __asm__ volatile ("1:\n" "subs %0, %1, #1\n" |
42 | "bne 1b":"=r" (loops):"0" (loops)); | |
8ed96046 WD |
43 | } |
44 | ||
45 | /********************************************************************************* | |
46 | * prcm_init() - inits clocks for PRCM as defined in clocks.h (config II default). | |
47 | * -- called from SRAM, or Flash (using temp SRAM stack). | |
48 | *********************************************************************************/ | |
49 | void prcm_init(void) | |
50 | { | |
49a7581c | 51 | u32 div; |
8ed96046 WD |
52 | void (*f_lock_pll) (u32, u32, u32, u32); |
53 | extern void *_end_vect, *_start; | |
54 | ||
55 | f_lock_pll = (void *)((u32)&_end_vect - (u32)&_start + SRAM_VECT_CODE); | |
8ed96046 WD |
56 | |
57 | __raw_writel(0, CM_FCLKEN1_CORE); /* stop all clocks to reduce ringing */ | |
58 | __raw_writel(0, CM_FCLKEN2_CORE); /* may not be necessary */ | |
59 | __raw_writel(0, CM_ICLKEN1_CORE); | |
60 | __raw_writel(0, CM_ICLKEN2_CORE); | |
61 | ||
62 | __raw_writel(DPLL_OUT, CM_CLKSEL2_PLL); /* set DPLL out */ | |
63 | __raw_writel(MPU_DIV, CM_CLKSEL_MPU); /* set MPU divider */ | |
64 | __raw_writel(DSP_DIV, CM_CLKSEL_DSP); /* set dsp and iva dividers */ | |
65 | __raw_writel(GFX_DIV, CM_CLKSEL_GFX); /* set gfx dividers */ | |
66 | ||
49a7581c | 67 | div = BUS_DIV; |
8ed96046 WD |
68 | __raw_writel(div, CM_CLKSEL1_CORE);/* set L3/L4/USB/Display/Vlnc/SSi dividers */ |
69 | sdelay(1000); | |
70 | ||
289f932c WD |
71 | if(running_in_sram()){ |
72 | /* If running fully from SRAM this is OK. The Flash bus drops out for just a little. | |
5a95f6fb WD |
73 | * but then comes back. If running from Flash this sequence kills you, thus you need |
74 | * to run it using CONFIG_PARTIAL_SRAM. | |
75 | */ | |
289f932c WD |
76 | __raw_writel(MODE_BYPASS_FAST, CM_CLKEN_PLL); /* go to bypass, fast relock */ |
77 | wait_on_value(BIT0|BIT1, BIT0, CM_IDLEST_CKGEN, LDELAY); /* wait till in bypass */ | |
78 | sdelay(1000); | |
79 | /* set clock selection and dpll dividers. */ | |
80 | __raw_writel(DPLL_VAL, CM_CLKSEL1_PLL); /* set pll for target rate */ | |
81 | __raw_writel(COMMIT_DIVIDERS, PRCM_CLKCFG_CTRL); /* commit dividers */ | |
82 | sdelay(10000); | |
83 | __raw_writel(DPLL_LOCK, CM_CLKEN_PLL); /* enable dpll */ | |
84 | sdelay(10000); | |
85 | wait_on_value(BIT0|BIT1, BIT1, CM_IDLEST_CKGEN, LDELAY); /*wait for dpll lock */ | |
86 | }else if(running_in_flash()){ | |
87 | /* if running from flash, need to jump to small relocated code area in SRAM. | |
88 | * This is the only safe spot to do configurations from. | |
89 | */ | |
90 | (*f_lock_pll)(PRCM_CLKCFG_CTRL, CM_CLKEN_PLL, DPLL_LOCK, CM_IDLEST_CKGEN); | |
91 | } | |
8ed96046 WD |
92 | |
93 | __raw_writel(DPLL_LOCK|APLL_LOCK, CM_CLKEN_PLL); /* enable apll */ | |
94 | wait_on_value(BIT8, BIT8, CM_IDLEST_CKGEN, LDELAY); /* wait for apll lock */ | |
95 | sdelay(1000); | |
96 | } | |
97 | ||
49a7581c WD |
98 | /************************************************************************** |
99 | * make_cs1_contiguous() - for es2 and above remap cs1 behind cs0 to allow | |
100 | * command line mem=xyz use all memory with out discontigious support | |
101 | * compiled in. Could do it at the ATAG, but there really is two banks... | |
102 | * Called as part of 2nd phase DDR init. | |
103 | **************************************************************************/ | |
104 | void make_cs1_contiguous(void) | |
105 | { | |
106 | u32 size, a_add_low, a_add_high; | |
107 | ||
108 | size = get_sdr_cs_size(SDRC_CS0_OSET); | |
109 | size /= SZ_32M; /* find size to offset CS1 */ | |
110 | a_add_high = (size & 3) << 8; /* set up low field */ | |
111 | a_add_low = (size & 0x3C) >> 2; /* set up high field */ | |
112 | __raw_writel((a_add_high|a_add_low),SDRC_CS_CFG); | |
113 | ||
114 | } | |
8ed96046 WD |
115 | |
116 | /******************************************************** | |
117 | * mem_ok() - test used to see if timings are correct | |
118 | * for a part. Helps in gussing which part | |
119 | * we are currently using. | |
120 | *******************************************************/ | |
121 | u32 mem_ok(void) | |
289f932c WD |
122 | { |
123 | u32 val1, val2; | |
124 | u32 pattern = 0x12345678; | |
125 | ||
126 | __raw_writel(0x0,OMAP2420_SDRC_CS0+0x400); /* clear pos A */ | |
127 | __raw_writel(pattern, OMAP2420_SDRC_CS0); /* pattern to pos B */ | |
128 | __raw_writel(0x0,OMAP2420_SDRC_CS0+4); /* remove pattern off the bus */ | |
129 | val1 = __raw_readl(OMAP2420_SDRC_CS0+0x400); /* get pos A value */ | |
130 | val2 = __raw_readl(OMAP2420_SDRC_CS0); /* get val2 */ | |
131 | ||
132 | if ((val1 != 0) || (val2 != pattern)) /* see if pos A value changed*/ | |
8ed96046 WD |
133 | return(0); |
134 | else | |
135 | return(1); | |
136 | } | |
137 | ||
49a7581c | 138 | |
8ed96046 WD |
139 | /******************************************************** |
140 | * sdrc_init() - init the sdrc chip selects CS0 and CS1 | |
141 | * - early init routines, called from flash or | |
142 | * SRAM. | |
143 | *******************************************************/ | |
144 | void sdrc_init(void) | |
145 | { | |
146 | #define EARLY_INIT 1 | |
147 | do_sdrc_init(SDRC_CS0_OSET, EARLY_INIT); /* only init up first bank here */ | |
148 | } | |
149 | ||
289f932c | 150 | /************************************************************************* |
8ed96046 WD |
151 | * do_sdrc_init(): initialize the SDRAM for use. |
152 | * -called from low level code with stack only. | |
153 | * -code sets up SDRAM timing and muxing for 2422 or 2420. | |
154 | * -optimal settings can be placed here, or redone after i2c | |
155 | * inspection of board info | |
156 | * | |
289f932c WD |
157 | * This is a bit ugly, but should handle all memory moduels |
158 | * used with the H4. The first time though this code from s_init() | |
159 | * we configure the first chip select. Later on we come back and | |
160 | * will configure the 2nd chip select if it exists. | |
161 | * | |
162 | **************************************************************************/ | |
8ed96046 WD |
163 | void do_sdrc_init(u32 offset, u32 early) |
164 | { | |
49a7581c | 165 | u32 cpu, dllen=0, rev, common=0, cs0=0, pmask=0, pass_type, mtype; |
8ed96046 | 166 | sdrc_data_t *sdata; /* do not change type */ |
289f932c | 167 | u32 a, b, r; |
8ed96046 WD |
168 | |
169 | static const sdrc_data_t sdrc_2422 = | |
170 | { | |
289f932c | 171 | H4_2422_SDRC_SHARING, H4_2422_SDRC_MDCFG_0_DDR, 0 , H4_2422_SDRC_ACTIM_CTRLA_0, |
49a7581c WD |
172 | H4_2422_SDRC_ACTIM_CTRLB_0, H4_2422_SDRC_RFR_CTRL, H4_2422_SDRC_MR_0_DDR, |
173 | 0, H4_2422_SDRC_DLLAB_CTRL | |
8ed96046 WD |
174 | }; |
175 | static const sdrc_data_t sdrc_2420 = | |
176 | { | |
289f932c WD |
177 | H4_2420_SDRC_SHARING, H4_2420_SDRC_MDCFG_0_DDR, H4_2420_SDRC_MDCFG_0_SDR, |
178 | H4_2420_SDRC_ACTIM_CTRLA_0, H4_2420_SDRC_ACTIM_CTRLB_0, | |
49a7581c WD |
179 | H4_2420_SDRC_RFR_CTRL, H4_2420_SDRC_MR_0_DDR, H4_2420_SDRC_MR_0_SDR, |
180 | H4_2420_SDRC_DLLAB_CTRL | |
8ed96046 WD |
181 | }; |
182 | ||
183 | if (offset == SDRC_CS0_OSET) | |
289f932c | 184 | cs0 = common = 1; /* int regs shared between both chip select */ |
8ed96046 WD |
185 | |
186 | cpu = get_cpu_type(); | |
49a7581c | 187 | rev = get_cpu_rev(); |
8ed96046 | 188 | |
289f932c | 189 | /* warning generated, though code generation is correct. this may bite later, |
5a95f6fb WD |
190 | * but is ok for now. there is only so much C code you can do on stack only |
191 | * operation. | |
8ed96046 | 192 | */ |
289f932c WD |
193 | if (cpu == CPU_2422){ |
194 | sdata = (sdrc_data_t *)&sdrc_2422; | |
195 | pass_type = STACKED; | |
5a95f6fb | 196 | } else{ |
289f932c WD |
197 | sdata = (sdrc_data_t *)&sdrc_2420; |
198 | pass_type = IP_DDR; | |
199 | } | |
8ed96046 | 200 | |
289f932c | 201 | __asm__ __volatile__("": : :"memory"); /* limit compiler scope */ |
8ed96046 | 202 | |
289f932c | 203 | /* u-boot is compiled to run in DDR or SRAM at 8xxxxxxx or 4xxxxxxx. |
5a95f6fb WD |
204 | * If we are running in flash prior to relocation and we use data |
205 | * here which is not pc relative we need to get the address correct. | |
206 | * We need to find the current flash mapping to dress up the initial | |
207 | * pointer load. As long as this is const data we should be ok. | |
289f932c WD |
208 | */ |
209 | if((early) && running_in_flash()){ | |
210 | sdata = (sdrc_data_t *)(((u32)sdata & 0x0003FFFF) | get_gpmc0_base()); | |
211 | /* NOR internal boot offset is 0x4000 from xloader signature */ | |
212 | if(running_from_internal_boot()) | |
213 | sdata = (sdrc_data_t *)((u32)sdata + 0x4000); | |
214 | } | |
49a7581c WD |
215 | |
216 | if (!early && (((mtype = get_mem_type()) == DDR_COMBO)||(mtype == DDR_STACKED))) { | |
217 | if(mtype == DDR_COMBO){ | |
218 | pmask = BIT2;/* combo part has a shared CKE signal, can't use feature */ | |
219 | pass_type = COMBO_DDR; /* CS1 config */ | |
220 | __raw_writel((__raw_readl(SDRC_POWER)) & ~pmask, SDRC_POWER); | |
221 | } | |
222 | if(rev != CPU_2420_2422_ES1) /* for es2 and above smooth things out */ | |
223 | make_cs1_contiguous(); | |
8ed96046 WD |
224 | } |
225 | ||
289f932c WD |
226 | next_mem_type: |
227 | if (common) { /* do a SDRC reset between types to clear regs*/ | |
228 | __raw_writel(SOFTRESET, SDRC_SYSCONFIG); /* reset sdrc */ | |
229 | wait_on_value(BIT0, BIT0, SDRC_STATUS, 12000000);/* wait till reset done set */ | |
230 | __raw_writel(0, SDRC_SYSCONFIG); /* clear soft reset */ | |
8ed96046 | 231 | __raw_writel(sdata->sdrc_sharing, SDRC_SHARING); |
289f932c WD |
232 | #ifdef POWER_SAVE |
233 | __raw_writel(__raw_readl(SMS_SYSCONFIG)|SMART_IDLE, SMS_SYSCONFIG); | |
234 | __raw_writel(sdata->sdrc_sharing|SMART_IDLE, SDRC_SHARING); | |
49a7581c | 235 | __raw_writel((__raw_readl(SDRC_POWER)|BIT6), SDRC_POWER); |
289f932c WD |
236 | #endif |
237 | } | |
238 | ||
239 | if ((pass_type == IP_DDR) || (pass_type == STACKED)) /* (IP ddr-CS0),(2422-CS0/CS1) */ | |
240 | __raw_writel(sdata->sdrc_mdcfg_0_ddr, SDRC_MCFG_0+offset); | |
241 | else if (pass_type == COMBO_DDR){ /* (combo-CS0/CS1) */ | |
242 | __raw_writel(H4_2420_COMBO_MDCFG_0_DDR,SDRC_MCFG_0+offset); | |
243 | } else if (pass_type == IP_SDR){ /* ip sdr-CS0 */ | |
244 | __raw_writel(sdata->sdrc_mdcfg_0_sdr, SDRC_MCFG_0+offset); | |
8ed96046 | 245 | } |
289f932c | 246 | |
49a7581c WD |
247 | a = sdata->sdrc_actim_ctrla_0; |
248 | b = sdata->sdrc_actim_ctrlb_0; | |
249 | r = sdata->sdrc_dllab_ctrl; | |
250 | ||
251 | /* work around ES1 DDR issues */ | |
252 | if((pass_type != IP_SDR) && (rev == CPU_2420_2422_ES1)){ | |
253 | a = H4_242x_SDRC_ACTIM_CTRLA_0_ES1; | |
254 | b = H4_242x_SDRC_ACTIM_CTRLB_0_ES1; | |
255 | r = H4_242x_SDRC_RFR_CTRL_ES1; | |
53677ef1 | 256 | } |
8ed96046 WD |
257 | |
258 | if (cs0) { | |
289f932c WD |
259 | __raw_writel(a, SDRC_ACTIM_CTRLA_0); |
260 | __raw_writel(b, SDRC_ACTIM_CTRLB_0); | |
8ed96046 | 261 | } else { |
289f932c WD |
262 | __raw_writel(a, SDRC_ACTIM_CTRLA_1); |
263 | __raw_writel(b, SDRC_ACTIM_CTRLB_1); | |
8ed96046 | 264 | } |
289f932c | 265 | __raw_writel(r, SDRC_RFR_CTRL+offset); |
8ed96046 | 266 | |
289f932c | 267 | /* init sequence for mDDR/mSDR using manual commands (DDR is a bit different) */ |
8ed96046 | 268 | __raw_writel(CMD_NOP, SDRC_MANUAL_0+offset); |
289f932c | 269 | sdelay(5000); /* susposed to be 100us per design spec for mddr/msdr */ |
8ed96046 WD |
270 | __raw_writel(CMD_PRECHARGE, SDRC_MANUAL_0+offset); |
271 | __raw_writel(CMD_AUTOREFRESH, SDRC_MANUAL_0+offset); | |
272 | __raw_writel(CMD_AUTOREFRESH, SDRC_MANUAL_0+offset); | |
273 | ||
274 | /* | |
275 | * CSx SDRC Mode Register | |
289f932c | 276 | * Burst length = (4 - DDR) (2-SDR) |
8ed96046 WD |
277 | * Serial mode |
278 | * CAS latency = x | |
279 | */ | |
289f932c WD |
280 | if(pass_type == IP_SDR) |
281 | __raw_writel(sdata->sdrc_mr_0_sdr, SDRC_MR_0+offset); | |
282 | else | |
283 | __raw_writel(sdata->sdrc_mr_0_ddr, SDRC_MR_0+offset); | |
8ed96046 | 284 | |
289f932c | 285 | /* NOTE: ES1 242x _BUG_ DLL + External Bandwidth fix*/ |
49a7581c WD |
286 | if (rev == CPU_2420_2422_ES1){ |
287 | dllen = (BIT0|BIT3); /* es1 clear both bit0 and bit3 */ | |
289f932c WD |
288 | __raw_writel((__raw_readl(SMS_CLASS_ARB0)|BURSTCOMPLETE_GROUP7) |
289 | ,SMS_CLASS_ARB0);/* enable bust complete for lcd */ | |
290 | } | |
49a7581c WD |
291 | else |
292 | dllen = BIT0|BIT1; /* es2, clear bit0, and 1 (set phase to 72) */ | |
293 | ||
294 | /* enable & load up DLL with good value for 75MHz, and set phase to 90 | |
295 | * ES1 recommends 90 phase, ES2 recommends 72 phase. | |
296 | */ | |
289f932c | 297 | if (common && (pass_type != IP_SDR)) { |
49a7581c WD |
298 | __raw_writel(sdata->sdrc_dllab_ctrl, SDRC_DLLA_CTRL); |
299 | __raw_writel(sdata->sdrc_dllab_ctrl & ~(BIT2|dllen), SDRC_DLLA_CTRL); | |
300 | __raw_writel(sdata->sdrc_dllab_ctrl, SDRC_DLLB_CTRL); | |
301 | __raw_writel(sdata->sdrc_dllab_ctrl & ~(BIT2|dllen) , SDRC_DLLB_CTRL); | |
8ed96046 | 302 | } |
289f932c | 303 | sdelay(90000); |
8ed96046 | 304 | |
289f932c WD |
305 | if(mem_ok()) |
306 | return; /* STACKED, other configued type */ | |
307 | ++pass_type; /* IPDDR->COMBODDR->IPSDR for CS0 */ | |
308 | goto next_mem_type; | |
309 | } | |
8ed96046 WD |
310 | |
311 | /***************************************************** | |
312 | * gpmc_init(): init gpmc bus | |
313 | * Init GPMC for x16, MuxMode (SDRAM in x32). | |
314 | * This code can only be executed from SRAM or SDRAM. | |
315 | *****************************************************/ | |
316 | void gpmc_init(void) | |
317 | { | |
49a7581c WD |
318 | u32 mux=0, mtype, mwidth, rev, tval; |
319 | ||
320 | rev = get_cpu_rev(); | |
321 | if (rev == CPU_2420_2422_ES1) | |
322 | tval = 1; | |
323 | else | |
324 | tval = 0; /* disable bit switched meaning */ | |
8ed96046 WD |
325 | |
326 | /* global settings */ | |
327 | __raw_writel(0x10, GPMC_SYSCONFIG); /* smart idle */ | |
328 | __raw_writel(0x0, GPMC_IRQENABLE); /* isr's sources masked */ | |
49a7581c | 329 | __raw_writel(tval, GPMC_TIMEOUT_CONTROL);/* timeout disable */ |
6d0f6bcf | 330 | #ifdef CONFIG_SYS_NAND_BOOT |
289f932c WD |
331 | __raw_writel(0x001, GPMC_CONFIG); /* set nWP, disable limited addr */ |
332 | #else | |
8ed96046 | 333 | __raw_writel(0x111, GPMC_CONFIG); /* set nWP, disable limited addr */ |
289f932c | 334 | #endif |
8ed96046 WD |
335 | |
336 | /* discover bus connection from sysboot */ | |
337 | if (is_gpmc_muxed() == GPMC_MUXED) | |
338 | mux = BIT9; | |
339 | mtype = get_gpmc0_type(); | |
340 | mwidth = get_gpmc0_width(); | |
341 | ||
342 | /* setup cs0 */ | |
343 | __raw_writel(0x0, GPMC_CONFIG7_0); /* disable current map */ | |
344 | sdelay(1000); | |
289f932c | 345 | |
6d0f6bcf | 346 | #ifdef CONFIG_SYS_NAND_BOOT |
289f932c WD |
347 | __raw_writel(H4_24XX_GPMC_CONFIG1_0|mtype|mwidth, GPMC_CONFIG1_0); |
348 | #else | |
8ed96046 | 349 | __raw_writel(H4_24XX_GPMC_CONFIG1_0|mux|mtype|mwidth, GPMC_CONFIG1_0); |
289f932c WD |
350 | #endif |
351 | ||
352 | #ifdef PRCM_CONFIG_III | |
353 | __raw_writel(H4_24XX_GPMC_CONFIG2_0, GPMC_CONFIG2_0); | |
354 | #endif | |
8ed96046 WD |
355 | __raw_writel(H4_24XX_GPMC_CONFIG3_0, GPMC_CONFIG3_0); |
356 | __raw_writel(H4_24XX_GPMC_CONFIG4_0, GPMC_CONFIG4_0); | |
289f932c WD |
357 | #ifdef PRCM_CONFIG_III |
358 | __raw_writel(H4_24XX_GPMC_CONFIG5_0, GPMC_CONFIG5_0); | |
359 | __raw_writel(H4_24XX_GPMC_CONFIG6_0, GPMC_CONFIG6_0); | |
360 | #endif | |
8ed96046 WD |
361 | __raw_writel(H4_24XX_GPMC_CONFIG7_0, GPMC_CONFIG7_0);/* enable new mapping */ |
362 | sdelay(2000); | |
363 | ||
364 | /* setup cs1 */ | |
365 | __raw_writel(0, GPMC_CONFIG7_1); /* disable any mapping */ | |
366 | sdelay(1000); | |
367 | __raw_writel(H4_24XX_GPMC_CONFIG1_1|mux, GPMC_CONFIG1_1); | |
368 | __raw_writel(H4_24XX_GPMC_CONFIG2_1, GPMC_CONFIG2_1); | |
369 | __raw_writel(H4_24XX_GPMC_CONFIG3_1, GPMC_CONFIG3_1); | |
370 | __raw_writel(H4_24XX_GPMC_CONFIG4_1, GPMC_CONFIG4_1); | |
371 | __raw_writel(H4_24XX_GPMC_CONFIG5_1, GPMC_CONFIG5_1); | |
372 | __raw_writel(H4_24XX_GPMC_CONFIG6_1, GPMC_CONFIG6_1); | |
373 | __raw_writel(H4_24XX_GPMC_CONFIG7_1, GPMC_CONFIG7_1); /* enable mapping */ | |
374 | sdelay(2000); | |
375 | } |