Angel Pons | e67ab18 | 2020-04-04 18:51:11 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
Peter Kao | da1e02a | 2015-07-31 17:11:14 +0800 | [diff] [blame] | 2 | |
Kyösti Mälkki | 13f6650 | 2019-03-03 08:01:05 +0200 | [diff] [blame] | 3 | #include <device/mmio.h> |
Peter Kao | da1e02a | 2015-07-31 17:11:14 +0800 | [diff] [blame] | 4 | #include <console/console.h> |
Peter Kao | da1e02a | 2015-07-31 17:11:14 +0800 | [diff] [blame] | 5 | #include <soc/addressmap.h> |
| 6 | #include <soc/dramc_common.h> |
| 7 | #include <soc/dramc_register.h> |
| 8 | #include <soc/dramc_pi_api.h> |
Xi Chen | a3b1944 | 2021-03-03 18:04:28 +0800 | [diff] [blame] | 9 | #include <soc/dramc_soc.h> |
Peter Kao | da1e02a | 2015-07-31 17:11:14 +0800 | [diff] [blame] | 10 | #include <soc/mt6391.h> |
Tristan Shieh | ab1b83d | 2018-11-01 18:01:50 +0800 | [diff] [blame] | 11 | #include <soc/pmic_wrap.h> |
Peter Kao | da1e02a | 2015-07-31 17:11:14 +0800 | [diff] [blame] | 12 | #include <soc/pll.h> |
PH Hsu | 3693d0f | 2015-12-16 13:48:10 +0800 | [diff] [blame] | 13 | #include <soc/infracfg.h> |
| 14 | #include <soc/pericfg.h> |
Peter Kao | da1e02a | 2015-07-31 17:11:14 +0800 | [diff] [blame] | 15 | |
| 16 | struct emi_regs *emi_regs = (void *)EMI_BASE; |
| 17 | |
| 18 | static void dram_vcore_adjust(void) |
| 19 | { |
| 20 | /* options: Vcore_HV_LPPDR3/Vcore_NV_LPPDR3/Vcore_LV_LPPDR3 */ |
Tristan Shieh | ab1b83d | 2018-11-01 18:01:50 +0800 | [diff] [blame] | 21 | pwrap_write_field(PMIC_RG_VCORE_CON9, Vcore_NV_LPPDR3, 0x7F, 0); |
| 22 | pwrap_write_field(PMIC_RG_VCORE_CON10, Vcore_NV_LPPDR3, 0x7F, 0); |
Peter Kao | da1e02a | 2015-07-31 17:11:14 +0800 | [diff] [blame] | 23 | } |
| 24 | |
| 25 | static void dram_vmem_adjust(void) |
| 26 | { |
| 27 | /* options: Vmem_HV_LPPDR3/Vmem_NV_LPPDR3/Vmem_LV_LPPDR3 */ |
Tristan Shieh | ab1b83d | 2018-11-01 18:01:50 +0800 | [diff] [blame] | 28 | pwrap_write_field(PMIC_RG_VDRM_CON9, Vmem_NV_LPDDR3, 0x7F, 0); |
| 29 | pwrap_write_field(PMIC_RG_VDRM_CON10, Vmem_NV_LPDDR3, 0x7F, 0); |
Peter Kao | da1e02a | 2015-07-31 17:11:14 +0800 | [diff] [blame] | 30 | } |
| 31 | |
| 32 | static void emi_init(const struct mt8173_sdram_params *sdram_params) |
| 33 | { |
| 34 | /* EMI setting initialization */ |
| 35 | write32(&emi_regs->emi_conf, sdram_params->emi_set.conf); |
| 36 | write32(&emi_regs->emi_conm, sdram_params->emi_set.conm_1); |
| 37 | write32(&emi_regs->emi_arbi, sdram_params->emi_set.arbi); |
| 38 | write32(&emi_regs->emi_arba, sdram_params->emi_set.arba); |
| 39 | write32(&emi_regs->emi_arbc, sdram_params->emi_set.arbc); |
| 40 | write32(&emi_regs->emi_arbd, sdram_params->emi_set.arbd); |
| 41 | write32(&emi_regs->emi_arbe, sdram_params->emi_set.arbe); |
| 42 | write32(&emi_regs->emi_arbf, sdram_params->emi_set.arbf); |
| 43 | write32(&emi_regs->emi_arbg, sdram_params->emi_set.arbg); |
| 44 | write32(&emi_regs->emi_arbj, sdram_params->emi_set.arbj); |
| 45 | write32(&emi_regs->emi_cona, sdram_params->emi_set.cona); |
| 46 | write32(&emi_regs->emi_testd, sdram_params->emi_set.testd); |
| 47 | write32(&emi_regs->emi_bmen, sdram_params->emi_set.bmen); |
| 48 | write32(&emi_regs->emi_conb, sdram_params->emi_set.conb); |
| 49 | write32(&emi_regs->emi_conc, sdram_params->emi_set.conc); |
| 50 | write32(&emi_regs->emi_cond, sdram_params->emi_set.cond); |
| 51 | write32(&emi_regs->emi_cone, sdram_params->emi_set.cone); |
| 52 | write32(&emi_regs->emi_cong, sdram_params->emi_set.cong); |
| 53 | write32(&emi_regs->emi_conh, sdram_params->emi_set.conh); |
| 54 | write32(&emi_regs->emi_slct, sdram_params->emi_set.slct_1); |
| 55 | write32(&emi_regs->emi_mdct, sdram_params->emi_set.mdct_1); |
| 56 | write32(&emi_regs->emi_arbk, sdram_params->emi_set.arbk); |
| 57 | write32(&emi_regs->emi_testc, sdram_params->emi_set.testc); |
| 58 | write32(&emi_regs->emi_mdct, sdram_params->emi_set.mdct_2); |
| 59 | write32(&emi_regs->emi_testb, sdram_params->emi_set.testb); |
| 60 | write32(&emi_regs->emi_slct, sdram_params->emi_set.slct_2); |
| 61 | write32(&emi_regs->emi_conm, sdram_params->emi_set.conm_2); |
| 62 | write32(&emi_regs->emi_test0, sdram_params->emi_set.test0); |
| 63 | write32(&emi_regs->emi_test1, sdram_params->emi_set.test1); |
| 64 | } |
| 65 | |
| 66 | static void do_calib(const struct mt8173_sdram_params *sdram_params) |
| 67 | { |
| 68 | u32 channel; |
| 69 | |
| 70 | sw_impedance_cal(CHANNEL_A, sdram_params); |
| 71 | sw_impedance_cal(CHANNEL_B, sdram_params); |
| 72 | |
| 73 | /* SPM_CONTROL_AFTERK */ |
| 74 | transfer_to_reg_control(); |
| 75 | |
| 76 | /* do dram calibration for channel A and B */ |
Elyes HAOUAS | 4a83f1c | 2016-08-25 21:07:59 +0200 | [diff] [blame] | 77 | for (channel = 0; channel < CHANNEL_NUM; channel++) { |
Peter Kao | da1e02a | 2015-07-31 17:11:14 +0800 | [diff] [blame] | 78 | ca_training(channel, sdram_params); |
| 79 | write_leveling(channel, sdram_params); |
| 80 | |
| 81 | /* rx gating and datlat for single or dual rank */ |
| 82 | if (is_dual_rank(channel, sdram_params)) { |
| 83 | dual_rank_rx_dqs_gating_cal(channel, sdram_params); |
| 84 | dual_rank_rx_datlat_cal(channel, sdram_params); |
| 85 | } else { |
| 86 | rx_dqs_gating_cal(channel, 0, sdram_params); |
| 87 | rx_datlat_cal(channel, 0, sdram_params); |
| 88 | } |
| 89 | |
| 90 | clk_duty_cal(channel); |
| 91 | /* rx window perbit calibration */ |
| 92 | perbit_window_cal(channel, RX_WIN); |
| 93 | /* tx window perbit calibration */ |
| 94 | perbit_window_cal(channel, TX_WIN); |
| 95 | |
| 96 | dramc_rankinctl_config(channel, sdram_params); |
| 97 | dramc_runtime_config(channel, sdram_params); |
| 98 | } |
| 99 | |
| 100 | /* SPM_CONTROL_AFTERK */ |
| 101 | transfer_to_spm_control(); |
| 102 | } |
| 103 | |
| 104 | static void init_dram(const struct mt8173_sdram_params *sdram_params) |
| 105 | { |
| 106 | emi_init(sdram_params); |
| 107 | |
| 108 | dramc_pre_init(CHANNEL_A, sdram_params); |
| 109 | dramc_pre_init(CHANNEL_B, sdram_params); |
| 110 | |
| 111 | div2_phase_sync(); |
| 112 | |
| 113 | dramc_init(CHANNEL_A, sdram_params); |
| 114 | dramc_init(CHANNEL_B, sdram_params); |
| 115 | } |
| 116 | |
Yidi Lin | c6d7dcc | 2016-02-04 17:26:48 +0800 | [diff] [blame] | 117 | size_t sdram_size(void) |
| 118 | { |
| 119 | u32 value = read32(&emi_regs->emi_cona); |
| 120 | u32 bit_counter = 0; |
| 121 | |
| 122 | /* check if dual channel */ |
| 123 | if (value & CONA_DUAL_CH_EN) |
| 124 | bit_counter++; |
| 125 | |
Elyes HAOUAS | a342f39 | 2018-10-17 10:56:26 +0200 | [diff] [blame] | 126 | /* check if 32bit, 32 = 2^5*/ |
Yidi Lin | c6d7dcc | 2016-02-04 17:26:48 +0800 | [diff] [blame] | 127 | if (value & CONA_32BIT_EN) |
| 128 | bit_counter += 5; |
| 129 | else |
| 130 | bit_counter += 4; |
| 131 | |
| 132 | /* check column address */ |
Elyes HAOUAS | a342f39 | 2018-10-17 10:56:26 +0200 | [diff] [blame] | 133 | /* 00 is 9 bits, 01 is 10 bits, 10 is 11 bits */ |
Yidi Lin | c6d7dcc | 2016-02-04 17:26:48 +0800 | [diff] [blame] | 134 | bit_counter += ((value & COL_ADDR_BITS_MASK) >> COL_ADDR_BITS_SHIFT) + |
| 135 | 9; |
| 136 | |
| 137 | /* check if row address */ |
Elyes HAOUAS | 1f220a9 | 2020-02-20 14:17:55 +0100 | [diff] [blame] | 138 | /* 00 is 13 bits, 01 is 14 bits, 10 is 15bits, 11 is 16 bits */ |
Yidi Lin | c6d7dcc | 2016-02-04 17:26:48 +0800 | [diff] [blame] | 139 | bit_counter += ((value & ROW_ADDR_BITS_MASK) >> ROW_ADDR_BITS_SHIFT) + |
| 140 | 13; |
| 141 | |
| 142 | /* check if dual rank */ |
| 143 | if (value & CONA_DUAL_RANK_EN) |
| 144 | bit_counter++; |
| 145 | |
| 146 | /* add bank address bit, LPDDR3 is 8 banks =2^3 */ |
| 147 | bit_counter += 3; |
| 148 | |
Elyes HAOUAS | 1f220a9 | 2020-02-20 14:17:55 +0100 | [diff] [blame] | 149 | /* transform bits to bytes */ |
Yidi Lin | c6d7dcc | 2016-02-04 17:26:48 +0800 | [diff] [blame] | 150 | return ((size_t)1 << (bit_counter - 3)); |
| 151 | } |
| 152 | |
PH Hsu | 3693d0f | 2015-12-16 13:48:10 +0800 | [diff] [blame] | 153 | static void init_4GB_mode(void) |
| 154 | { |
| 155 | if (sdram_size() == (size_t)4 * GiB) { |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 156 | setbits32(&mt8173_pericfg->axi_bus_ctl3, PERISYS_4G_SUPPORT); |
| 157 | setbits32(&mt8173_infracfg->infra_misc, DDR_4GB_SUPPORT_EN); |
PH Hsu | 3693d0f | 2015-12-16 13:48:10 +0800 | [diff] [blame] | 158 | } else { |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 159 | clrbits32(&mt8173_pericfg->axi_bus_ctl3, PERISYS_4G_SUPPORT); |
| 160 | clrbits32(&mt8173_infracfg->infra_misc, DDR_4GB_SUPPORT_EN); |
PH Hsu | 3693d0f | 2015-12-16 13:48:10 +0800 | [diff] [blame] | 161 | } |
| 162 | } |
| 163 | |
Peter Kao | da1e02a | 2015-07-31 17:11:14 +0800 | [diff] [blame] | 164 | void mt_set_emi(const struct mt8173_sdram_params *sdram_params) |
| 165 | { |
| 166 | /* voltage info */ |
| 167 | dram_vcore_adjust(); |
| 168 | dram_vmem_adjust(); |
| 169 | |
| 170 | if (sdram_params->type != TYPE_LPDDR3) { |
| 171 | die("The DRAM type is not supported"); |
| 172 | } |
| 173 | |
| 174 | init_dram(sdram_params); |
| 175 | do_calib(sdram_params); |
PH Hsu | 3693d0f | 2015-12-16 13:48:10 +0800 | [diff] [blame] | 176 | init_4GB_mode(); |
Peter Kao | da1e02a | 2015-07-31 17:11:14 +0800 | [diff] [blame] | 177 | } |