diff options
Diffstat (limited to 'src/soc/nvidia/tegra124/sdram.c')
-rw-r--r-- | src/soc/nvidia/tegra124/sdram.c | 611 |
1 files changed, 611 insertions, 0 deletions
diff --git a/src/soc/nvidia/tegra124/sdram.c b/src/soc/nvidia/tegra124/sdram.c new file mode 100644 index 0000000000..283cbf4998 --- /dev/null +++ b/src/soc/nvidia/tegra124/sdram.c @@ -0,0 +1,611 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2013 Google 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; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <arch/io.h> +#include <console/console.h> +#include <delay.h> +#include <soc/addressmap.h> +#include <soc/clock.h> + +#include "emc.h" +#include "mc.h" +#include "pmc.h" +#include "sdram.h" + +static void sdram_patch(uintptr_t addr, uint32_t value) +{ + if (addr) + writel(value, (uint32_t*)addr); +} + +static void writebits(uint32_t value, uint32_t *addr, uint32_t mask) +{ + clrsetbits_le32(addr, mask, (value & mask)); +} + +/* PMC must be configured before clock-enable and de-reset of MC/EMC. */ +static void sdram_configure_pmc(const struct sdram_params *param, + struct tegra_pmc_regs *regs) +{ + /* VDDP Select */ + writel(param->PmcVddpSel, ®s->vddp_sel); + udelay(param->PmcVddpSelWait); + + /* Set DDR pad voltage */ + writebits(param->PmcDdrPwr, ®s->ddr_pwr, PMC_DDR_PWR_VAL_MASK); + + /* Set package and DPD pad control */ + writebits(param->PmcDdrCfg, ®s->ddr_cfg, + (PMC_DDR_CFG_PKG_MASK | PMC_DDR_CFG_IF_MASK | + PMC_DDR_CFG_XM0_RESET_TRI_MASK | + PMC_DDR_CFG_XM0_RESET_DPDIO_MASK)); + + /* Turn on MEM IO Power */ + writebits(param->PmcNoIoPower, ®s->no_iopower, + (PMC_NO_IOPOWER_MEM_MASK | PMC_NO_IOPOWER_MEM_COMP_MASK)); + + writel(param->PmcRegShort, ®s->reg_short); +} + +static void sdram_start_clocks(const struct sdram_params *param) +{ + u32 is_same_freq = (param->McEmemArbMisc0 & + MC_EMEM_ARB_MISC0_MC_EMC_SAME_FREQ_MASK) ? 1 : 0; + + clock_sdram(param->PllMInputDivider, param->PllMFeedbackDivider, + param->PllMSelectDiv2, param->PllMSetupControl, + param->PllMPDLshiftPh45, param->PllMPDLshiftPh90, + param->PllMPDLshiftPh135, param->PllMKVCO, + param->PllMKCP, param->PllMStableTime, + param->EmcClockSource, is_same_freq); +} + +static void sdram_deassert_clock_enable_signal(const struct sdram_params *param, + struct tegra_pmc_regs *regs) +{ + clrbits_le32(®s->por_dpd_ctrl, + PMC_POR_DPD_CTRL_MEM0_HOLD_CKE_LOW_OVR_MASK); + udelay(param->PmcPorDpdCtrlWait); +} + +static void sdram_deassert_sel_dpd(const struct sdram_params *param, + struct tegra_pmc_regs *regs) +{ + clrbits_le32(®s->por_dpd_ctrl, + (PMC_POR_DPD_CTRL_MEM0_ADDR0_CLK_SEL_DPD_MASK | + PMC_POR_DPD_CTRL_MEM0_ADDR1_CLK_SEL_DPD_MASK)); + /* + * Note NVIDIA recommended to always do 10us delay here and ignore + * BCT.PmcPorDpdCtrlWait. + * */ + udelay(10); +} + +static void sdram_set_swizzle(const struct sdram_params *param, + struct tegra_emc_regs *regs) +{ + writel(param->EmcSwizzleRank0ByteCfg, ®s->swizzle_rank0_byte_cfg); + writel(param->EmcSwizzleRank0Byte0, ®s->swizzle_rank0_byte0); + writel(param->EmcSwizzleRank0Byte1, ®s->swizzle_rank0_byte1); + writel(param->EmcSwizzleRank0Byte2, ®s->swizzle_rank0_byte2); + writel(param->EmcSwizzleRank0Byte3, ®s->swizzle_rank0_byte3); + writel(param->EmcSwizzleRank1ByteCfg, ®s->swizzle_rank1_byte_cfg); + writel(param->EmcSwizzleRank1Byte0, ®s->swizzle_rank1_byte0); + writel(param->EmcSwizzleRank1Byte1, ®s->swizzle_rank1_byte1); + writel(param->EmcSwizzleRank1Byte2, ®s->swizzle_rank1_byte2); + writel(param->EmcSwizzleRank1Byte3, ®s->swizzle_rank1_byte3); +} + +static void sdram_set_pad_controls(const struct sdram_params *param, + struct tegra_emc_regs *regs) +{ + /* Program the pad controls */ + writel(param->EmcXm2CmdPadCtrl, ®s->xm2cmdpadctrl); + writel(param->EmcXm2CmdPadCtrl2, ®s->xm2cmdpadctrl2); + writel(param->EmcXm2CmdPadCtrl3, ®s->xm2cmdpadctrl3); + writel(param->EmcXm2CmdPadCtrl4, ®s->xm2cmdpadctrl4); + writel(param->EmcXm2CmdPadCtrl5, ®s->xm2cmdpadctrl5); + + writel(param->EmcXm2DqsPadCtrl, ®s->xm2dqspadctrl); + writel(param->EmcXm2DqsPadCtrl2, ®s->xm2dqspadctrl2); + writel(param->EmcXm2DqsPadCtrl3, ®s->xm2dqspadctrl3); + writel(param->EmcXm2DqsPadCtrl4, ®s->xm2dqspadctrl4); + writel(param->EmcXm2DqsPadCtrl5, ®s->xm2dqspadctrl5); + writel(param->EmcXm2DqsPadCtrl6, ®s->xm2dqspadctrl6); + + writel(param->EmcXm2DqPadCtrl, ®s->xm2dqpadctrl); + writel(param->EmcXm2DqPadCtrl2, ®s->xm2dqpadctrl2); + writel(param->EmcXm2DqPadCtrl3, ®s->xm2dqpadctrl3); + + writel(param->EmcXm2ClkPadCtrl, ®s->xm2clkpadctrl); + writel(param->EmcXm2ClkPadCtrl2, ®s->xm2clkpadctrl2); + + writel(param->EmcXm2CompPadCtrl, ®s->xm2comppadctrl); + + writel(param->EmcXm2VttGenPadCtrl, ®s->xm2vttgenpadctrl); + writel(param->EmcXm2VttGenPadCtrl2, ®s->xm2vttgenpadctrl2); + writel(param->EmcXm2VttGenPadCtrl3, ®s->xm2vttgenpadctrl3); + + writel(param->EmcCttTermCtrl, ®s->ctt_term_ctrl); +} + +static void sdram_trigger_emc_timing_update(struct tegra_emc_regs *regs) +{ + writel(EMC_TIMING_CONTROL_TIMING_UPDATE, ®s->timing_control); +} + +static void sdram_init_mc(const struct sdram_params *param, + struct tegra_mc_regs *regs) +{ + /* Initialize MC VPR settings */ + writel(param->McDisplaySnapRing, ®s->display_snap_ring); + writel(param->McVideoProtectBom, ®s->video_protect_bom); + writel(param->McVideoProtectBomAdrHi, ®s->video_protect_bom_adr_hi); + writel(param->McVideoProtectSizeMb, ®s->video_protect_size_mb); + writel(param->McVideoProtectVprOverride, + ®s->video_protect_vpr_override); + writel(param->McVideoProtectVprOverride1, + ®s->video_protect_vpr_override1); + writel(param->McVideoProtectGpuOverride0, + ®s->video_protect_gpu_override_0); + writel(param->McVideoProtectGpuOverride1, + ®s->video_protect_gpu_override_1); + + /* Program SDRAM geometry paarameters */ + writel(param->McEmemAdrCfg, ®s->emem_adr_cfg); + writel(param->McEmemAdrCfgDev0, ®s->emem_adr_cfg_dev0); + writel(param->McEmemAdrCfgDev1, ®s->emem_adr_cfg_dev1); + + /* Program bank swizzling */ + writel(param->McEmemAdrCfgBankMask0, ®s->emem_bank_swizzle_cfg0); + writel(param->McEmemAdrCfgBankMask1, ®s->emem_bank_swizzle_cfg1); + writel(param->McEmemAdrCfgBankMask2, ®s->emem_bank_swizzle_cfg2); + writel(param->McEmemAdrCfgBankSwizzle3, ®s->emem_bank_swizzle_cfg3); + + /* Program external memory aperature (base and size) */ + writel(param->McEmemCfg, ®s->emem_cfg); + + /* Program SEC carveout (base and size) */ + writel(param->McSecCarveoutBom, ®s->sec_carveout_bom); + writel(param->McSecCarveoutAdrHi, ®s->sec_carveout_adr_hi); + writel(param->McSecCarveoutSizeMb, ®s->sec_carveout_size_mb); + + /* Program MTS carveout (base and size) */ + writel(param->McMtsCarveoutBom, ®s->mts_carveout_bom); + writel(param->McMtsCarveoutAdrHi, ®s->mts_carveout_adr_hi); + writel(param->McMtsCarveoutSizeMb, ®s->mts_carveout_size_mb); + + /* Program the memory arbiter */ + writel(param->McEmemArbCfg, ®s->emem_arb_cfg); + writel(param->McEmemArbOutstandingReq, ®s->emem_arb_outstanding_req); + writel(param->McEmemArbTimingRcd, ®s->emem_arb_timing_rcd); + writel(param->McEmemArbTimingRp, ®s->emem_arb_timing_rp); + writel(param->McEmemArbTimingRc, ®s->emem_arb_timing_rc); + writel(param->McEmemArbTimingRas, ®s->emem_arb_timing_ras); + writel(param->McEmemArbTimingFaw, ®s->emem_arb_timing_faw); + writel(param->McEmemArbTimingRrd, ®s->emem_arb_timing_rrd); + writel(param->McEmemArbTimingRap2Pre, ®s->emem_arb_timing_rap2pre); + writel(param->McEmemArbTimingWap2Pre, ®s->emem_arb_timing_wap2pre); + writel(param->McEmemArbTimingR2R, ®s->emem_arb_timing_r2r); + writel(param->McEmemArbTimingW2W, ®s->emem_arb_timing_w2w); + writel(param->McEmemArbTimingR2W, ®s->emem_arb_timing_r2w); + writel(param->McEmemArbTimingW2R, ®s->emem_arb_timing_w2r); + writel(param->McEmemArbDaTurns, ®s->emem_arb_da_turns); + writel(param->McEmemArbDaCovers, ®s->emem_arb_da_covers); + writel(param->McEmemArbMisc0, ®s->emem_arb_misc0); + writel(param->McEmemArbMisc1, ®s->emem_arb_misc1); + writel(param->McEmemArbRing1Throttle, ®s->emem_arb_ring1_throttle); + writel(param->McEmemArbOverride, ®s->emem_arb_override); + writel(param->McEmemArbOverride1, ®s->emem_arb_override_1); + writel(param->McEmemArbRsv, ®s->emem_arb_rsv); + + /* Program extra snap levels for display client */ + writel(param->McDisExtraSnapLevels, ®s->dis_extra_snap_levels); + + /* Trigger MC timing update */ + writel(MC_TIMING_CONTROL_TIMING_UPDATE, ®s->timing_control); + + /* Program second-level clock enable overrides */ + writel(param->McClkenOverride, ®s->clken_override); + + /* Program statistics gathering */ + writel(param->McStatControl, ®s->stat_control); +} + +static void sdram_init_emc(const struct sdram_params *param, + struct tegra_emc_regs *regs) +{ + /* Program SDRAM geometry parameters */ + writel(param->EmcAdrCfg, ®s->adr_cfg); + + /* Program second-level clock enable overrides */ + writel(param->EmcClkenOverride, ®s->clken_override); + + /* Program EMC pad auto calibration */ + writel(param->EmcAutoCalInterval, ®s->auto_cal_interval); + writel(param->EmcAutoCalConfig2, ®s->auto_cal_config2); + writel(param->EmcAutoCalConfig3, ®s->auto_cal_config3); + writel(param->EmcAutoCalConfig, ®s->auto_cal_config); + udelay(param->EmcAutoCalWait); +} + +static void sdram_set_emc_timing(const struct sdram_params *param, + struct tegra_emc_regs *regs) +{ + /* Program EMC timing configuration */ + writel(param->EmcCfg2, ®s->cfg_2); + writel(param->EmcCfgPipe, ®s->cfg_pipe); + writel(param->EmcDbg, ®s->dbg); + writel(param->EmcCmdQ, ®s->cmdq); + writel(param->EmcMc2EmcQ, ®s->mc2emcq); + writel(param->EmcMrsWaitCnt, ®s->mrs_wait_cnt); + writel(param->EmcMrsWaitCnt2, ®s->mrs_wait_cnt2); + writel(param->EmcFbioCfg5, ®s->fbio_cfg5); + writel(param->EmcRc, ®s->rc); + writel(param->EmcRfc, ®s->rfc); + writel(param->EmcRfcSlr, ®s->rfc_slr); + writel(param->EmcRas, ®s->ras); + writel(param->EmcRp, ®s->rp); + writel(param->EmcR2r, ®s->r2r); + writel(param->EmcW2w, ®s->w2w); + writel(param->EmcR2w, ®s->r2w); + writel(param->EmcW2r, ®s->w2r); + writel(param->EmcR2p, ®s->r2p); + writel(param->EmcW2p, ®s->w2p); + writel(param->EmcRdRcd, ®s->rd_rcd); + writel(param->EmcWrRcd, ®s->wr_rcd); + writel(param->EmcRrd, ®s->rrd); + writel(param->EmcRext, ®s->rext); + writel(param->EmcWext, ®s->wext); + writel(param->EmcWdv, ®s->wdv); + writel(param->EmcWdvMask, ®s->wdv_mask); + writel(param->EmcQUse, ®s->quse); + writel(param->EmcQuseWidth, ®s->quse_width); + writel(param->EmcIbdly, ®s->ibdly); + writel(param->EmcEInput, ®s->einput); + writel(param->EmcEInputDuration, ®s->einput_duration); + writel(param->EmcPutermExtra, ®s->puterm_extra); + writel(param->EmcPutermWidth, ®s->puterm_width); + writel(param->EmcPutermAdj, ®s->puterm_adj); + writel(param->EmcCdbCntl1, ®s->cdb_cntl_1); + writel(param->EmcCdbCntl2, ®s->cdb_cntl_2); + writel(param->EmcCdbCntl3, ®s->cdb_cntl_3); + writel(param->EmcQRst, ®s->qrst); + writel(param->EmcQSafe, ®s->qsafe); + writel(param->EmcRdv, ®s->rdv); + writel(param->EmcRdvMask, ®s->rdv_mask); + writel(param->EmcQpop, ®s->qpop); + writel(param->EmcCtt, ®s->ctt); + writel(param->EmcCttDuration, ®s->ctt_duration); + writel(param->EmcRefresh, ®s->refresh); + writel(param->EmcBurstRefreshNum, ®s->burst_refresh_num); + writel(param->EmcPreRefreshReqCnt, ®s->pre_refresh_req_cnt); + writel(param->EmcPdEx2Wr, ®s->pdex2wr); + writel(param->EmcPdEx2Rd, ®s->pdex2rd); + writel(param->EmcPChg2Pden, ®s->pchg2pden); + writel(param->EmcAct2Pden, ®s->act2pden); + writel(param->EmcAr2Pden, ®s->ar2pden); + writel(param->EmcRw2Pden, ®s->rw2pden); + writel(param->EmcTxsr, ®s->txsr); + writel(param->EmcTxsrDll, ®s->txsrdll); + writel(param->EmcTcke, ®s->tcke); + writel(param->EmcTckesr, ®s->tckesr); + writel(param->EmcTpd, ®s->tpd); + writel(param->EmcTfaw, ®s->tfaw); + writel(param->EmcTrpab, ®s->trpab); + writel(param->EmcTClkStable, ®s->tclkstable); + writel(param->EmcTClkStop, ®s->tclkstop); + writel(param->EmcTRefBw, ®s->trefbw); + writel(param->EmcOdtWrite, ®s->odt_write); + writel(param->EmcOdtRead, ®s->odt_read); + writel(param->EmcFbioCfg6, ®s->fbio_cfg6); + writel(param->EmcCfgDigDll, ®s->cfg_dig_dll); + writel(param->EmcCfgDigDllPeriod, ®s->cfg_dig_dll_period); + + /* Don't write bit 1: addr swizzle lock bit. Written at end of sequence. */ + writel(param->EmcFbioSpare & 0xfffffffd, ®s->fbio_spare); + + writel(param->EmcCfgRsv, ®s->cfg_rsv); + writel(param->EmcDllXformDqs0, ®s->dll_xform_dqs0); + writel(param->EmcDllXformDqs1, ®s->dll_xform_dqs1); + writel(param->EmcDllXformDqs2, ®s->dll_xform_dqs2); + writel(param->EmcDllXformDqs3, ®s->dll_xform_dqs3); + writel(param->EmcDllXformDqs4, ®s->dll_xform_dqs4); + writel(param->EmcDllXformDqs5, ®s->dll_xform_dqs5); + writel(param->EmcDllXformDqs6, ®s->dll_xform_dqs6); + writel(param->EmcDllXformDqs7, ®s->dll_xform_dqs7); + writel(param->EmcDllXformDqs8, ®s->dll_xform_dqs8); + writel(param->EmcDllXformDqs9, ®s->dll_xform_dqs9); + writel(param->EmcDllXformDqs10, ®s->dll_xform_dqs10); + writel(param->EmcDllXformDqs11, ®s->dll_xform_dqs11); + writel(param->EmcDllXformDqs12, ®s->dll_xform_dqs12); + writel(param->EmcDllXformDqs13, ®s->dll_xform_dqs13); + writel(param->EmcDllXformDqs14, ®s->dll_xform_dqs14); + writel(param->EmcDllXformDqs15, ®s->dll_xform_dqs15); + writel(param->EmcDllXformQUse0, ®s->dll_xform_quse0); + writel(param->EmcDllXformQUse1, ®s->dll_xform_quse1); + writel(param->EmcDllXformQUse2, ®s->dll_xform_quse2); + writel(param->EmcDllXformQUse3, ®s->dll_xform_quse3); + writel(param->EmcDllXformQUse4, ®s->dll_xform_quse4); + writel(param->EmcDllXformQUse5, ®s->dll_xform_quse5); + writel(param->EmcDllXformQUse6, ®s->dll_xform_quse6); + writel(param->EmcDllXformQUse7, ®s->dll_xform_quse7); + writel(param->EmcDllXformQUse8, ®s->dll_xform_quse8); + writel(param->EmcDllXformQUse9, ®s->dll_xform_quse9); + writel(param->EmcDllXformQUse10, ®s->dll_xform_quse10); + writel(param->EmcDllXformQUse11, ®s->dll_xform_quse11); + writel(param->EmcDllXformQUse12, ®s->dll_xform_quse12); + writel(param->EmcDllXformQUse13, ®s->dll_xform_quse13); + writel(param->EmcDllXformQUse14, ®s->dll_xform_quse14); + writel(param->EmcDllXformQUse15, ®s->dll_xform_quse15); + writel(param->EmcDllXformDq0, ®s->dll_xform_dq0); + writel(param->EmcDllXformDq1, ®s->dll_xform_dq1); + writel(param->EmcDllXformDq2, ®s->dll_xform_dq2); + writel(param->EmcDllXformDq3, ®s->dll_xform_dq3); + writel(param->EmcDllXformDq4, ®s->dll_xform_dq4); + writel(param->EmcDllXformDq5, ®s->dll_xform_dq5); + writel(param->EmcDllXformDq6, ®s->dll_xform_dq6); + writel(param->EmcDllXformDq7, ®s->dll_xform_dq7); + writel(param->EmcDllXformAddr0, ®s->dll_xform_addr0); + writel(param->EmcDllXformAddr1, ®s->dll_xform_addr1); + writel(param->EmcDllXformAddr2, ®s->dll_xform_addr2); + writel(param->EmcDllXformAddr3, ®s->dll_xform_addr3); + writel(param->EmcDllXformAddr4, ®s->dll_xform_addr4); + writel(param->EmcDllXformAddr5, ®s->dll_xform_addr5); + writel(param->EmcAcpdControl, ®s->acpd_control); + writel(param->EmcDsrVttgenDrv, ®s->dsr_vttgen_drv); + writel(param->EmcTxdsrvttgen, ®s->txdsrvttgen); + writel(param->EmcBgbiasCtl0, ®s->bgbias_ctl0); + + /* + * Set pipe bypass enable bits before sending any DRAM commands. + * Note other bits in EMC_CFG must be set AFTER REFCTRL is configured. + */ + writebits(param->EmcCfg, ®s->cfg, + (EMC_CFG_EMC2PMACRO_CFG_BYPASS_ADDRPIPE_MASK | + EMC_CFG_EMC2PMACRO_CFG_BYPASS_DATAPIPE1_MASK | + EMC_CFG_EMC2PMACRO_CFG_BYPASS_DATAPIPE2_MASK)); +} + +static void sdram_patch_bootrom(const struct sdram_params *param, + struct tegra_mc_regs *regs) +{ + if (param->BootRomPatchControl & BOOT_ROM_PATCH_CONTROL_ENABLE_MASK) { + uintptr_t addr = ((param->BootRomPatchControl & + BOOT_ROM_PATCH_CONTROL_OFFSET_MASK) >> + BOOT_ROM_PATCH_CONTROL_OFFSET_SHIFT); + addr = BOOT_ROM_PATCH_CONTROL_BASE_ADDRESS + (addr << 2); + writel(param->BootRomPatchData, (uint32_t *)addr); + writel(1, ®s->timing_control); + } +} + +static void sdram_set_dpd3(const struct sdram_params *param, + struct tegra_pmc_regs *regs) +{ + /* Program DPD request */ + writel(param->PmcIoDpd3Req, ®s->io_dpd3_req); + udelay(param->PmcIoDpd3ReqWait); +} + +static void sdram_set_dli_trims(const struct sdram_params *param, + struct tegra_emc_regs *regs) +{ + /* Program DLI trims */ + writel(param->EmcDliTrimTxDqs0, ®s->dli_trim_txdqs0); + writel(param->EmcDliTrimTxDqs1, ®s->dli_trim_txdqs1); + writel(param->EmcDliTrimTxDqs2, ®s->dli_trim_txdqs2); + writel(param->EmcDliTrimTxDqs3, ®s->dli_trim_txdqs3); + writel(param->EmcDliTrimTxDqs4, ®s->dli_trim_txdqs4); + writel(param->EmcDliTrimTxDqs5, ®s->dli_trim_txdqs5); + writel(param->EmcDliTrimTxDqs6, ®s->dli_trim_txdqs6); + writel(param->EmcDliTrimTxDqs7, ®s->dli_trim_txdqs7); + writel(param->EmcDliTrimTxDqs8, ®s->dli_trim_txdqs8); + writel(param->EmcDliTrimTxDqs9, ®s->dli_trim_txdqs9); + writel(param->EmcDliTrimTxDqs10, ®s->dli_trim_txdqs10); + writel(param->EmcDliTrimTxDqs11, ®s->dli_trim_txdqs11); + writel(param->EmcDliTrimTxDqs12, ®s->dli_trim_txdqs12); + writel(param->EmcDliTrimTxDqs13, ®s->dli_trim_txdqs13); + writel(param->EmcDliTrimTxDqs14, ®s->dli_trim_txdqs14); + writel(param->EmcDliTrimTxDqs15, ®s->dli_trim_txdqs15); + + writel(param->EmcCaTrainingTimingCntl1, + ®s->ca_training_timing_cntl1); + writel(param->EmcCaTrainingTimingCntl2, + ®s->ca_training_timing_cntl2); + + sdram_trigger_emc_timing_update(regs); + udelay(param->EmcTimingControlWait); +} + +static void sdram_set_clock_enable_signal(const struct sdram_params *param, + struct tegra_emc_regs *regs) +{ + volatile uint32_t dummy = 0; + clrbits_le32(®s->pin, (EMC_PIN_RESET_MASK | EMC_PIN_DQM_MASK | + EMC_PIN_CKE_MASK)); + /* + * Assert dummy read of PIN register to ensure above write to PIN + * register went through. 200 is the recommended value by NVIDIA. + */ + dummy |= readl(®s->pin); + udelay(200 + param->EmcPinExtraWait); + + /* Deassert reset */ + setbits_le32(®s->pin, EMC_PIN_RESET_INACTIVE); + /* + * Assert dummy read of PIN register to ensure above write to PIN + * register went through. 200 is the recommended value by NVIDIA. + */ + dummy |= readl(®s->pin); + udelay(500 + param->EmcPinExtraWait); + + /* Enable clock enable signal */ + setbits_le32(®s->pin, EMC_PIN_CKE_NORMAL); + /* + * Assert dummy read of PIN register to ensure above write to PIN + * register went through. 200 is the recommended value by NVIDIA. + */ + dummy |= readl(®s->pin); + udelay(param->EmcPinProgramWait); + + if (!dummy) { + die("Failed to program EMC pin."); + } + + /* Send NOP (trigger) */ + writebits(((1 << EMC_NOP_NOP_CMD_SHIFT) | + (param->EmcDevSelect << EMC_NOP_NOP_DEV_SELECTN_SHIFT)), + ®s->nop, + EMC_NOP_NOP_CMD_MASK | EMC_NOP_NOP_DEV_SELECTN_MASK); + + /* Write mode registers */ + writel(param->EmcEmrs2, ®s->emrs2); + writel(param->EmcEmrs3, ®s->emrs3); + writel(param->EmcEmrs, ®s->emrs); + writel(param->EmcMrs, ®s->mrs); + + if (param->EmcExtraModeRegWriteEnable) { + writel(param->EmcMrwExtra, ®s->mrs); + } +} + +static void sdram_init_zq_calibration(const struct sdram_params *param, + struct tegra_emc_regs *regs) +{ + if ((param->EmcZcalWarmColdBootEnables & + EMC_ZCAL_WARM_COLD_BOOT_ENABLES_COLDBOOT_MASK) == 1) { + /* Need to initialize ZCAL on coldboot. */ + writel(param->EmcZcalInitDev0, ®s->zq_cal); + udelay(param->EmcZcalInitWait); + + if ((param->EmcDevSelect & 2) == 0) { + writel(param->EmcZcalInitDev1, ®s->zq_cal); + udelay(param->EmcZcalInitWait); + } + } else { + udelay(param->EmcZcalInitWait); + } +} + +static void sdram_set_zq_calibration(const struct sdram_params *param, + struct tegra_emc_regs *regs) +{ + /* Start periodic ZQ calibration */ + writel(param->EmcZcalInterval, ®s->zcal_interval); + writel(param->EmcZcalWaitCnt, ®s->zcal_wait_cnt); + writel(param->EmcZcalMrwCmd, ®s->zcal_mrw_cmd); +} + +static void sdram_set_refresh(const struct sdram_params *param, + struct tegra_emc_regs *regs) +{ + /* Insert burst refresh */ + if (param->EmcExtraRefreshNum > 0) { + uint32_t refresh_num = (1 << param->EmcExtraRefreshNum) - 1; + writebits((EMC_REF_CMD_REFRESH | EMC_REF_NORMAL_ENABLED | + (refresh_num << EMC_REF_NUM_SHIFT) | + (param->EmcDevSelect << EMC_REF_DEV_SELECTN_SHIFT)), + ®s->ref, (EMC_REF_CMD_MASK | EMC_REF_NORMAL_MASK | + EMC_REF_NUM_MASK | + EMC_REF_DEV_SELECTN_MASK)); + } + + /* Enable refresh */ + writel((param->EmcDevSelect | EMC_REFCTRL_REF_VALID_ENABLED), + ®s->refctrl); + + writel(param->EmcDynSelfRefControl, ®s->dyn_self_ref_control); + writel(param->EmcCfg, ®s->cfg); + writel(param->EmcSelDpdCtrl, ®s->sel_dpd_ctrl); + + /* Write addr swizzle lock bit */ + writel(param->EmcFbioSpare, ®s->fbio_spare); + + /* Re-trigger timing to latch power saving functions */ + sdram_trigger_emc_timing_update(regs); +} + +static void sdram_enable_arbiter(const struct sdram_params *param) +{ + /* TODO(hungte) Move values here to standalone header file. */ + uint32_t *AHB_ARBITRATION_XBAR_CTRL = (uint32_t*)(0x6000c000 + 0xe0); + setbits_le32(AHB_ARBITRATION_XBAR_CTRL, + param->AhbArbitrationXbarCtrlMemInitDone << 16); +} + +static void sdram_lock_carveouts(const struct sdram_params *param, + struct tegra_mc_regs *regs) +{ + /* Lock carveouts, and emem_cfg registers */ + writel(param->McVideoProtectWriteAccess, ®s->video_protect_reg_ctrl); + writel(MC_EMEM_CFG_ACCESS_CTRL_WRITE_ACCESS_DISABLED, + ®s->emem_cfg_access_ctrl); + writel(param->McSecCarveoutProtectWriteAccess, + ®s->sec_carveout_reg_ctrl); + writel(param->McMtsCarveoutRegCtrl, ®s->mts_carveout_reg_ctrl); +} + +void sdram_init(const struct sdram_params *param) +{ + struct tegra_pmc_regs *pmc = (struct tegra_pmc_regs*)TEGRA_PMC_BASE; + struct tegra_mc_regs *mc = (struct tegra_mc_regs*)TEGRA_MC_BASE; + struct tegra_emc_regs *emc = (struct tegra_emc_regs*)TEGRA_EMC_BASE; + + sdram_configure_pmc(param, pmc); + sdram_patch(param->EmcBctSpare0, param->EmcBctSpare1); + + sdram_start_clocks(param); + sdram_patch(param->EmcBctSpare2, param->EmcBctSpare3); + + sdram_deassert_sel_dpd(param, pmc); + sdram_set_swizzle(param, emc); + sdram_set_pad_controls(param, emc); + sdram_patch(param->EmcBctSpare4, param->EmcBctSpare5); + + sdram_trigger_emc_timing_update(emc); + sdram_init_mc(param, mc); + sdram_init_emc(param, emc); + sdram_patch(param->EmcBctSpare6, param->EmcBctSpare7); + + sdram_set_emc_timing(param, emc); + sdram_patch_bootrom(param, mc); + sdram_set_dpd3(param, pmc); + sdram_set_dli_trims(param, emc); + sdram_deassert_clock_enable_signal(param, pmc); + sdram_set_clock_enable_signal(param, emc); + sdram_init_zq_calibration(param, emc); + sdram_patch(param->EmcBctSpare8, param->EmcBctSpare9); + + sdram_set_zq_calibration(param, emc); + sdram_patch(param->EmcBctSpare10, param->EmcBctSpare11); + + sdram_trigger_emc_timing_update(emc); + sdram_set_refresh(param, emc); + sdram_enable_arbiter(param); + sdram_lock_carveouts(param, mc); +} + +uint32_t sdram_get_ram_code(void) +{ + struct tegra_pmc_regs *pmc = (struct tegra_pmc_regs*)TEGRA_PMC_BASE; + return ((readl(&pmc->strapping_opt_a) & + PMC_STRAPPING_OPT_A_RAM_CODE_MASK) >> + PMC_STRAPPING_OPT_A_RAM_CODE_SHIFT); +} |