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