/*
 * Copyright 2008 Freescale Semiconductor, Inc.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * Version 2 as published by the Free Software Foundation.
 */

#include <common.h>
#include <i2c.h>

#include <asm/fsl_ddr_sdram.h>
#include <asm/fsl_ddr_dimm_params.h>

static void
get_spd(ddr2_spd_eeprom_t *spd, unsigned char i2c_address)
{
	i2c_read(i2c_address, 0, 1, (uchar *)spd, sizeof(ddr2_spd_eeprom_t));
}

unsigned int fsl_ddr_get_mem_data_rate(void)
{
	return get_bus_freq(0);
}

void fsl_ddr_get_spd(ddr2_spd_eeprom_t *ctrl_dimms_spd,
		      unsigned int ctrl_num)
{
	unsigned int i;
	unsigned int i2c_address = 0;

	for (i = 0; i < CONFIG_DIMM_SLOTS_PER_CTLR; i++) {
		if (ctrl_num == 0 && i == 0) {
			i2c_address = SPD_EEPROM_ADDRESS1;
		}
		if (ctrl_num == 0 && i == 1) {
			i2c_address = SPD_EEPROM_ADDRESS2;
		}
		if (ctrl_num == 1 && i == 0) {
			i2c_address = SPD_EEPROM_ADDRESS3;
		}
		if (ctrl_num == 1 && i == 1) {
			i2c_address = SPD_EEPROM_ADDRESS4;
		}
		get_spd(&(ctrl_dimms_spd[i]), i2c_address);
	}
}

typedef struct {
        u32 datarate_mhz_low;
        u32 datarate_mhz_high;
        u32 n_ranks;
        u32 clk_adjust;
        u32 cpo;
        u32 write_data_delay;
} board_specific_parameters_t;

/* XXX: these values need to be checked for all interleaving modes.  */
const board_specific_parameters_t board_specific_parameters[2][16] = {
	{
	/* 	memory controller 0		 	*/
	/*	  lo|  hi|  num|  clk| cpo|wrdata	*/
	/*	 mhz| mhz|ranks|adjst|    | delay	*/
		{  0, 333,    4,    7,   7,     3},
		{334, 400,    4,    7,   9,     3},
		{401, 549,    4,    7,   9,     3},
		{550, 650,    4,    7,  10,     4},

		{  0, 333,    3,    7,   7,     3},
		{334, 400,    3,    7,   9,     3},
		{401, 549,    3,    7,   9,     3},
		{550, 650,    3,    7,  10,     4},

		{  0, 333,    2,    7,   7,     3},
		{334, 400,    2,    7,   9,     3},
		{401, 549,    2,    7,   9,     3},
		{550, 650,    2,    7,  10,     4},

		{  0, 333,    1,    7,   7,     3},
		{334, 400,    1,    7,   9,     3},
		{401, 549,    1,    7,   9,     3},
		{550, 650,    1,    7,  10,     4}
	},

	{
	/* 	memory controller 1			*/
	/*        lo|  hi|  num|  clk| cpo|wrdata	*/
	/*       mhz| mhz|ranks|adjst|    | delay	*/
		{  0, 333,    4,    7,   7,    3},
		{334, 400,    4,    7,   9,    3},
		{401, 549,    4,    7,   9,    3},
		{550, 650,    4,    7,  10,    4},

		{  0, 333,    3,    7,   7,    3},
		{334, 400,    3,    7,   9,    3},
		{401, 549,    3,    7,   9,    3},
		{550, 650,    3,    7,  10,    4},

		{  0, 333,    2,    7,   7,    3},
		{334, 400,    2,    7,   9,    3},
		{401, 549,    2,    7,   9,    3},
		{550, 650,    2,    7,  10,    4},

		{  0, 333,    1,    7,   7,    3},
		{334, 400,    1,    7,   9,    3},
		{401, 549,    1,    7,   9,    3},
		{550, 650,    1,    7,  10,    4}
	}
};

void fsl_ddr_board_options(memctl_options_t *popts,
			dimm_params_t *pdimm,
			unsigned int ctrl_num)
{
	const board_specific_parameters_t *pbsp =
			&(board_specific_parameters[ctrl_num][0]);
	u32 num_params = sizeof(board_specific_parameters[ctrl_num]) /
			sizeof(board_specific_parameters[0][0]);
	u32 i;
	u32 j;
	ulong ddr_freq;

	/* set odt_rd_cfg and odt_wr_cfg. If the there is only one dimm in
	 * that controller, set odt_wr_cfg to 4 for CS0, and 0 to CS1. If
	 * there are two dimms in the controller, set odt_rd_cfg to 3 and
	 * odt_wr_cfg to 3 for the even CS, 0 for the odd CS.
	 */
	for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
		if (i&1) {      /* odd CS */
			popts->cs_local_opts[i].odt_rd_cfg = 0;
			popts->cs_local_opts[i].odt_wr_cfg = 0;
		} else {        /* even CS */
			if ((CONFIG_DIMM_SLOTS_PER_CTLR == 2) &&
				(pdimm[i/2].n_ranks != 0)) {
				popts->cs_local_opts[i].odt_rd_cfg = 3;
				popts->cs_local_opts[i].odt_wr_cfg = 3;
			} else {
				popts->cs_local_opts[i].odt_rd_cfg = 0;
				popts->cs_local_opts[i].odt_wr_cfg = 4;
			}
		}
	}

	/* Get clk_adjust, cpo, write_data_delay, according to the board ddr
	 * freqency and n_banks specified in board_specific_parameters table.
	 */
	ddr_freq = fsl_ddr_get_mem_data_rate() / 1000000;
	for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
		if (pdimm[j].n_ranks > 0) {
			for (i = 0; i < num_params; i++) {
				if (ddr_freq >= pbsp->datarate_mhz_low &&
				ddr_freq <= pbsp->datarate_mhz_high &&
				pdimm[j].n_ranks == pbsp->n_ranks) {
					popts->clk_adjust = pbsp->clk_adjust;
					popts->cpo_override = pbsp->cpo;
					popts->write_data_delay =
						pbsp->write_data_delay;
					break;
				}
				pbsp++;
			}
		}
	}

}
