xref: /rk3399_ARM-atf/drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_reginterface.c (revision b47dddd061e92054c3b2096fc8aa9688bfef68d6)
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