diff options
Diffstat (limited to 'arch/powerpc/ddr-8xxx/ctrl_regs.c')
-rw-r--r-- | arch/powerpc/ddr-8xxx/ctrl_regs.c | 778 |
1 files changed, 778 insertions, 0 deletions
diff --git a/arch/powerpc/ddr-8xxx/ctrl_regs.c b/arch/powerpc/ddr-8xxx/ctrl_regs.c new file mode 100644 index 0000000000..e3d43ab09e --- /dev/null +++ b/arch/powerpc/ddr-8xxx/ctrl_regs.c @@ -0,0 +1,778 @@ +/* + * Copyright 2008-2012 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 as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +/* + * Generic driver for Freescale DDR2/DDR3 memory controller. + * Based on code from spd_sdram.c + * Author: James Yang [at freescale.com] + */ + +#include <common.h> +#include <asm/fsl_ddr_sdram.h> +#include "ddr.h" + +static uint32_t compute_cas_write_latency(void) +{ + uint32_t cwl; + const uint32_t mclk_ps = get_memory_clk_period_ps(); + + if (mclk_ps >= 2500) + cwl = 5; + else if (mclk_ps >= 1875) + cwl = 6; + else if (mclk_ps >= 1500) + cwl = 7; + else if (mclk_ps >= 1250) + cwl = 8; + else if (mclk_ps >= 1070) + cwl = 9; + else if (mclk_ps >= 935) + cwl = 10; + else if (mclk_ps >= 833) + cwl = 11; + else if (mclk_ps >= 750) + cwl = 12; + else + cwl = 12; + + return cwl; +} + +static void set_csn_config(int dimm_number, int i, + struct fsl_ddr_cfg_regs_s *ddr, + const struct memctl_options_s *popts, + const struct dimm_params_s *dimm) +{ + uint32_t cs_n_en = 0, ap_n_en = 0, odt_rd_cfg = 0, odt_wr_cfg = 0, + ba_bits_cs_n = 0, row_bits_cs_n = 0, col_bits_cs_n = 0, + n_banks_per_sdram_device; + int go_config = 0; + + switch (i) { + case 0: + if (dimm[dimm_number].n_ranks > 0) + go_config = 1; + break; + case 1: + if ((dimm_number == 0 && dimm[0].n_ranks > 1) || + (dimm_number == 1 && dimm[1].n_ranks > 0)) + go_config = 1; + break; + case 2: + if ((dimm_number == 0 && dimm[0].n_ranks > 2) || + (dimm_number >= 1 && dimm[dimm_number].n_ranks > 0)) + go_config = 1; + break; + case 3: + if ((dimm_number == 0 && dimm[0].n_ranks > 3) || + (dimm_number == 1 && dimm[1].n_ranks > 1) || + (dimm_number == 3 && dimm[3].n_ranks > 0)) + go_config = 1; + break; + default: + break; + } + + if (go_config) { + /* Chip Select enable */ + cs_n_en = 1; + /* CSn auto-precharge enable */ + ap_n_en = popts->cs_local_opts[i].auto_precharge; + /* ODT for reads configuration */ + odt_rd_cfg = popts->cs_local_opts[i].odt_rd_cfg; + /* ODT for writes configuration */ + odt_wr_cfg = popts->cs_local_opts[i].odt_wr_cfg; + /* Num of bank bits for SDRAM on CSn */ + n_banks_per_sdram_device = + dimm[dimm_number].n_banks_per_sdram_device; + ba_bits_cs_n = __ilog2(n_banks_per_sdram_device) - 2; + /* Num of row bits for SDRAM on CSn */ + row_bits_cs_n = dimm[dimm_number].n_row_addr - 12; + /* Num of ocl bits for SDRAM on CSn */ + col_bits_cs_n = dimm[dimm_number].n_col_addr - 8; + } + + ddr->cs[i].config = (((cs_n_en & 0x1) << 31) + | ((ap_n_en & 0x1) << 23) + | ((odt_rd_cfg & 0x7) << 20) + | ((odt_wr_cfg & 0x7) << 16) + | ((ba_bits_cs_n & 0x3) << 14) + | ((row_bits_cs_n & 0x7) << 8) + | ((col_bits_cs_n & 0x7) << 0)); +} + +static void set_timing_cfg_0(struct fsl_ddr_cfg_regs_s *ddr, + const struct memctl_options_s *popts, + const struct dimm_params_s *dimm) +{ + uint32_t trwt_mclk = 0, twrt_mclk = 0, act_pd_exit_mclk, + pre_pd_exit_mclk, taxpd_mclk, tmrd_mclk, txp, + data_rate = fsl_get_ddr_freq(0); + + if (popts->sdram_type == SDRAM_TYPE_DDR2) { + act_pd_exit_mclk = popts->txard; + pre_pd_exit_mclk = popts->txp; + taxpd_mclk = popts->taxpd; + tmrd_mclk = popts->tmrd; + } else { + /* + * tXARD is not part of the DDR3 specification, use the + * parameter txp instead of it. That is: + * txp=max(3nCK, 7.5ns). As well, use tAXPD=1. + */ + txp = max_t(uint32_t, (get_memory_clk_period_ps() * 3), 7500); + data_rate = fsl_get_ddr_freq(0); + tmrd_mclk = 4; + + /* for faster clock, need more time for data setup */ + if (popts->trwt_override) + trwt_mclk = popts->trwt; + else if (data_rate / 1000000 > 1800) + trwt_mclk = 2; + else + trwt_mclk = 0; + + if (data_rate / 1000000 > 1150) + twrt_mclk = 1; + else + twrt_mclk = 0; + + taxpd_mclk = 1; + if (popts->dynamic_power == 0) { + act_pd_exit_mclk = 1; + pre_pd_exit_mclk = 1; + } else { + /* act_pd_exit_mclk = tXARD, see above */ + act_pd_exit_mclk = picos_to_mclk(txp); + /* Mode register MR0[A12] is '1' - fast exit */ + pre_pd_exit_mclk = act_pd_exit_mclk; + } + } + + ddr->timing_cfg_0 = (((trwt_mclk & 0x3) << 30) + | ((twrt_mclk & 0x3) << 28) + | ((act_pd_exit_mclk & 0xf) << 20) + | ((pre_pd_exit_mclk & 0xf) << 16) + | ((taxpd_mclk & 0xf) << 8) + | ((tmrd_mclk & 0x1f) << 0) + ); +} + +static void set_timing_cfg_3(struct fsl_ddr_cfg_regs_s *ddr, + const struct memctl_options_s *popts, + const struct common_timing_params_s *dimm, + uint32_t cas_latency, uint32_t additive_latency) +{ + uint32_t ext_pretoact, ext_acttopre, ext_acttorw, ext_refrec, ext_wrrec; + + ext_pretoact = picos_to_mclk(dimm->tRP_ps) >> 4; + ext_acttopre = picos_to_mclk(dimm->tRAS_ps) >> 4; + ext_acttorw = picos_to_mclk(dimm->tRCD_ps) >> 4; + cas_latency = ((cas_latency << 1) - 1) >> 4; + additive_latency = additive_latency >> 4; + ext_refrec = (picos_to_mclk(dimm->tRFC_ps) - 8) >> 4; + /* ext_wrrec only deals with 16 clock and above, or 14 with OTF */ + ext_wrrec = (picos_to_mclk(dimm->tWR_ps) + + (popts->otf_burst_chop_en ? 2 : 0)) >> 4; + + ddr->timing_cfg_3 = (((ext_pretoact & 0x1) << 28) + | ((ext_acttopre & 0x3) << 24) + | ((ext_acttorw & 0x1) << 22) + | ((ext_refrec & 0x1F) << 16) + | ((cas_latency & 0x3) << 12) + | ((additive_latency & 0x1) << 10) + | ((ext_wrrec & 0x1) << 8) + ); +} + +static void set_timing_cfg_1(struct fsl_ddr_cfg_regs_s *ddr, + const struct memctl_options_s *popts, + const struct common_timing_params_s *dimm, + uint32_t cas_latency) +{ + uint32_t pretoact_mclk, acttopre_mclk, acttorw_mclk, refrec_ctrl, + wrrec_mclk, acttoact_mclk, wrtord_mclk; + /* DDR_SDRAM_MODE doesn't support 9,11,13,15 */ + static const u8 wrrec_table[] = { + 1, 2, 3, 4, 5, 6, 7, 8, 10, 10, 12, 12, 14, 14, 0, 0 + }; + + pretoact_mclk = picos_to_mclk(dimm->tRP_ps); + acttopre_mclk = picos_to_mclk(dimm->tRAS_ps); + acttorw_mclk = picos_to_mclk(dimm->tRCD_ps); + + /* + * Translate CAS Latency to a DDR controller field value: + * + * CAS Lat DDR II Ctrl + * Clocks SPD Bit Value + * ------- ------- ------ + * 1.0 0001 + * 1.5 0010 + * 2.0 2 0011 + * 2.5 0100 + * 3.0 3 0101 + * 3.5 0110 + * 4.0 4 0111 + * 4.5 1000 + * 5.0 5 1001 + */ + cas_latency = (cas_latency << 1) - 1; + refrec_ctrl = picos_to_mclk(dimm->tRFC_ps) - 8; + acttoact_mclk = picos_to_mclk(dimm->tRRD_ps); + + wrrec_mclk = picos_to_mclk(dimm->tWR_ps); + if (wrrec_mclk <= 16) + wrrec_mclk = wrrec_table[wrrec_mclk - 1]; + if (popts->otf_burst_chop_en) + wrrec_mclk += 2; + + wrtord_mclk = picos_to_mclk(dimm->tWTR_ps); + if (popts->sdram_type == SDRAM_TYPE_DDR2) { + wrtord_mclk = max_t(uint32_t, wrtord_mclk, 2); + } else { + wrtord_mclk = max_t(uint32_t, wrtord_mclk, 4); + acttoact_mclk = max_t(uint32_t, acttoact_mclk, 4); + } + + if (popts->otf_burst_chop_en) + wrtord_mclk += 2; + + ddr->timing_cfg_1 = (((pretoact_mclk & 0x0F) << 28) + | ((acttopre_mclk & 0x0F) << 24) + | ((acttorw_mclk & 0xF) << 20) + | ((cas_latency & 0xF) << 16) + | ((refrec_ctrl & 0xF) << 12) + | ((wrrec_mclk & 0x0F) << 8) + | ((acttoact_mclk & 0x0F) << 4) + | ((wrtord_mclk & 0x0F) << 0)); +} + +static void set_timing_cfg_2(struct fsl_ddr_cfg_regs_s *ddr, + const struct memctl_options_s *popts, + const struct common_timing_params_s *dimm, + uint32_t cas_latency, uint32_t additive_latency) +{ + uint32_t cpo, rd_to_pre, wr_data_delay, cke_pls, four_act; + + cpo = popts->cpo_override; + rd_to_pre = picos_to_mclk(dimm->tRTP_ps); + if (popts->sdram_type == SDRAM_TYPE_DDR2) { + cas_latency = cas_latency - 1; + rd_to_pre = max_t(uint32_t, rd_to_pre, 2); + } else { + cas_latency = compute_cas_write_latency(); + rd_to_pre = max_t(uint32_t, rd_to_pre, 4); + } + + if (popts->otf_burst_chop_en) + rd_to_pre += 2; + + wr_data_delay = popts->write_data_delay; + cke_pls = picos_to_mclk(popts->tCKE_clock_pulse_width_ps); + four_act = picos_to_mclk(popts->tFAW_window_four_activates_ps); + + ddr->timing_cfg_2 = (((additive_latency & 0xf) << 28) + | ((cpo & 0x1f) << 23) + | ((cas_latency & 0xf) << 19) + | ((rd_to_pre & 7) << 13) + | ((wr_data_delay & 7) << 10) + | ((cke_pls & 0x7) << 6) + | ((four_act & 0x3f) << 0)); +} + +static void set_ddr_sdram_cfg(struct fsl_ddr_cfg_regs_s *ddr, + const struct memctl_options_s *popts, + const struct common_timing_params_s *dimm) +{ + uint32_t mem_en, sren, ecc_en, sdram_type, dyn_pwr, dbw, twoT_en, hse, + threet_en, eight_be = 0; + + mem_en = 1; + sren = popts->self_refresh_in_sleep; + if (dimm->all_DIMMs_ECC_capable) + ecc_en = popts->ECC_mode; + else + ecc_en = 0; + + sdram_type = popts->sdram_type; + twoT_en = popts->twoT_en; + dyn_pwr = popts->dynamic_power; + dbw = popts->data_bus_width; + hse = popts->half_strength_driver_enable; + threet_en = popts->threet_en; + + if (sdram_type == SDRAM_TYPE_DDR3) + if ((popts->burst_length == DDR_BL8) || (dbw == 1)) + eight_be = 1; + + ddr->ddr_sdram_cfg = (((mem_en & 0x1) << 31) + | ((sren & 0x1) << 30) + | ((ecc_en & 0x1) << 29) + | ((sdram_type & 0x7) << 24) + | ((dyn_pwr & 0x1) << 21) + | ((dbw & 0x3) << 19) + | ((eight_be & 0x1) << 18) + | ((threet_en & 0x1) << 16) + | ((twoT_en & 0x1) << 15) + | ((hse & 0x1) << 3)); +} + +static void set_ddr_sdram_cfg_2(struct fsl_ddr_cfg_regs_s *ddr, + const struct memctl_options_s *popts) +{ + struct ddr_board_info_s *bi = popts->board_info; + uint32_t i, dll_rst_dis, dqs_cfg, odt_cfg = 0, num_pr, d_init = 0, + obc_cfg = 0, x4_en, md_en = 0, rcw_en = 0; + + dll_rst_dis = popts->dll_rst_dis; + dqs_cfg = popts->DQS_config; + + /* + * Check for On-Die Termination options and + * assert ODT only during reads to DRAM. + */ + for (i = 0; i < bi->cs_per_ctrl; i++) + if (popts->cs_local_opts[i].odt_rd_cfg || + popts->cs_local_opts[i].odt_wr_cfg) { + odt_cfg = SDRAM_CFG2_ODT_ONLY_READ; + break; + } + + /* Default number of posted refresh */ + num_pr = 1; + + if (popts->ECC_init_using_memctl) { + d_init = 1; + ddr->ddr_data_init = popts->data_init; + } + + if (popts->sdram_type == SDRAM_TYPE_DDR3) { + obc_cfg = popts->otf_burst_chop_en; + md_en = popts->mirrored_dimm; + } + + x4_en = popts->x4_en ? 1 : 0; + + ddr->ddr_sdram_cfg_2 = (((dll_rst_dis & 0x1) << 29) + | ((dqs_cfg & 0x3) << 26) + | ((odt_cfg & 0x3) << 21) + | ((num_pr & 0xf) << 12) + | (x4_en << 10) + | ((obc_cfg & 0x1) << 6) + | ((d_init & 0x1) << 4) + | ((rcw_en & 0x1) << 2) + | ((md_en & 0x1) << 0) + ); +} + +static void set_ddr_sdram_mode_2(struct fsl_ddr_cfg_regs_s *ddr, + const struct memctl_options_s *popts, + const struct common_timing_params_s *dimm) +{ + uint16_t esdmode2; + uint32_t rtt_wr, srt = 0, cwl; + + cwl = compute_cas_write_latency() - 5; + + if (popts->rtt_override) + rtt_wr = popts->rtt_wr_override_value; + else + rtt_wr = popts->cs_local_opts[0].odt_rtt_wr; + + if (dimm->extended_op_srt) + srt = dimm->extended_op_srt; + + esdmode2 = (((rtt_wr & 0x3) << 9) + | ((srt & 0x1) << 7) + | ((cwl & 0x7) << 3) + ); + + ddr->ddr_sdram_mode_2 = (esdmode2 & 0xffff) << 16; +} + +static void +set_ddr_sdram_interval(struct fsl_ddr_cfg_regs_s *ddr, + const struct memctl_options_s *popts, + const struct common_timing_params_s *dimm) +{ + uint32_t refint, bstopre; + + refint = picos_to_mclk(dimm->refresh_rate_ps); + /* Precharge interval */ + bstopre = popts->bstopre; + + ddr->ddr_sdram_interval = (((refint & 0xFFFF) << 16) + | ((bstopre & 0x3FFF) << 0)); +} +void set_ddr3_sdram_mode(struct fsl_ddr_cfg_regs_s *ddr, + const struct memctl_options_s *popts, + const struct common_timing_params_s *dimm, + uint32_t cas_latency, uint32_t additive_latency) +{ + uint16_t esdmode, sdmode; + /* Mode Register - MR1 */ + uint32_t rtt, al; + /* Mode Register - MR0 */ + uint32_t dll_on, wr = 0, dll_rst, mode, caslat = 4, bt, bl, wr_mclk; + /* + * DDR_SDRAM_MODE doesn't support 9,11,13,15 + * Please refer JEDEC Standard No. 79-3E for Mode Register MR0 + * for this table + */ + static const u8 wr_table[] = {1, 2, 3, 4, 5, 5, 6, 6, 7, 7, 0, 0}; + uint8_t cas_latency_table[] = { /* From 5 to 16 clocks */ + 0x2, 0x4, 0x6, 0x8, 0xa, 0xc, 0xe, 0x1, 0x3, 0x5, 0x7, 0x9, + }; + const unsigned int mclk_ps = get_memory_clk_period_ps(); + + if (popts->rtt_override) + rtt = popts->rtt_override_value; + else + rtt = popts->cs_local_opts[0].odt_rtt_norm; + + if (additive_latency == (cas_latency - 1)) + al = 1; + else if (additive_latency == (cas_latency - 2)) + al = 2; + else + al = 0; + + /* + * The esdmode value will also be used for writing + * MR1 during write leveling for DDR3, although the + * bits specifically related to the write leveling + * scheme will be handled automatically by the DDR + * controller. So wrlvl_en is set to 0 here. + */ + esdmode = (((rtt & 0x4) << 7) + | ((rtt & 0x2) << 5) + | ((al & 0x3) << 3) + | ((rtt & 0x1) << 2) + ); + + /* + * DLL control for precharge PD + * 0=slow exit DLL off (tXPDLL) + * 1=fast exit DLL on (tXP) + */ + dll_on = 1; + + wr_mclk = (dimm->tWR_ps + mclk_ps - 1) / mclk_ps; + if (wr_mclk <= 16) + wr = wr_table[wr_mclk - 5]; + + dll_rst = 0; /* dll no reset */ + mode = 0; /* normal mode */ + + /* look up table to get the cas latency bits */ + if (cas_latency >= 5 && cas_latency <= 16) + caslat = cas_latency_table[cas_latency - 5]; + + /* BT: Burst Type (0=Nibble Sequential, 1=Interleaved) */ + bt = 0; + + switch (popts->burst_length) { + case DDR_BL8: + bl = 0; + break; + case DDR_OTF: + bl = 1; + break; + case DDR_BC4: + bl = 2; + break; + default: + bl = 1; + break; + } + + sdmode = (((dll_on & 0x1) << 12) + | ((wr & 0x7) << 9) + | ((dll_rst & 0x1) << 8) + | ((mode & 0x1) << 7) + | (((caslat >> 1) & 0x7) << 4) + | ((bt & 0x1) << 3) + | ((caslat & 1) << 2) + | ((bl & 0x3) << 0) + ); + + ddr->ddr_sdram_mode = (((esdmode & 0xffff) << 16) + | ((sdmode & 0xffff) << 0) + ); +} + +void set_ddr2_sdram_mode(struct fsl_ddr_cfg_regs_s *ddr, + const struct memctl_options_s *popts, + const struct common_timing_params_s *dimm, + uint32_t cas_latency, uint32_t additive_latency) +{ + uint16_t esdmode, sdmode; + uint32_t dqs_en, rtt, al, wr, bl; + const uint32_t mclk_ps = get_memory_clk_period_ps(); + + /* DQS# Enable: 0=enable, 1=disable */ + dqs_en = !popts->DQS_config; + /* Posted CAS# additive latency (AL) */ + al = additive_latency; + /* Internal Termination Resistor */ + if (popts->rtt_override) + rtt = popts->rtt_override_value; + else + rtt = popts->cs_local_opts[0].odt_rtt_norm; + + /* + * Extended SDRAM mode. + * The variable also selects: + * - OCD set to exit mode + * - all outputs bit i.e DQ, DQS, RDQS output enabled + * - RDQS ball disabled + * - DQS ball enabled + * - DLL enabled + * - Output drive strength: full strength. + */ + esdmode = (((dqs_en & 0x1) << 10) + | ((rtt & 0x2) << 5) + | ((al & 0x7) << 3) + | ((rtt & 0x1) << 2)); + + /* Write recovery */ + wr = ((dimm->tWR_ps + mclk_ps - 1) / mclk_ps) - 1; + + switch (popts->burst_length) { + case DDR_BL4: + bl = 2; + break; + case DDR_BL8: + bl = 3; + break; + default: + bl = 2; + break; + } + + /* SDRAM mode + * The variable also selects: + * - power down mode: fast exit (normal) + * - DLL reset disabled. + * - burst type: sequential + */ + sdmode = (((wr & 0x7) << 9) + | ((cas_latency & 0x7) << 4) + | ((bl & 0x7) << 0)); + + ddr->ddr_sdram_mode = (((esdmode & 0xFFFF) << 16) + | ((sdmode & 0xFFFF) << 0)); +} + +void set_ddrx_sdram_mode(struct fsl_ddr_cfg_regs_s *ddr, + const struct memctl_options_s *popts, + const struct common_timing_params_s *dimm, + uint32_t cas_latency, uint32_t additive_latency) +{ + if (popts->sdram_type == SDRAM_TYPE_DDR2) + set_ddr2_sdram_mode(ddr, popts, dimm, cas_latency, + additive_latency); + else + set_ddr3_sdram_mode(ddr, popts, dimm, cas_latency, + additive_latency); +} + +uint32_t check_fsl_memctl_config_regs(const struct fsl_ddr_cfg_regs_s *ddr) +{ + /* + * DDR_SDRAM_CFG[RD_EN] and DDR_SDRAM_CFG[2T_EN should not + * be set at the same time. + */ + if ((ddr->ddr_sdram_cfg & 0x10000000) && + (ddr->ddr_sdram_cfg & 0x00008000)) + return 1; + + return 0; +} + +static void set_timing_cfg_4(struct fsl_ddr_cfg_regs_s *ddr, + const struct memctl_options_s *popts) +{ + uint32_t rrt = 0, wwt = 0, dll_lock = 1; + + if (popts->burst_length != DDR_BL8) + rrt = wwt = 2; + + ddr->timing_cfg_4 = (((rrt & 0xf) << 20) + | ((wwt & 0xf) << 16) + | (dll_lock & 0x3) + ); +} + +static void set_timing_cfg_5(struct fsl_ddr_cfg_regs_s *ddr, + const struct memctl_options_s *popts, + uint32_t cas_latency) +{ + uint32_t rodt_on, rodt_off = 4, wodt_on = 1, wodt_off = 4; + + /* rodt_on = timing_cfg_1[caslat] - timing_cfg_2[wrlat] + 1 */ + rodt_on = cas_latency - ((ddr->timing_cfg_2 & 0x00780000) >> 19) + 1; + + ddr->timing_cfg_5 = (((rodt_on & 0x1f) << 24) + | ((rodt_off & 0x7) << 20) + | ((wodt_on & 0x1f) << 12) + | ((wodt_off & 0x7) << 8) + ); +} + +static void set_ddr_zq_cntl(struct fsl_ddr_cfg_regs_s *ddr, uint32_t zq_en) +{ + uint32_t zqinit = 0, zqoper = 0, zqcs = 0; + + if (zq_en) { + zqinit = 9; + zqoper = 8; + zqcs = 6; + } + + ddr->ddr_zq_cntl = (((zq_en & 0x1) << 31) + | ((zqinit & 0xf) << 24) + | ((zqoper & 0xf) << 16) + | ((zqcs & 0xf) << 8) + ); +} + +static void set_ddr_wrlvl_cntl(struct fsl_ddr_cfg_regs_s *ddr, + uint32_t wrlvl_en, const struct memctl_options_s *popts) +{ + uint32_t wrlvl_mrd = 0, wrlvl_odten = 0, wrlvl_dqsen = 0, + wrlvl_wlr = 0, wrlvl_start = 0, wrlvl_smpl = 0; + + /* Enable write leveling for DDR3 due to fly-by topology */ + if (wrlvl_en) { + wrlvl_mrd = 0x6; + wrlvl_odten = 0x7; + wrlvl_dqsen = 0x5; + /* + * Write leveling sample time at least need 6 clocks + * higher than tWLO to allow enough time for progagation + * delay and sampling the prime data bits. + */ + wrlvl_smpl = 0xf; + /* + * Write leveling repetition time. At least tWLO + 6 clocks + * Set it to 64 + */ + wrlvl_wlr = 0x6; + /* + * Write leveling start time + * The value use for the DQS_ADJUST for the first sample + * when write leveling is enabled. It probably needs to be + * overriden per platform. + */ + wrlvl_start = 0x8; + if (popts->wrlvl_override) { + wrlvl_smpl = popts->wrlvl_sample; + wrlvl_start = popts->wrlvl_start; + } + } + + ddr->ddr_wrlvl_cntl = (((wrlvl_en & 0x1) << 31) + | ((wrlvl_mrd & 0x7) << 24) + | ((wrlvl_odten & 0x7) << 20) + | ((wrlvl_dqsen & 0x7) << 16) + | ((wrlvl_smpl & 0xf) << 12) + | ((wrlvl_wlr & 0x7) << 8) + | ((wrlvl_start & 0x1f) << 0) + ); +} + +uint32_t +compute_fsl_memctl_config_regs(const struct memctl_options_s *popts, + struct fsl_ddr_cfg_regs_s *ddr, + const struct common_timing_params_s *dimm, + const struct dimm_params_s *dimmp, + uint32_t dbw_cap_adj) +{ + struct ddr_board_info_s *binfo = popts->board_info; + uint32_t cas_latency, additive_latency, i, cs_per_dimm, + dimm_number, zq_en, wrlvl_en, sr_it = 0; + uint64_t ea, sa, rank_density; + + if (dimm == NULL) + return 1; + + memset(ddr, 0, sizeof(struct fsl_ddr_cfg_regs_s)); + + /* Process overrides first. */ + if (popts->cas_latency_override) + cas_latency = popts->cas_latency_override_value; + else + cas_latency = dimm->lowest_common_SPD_caslat; + + if (popts->additive_latency_override) + additive_latency = popts->additive_latency_override_value; + else + additive_latency = dimm->additive_latency; + + if (popts->auto_self_refresh_en) + sr_it = popts->sr_it; + + /* Chip Select Memory Bounds (CSn_BNDS) */ + for (i = 0; i < binfo->cs_per_ctrl; i++) { + cs_per_dimm = binfo->cs_per_ctrl / binfo->dimm_slots_per_ctrl; + dimm_number = i / cs_per_dimm; + rank_density = + dimmp[dimm_number].rank_density >> dbw_cap_adj; + + if (dimmp[dimm_number].n_ranks == 0) + continue; + + sa = dimmp[dimm_number].base_address; + ea = sa + rank_density - 1; + if (dimmp[dimm_number].n_ranks > (i % cs_per_dimm)) { + sa += (i % cs_per_dimm) * rank_density; + ea += (i % cs_per_dimm) * rank_density; + } else { + sa = 0; + ea = 0; + } + sa >>= 24; + ea >>= 24; + + ddr->cs[i].bnds = + (((sa & 0xffff) << 16) | ((ea & 0xffff) << 0)); + set_csn_config(dimm_number, i, ddr, popts, dimmp); + } + + set_timing_cfg_0(ddr, popts, dimmp); + set_timing_cfg_3(ddr, popts, dimm, cas_latency, additive_latency); + set_timing_cfg_1(ddr, popts, dimm, cas_latency); + set_timing_cfg_2(ddr, popts, dimm, cas_latency, additive_latency); + + ddr->ddr_cdr1 = popts->ddr_cdr1; + ddr->ddr_cdr1 = popts->ddr_cdr2; + + set_ddr_sdram_cfg(ddr, popts, dimm); + set_ddr_sdram_cfg_2(ddr, popts); + set_ddrx_sdram_mode(ddr, popts, dimm, cas_latency, additive_latency); + if (popts->sdram_type == SDRAM_TYPE_DDR3) { + set_ddr_sdram_mode_2(ddr, popts, dimm); + set_timing_cfg_4(ddr, popts); + set_timing_cfg_5(ddr, popts, cas_latency); + zq_en = (popts->zq_en) ? 1 : 0; + set_ddr_zq_cntl(ddr, zq_en); + wrlvl_en = (popts->wrlvl_en) ? 1 : 0; + set_ddr_wrlvl_cntl(ddr, wrlvl_en, popts); + } + set_ddr_sdram_interval(ddr, popts, dimm); + + ddr->ddr_data_init = popts->data_init; + ddr->ddr_sdram_clk_cntl = (popts->clk_adjust & 0xF) << 23; + + ddr->ddr_sr_cntr = (sr_it & 0xf) << 16; + + return check_fsl_memctl_config_regs(ddr); +} |