1 /* 2 * Copyright (C) 2021-2024, STMicroelectronics - All Rights Reserved 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <stdlib.h> 8 9 #include <common/debug.h> 10 11 #include <ddrphy_phyinit.h> 12 13 #include <lib/mmio.h> 14 15 #include <platform_def.h> 16 17 /* 18 * This function can be used to implement saving of PHY registers to be 19 * restored on retention exit. 20 * 21 * The requirement of this function is to issue register reads and store the 22 * value to be recovered on retention exit. The following is an example 23 * implementation and the user may implement alternate methods that suit their 24 * specific SoC system needs. 25 * 26 * In this implementation PhyInit saves register values in an internal C array. 27 * During retention exit it restores register values from the array. The exact 28 * list of registers to save and later restore can be seen in the output txt 29 * file with an associated calls to mmio_read_16(). 30 * 31 * PhyInit provides a register interface and a tracking mechanism to minimize 32 * the number registers needing restore. Refer to source code for 33 * ddrphy_phyinit_reginterface() for detailed implementation of tracking 34 * mechanism. Tracking is disabled from step D to Step H as these involve 35 * loading, executing and checking the state of training firmware execution 36 * which are not required to implement the retention exit sequence. The registers 37 * specified representing training results are also saved in addition to registers 38 * written by PhyInit during PHY initialization. 39 * 40 * \return 0 on success. 41 */ ddrphy_phyinit_usercustom_saveretregs(struct stm32mp_ddr_config * config)42int ddrphy_phyinit_usercustom_saveretregs(struct stm32mp_ddr_config *config) 43 { 44 uint32_t anib; 45 uint32_t byte; 46 uint32_t nibble; 47 uint32_t lane; 48 uint32_t c_addr; 49 uint32_t u_addr; 50 uint32_t b_addr; 51 uint32_t r_addr; 52 int ret; 53 54 /* 55 * -------------------------------------------------------------------------- 56 * 1. Enable tracking of training firmware result registers 57 * 58 * \note The tagged registers in this step are in 59 * addition to what is automatically tagged during Steps C to I. 60 * 61 * -------------------------------------------------------------------------- 62 */ 63 64 ret = ddrphy_phyinit_trackreg(TMASTER | CSR_PLLCTRL3_ADDR); 65 if (ret != 0) { 66 return ret; 67 } 68 69 /* Non-PState Dbyte Registers */ 70 for (byte = 0U; byte < config->uib.numdbyte; byte++) { 71 c_addr = byte << 12; 72 73 for (lane = 0U; lane <= R_MAX; lane++) { 74 r_addr = lane << 8; 75 76 ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | r_addr | 77 CSR_RXPBDLYTG0_ADDR); 78 if (ret != 0) { 79 return ret; 80 } 81 #if STM32MP_LPDDR4_TYPE 82 ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | r_addr | 83 CSR_RXPBDLYTG1_ADDR); 84 if (ret != 0) { 85 return ret; 86 } 87 #endif /* STM32MP_LPDDR4_TYPE */ 88 } 89 90 #if STM32MP_LPDDR4_TYPE 91 ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_PPTCTLSTATIC_ADDR); 92 if (ret != 0) { 93 return ret; 94 } 95 96 ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_TRAININGINCDECDTSMEN_ADDR); 97 if (ret != 0) { 98 return ret; 99 } 100 101 ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_TSMBYTE0_ADDR); 102 if (ret != 0) { 103 return ret; 104 } 105 106 ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_DQ0LNSEL_ADDR); 107 if (ret != 0) { 108 return ret; 109 } 110 111 ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_DQ1LNSEL_ADDR); 112 if (ret != 0) { 113 return ret; 114 } 115 116 ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_DQ2LNSEL_ADDR); 117 if (ret != 0) { 118 return ret; 119 } 120 121 ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_DQ3LNSEL_ADDR); 122 if (ret != 0) { 123 return ret; 124 } 125 126 ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_DQ4LNSEL_ADDR); 127 if (ret != 0) { 128 return ret; 129 } 130 131 ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_DQ5LNSEL_ADDR); 132 if (ret != 0) { 133 return ret; 134 } 135 136 ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_DQ6LNSEL_ADDR); 137 if (ret != 0) { 138 return ret; 139 } 140 141 ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_DQ7LNSEL_ADDR); 142 if (ret != 0) { 143 return ret; 144 } 145 #endif /* STM32MP_LPDDR4_TYPE */ 146 } 147 148 ret = ddrphy_phyinit_trackreg(TMASTER | CSR_VREFINGLOBAL_ADDR); 149 if (ret != 0) { 150 return ret; 151 } 152 153 /* Anib Registers */ 154 for (anib = 0U; anib < config->uib.numanib; anib++) { 155 c_addr = anib << 12; 156 157 ret = ddrphy_phyinit_trackreg(TANIB | c_addr | CSR_ATXDLY_ADDR); 158 if (ret != 0) { 159 return ret; 160 } 161 } 162 163 /* Dbyte Registers */ 164 for (byte = 0U; byte < config->uib.numdbyte; byte++) { 165 c_addr = byte << 12; 166 167 ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_DFIMRL_ADDR); 168 if (ret != 0) { 169 return ret; 170 } 171 172 for (nibble = 0U; nibble <= B_MAX; nibble++) { 173 b_addr = nibble << 8; 174 175 ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | b_addr | 176 CSR_DQDQSRCVCNTRL_ADDR); 177 if (ret != 0) { 178 return ret; 179 } 180 } 181 182 for (nibble = 0U; nibble < 2U; nibble++) { 183 u_addr = nibble << 8; 184 185 ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | u_addr | 186 CSR_RXENDLYTG0_ADDR); 187 if (ret != 0) { 188 return ret; 189 } 190 #if STM32MP_LPDDR4_TYPE 191 ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | u_addr | 192 CSR_RXENDLYTG1_ADDR); 193 if (ret != 0) { 194 return ret; 195 } 196 #endif /* STM32MP_LPDDR4_TYPE */ 197 ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | u_addr | 198 CSR_TXDQSDLYTG0_ADDR); 199 if (ret != 0) { 200 return ret; 201 } 202 #if STM32MP_LPDDR4_TYPE 203 ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | u_addr | 204 CSR_TXDQSDLYTG1_ADDR); 205 if (ret != 0) { 206 return ret; 207 } 208 #endif /* STM32MP_LPDDR4_TYPE */ 209 ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | u_addr | 210 CSR_RXCLKDLYTG0_ADDR); 211 if (ret != 0) { 212 return ret; 213 } 214 #if STM32MP_LPDDR4_TYPE 215 ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | u_addr | 216 CSR_RXCLKDLYTG1_ADDR); 217 if (ret != 0) { 218 return ret; 219 } 220 #endif /* STM32MP_LPDDR4_TYPE */ 221 } 222 223 for (lane = R_MIN; lane <= R_MAX; lane++) { 224 r_addr = lane << 8; 225 226 ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | r_addr | 227 CSR_TXDQDLYTG0_ADDR); 228 if (ret != 0) { 229 return ret; 230 } 231 #if STM32MP_LPDDR4_TYPE 232 ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | r_addr | 233 CSR_TXDQDLYTG1_ADDR); 234 if (ret != 0) { 235 return ret; 236 } 237 #endif /* STM32MP_LPDDR4_TYPE */ 238 } 239 240 #if STM32MP_LPDDR4_TYPE 241 ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_PPTDQSCNTINVTRNTG0_ADDR); 242 if (ret != 0) { 243 return ret; 244 } 245 ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_PPTDQSCNTINVTRNTG1_ADDR); 246 if (ret != 0) { 247 return ret; 248 } 249 #endif /* STM32MP_LPDDR4_TYPE */ 250 } 251 252 /* PIE Registers */ 253 ret = ddrphy_phyinit_trackreg(TINITENG | CSR_SEQ0BGPR1_ADDR); 254 if (ret != 0) { 255 return ret; 256 } 257 258 ret = ddrphy_phyinit_trackreg(TINITENG | CSR_SEQ0BGPR2_ADDR); 259 if (ret != 0) { 260 return ret; 261 } 262 263 ret = ddrphy_phyinit_trackreg(TINITENG | CSR_SEQ0BGPR3_ADDR); 264 if (ret != 0) { 265 return ret; 266 } 267 268 ret = ddrphy_phyinit_trackreg(TINITENG | CSR_SEQ0BGPR4_ADDR); 269 if (ret != 0) { 270 return ret; 271 } 272 273 ret = ddrphy_phyinit_trackreg(TINITENG | CSR_SEQ0BGPR5_ADDR); 274 if (ret != 0) { 275 return ret; 276 } 277 278 ret = ddrphy_phyinit_trackreg(TINITENG | CSR_SEQ0BGPR6_ADDR); 279 if (ret != 0) { 280 return ret; 281 } 282 283 ret = ddrphy_phyinit_trackreg(TINITENG | CSR_SEQ0BGPR7_ADDR); 284 if (ret != 0) { 285 return ret; 286 } 287 288 ret = ddrphy_phyinit_trackreg(TINITENG | CSR_SEQ0BGPR8_ADDR); 289 if (ret != 0) { 290 return ret; 291 } 292 293 /* Master Registers */ 294 ret = ddrphy_phyinit_trackreg(TMASTER | CSR_DLLGAINCTL_ADDR); 295 if (ret != 0) { 296 return ret; 297 } 298 299 ret = ddrphy_phyinit_trackreg(TMASTER | CSR_DLLLOCKPARAM_ADDR); 300 if (ret != 0) { 301 return ret; 302 } 303 #if STM32MP_LPDDR4_TYPE 304 ret = ddrphy_phyinit_trackreg(TMASTER | CSR_HWTMRL_ADDR); 305 if (ret != 0) { 306 return ret; 307 } 308 309 /* INITENG Registers */ 310 ret = ddrphy_phyinit_trackreg(TINITENG | CSR_SEQ0BDISABLEFLAG6_ADDR); 311 if (ret != 0) { 312 return ret; 313 } 314 #endif /* STM32MP_LPDDR4_TYPE */ 315 316 ret = ddrphy_phyinit_trackreg(TMASTER | CSR_HWTCAMODE_ADDR); 317 if (ret != 0) { 318 return ret; 319 } 320 321 #if STM32MP_LPDDR4_TYPE 322 ret = ddrphy_phyinit_trackreg(TMASTER | CSR_HWTLPCSENA_ADDR); 323 if (ret != 0) { 324 return ret; 325 } 326 327 ret = ddrphy_phyinit_trackreg(TMASTER | CSR_HWTLPCSENB_ADDR); 328 if (ret != 0) { 329 return ret; 330 } 331 332 /* ACSM registers */ 333 ret = ddrphy_phyinit_trackreg(TACSM | CSR_ACSMCTRL13_ADDR); 334 if (ret != 0) { 335 return ret; 336 } 337 338 ret = ddrphy_phyinit_trackreg(TACSM | CSR_ACSMCTRL23_ADDR); 339 if (ret != 0) { 340 return ret; 341 } 342 #endif /* STM32MP_LPDDR4_TYPE */ 343 344 /* 345 * -------------------------------------------------------------------------- 346 * 2. Track any additional registers 347 * Register writes made using the any of the PhyInit functions are 348 * automatically tracked using the call to ddrphy_phyinit_trackreg() in 349 * mmio_write_16(). Use this section to track additional registers. 350 * -------------------------------------------------------------------------- 351 */ 352 353 /* 354 * Example: 355 * ddrphy_phyinit_trackreg(<addr>); 356 */ 357 358 /* 359 * -------------------------------------------------------------------------- 360 * 3. Prepare for register reads 361 * - Write the MicroContMuxSel CSR to 0x0 to allow access to the internal CSRs 362 * - Write the UcclkHclkEnables CSR to 0x3 to enable all the clocks so the reads 363 * can complete. 364 * -------------------------------------------------------------------------- 365 */ 366 mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TAPBONLY | CSR_MICROCONTMUXSEL_ADDR))), 367 0x0U); 368 mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TDRTUB | CSR_UCCLKHCLKENABLES_ADDR))), 369 0x3U); 370 371 /* 372 * -------------------------------------------------------------------------- 373 * / 4. Read and save all the registers 374 * / - The list of registers differ depending on protocol and 1D training. 375 * -------------------------------------------------------------------------- 376 */ 377 378 ret = ddrphy_phyinit_reginterface(SAVEREGS, 0U, 0U); 379 if (ret != 0) { 380 return ret; 381 } 382 383 /* 384 * -------------------------------------------------------------------------- 385 * 5. Prepare for mission mode 386 * - Write the UcclkHclkEnables CSR to disable the appropriate clocks after all reads done. 387 * - Write the MicroContMuxSel CSR to 0x1 to isolate the internal CSRs during mission mode. 388 * -------------------------------------------------------------------------- 389 */ 390 391 /* Disabling Ucclk (PMU) and Hclk (training hardware) */ 392 mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TDRTUB | CSR_UCCLKHCLKENABLES_ADDR))), 393 0x0U); 394 395 mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TAPBONLY | CSR_MICROCONTMUXSEL_ADDR))), 396 0x1U); 397 398 return 0; 399 } 400