]>
Commit | Line | Data |
---|---|---|
5da6f806 PT |
1 | /* |
2 | * Copyright 2009 Extreme Engineering Solutions, Inc. | |
3 | * Copyright 2007-2008 Freescale Semiconductor, Inc. | |
4 | * | |
5 | * See file CREDITS for list of people who contributed to this | |
6 | * project. | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU General Public License as | |
10 | * published by the Free Software Foundation; either version 2 of | |
11 | * the License, or (at your option) any later version. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
21 | * MA 02111-1307 USA | |
22 | */ | |
23 | ||
24 | #include <common.h> | |
25 | #include <i2c.h> | |
26 | #include <asm/fsl_ddr_sdram.h> | |
27 | #include <asm/fsl_ddr_dimm_params.h> | |
28 | ||
29 | static void get_spd(ddr2_spd_eeprom_t *spd, unsigned char i2c_address) | |
30 | { | |
31 | i2c_read(i2c_address, SPD_EEPROM_OFFSET, 2, (uchar *)spd, | |
32 | sizeof(ddr2_spd_eeprom_t)); | |
33 | } | |
34 | ||
35 | unsigned int fsl_ddr_get_mem_data_rate(void) | |
36 | { | |
37 | return get_bus_freq(0); | |
38 | } | |
39 | ||
40 | void fsl_ddr_get_spd(ddr2_spd_eeprom_t *ctrl_dimms_spd, | |
41 | unsigned int ctrl_num) | |
42 | { | |
43 | unsigned int i; | |
44 | unsigned int i2c_address = 0; | |
45 | ||
46 | for (i = 0; i < CONFIG_DIMM_SLOTS_PER_CTLR; i++) { | |
47 | if (ctrl_num == 0) { | |
48 | i2c_address = SPD_EEPROM_ADDRESS1; | |
49 | #ifdef SPD_EEPROM_ADDRESS2 | |
50 | } else if (ctrl_num == 1) { | |
51 | i2c_address = SPD_EEPROM_ADDRESS2; | |
52 | #endif | |
53 | } else { | |
54 | /* An inalid ctrl number was give, use default SPD */ | |
55 | printf("ERROR: invalid DDR ctrl: %d\n", ctrl_num); | |
56 | i2c_address = SPD_EEPROM_ADDRESS1; | |
57 | } | |
58 | ||
59 | get_spd(&(ctrl_dimms_spd[i]), i2c_address); | |
60 | } | |
61 | } | |
62 | ||
63 | /* | |
64 | * There are four board-specific SDRAM timing parameters which must be | |
65 | * calculated based on the particular PCB artwork. These are: | |
66 | * 1.) CPO (Read Capture Delay) | |
67 | * - TIMING_CFG_2 register | |
68 | * Source: Calculation based on board trace lengths and | |
69 | * chip-specific internal delays. | |
70 | * 2.) WR_DATA_DELAY (Write Command to Data Strobe Delay) | |
71 | * - TIMING_CFG_2 register | |
72 | * Source: Calculation based on board trace lengths. | |
73 | * Unless clock and DQ lanes are very different | |
74 | * lengths (>2"), this should be set to the nominal value | |
75 | * of 1/2 clock delay. | |
76 | * 3.) CLK_ADJUST (Clock and Addr/Cmd alignment control) | |
77 | * - DDR_SDRAM_CLK_CNTL register | |
78 | * Source: Signal Integrity Simulations | |
79 | * 4.) 2T Timing on Addr/Ctl | |
80 | * - TIMING_CFG_2 register | |
81 | * Source: Signal Integrity Simulations | |
82 | * Usually only needed with heavy load/very high speed (>DDR2-800) | |
83 | * | |
84 | * PCB routing on the XPedite5170 is nearly identical to the XPedite5370 | |
85 | * so we use the XPedite5370 settings as a basis for the XPedite5170. | |
86 | */ | |
87 | ||
88 | typedef struct board_memctl_options { | |
89 | uint16_t datarate_mhz_low; | |
90 | uint16_t datarate_mhz_high; | |
91 | uint8_t clk_adjust; | |
92 | uint8_t cpo_override; | |
93 | uint8_t write_data_delay; | |
94 | } board_memctl_options_t; | |
95 | ||
96 | static struct board_memctl_options bopts_ctrl[][2] = { | |
97 | { | |
98 | /* Controller 0 */ | |
99 | { | |
100 | /* DDR2 600/667 */ | |
101 | .datarate_mhz_low = 500, | |
102 | .datarate_mhz_high = 750, | |
103 | .clk_adjust = 5, | |
104 | .cpo_override = 8, | |
105 | .write_data_delay = 2, | |
106 | }, | |
107 | { | |
108 | /* DDR2 800 */ | |
109 | .datarate_mhz_low = 750, | |
110 | .datarate_mhz_high = 850, | |
111 | .clk_adjust = 5, | |
112 | .cpo_override = 9, | |
113 | .write_data_delay = 2, | |
114 | }, | |
115 | }, | |
116 | { | |
117 | /* Controller 1 */ | |
118 | { | |
119 | /* DDR2 600/667 */ | |
120 | .datarate_mhz_low = 500, | |
121 | .datarate_mhz_high = 750, | |
122 | .clk_adjust = 5, | |
123 | .cpo_override = 7, | |
124 | .write_data_delay = 2, | |
125 | }, | |
126 | { | |
127 | /* DDR2 800 */ | |
128 | .datarate_mhz_low = 750, | |
129 | .datarate_mhz_high = 850, | |
130 | .clk_adjust = 5, | |
131 | .cpo_override = 8, | |
132 | .write_data_delay = 2, | |
133 | }, | |
134 | }, | |
135 | }; | |
136 | ||
137 | void fsl_ddr_board_options(memctl_options_t *popts, | |
138 | dimm_params_t *pdimm, | |
139 | unsigned int ctrl_num) | |
140 | { | |
141 | struct board_memctl_options *bopts = bopts_ctrl[ctrl_num]; | |
142 | sys_info_t sysinfo; | |
143 | int i; | |
144 | unsigned int datarate; | |
145 | ||
146 | get_sys_info(&sysinfo); | |
147 | datarate = fsl_ddr_get_mem_data_rate() / 1000000; | |
148 | ||
149 | for (i = 0; i < ARRAY_SIZE(bopts_ctrl[ctrl_num]); i++) { | |
150 | if ((bopts[i].datarate_mhz_low <= datarate) && | |
151 | (bopts[i].datarate_mhz_high >= datarate)) { | |
152 | debug("controller %d:\n", ctrl_num); | |
153 | debug(" clk_adjust = %d\n", bopts[i].clk_adjust); | |
154 | debug(" cpo = %d\n", bopts[i].cpo_override); | |
155 | debug(" write_data_delay = %d\n", | |
156 | bopts[i].write_data_delay); | |
157 | popts->clk_adjust = bopts[i].clk_adjust; | |
158 | popts->cpo_override = bopts[i].cpo_override; | |
159 | popts->write_data_delay = bopts[i].write_data_delay; | |
160 | } | |
161 | } | |
162 | ||
163 | /* | |
164 | * Factors to consider for half-strength driver enable: | |
165 | * - number of DIMMs installed | |
166 | */ | |
167 | popts->half_strength_driver_enable = 0; | |
168 | } |