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 42*4ca06607SHaiying Wang typedef struct { 43*4ca06607SHaiying Wang u32 datarate_mhz_low; 44*4ca06607SHaiying Wang u32 datarate_mhz_high; 45*4ca06607SHaiying Wang u32 n_ranks; 46*4ca06607SHaiying Wang u32 clk_adjust; 47*4ca06607SHaiying Wang u32 cpo; 48*4ca06607SHaiying Wang u32 write_data_delay; 49*4ca06607SHaiying Wang u32 force_2T; 50*4ca06607SHaiying Wang } board_specific_parameters_t; 51*4ca06607SHaiying Wang 52*4ca06607SHaiying Wang /* ranges for parameters: 53*4ca06607SHaiying Wang * wr_data_delay = 0-6 54*4ca06607SHaiying Wang * clk adjust = 0-8 55*4ca06607SHaiying Wang * cpo 2-0x1E (30) 56*4ca06607SHaiying Wang */ 57*4ca06607SHaiying Wang 58*4ca06607SHaiying Wang 59*4ca06607SHaiying Wang /* XXX: these values need to be checked for all interleaving modes. */ 60*4ca06607SHaiying Wang /* XXX: No reliable dual-rank 800 MHz setting has been found. It may 61*4ca06607SHaiying Wang * seem reliable, but errors will appear when memory intensive 62*4ca06607SHaiying Wang * program is run. */ 63*4ca06607SHaiying Wang /* XXX: Single rank at 800 MHz is OK. */ 64*4ca06607SHaiying Wang const board_specific_parameters_t board_specific_parameters[][20] = { 65*4ca06607SHaiying Wang { 66*4ca06607SHaiying Wang /* memory controller 0 */ 67*4ca06607SHaiying Wang /* lo| hi| num| clk| cpo|wrdata|2T */ 68*4ca06607SHaiying Wang /* mhz| mhz|ranks|adjst| | delay| */ 69*4ca06607SHaiying Wang { 0, 333, 2, 6, 7, 3, 0}, 70*4ca06607SHaiying Wang {334, 400, 2, 6, 9, 3, 0}, 71*4ca06607SHaiying Wang {401, 549, 2, 6, 11, 3, 0}, 72*4ca06607SHaiying Wang {550, 680, 2, 1, 10, 5, 0}, 73*4ca06607SHaiying Wang {681, 850, 2, 1, 12, 5, 1}, 74*4ca06607SHaiying Wang { 0, 333, 1, 6, 7, 3, 0}, 75*4ca06607SHaiying Wang {334, 400, 1, 6, 9, 3, 0}, 76*4ca06607SHaiying Wang {401, 549, 1, 6, 11, 3, 0}, 77*4ca06607SHaiying Wang {550, 680, 1, 1, 10, 5, 0}, 78*4ca06607SHaiying Wang {681, 850, 1, 1, 12, 5, 0} 79*4ca06607SHaiying Wang }, 80*4ca06607SHaiying Wang 81*4ca06607SHaiying Wang { 82*4ca06607SHaiying Wang /* memory controller 1 */ 83*4ca06607SHaiying Wang /* lo| hi| num| clk| cpo|wrdata|2T */ 84*4ca06607SHaiying Wang /* mhz| mhz|ranks|adjst| | delay| */ 85*4ca06607SHaiying Wang { 0, 333, 2, 6, 7, 3, 0}, 86*4ca06607SHaiying Wang {334, 400, 2, 6, 9, 3, 0}, 87*4ca06607SHaiying Wang {401, 549, 2, 6, 11, 3, 0}, 88*4ca06607SHaiying Wang {550, 680, 2, 1, 11, 6, 0}, 89*4ca06607SHaiying Wang {681, 850, 2, 1, 13, 6, 1}, 90*4ca06607SHaiying Wang { 0, 333, 1, 6, 7, 3, 0}, 91*4ca06607SHaiying Wang {334, 400, 1, 6, 9, 3, 0}, 92*4ca06607SHaiying Wang {401, 549, 1, 6, 11, 3, 0}, 93*4ca06607SHaiying Wang {550, 680, 1, 1, 11, 6, 0}, 94*4ca06607SHaiying Wang {681, 850, 1, 1, 13, 6, 0} 95*4ca06607SHaiying Wang } 96*4ca06607SHaiying Wang }; 97*4ca06607SHaiying Wang 98dfb49108SHaiying Wang void fsl_ddr_board_options(memctl_options_t *popts, 99dfb49108SHaiying Wang dimm_params_t *pdimm, 100dfb49108SHaiying Wang unsigned int ctrl_num) 101129ba616SKumar Gala { 102*4ca06607SHaiying Wang const board_specific_parameters_t *pbsp = 103*4ca06607SHaiying Wang &(board_specific_parameters[ctrl_num][0]); 104*4ca06607SHaiying Wang u32 num_params = sizeof(board_specific_parameters[ctrl_num]) / 105*4ca06607SHaiying Wang sizeof(board_specific_parameters[0][0]); 106*4ca06607SHaiying Wang u32 i; 107*4ca06607SHaiying Wang ulong ddr_freq; 108129ba616SKumar Gala 109*4ca06607SHaiying Wang /* set odt_rd_cfg and odt_wr_cfg. If the there is only one dimm in 110*4ca06607SHaiying Wang * that controller, set odt_wr_cfg to 4 for CS0, and 0 to CS1. If 111*4ca06607SHaiying Wang * there are two dimms in the controller, set odt_rd_cfg to 3 and 112*4ca06607SHaiying Wang * odt_wr_cfg to 3 for the even CS, 0 for the odd CS. 113129ba616SKumar Gala */ 114*4ca06607SHaiying Wang for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { 115*4ca06607SHaiying Wang if (i&1) { /* odd CS */ 116*4ca06607SHaiying Wang popts->cs_local_opts[i].odt_rd_cfg = 0; 117*4ca06607SHaiying Wang popts->cs_local_opts[i].odt_wr_cfg = 0; 118*4ca06607SHaiying Wang } else { /* even CS */ 119*4ca06607SHaiying Wang if (CONFIG_DIMM_SLOTS_PER_CTLR == 1) { 120*4ca06607SHaiying Wang popts->cs_local_opts[i].odt_rd_cfg = 0; 121*4ca06607SHaiying Wang popts->cs_local_opts[i].odt_wr_cfg = 4; 122*4ca06607SHaiying Wang } else if (CONFIG_DIMM_SLOTS_PER_CTLR == 2) { 123*4ca06607SHaiying Wang popts->cs_local_opts[i].odt_rd_cfg = 3; 124*4ca06607SHaiying Wang popts->cs_local_opts[i].odt_wr_cfg = 3; 125*4ca06607SHaiying Wang } 126*4ca06607SHaiying Wang } 127*4ca06607SHaiying Wang } 128129ba616SKumar Gala 129*4ca06607SHaiying Wang /* Get clk_adjust, cpo, write_data_delay,2T, according to the board ddr 130*4ca06607SHaiying Wang * freqency and n_banks specified in board_specific_parameters table. 131129ba616SKumar Gala */ 132*4ca06607SHaiying Wang ddr_freq = get_ddr_freq(0) / 1000000; 133*4ca06607SHaiying Wang for (i = 0; i < num_params; i++) { 134*4ca06607SHaiying Wang if (ddr_freq >= pbsp->datarate_mhz_low && 135*4ca06607SHaiying Wang ddr_freq <= pbsp->datarate_mhz_high && 136*4ca06607SHaiying Wang pdimm->n_ranks == pbsp->n_ranks) { 137*4ca06607SHaiying Wang popts->clk_adjust = pbsp->clk_adjust; 138*4ca06607SHaiying Wang popts->cpo_override = pbsp->cpo; 139*4ca06607SHaiying Wang popts->write_data_delay = pbsp->write_data_delay; 140*4ca06607SHaiying Wang popts->twoT_en = pbsp->force_2T; 141*4ca06607SHaiying Wang } 142*4ca06607SHaiying Wang pbsp++; 143*4ca06607SHaiying Wang } 144129ba616SKumar Gala 145129ba616SKumar Gala /* 146129ba616SKumar Gala * Factors to consider for half-strength driver enable: 147129ba616SKumar Gala * - number of DIMMs installed 148129ba616SKumar Gala */ 149129ba616SKumar Gala popts->half_strength_driver_enable = 0; 150129ba616SKumar Gala } 151