/* * This file is part of the coreboot project. * * Copyright 2014 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 #include #include #include #include #include #include #include #include #include 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); } static void sdram_init_ddr3(const struct sdram_params *param, struct tegra_emc_regs *regs) { /* 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->EmcMrsExtra, ®s->mrs); } writel(param->EmcZcalInitDev0, ®s->zq_cal); udelay(param->EmcZcalInitWait); if ((param->EmcDevSelect & 2) == 0) { writel(param->EmcZcalInitDev1, ®s->zq_cal); udelay(param->EmcZcalInitWait); } } static void sdram_init_lpddr3(const struct sdram_params *param, struct tegra_emc_regs *regs) { /* Precharge all banks. DEV_SELECTN = 0 => Select all devices */ writel(((param->EmcDevSelect << EMC_REF_DEV_SELECTN_SHIFT) | 1), ®s->pre); /* Send Reset MRW command */ writel(param->EmcMrwResetCommand, ®s->mrw); udelay(param->EmcMrwResetNInitWait); writel(param->EmcZcalInitDev0, ®s->mrw); udelay(param->EmcZcalInitWait); if ((param->EmcDevSelect & 2) == 0) { writel(param->EmcZcalInitDev1, ®s->mrw); udelay(param->EmcZcalInitWait); } /* Write mode registers */ writel(param->EmcMrw2, ®s->mrw2); writel(param->EmcMrw1, ®s->mrw); writel(param->EmcMrw3, ®s->mrw3); writel(param->EmcMrw4, ®s->mrw4); if (param->EmcExtraModeRegWriteEnable) { writel(param->EmcMrwExtra, ®s->mrw); } } 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. */ if (param->MemoryType == NvBootMemoryType_Ddr3) sdram_init_ddr3(param, regs); else if (param->MemoryType == NvBootMemoryType_LpDdr2) sdram_init_lpddr3(param, regs); } else { /* Wait for DLL stablization time even without ZCAL */ 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; printk(BIOS_DEBUG, "Initializing SDRAM of type %d with %dKHz\n", param->MemoryType, clock_get_pll_input_khz() * param->PllMFeedbackDivider / param->PllMInputDivider / (1 + param->PllMSelectDiv2)); if (param->MemoryType != NvBootMemoryType_Ddr3 && param->MemoryType != NvBootMemoryType_LpDdr2) die("Unsupported memory type!\n"); 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); sdram_lp0_save_params(param); } 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); }