1 /* 2 * Copyright (C) 2021-2024, STMicroelectronics - All Rights Reserved 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 /* 8 * This file provides a group of functions that are used to track PHY register 9 * writes by intercepting io_write16 function calls. Once the registers are 10 * tracked, their value can be saved at a given time spot, and restored later 11 * as required. This implementation is useful to capture any PHY register 12 * programing in any function during PHY initialization. 13 */ 14 15 #include <stdint.h> 16 17 #include <common/debug.h> 18 19 #include <ddrphy_phyinit.h> 20 21 #include <lib/mmio.h> 22 23 #include <platform_def.h> 24 25 /* 26 * MAX_NUM_RET_REGS default Max number of retention registers. 27 * 28 * This define is only used by the PhyInit Register interface to define the max 29 * amount of registered that can be saved. The user may increase this variable 30 * as desired if a larger number of registers need to be restored. 31 */ 32 #if STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE 33 #define MAX_NUM_RET_REGS 129 34 #else /* STM32MP_LPDDR4_TYPE */ 35 #define MAX_NUM_RET_REGS 283 36 #endif /* STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE */ 37 38 /* 39 * Array of Address/value pairs used to store register values for the purpose 40 * of retention restore. 41 */ 42 #define RETREG_AREA (MAX_NUM_RET_REGS + 1) * sizeof(struct reg_addr_val) 43 #define RETREG_BASE RETRAM_BASE + RETRAM_SIZE - RETREG_AREA 44 45 static int *retregsize = (int *)(RETREG_BASE); 46 static struct reg_addr_val *retreglist = (struct reg_addr_val *)(RETREG_BASE + sizeof(int)); 47 48 static int numregsaved; /* Current Number of registers saved. */ 49 static int tracken = 1; /* Enabled tracking of registers */ 50 51 /* 52 * Tags a register if tracking is enabled in the register 53 * interface. 54 * 55 * During PhyInit registers writes, keeps track of address 56 * for the purpose of restoring the PHY register state during PHY 57 * retention exit process. Tracking can be turned on/off via the 58 * ddrphy_phyinit_reginterface STARTTRACK, STOPTRACK instructions. By 59 * default tracking is always turned on. 60 * 61 * \return 0 on success. 62 */ 63 int ddrphy_phyinit_trackreg(uint32_t adr) 64 { 65 int regindx = 0; 66 67 /* Return if tracking is disabled */ 68 if (tracken == 0) { 69 return 0; 70 } 71 72 /* Search register address within the array */ 73 for (regindx = 0; regindx < numregsaved; regindx++) { 74 if (retreglist[regindx].address == adr) { 75 /* Register found */ 76 return 0; 77 } 78 } 79 80 /* Register not found, so add it */ 81 if (numregsaved > MAX_NUM_RET_REGS) { 82 ERROR("numregsaved > MAX_NUM_RET_REGS\n"); 83 VERBOSE("[ddrphy_phyinit_reginterface:%s]\n", __func__); 84 VERBOSE("Max Number of Restore Registers reached: %d.\n", numregsaved); 85 VERBOSE("Please recompile PhyInit with larger MAX_NUM_RET_REG value.\n"); 86 return -1; 87 } 88 89 retreglist[regindx].address = adr; 90 numregsaved++; 91 92 return 0; 93 } 94 95 /* 96 * Register interface function used to track, save and restore retention registers. 97 * 98 * ### Usage 99 * Register tracking is enabled by calling: 100 * 101 * \code 102 * ddrphy_phyinit_reginterface(STARTTRACK,0,0); 103 * \endcode 104 * 105 * from this point on any call to mmio_write_16() in 106 * return will be capture by the register interface via a call to 107 * ddrphy_phyinit_trackreg(). Tracking is disabled by calling: 108 * 109 * \code 110 * ddrphy_phyinit_reginterface(STOPTRACK,0,0); 111 * \endcode 112 * 113 * On calling this function, register write via mmio_write_16 are no longer tracked until a 114 * STARTTRACK call is made. Once all the register write are complete, SAVEREGS 115 * command can be issue to save register values into the internal data array of 116 * the register interface. Upon retention exit RESTOREREGS are command can be 117 * used to issue register write commands to the PHY based on values stored in 118 * the array. 119 * \code 120 * ddrphy_phyinit_reginterface(SAVEREGS,0,0); 121 * ddrphy_phyinit_reginterface(RESTOREREGS,0,0); 122 * \endcode 123 * \return 0 on success. 124 */ 125 int ddrphy_phyinit_reginterface(enum reginstr myreginstr, uint32_t adr, uint16_t dat) 126 { 127 if (myreginstr == SAVEREGS) { 128 int regindx; 129 130 /* 131 * Go through all the tracked registers, issue a register read and place 132 * the result in the data structure for future recovery. 133 */ 134 for (regindx = 0; regindx < numregsaved; regindx++) { 135 uint16_t data; 136 137 data = mmio_read_16((uintptr_t)(DDRPHYC_BASE + 138 (4U * retreglist[regindx].address))); 139 retreglist[regindx].value = data; 140 } 141 142 *retregsize = numregsaved; 143 144 return 0; 145 } else if (myreginstr == RESTOREREGS) { 146 int regindx; 147 148 /* 149 * Write PHY registers based on Address, Data value pairs stores in 150 * retreglist. 151 */ 152 for (regindx = 0; regindx < *retregsize; regindx++) { 153 mmio_write_16((uintptr_t) 154 (DDRPHYC_BASE + (4U * retreglist[regindx].address)), 155 retreglist[regindx].value); 156 } 157 158 return 0; 159 } else if (myreginstr == STARTTRACK) { 160 /* Enable tracking */ 161 tracken = 1; 162 return 0; 163 } else if (myreginstr == STOPTRACK) { 164 /* Disable tracking */ 165 tracken = 0; 166 return 0; 167 } else { 168 return -1; 169 } 170 } 171