/* * This file is part of the coreboot project. * * 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 */ #ifndef CPU_SAMSUNG_EXYNOS5420_DMC_H #define CPU_SAMSUNG_EXYNOS5420_DMC_H #define DMC_INTERLEAVE_SIZE 0x1f #define PAD_RETENTION_DRAM_COREBLK_VAL 0x10000000 /* CONCONTROL register fields */ #define CONCONTROL_DFI_INIT_START_SHIFT 28 #define CONCONTROL_RD_FETCH_SHIFT 12 #define CONCONTROL_RD_FETCH_MASK (0x7 << CONCONTROL_RD_FETCH_SHIFT) #define CONCONTROL_AREF_EN_SHIFT 5 /* PRECHCONFIG register field */ #define PRECHCONFIG_TP_CNT_SHIFT 24 /* PWRDNCONFIG register field */ #define PWRDNCONFIG_DPWRDN_CYC_SHIFT 0 #define PWRDNCONFIG_DSREF_CYC_SHIFT 16 /* PHY_CON0 register fields */ #define PHY_CON0_T_WRRDCMD_SHIFT 17 #define PHY_CON0_T_WRRDCMD_MASK (0x7 << PHY_CON0_T_WRRDCMD_SHIFT) #define PHY_CON0_CTRL_DDR_MODE_MASK 0x3 #define PHY_CON0_CTRL_DDR_MODE_SHIFT 11 /* PHY_CON1 register fields */ #define PHY_CON1_RDLVL_RDDATA_ADJ_SHIFT 0 /* PHY_CON12 register fields */ #define PHY_CON12_CTRL_START_POINT_SHIFT 24 #define PHY_CON12_CTRL_INC_SHIFT 16 #define PHY_CON12_CTRL_FORCE_SHIFT 8 #define PHY_CON12_CTRL_START_SHIFT 6 #define PHY_CON12_CTRL_START_MASK (1 << PHY_CON12_CTRL_START_SHIFT) #define PHY_CON12_CTRL_DLL_ON_SHIFT 5 #define PHY_CON12_CTRL_DLL_ON_MASK (1 << PHY_CON12_CTRL_DLL_ON_SHIFT) #define PHY_CON12_CTRL_REF_SHIFT 1 /* PHY_CON16 register fields */ #define PHY_CON16_ZQ_MODE_DDS_SHIFT 24 #define PHY_CON16_ZQ_MODE_DDS_MASK (0x7 << PHY_CON16_ZQ_MODE_DDS_SHIFT) #define PHY_CON16_ZQ_MODE_TERM_SHIFT 21 #define PHY_CON16_ZQ_MODE_TERM_MASK (0x7 << PHY_CON16_ZQ_MODE_TERM_SHIFT) #define PHY_CON16_ZQ_MODE_NOTERM_MASK (1 << 19) /* PHY_CON42 register fields */ #define PHY_CON42_CTRL_BSTLEN_SHIFT 8 #define PHY_CON42_CTRL_BSTLEN_MASK (0xff << PHY_CON42_CTRL_BSTLEN_SHIFT) #define PHY_CON42_CTRL_RDLAT_SHIFT 0 #define PHY_CON42_CTRL_RDLAT_MASK (0x1f << PHY_CON42_CTRL_RDLAT_SHIFT) #ifndef __ASSEMBLER__ #include "cpu.h" struct exynos5_dmc { uint32_t concontrol; uint32_t memcontrol; uint32_t cgcontrol; uint32_t memconfig1; uint32_t directcmd; uint32_t prechconfig0; uint32_t phycontrol0; uint32_t prechconfig1; uint8_t res1[0x8]; uint32_t pwrdnconfig; /* 0x0028*/ uint32_t timingpzq; uint32_t timingref; uint32_t timingrow; uint32_t timingdata; uint32_t timingpower; uint32_t phystatus; uint8_t res2[0x4]; uint32_t chipstatus_ch0; /* 0x0048 */ uint32_t chipstatus_ch1; uint8_t res3[0x4]; uint32_t mrstatus; uint8_t res4[0x8]; uint32_t qoscontrol0; /* 0x0060 */ uint8_t resr5[0x4]; uint32_t qoscontrol1; uint8_t res6[0x4]; uint32_t qoscontrol2; uint8_t res7[0x4]; uint32_t qoscontrol3; uint8_t res8[0x4]; uint32_t qoscontrol4; uint8_t res9[0x4]; uint32_t qoscontrol5; uint8_t res10[0x4]; uint32_t qoscontrol6; uint8_t res11[0x4]; uint32_t qoscontrol7; uint8_t res12[0x4]; uint32_t qoscontrol8; uint8_t res13[0x4]; uint32_t qoscontrol9; uint8_t res14[0x4]; uint32_t qoscontrol10; uint8_t res15[0x4]; uint32_t qoscontrol11; uint8_t res16[0x4]; uint32_t qoscontrol12; uint8_t res17[0x4]; uint32_t qoscontrol13; uint8_t res18[0x4]; uint32_t qoscontrol14; uint8_t res19[0x4]; uint32_t qoscontrol15; uint8_t res20[0x4]; uint32_t timing_set_sw; /* 0x00e0 */ uint32_t timingrow1; uint32_t timingdata1; uint32_t timingpower1; uint32_t ivcontrol; uint32_t wrtra_config; uint32_t rdlvl_config; uint8_t res21[0x4]; uint32_t brbrsvcontrol; /* 0x0100*/ uint32_t brbrsvconfig; uint32_t brbqosconfig; uint32_t membaseconfig0; uint32_t membaseconfig1; /* 0x0110 */ uint8_t res22[0xc]; uint32_t wrlvl_config0; /* 0x0120 */ uint32_t wrlvl_config1; uint32_t wrlvl_status; uint8_t res23[0x4]; uint32_t perevcontrol; /* 0x0130 */ uint32_t perev0config; uint32_t perev1config; uint32_t perev2config; uint32_t perev3config; uint8_t res22a[0xc]; uint32_t ctrl_io_rdata_ch0; uint32_t ctrl_io_rdata_ch1; uint8_t res23a[0x8]; uint32_t cacal_config0; uint32_t cacal_config1; uint32_t cacal_status; uint8_t res24[0x94]; uint32_t emergent_config0; /* 0x0200 */ uint32_t emergent_config1; uint8_t res25[0x8]; uint32_t bp_control0; uint32_t bp_control0_r; uint32_t bp_control0_w; uint8_t res26[0x4]; uint32_t bp_control1; uint32_t bp_control1_r; uint32_t bp_control1_w; uint8_t res27[0x4]; uint32_t bp_control2; uint32_t bp_control2_r; uint32_t bp_control2_w; uint8_t res28[0x4]; uint32_t bp_control3; uint32_t bp_control3_r; uint32_t bp_control3_w; uint8_t res29[0xb4]; uint32_t winconfig_odt_w; /* 0x0300 */ uint8_t res30[0x4]; uint32_t winconfig_ctrl_read; uint32_t winconfig_ctrl_gate; uint8_t res31[0xdcf0]; uint32_t pmnc_ppc; uint8_t res32[0xc]; uint32_t cntens_ppc; uint8_t res33[0xc]; uint32_t cntenc_ppc; uint8_t res34[0xc]; uint32_t intens_ppc; uint8_t res35[0xc]; uint32_t intenc_ppc; uint8_t res36[0xc]; uint32_t flag_ppc; /* 0xe050 */ uint8_t res37[0xac]; uint32_t ccnt_ppc; uint8_t res38[0xc]; uint32_t pmcnt0_ppc; uint8_t res39[0xc]; uint32_t pmcnt1_ppc; uint8_t res40[0xc]; uint32_t pmcnt2_ppc; uint8_t res41[0xc]; uint32_t pmcnt3_ppc; /* 0xe140 */ } __attribute__((packed)); check_member(exynos5_dmc, pmcnt3_ppc, 0xe140); static struct exynos5_dmc * const exynos_drex0 = (void *)EXYNOS5420_DMC_DREXI_0; static struct exynos5_dmc * const exynos_drex1 = (void *)EXYNOS5420_DMC_DREXI_1; struct exynos5_phy_control { uint32_t phy_con0; uint32_t phy_con1; uint32_t phy_con2; uint32_t phy_con3; uint32_t phy_con4; uint8_t res1[4]; uint32_t phy_con6; uint8_t res2[4]; uint32_t phy_con8; uint32_t phy_con9; uint32_t phy_con10; uint8_t res3[4]; uint32_t phy_con12; uint32_t phy_con13; uint32_t phy_con14; uint32_t phy_con15; uint32_t phy_con16; uint8_t res4[4]; /* NOT a mistake. Yes, it doesn't make sense. */ uint32_t phy_con17; uint32_t phy_con18; uint32_t phy_con19; uint32_t phy_con20; uint32_t phy_con21; uint32_t phy_con22; uint32_t phy_con23; uint32_t phy_con24; uint32_t phy_con25; uint32_t phy_con26; uint32_t phy_con27; uint32_t phy_con28; uint32_t phy_con29; uint32_t phy_con30; uint32_t phy_con31; uint32_t phy_con32; uint32_t phy_con33; uint32_t phy_con34; uint32_t phy_con35; uint32_t phy_con36; uint32_t phy_con37; uint32_t phy_con38; uint32_t phy_con39; uint32_t phy_con40; uint32_t phy_con41; uint32_t phy_con42; } __attribute__((packed)); check_member(exynos5_phy_control, phy_con42, 0xac); static struct exynos5_phy_control * const exynos_phy0_control = (void *)EXYNOS5_DMC_PHY0_BASE; static struct exynos5_phy_control * const exynos_phy1_control = (void *)EXYNOS5_DMC_PHY1_BASE; struct exynos5_tzasc { uint8_t res1[0xf00]; uint32_t membaseconfig0; uint32_t membaseconfig1; uint8_t res2[0x8]; uint32_t memconfig0; uint32_t memconfig1; } __attribute__((packed)); static struct exynos5_tzasc * const exynos_tzasc0 = (void *)EXYNOS5420_DMC_TZASC_0; static struct exynos5_tzasc * const exynos_tzasc1 = (void *)EXYNOS5420_DMC_TZASC_1; enum ddr_mode { /* This is in order of ctrl_ddr_mode values. Do not change. */ DDR_MODE_DDR2 = 0x0, DDR_MODE_DDR3 = 0x1, DDR_MODE_LPDDR2 = 0x2, DDR_MODE_LPDDR3 = 0x3, DDR_MODE_COUNT, }; /* For reasons unknown, people are in the habit of taking a 32-bit * field with 2 possible values and packing it with, say, 2 bits. A * non-robust encoding, using only 2 bits of a 32-bit field, is * incredibly difficult to deal with when things go wrong, because * there are a lot of things that get expressed as 0, 1, or 2. If * you're scanning with jtag or dumping memory it is really hard to * tell when you've hit the beginning of the struct. So, let's be a * bit smart here. First, while it's common to let the enum count * entries for you, when there are two of them, we can do the * counting. And, let's set the values to something we can easily scan * for in memory. Since '1' and '2' are rather common, we pick * something that's actually of some value when things go wrong. This * setup motivated by a use case: something's going wrong and having a * manuf name of '1' or '2' is completely useless! */ enum mem_manuf { MEM_MANUF_AUTODETECT, MEM_MANUF_ELPIDA = 0xe7b1da, MEM_MANUF_SAMSUNG = 0x5a5096, MEM_MANUF_COUNT = 2, // fancy that. }; enum { MEM_TIMINGS_MSR_COUNT = 5, }; /* These are the memory timings for a particular memory type and speed */ struct mem_timings { enum mem_manuf mem_manuf; /* Memory manufacturer */ enum ddr_mode mem_type; /* Memory type */ unsigned int frequency_mhz; /* Frequency of memory in MHz */ /* Here follow the timing parameters for the selected memory */ uint8_t apll_mdiv; uint8_t apll_pdiv; uint8_t apll_sdiv; uint8_t mpll_mdiv; uint8_t mpll_pdiv; uint8_t mpll_sdiv; uint8_t cpll_mdiv; uint8_t cpll_pdiv; uint8_t cpll_sdiv; uint8_t gpll_pdiv; uint16_t gpll_mdiv; uint8_t gpll_sdiv; uint8_t epll_mdiv; uint8_t epll_pdiv; uint8_t epll_sdiv; uint8_t vpll_mdiv; uint8_t vpll_pdiv; uint8_t vpll_sdiv; uint8_t bpll_mdiv; uint8_t bpll_pdiv; uint8_t bpll_sdiv; uint8_t use_bpll; /* 1 to use BPLL for cdrex, 0 to use MPLL */ uint8_t pclk_cdrex_ratio; unsigned int direct_cmd_msr[MEM_TIMINGS_MSR_COUNT]; unsigned int timing_ref; unsigned int timing_row; unsigned int timing_data; unsigned int timing_power; /* DQS, DQ, DEBUG offsets */ unsigned int phy0_dqs; unsigned int phy1_dqs; unsigned int phy0_dq; unsigned int phy1_dq; uint8_t phy0_tFS; uint8_t phy1_tFS; uint8_t phy0_pulld_dqs; uint8_t phy1_pulld_dqs; uint8_t lpddr3_ctrl_phy_reset; uint8_t ctrl_start_point; uint8_t ctrl_inc; uint8_t ctrl_start; uint8_t ctrl_dll_on; uint8_t ctrl_ref; uint8_t ctrl_force; uint8_t ctrl_rdlat; uint8_t ctrl_bstlen; uint8_t fp_resync; uint8_t iv_size; uint8_t dfi_init_start; uint8_t aref_en; uint8_t rd_fetch; uint8_t zq_mode_dds; uint8_t zq_mode_term; uint8_t zq_mode_noterm; /* 1 to allow termination disable */ unsigned int memcontrol; unsigned int memconfig; unsigned int membaseconfig0; unsigned int membaseconfig1; unsigned int prechconfig_tp_cnt; unsigned int dpwrdn_cyc; unsigned int dsref_cyc; unsigned int concontrol; /* Channel and Chip Selection */ uint8_t dmc_channels; /* number of memory channels */ uint8_t chips_per_channel; /* number of chips per channel */ uint8_t chips_to_configure; /* number of chips to configure */ uint8_t send_zq_init; /* 1 to send this command */ unsigned int impedance; /* drive strength impedance */ uint8_t gate_leveling_enable; /* check gate leveling is enabled */ }; /** * Get the correct memory timings for our selected memory type and speed. * * @return pointer to the memory timings that we should use */ struct mem_timings *get_mem_timings(void); #endif #endif