18d67c368SShengzhou Liu /*
28d67c368SShengzhou Liu * Copyright 2014 Freescale Semiconductor, Inc.
38d67c368SShengzhou Liu *
45b8031ccSTom Rini * SPDX-License-Identifier: GPL-2.0
58d67c368SShengzhou Liu */
68d67c368SShengzhou Liu
78d67c368SShengzhou Liu #include <common.h>
88d67c368SShengzhou Liu #include <i2c.h>
98d67c368SShengzhou Liu #include <hwconfig.h>
108d67c368SShengzhou Liu #include <asm/mmu.h>
118d67c368SShengzhou Liu #include <fsl_ddr_sdram.h>
128d67c368SShengzhou Liu #include <fsl_ddr_dimm_params.h>
138d67c368SShengzhou Liu #include <asm/fsl_law.h>
148d67c368SShengzhou Liu #include "ddr.h"
158d67c368SShengzhou Liu
168d67c368SShengzhou Liu DECLARE_GLOBAL_DATA_PTR;
178d67c368SShengzhou Liu
fsl_ddr_board_options(memctl_options_t * popts,dimm_params_t * pdimm,unsigned int ctrl_num)188d67c368SShengzhou Liu void fsl_ddr_board_options(memctl_options_t *popts,
198d67c368SShengzhou Liu dimm_params_t *pdimm,
208d67c368SShengzhou Liu unsigned int ctrl_num)
218d67c368SShengzhou Liu {
228d67c368SShengzhou Liu const struct board_specific_parameters *pbsp, *pbsp_highest = NULL;
238d67c368SShengzhou Liu ulong ddr_freq;
248d67c368SShengzhou Liu
258d67c368SShengzhou Liu if (ctrl_num > 1) {
268d67c368SShengzhou Liu printf("Not supported controller number %d\n", ctrl_num);
278d67c368SShengzhou Liu return;
288d67c368SShengzhou Liu }
298d67c368SShengzhou Liu if (!pdimm->n_ranks)
308d67c368SShengzhou Liu return;
318d67c368SShengzhou Liu
328d67c368SShengzhou Liu pbsp = udimms[0];
338d67c368SShengzhou Liu
348d67c368SShengzhou Liu /* Get clk_adjust, wrlvl_start, wrlvl_ctl, according to the board ddr
358d67c368SShengzhou Liu * freqency and n_banks specified in board_specific_parameters table.
368d67c368SShengzhou Liu */
378d67c368SShengzhou Liu ddr_freq = get_ddr_freq(0) / 1000000;
388d67c368SShengzhou Liu while (pbsp->datarate_mhz_high) {
398d67c368SShengzhou Liu if (pbsp->n_ranks == pdimm->n_ranks &&
408d67c368SShengzhou Liu (pdimm->rank_density >> 30) >= pbsp->rank_gb) {
418d67c368SShengzhou Liu if (ddr_freq <= pbsp->datarate_mhz_high) {
428d67c368SShengzhou Liu popts->clk_adjust = pbsp->clk_adjust;
438d67c368SShengzhou Liu popts->wrlvl_start = pbsp->wrlvl_start;
448d67c368SShengzhou Liu popts->wrlvl_ctl_2 = pbsp->wrlvl_ctl_2;
458d67c368SShengzhou Liu popts->wrlvl_ctl_3 = pbsp->wrlvl_ctl_3;
468d67c368SShengzhou Liu goto found;
478d67c368SShengzhou Liu }
488d67c368SShengzhou Liu pbsp_highest = pbsp;
498d67c368SShengzhou Liu }
508d67c368SShengzhou Liu pbsp++;
518d67c368SShengzhou Liu }
528d67c368SShengzhou Liu
538d67c368SShengzhou Liu if (pbsp_highest) {
548d67c368SShengzhou Liu printf("Error: board specific timing not found");
558d67c368SShengzhou Liu printf("for data rate %lu MT/s\n", ddr_freq);
568d67c368SShengzhou Liu printf("Trying to use the highest speed (%u) parameters\n",
578d67c368SShengzhou Liu pbsp_highest->datarate_mhz_high);
588d67c368SShengzhou Liu popts->clk_adjust = pbsp_highest->clk_adjust;
598d67c368SShengzhou Liu popts->wrlvl_start = pbsp_highest->wrlvl_start;
608d67c368SShengzhou Liu popts->wrlvl_ctl_2 = pbsp->wrlvl_ctl_2;
618d67c368SShengzhou Liu popts->wrlvl_ctl_3 = pbsp->wrlvl_ctl_3;
628d67c368SShengzhou Liu } else {
638d67c368SShengzhou Liu panic("DIMM is not supported by this board");
648d67c368SShengzhou Liu }
658d67c368SShengzhou Liu found:
668d67c368SShengzhou Liu debug("Found timing match: n_ranks %d, data rate %d, rank_gb %d\n"
678d67c368SShengzhou Liu "\tclk_adjust %d, wrlvl_start %d, wrlvl_ctrl_2 0x%x, "
688d67c368SShengzhou Liu "wrlvl_ctrl_3 0x%x\n",
698d67c368SShengzhou Liu pbsp->n_ranks, pbsp->datarate_mhz_high, pbsp->rank_gb,
708d67c368SShengzhou Liu pbsp->clk_adjust, pbsp->wrlvl_start, pbsp->wrlvl_ctl_2,
718d67c368SShengzhou Liu pbsp->wrlvl_ctl_3);
728d67c368SShengzhou Liu
738d67c368SShengzhou Liu /*
748d67c368SShengzhou Liu * Factors to consider for half-strength driver enable:
758d67c368SShengzhou Liu * - number of DIMMs installed
768d67c368SShengzhou Liu */
778d67c368SShengzhou Liu popts->half_strength_driver_enable = 0;
788d67c368SShengzhou Liu /*
798d67c368SShengzhou Liu * Write leveling override
808d67c368SShengzhou Liu */
818d67c368SShengzhou Liu popts->wrlvl_override = 1;
828d67c368SShengzhou Liu popts->wrlvl_sample = 0xf;
838d67c368SShengzhou Liu
848d67c368SShengzhou Liu /*
858d67c368SShengzhou Liu * Rtt and Rtt_WR override
868d67c368SShengzhou Liu */
878d67c368SShengzhou Liu popts->rtt_override = 0;
888d67c368SShengzhou Liu
898d67c368SShengzhou Liu /* Enable ZQ calibration */
908d67c368SShengzhou Liu popts->zq_en = 1;
918d67c368SShengzhou Liu
928d67c368SShengzhou Liu /* DHC_EN =1, ODT = 75 Ohm */
938d67c368SShengzhou Liu popts->ddr_cdr1 = DDR_CDR1_DHC_EN | DDR_CDR1_ODT(DDR_CDR_ODT_75ohm);
948d67c368SShengzhou Liu popts->ddr_cdr2 = DDR_CDR2_ODT(DDR_CDR_ODT_75ohm);
9590101386SShengzhou Liu
9690101386SShengzhou Liu /* optimize cpo for erratum A-009942 */
9790101386SShengzhou Liu popts->cpo_sample = 0x54;
988d67c368SShengzhou Liu }
998d67c368SShengzhou Liu
dram_init(void)100*f1683aa7SSimon Glass int dram_init(void)
1018d67c368SShengzhou Liu {
1028d67c368SShengzhou Liu phys_size_t dram_size;
1038d67c368SShengzhou Liu
1044d666683SShengzhou Liu #if defined(CONFIG_SPL_BUILD) || !defined(CONFIG_RAMBOOT_PBL)
1058d67c368SShengzhou Liu puts("Initializing....using SPD\n");
1068d67c368SShengzhou Liu dram_size = fsl_ddr_sdram();
1074d666683SShengzhou Liu #else
1084d666683SShengzhou Liu /* DDR has been initialised by first stage boot loader */
1094d666683SShengzhou Liu dram_size = fsl_ddr_sdram_size();
1104d666683SShengzhou Liu #endif
11153499282SShengzhou Liu dram_size = setup_ddr_tlbs(dram_size / 0x100000);
11253499282SShengzhou Liu dram_size *= 0x100000;
11353499282SShengzhou Liu
114088454cdSSimon Glass gd->ram_size = dram_size;
115088454cdSSimon Glass
116088454cdSSimon Glass return 0;
1178d67c368SShengzhou Liu }
118