xref: /openbmc/u-boot/board/freescale/mpc8572ds/ddr.c (revision 634bc554)
1129ba616SKumar Gala /*
2129ba616SKumar Gala  * Copyright 2008 Freescale Semiconductor, Inc.
3129ba616SKumar Gala  *
4129ba616SKumar Gala  * This program is free software; you can redistribute it and/or
5129ba616SKumar Gala  * modify it under the terms of the GNU General Public License
6129ba616SKumar Gala  * Version 2 as published by the Free Software Foundation.
7129ba616SKumar Gala  */
8129ba616SKumar Gala 
9129ba616SKumar Gala #include <common.h>
10129ba616SKumar Gala #include <i2c.h>
11129ba616SKumar Gala 
12129ba616SKumar Gala #include <asm/fsl_ddr_sdram.h>
13dfb49108SHaiying Wang #include <asm/fsl_ddr_dimm_params.h>
14129ba616SKumar Gala 
15129ba616SKumar Gala static void get_spd(ddr2_spd_eeprom_t *spd, unsigned char i2c_address)
16129ba616SKumar Gala {
17129ba616SKumar Gala 	i2c_read(i2c_address, 0, 1, (uchar *)spd, sizeof(ddr2_spd_eeprom_t));
18129ba616SKumar Gala }
19129ba616SKumar Gala 
20129ba616SKumar Gala unsigned int fsl_ddr_get_mem_data_rate(void)
21129ba616SKumar Gala {
22129ba616SKumar Gala 	return get_ddr_freq(0);
23129ba616SKumar Gala }
24129ba616SKumar Gala 
25129ba616SKumar Gala void fsl_ddr_get_spd(ddr2_spd_eeprom_t *ctrl_dimms_spd,
26129ba616SKumar Gala 		      unsigned int ctrl_num)
27129ba616SKumar Gala {
28129ba616SKumar Gala 	unsigned int i;
29129ba616SKumar Gala 	unsigned int i2c_address = 0;
30129ba616SKumar Gala 
31129ba616SKumar Gala 	for (i = 0; i < CONFIG_DIMM_SLOTS_PER_CTLR; i++) {
32129ba616SKumar Gala 		if (ctrl_num == 0 && i == 0) {
33129ba616SKumar Gala 			i2c_address = SPD_EEPROM_ADDRESS1;
34129ba616SKumar Gala 		}
35129ba616SKumar Gala 		if (ctrl_num == 1 && i == 0) {
36129ba616SKumar Gala 			i2c_address = SPD_EEPROM_ADDRESS2;
37129ba616SKumar Gala 		}
38129ba616SKumar Gala 		get_spd(&(ctrl_dimms_spd[i]), i2c_address);
39129ba616SKumar Gala 	}
40129ba616SKumar Gala }
41129ba616SKumar Gala 
424ca06607SHaiying Wang typedef struct {
434ca06607SHaiying Wang 	u32 datarate_mhz_low;
444ca06607SHaiying Wang 	u32 datarate_mhz_high;
454ca06607SHaiying Wang 	u32 n_ranks;
464ca06607SHaiying Wang 	u32 clk_adjust;
474ca06607SHaiying Wang 	u32 cpo;
484ca06607SHaiying Wang 	u32 write_data_delay;
494ca06607SHaiying Wang 	u32 force_2T;
504ca06607SHaiying Wang } board_specific_parameters_t;
514ca06607SHaiying Wang 
52*634bc554SYork Sun /*
53*634bc554SYork Sun  * CPO value doesn't matter if workaround for errata 111 and 134 enabled.
54*634bc554SYork Sun  *
55*634bc554SYork Sun  * For DDR2 DIMM, all combinations of clk_adjust and write_data_delay have been
56*634bc554SYork Sun  * tested. For RDIMM, clk_adjust = 4 and write_data_delay = 3 is optimized for
57*634bc554SYork Sun  * all clocks from 400MT/s to 800MT/s, verified with Kingston KVR800D2D8P6/2G.
58*634bc554SYork Sun  * For UDIMM, clk_adjust = 8 and write_delay = 5 is optimized for all clocks
59*634bc554SYork Sun  * from 400MT/s to 800MT/s, verified with Micron MT18HTF25672AY-800E1.
604ca06607SHaiying Wang  */
61*634bc554SYork Sun const board_specific_parameters_t board_specific_parameters_udimm[][20] = {
624ca06607SHaiying Wang 	{
63*634bc554SYork Sun 	/*
64*634bc554SYork Sun 	 *	memory controller 0
65*634bc554SYork Sun 	 *	  lo|  hi|  num|  clk| cpo|wrdata|2T
66*634bc554SYork Sun 	 *	 mhz| mhz|ranks|adjst|    | delay|
67*634bc554SYork Sun 	 */
68*634bc554SYork Sun 		{  0, 333,    2,    8,   7,    5,  0},
69*634bc554SYork Sun 		{334, 400,    2,    8,   9,    5,  0},
70*634bc554SYork Sun 		{401, 549,    2,    8,  11,    5,  0},
71*634bc554SYork Sun 		{550, 680,    2,    8,  10,    5,  0},
72*634bc554SYork Sun 		{681, 850,    2,    8,  12,    5,  1},
734ca06607SHaiying Wang 		{  0, 333,    1,    6,   7,    3,  0},
744ca06607SHaiying Wang 		{334, 400,    1,    6,   9,    3,  0},
754ca06607SHaiying Wang 		{401, 549,    1,    6,  11,    3,  0},
764ca06607SHaiying Wang 		{550, 680,    1,    1,  10,    5,  0},
774ca06607SHaiying Wang 		{681, 850,    1,    1,  12,    5,  0}
784ca06607SHaiying Wang 	},
794ca06607SHaiying Wang 
804ca06607SHaiying Wang 	{
81*634bc554SYork Sun 	/*
82*634bc554SYork Sun 	 *	memory controller 1
83*634bc554SYork Sun 	 *	  lo|  hi|  num|  clk| cpo|wrdata|2T
84*634bc554SYork Sun 	 *	 mhz| mhz|ranks|adjst|    | delay|
85*634bc554SYork Sun 	 */
86*634bc554SYork Sun 		{  0, 333,    2,     8,  7,    5,  0},
87*634bc554SYork Sun 		{334, 400,    2,     8,  9,    5,  0},
88*634bc554SYork Sun 		{401, 549,    2,     8, 11,    5,  0},
89*634bc554SYork Sun 		{550, 680,    2,     8, 11,    5,  0},
90*634bc554SYork Sun 		{681, 850,    2,     8, 13,    5,  1},
914ca06607SHaiying Wang 		{  0, 333,    1,     6,  7,    3,  0},
924ca06607SHaiying Wang 		{334, 400,    1,     6,  9,    3,  0},
934ca06607SHaiying Wang 		{401, 549,    1,     6, 11,    3,  0},
944ca06607SHaiying Wang 		{550, 680,    1,     1, 11,    6,  0},
954ca06607SHaiying Wang 		{681, 850,    1,     1, 13,    6,  0}
964ca06607SHaiying Wang 	}
974ca06607SHaiying Wang };
984ca06607SHaiying Wang 
99*634bc554SYork Sun const board_specific_parameters_t board_specific_parameters_rdimm[][20] = {
100*634bc554SYork Sun 	{
101*634bc554SYork Sun 	/*
102*634bc554SYork Sun 	 *	memory controller 0
103*634bc554SYork Sun 	 *	  lo|  hi|  num|  clk| cpo|wrdata|2T
104*634bc554SYork Sun 	 *	 mhz| mhz|ranks|adjst|    | delay|
105*634bc554SYork Sun 	 */
106*634bc554SYork Sun 		{  0, 333,    2,    4,   7,    3,  0},
107*634bc554SYork Sun 		{334, 400,    2,    4,   9,    3,  0},
108*634bc554SYork Sun 		{401, 549,    2,    4,  11,    3,  0},
109*634bc554SYork Sun 		{550, 680,    2,    4,  10,    3,  0},
110*634bc554SYork Sun 		{681, 850,    2,    4,  12,    3,  1},
111*634bc554SYork Sun 	},
112*634bc554SYork Sun 
113*634bc554SYork Sun 	{
114*634bc554SYork Sun 	/*
115*634bc554SYork Sun 	 *	memory controller 1
116*634bc554SYork Sun 	 *	  lo|  hi|  num|  clk| cpo|wrdata|2T
117*634bc554SYork Sun 	 *	 mhz| mhz|ranks|adjst|    | delay|
118*634bc554SYork Sun 	 */
119*634bc554SYork Sun 		{  0, 333,    2,     4,  7,    3,  0},
120*634bc554SYork Sun 		{334, 400,    2,     4,  9,    3,  0},
121*634bc554SYork Sun 		{401, 549,    2,     4, 11,    3,  0},
122*634bc554SYork Sun 		{550, 680,    2,     4, 11,    3,  0},
123*634bc554SYork Sun 		{681, 850,    2,     4, 13,    3,  1},
124*634bc554SYork Sun 	}
125*634bc554SYork Sun };
126*634bc554SYork Sun 
127dfb49108SHaiying Wang void fsl_ddr_board_options(memctl_options_t *popts,
128dfb49108SHaiying Wang 				dimm_params_t *pdimm,
129dfb49108SHaiying Wang 				unsigned int ctrl_num)
130129ba616SKumar Gala {
131*634bc554SYork Sun 	const board_specific_parameters_t *pbsp;
132*634bc554SYork Sun 	u32 num_params;
1334ca06607SHaiying Wang 	u32 i;
1344ca06607SHaiying Wang 	ulong ddr_freq;
135*634bc554SYork Sun 	int matched = 0;
136*634bc554SYork Sun 
137*634bc554SYork Sun 	if (!pdimm->n_ranks)
138*634bc554SYork Sun 		return;
139*634bc554SYork Sun 
140*634bc554SYork Sun 	if (popts->registered_dimm_en) {
141*634bc554SYork Sun 		pbsp = &(board_specific_parameters_rdimm[ctrl_num][0]);
142*634bc554SYork Sun 		num_params = sizeof(board_specific_parameters_rdimm[ctrl_num]) /
143*634bc554SYork Sun 				sizeof(board_specific_parameters_rdimm[0][0]);
144*634bc554SYork Sun 	} else {
145*634bc554SYork Sun 		pbsp = &(board_specific_parameters_udimm[ctrl_num][0]);
146*634bc554SYork Sun 		num_params = sizeof(board_specific_parameters_udimm[ctrl_num]) /
147*634bc554SYork Sun 				sizeof(board_specific_parameters_udimm[0][0]);
148*634bc554SYork Sun 	}
149129ba616SKumar Gala 
1504ca06607SHaiying Wang 	/* set odt_rd_cfg and odt_wr_cfg. If the there is only one dimm in
1514ca06607SHaiying Wang 	 * that controller, set odt_wr_cfg to 4 for CS0, and 0 to CS1. If
1524ca06607SHaiying Wang 	 * there are two dimms in the controller, set odt_rd_cfg to 3 and
1534ca06607SHaiying Wang 	 * odt_wr_cfg to 3 for the even CS, 0 for the odd CS.
154129ba616SKumar Gala 	 */
1554ca06607SHaiying Wang 	for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
1564ca06607SHaiying Wang 		if (i&1) {	/* odd CS */
1574ca06607SHaiying Wang 			popts->cs_local_opts[i].odt_rd_cfg = 0;
1584ca06607SHaiying Wang 			popts->cs_local_opts[i].odt_wr_cfg = 0;
1594ca06607SHaiying Wang 		} else {	/* even CS */
1604ca06607SHaiying Wang 			if (CONFIG_DIMM_SLOTS_PER_CTLR == 1) {
1614ca06607SHaiying Wang 				popts->cs_local_opts[i].odt_rd_cfg = 0;
1624ca06607SHaiying Wang 				popts->cs_local_opts[i].odt_wr_cfg = 4;
1634ca06607SHaiying Wang 			} else if (CONFIG_DIMM_SLOTS_PER_CTLR == 2) {
1644ca06607SHaiying Wang 			popts->cs_local_opts[i].odt_rd_cfg = 3;
1654ca06607SHaiying Wang 			popts->cs_local_opts[i].odt_wr_cfg = 3;
1664ca06607SHaiying Wang 			}
1674ca06607SHaiying Wang 		}
1684ca06607SHaiying Wang 	}
169129ba616SKumar Gala 
1704ca06607SHaiying Wang 	/* Get clk_adjust, cpo, write_data_delay,2T, according to the board ddr
1714ca06607SHaiying Wang 	 * freqency and n_banks specified in board_specific_parameters table.
172129ba616SKumar Gala 	 */
1734ca06607SHaiying Wang 	ddr_freq = get_ddr_freq(0) / 1000000;
1744ca06607SHaiying Wang 	for (i = 0; i < num_params; i++) {
1754ca06607SHaiying Wang 		if (ddr_freq >= pbsp->datarate_mhz_low &&
1764ca06607SHaiying Wang 		    ddr_freq <= pbsp->datarate_mhz_high &&
1774ca06607SHaiying Wang 		    pdimm->n_ranks == pbsp->n_ranks) {
1784ca06607SHaiying Wang 			popts->clk_adjust = pbsp->clk_adjust;
1794ca06607SHaiying Wang 			popts->cpo_override = pbsp->cpo;
1804ca06607SHaiying Wang 			popts->write_data_delay = pbsp->write_data_delay;
1814ca06607SHaiying Wang 			popts->twoT_en = pbsp->force_2T;
182*634bc554SYork Sun 			matched = 1;
183*634bc554SYork Sun 			break;
1844ca06607SHaiying Wang 		}
1854ca06607SHaiying Wang 		pbsp++;
1864ca06607SHaiying Wang 	}
187129ba616SKumar Gala 
188*634bc554SYork Sun 	if (!matched)
189*634bc554SYork Sun 		printf("Warning: board specific timing not found!\n");
190*634bc554SYork Sun 
191129ba616SKumar Gala 	/*
192129ba616SKumar Gala 	 * Factors to consider for half-strength driver enable:
193129ba616SKumar Gala 	 *	- number of DIMMs installed
194129ba616SKumar Gala 	 */
195129ba616SKumar Gala 	popts->half_strength_driver_enable = 0;
196129ba616SKumar Gala }
197