c193069885a7425247c9cc4dcd1bb443e5a4511c
1 /******************************************************************************
2 * Copyright (c) 2019 Texas Instruments Incorporated - http://www.ti.com
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the
14 * distribution.
15 *
16 * Neither the name of Texas Instruments Incorporated nor the names of
17 * its contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 *****************************************************************************/
33 #include <string.h>
34 #include <ti/csl/csl_lpddr.h>
35 #include "board_ddr.h"
37 #ifdef BUILD_MCU1_0
38 typedef struct Board_DDRThermalMgmtInstance_s
39 {
40 LPDDR4_Config boardDDRCfg;
41 LPDDR4_PrivateData boardRuntimeDDRPd;
42 uint32_t boardDDRInitRefreshRate[LPDDR4_FSP_2+1];
43 HwiP_Handle boardTempInterruptHandle;
44 Board_thermalMgmtCallbackFunction_t appCallBackFunction;
45 } Board_DDRThermalMgmtInstance_t;
47 #pragma DATA_SECTION(gBoard_DDRThermalMgmtInstance, ".data:BOARD_DDR_thermalManagement");
48 static Board_DDRThermalMgmtInstance_t gBoard_DDRThermalMgmtInstance;
50 /* Local defines */
51 #define BOARD_SCICLIENT_RESP_TIMEOUT 1000000
53 /* Multiplication factors assumes scaling by 8 */
54 static const uint32_t gRefreshRateMultFactor[BOARD_MAX_TEMP_CHECK_REFRESH_RATE_VALUE+1] =
55 {
56 32U, /* 4 x */
57 32U, /* 4 x */
58 16U, /* 2 x */
59 8U, /* 1 x */
60 4U, /* 0.5 x */
61 2U, /* 0.25 x */
62 2U, /* 0.25 x with derating */
63 2U, /* 0.25 x with derating */
64 };
66 #pragma CODE_SECTION(Board_updateRefreshRate, ".text:BOARD_DDR_thermalManagement");
68 void Board_updateRefreshRate(const LPDDR4_CtlFspNum fsNum, uint32_t refreshMultFactor)
69 {
70 uint32_t refreshRate;
71 uint32_t status;
73 /* Calculate refresh rate */
74 refreshRate = (gBoard_DDRThermalMgmtInstance.boardDDRInitRefreshRate[fsNum] * refreshMultFactor) >> 3U;
76 /* Take action to update Refresh rate */
77 status = LPDDR4_SetRefreshRate(&(gBoard_DDRThermalMgmtInstance.boardRuntimeDDRPd), &fsNum, &refreshRate);
79 if (status > 0U)
80 {
81 BOARD_DEBUG_LOG("LPDDR4_GetRefreshRate: FAIL\n");
82 /* Add Assert if needed*/
83 }
84 }
86 #pragma CODE_SECTION(Board_updateAllRefreshRate, ".text:BOARD_DDR_thermalManagement");
88 void Board_updateAllRefreshRate(uint32_t refreshMultFactor)
89 {
91 Board_updateRefreshRate(LPDDR4_FSP_0, refreshMultFactor);
92 Board_updateRefreshRate(LPDDR4_FSP_1, refreshMultFactor);
93 Board_updateRefreshRate(LPDDR4_FSP_2, refreshMultFactor);
94 }
96 #pragma CODE_SECTION(Board_DDRInterruptHandler, ".text:BOARD_DDR_thermalManagement");
97 /**
98 * \brief Interrupt handler for DDR events
99 *
100 * Handles DDR events including temperature change events.
101 *
102 * \return BOARD_SOK in case of success or appropriate error code
103 *
104 */
105 void Board_DDRInterruptHandler(uintptr_t arg)
106 {
107 bool irqStatus;
108 uint32_t regValue;
109 uint32_t status;
110 uint32_t tempCheckRefreshRateIndex;
112 /* Get DDR interrupt status to check on thermal events */
113 LPDDR4_CheckCtlInterrupt (&(gBoard_DDRThermalMgmtInstance.boardRuntimeDDRPd), LPDDR4_TEMP_CHANGE, &irqStatus);
114 if (irqStatus)
115 {
116 /* Check Temp check register to check on the temperature change:
117 * Decide on refresh rate
118 */
119 /* Read Temp check register */
120 status = LPDDR4_ReadReg(&(gBoard_DDRThermalMgmtInstance.boardRuntimeDDRPd), LPDDR4_CTL_REGS,
121 LPDDR4__AUTO_TEMPCHK_VAL_0__REG_OFFSET,
122 ®Value);
123 if (status == 0U)
124 {
125 /* Calculate refresh rate index */
126 tempCheckRefreshRateIndex = ((regValue & LPDDR4__AUTO_TEMPCHK_VAL_0_MASK)
127 >> LPDDR4__AUTO_TEMPCHK_VAL_0_SHIFT )
128 & LPDDR4__AUTO_TEMPCHK_OP0_MASK;
130 /* Adjust refresh rate */
131 Board_updateAllRefreshRate(gRefreshRateMultFactor[tempCheckRefreshRateIndex]);
133 /* Call application callback function */
134 if (gBoard_DDRThermalMgmtInstance.appCallBackFunction != NULL)
135 {
136 gBoard_DDRThermalMgmtInstance.appCallBackFunction((Board_DDRTempEventType)
137 (BOARD_DDR_TEMP_EVENT_LOW_TEMP_ALARM
138 + tempCheckRefreshRateIndex));
139 }
140 }
142 /* Ack interrupt */
143 LPDDR4_AckCtlInterrupt (&(gBoard_DDRThermalMgmtInstance.boardRuntimeDDRPd), LPDDR4_TEMP_CHANGE);
144 }
145 /* Get DDR interrupt status to check on alarm events */
146 LPDDR4_CheckCtlInterrupt (&(gBoard_DDRThermalMgmtInstance.boardRuntimeDDRPd), LPDDR4_TEMP_ALERT, &irqStatus);
147 if (irqStatus)
148 {
149 /* High or Low temperature alarm : call application callback */
150 if (gBoard_DDRThermalMgmtInstance.appCallBackFunction != NULL)
151 {
152 gBoard_DDRThermalMgmtInstance.appCallBackFunction(BOARD_DDR_TEMP_EVENT_TEMP_ALERT);
153 }
154 /* Ack interrupt */
155 LPDDR4_AckCtlInterrupt (&(gBoard_DDRThermalMgmtInstance.boardRuntimeDDRPd), LPDDR4_TEMP_ALERT);
156 }
158 /* NOTE: Code to handle other DDR events can be added here */
160 }
162 /**
163 * \brief DDR Temperature monitoring initialization function
164 *
165 * Configures and initializes DDR temperature handling.
166 * NOTE: This assumes that the DDR parameters are already have the thermal events
167 * enabled in the DDR controller. This only handles software handling of the
168 * thermal events
169 *
170 * \return BOARD_SOK in case of success or appropriate error code
171 *
172 */
173 Board_STATUS Board_DDRTempMonitoringInit(Board_thermalMgmtCallbackFunction_t callbackFunction)
174 {
175 Board_STATUS status = BOARD_SOK;
176 OsalRegisterIntrParams_t intrPrms;
177 OsalInterruptRetCode_e osalRet;
178 uint64_t interruptMask;
179 uint32_t lpddrStatus;
180 LPDDR4_CtlFspNum fspNum;
182 struct tisci_msg_rm_irq_release_req irq_release_req =
183 {
184 .ia_id = 0,
185 .vint = 0,
186 .global_event = 0,
187 .vint_status_bit_index = 0,
188 };
189 struct tisci_msg_rm_irq_set_req irq_set_req =
190 {
191 .ia_id = 0,
192 .vint = 0,
193 .global_event = 0,
194 .vint_status_bit_index = 0,
195 };
196 struct tisci_msg_rm_irq_set_resp resp;
198 /* Initialize LPDDR4 driver */
199 gBoard_DDRThermalMgmtInstance.boardDDRCfg.ctlBase = (struct LPDDR4_CtlRegs_s *)BOARD_DDR_SS_BASE;
201 status = LPDDR4_Init(&(gBoard_DDRThermalMgmtInstance.boardRuntimeDDRPd), &(gBoard_DDRThermalMgmtInstance.boardDDRCfg));
203 if ((status > 0U) ||
204 (gBoard_DDRThermalMgmtInstance.boardRuntimeDDRPd.ctlBase != (struct LPDDR4_CtlRegs_s *)gBoard_DDRThermalMgmtInstance.boardDDRCfg.ctlBase))
205 {
206 BOARD_DEBUG_LOG("LPDDR4_Init: FAIL\n");
207 status = BOARD_FAIL;
208 }
210 if (status == BOARD_SOK)
211 {
212 /* Read and preserve the initial Refresh Rates as baseline */
213 for (fspNum = LPDDR4_FSP_0; fspNum <= LPDDR4_FSP_2; fspNum++)
214 {
215 lpddrStatus = LPDDR4_GetRefreshRate(&(gBoard_DDRThermalMgmtInstance.boardRuntimeDDRPd), &fspNum,
216 &(gBoard_DDRThermalMgmtInstance.boardDDRInitRefreshRate[fspNum]));
217 if (lpddrStatus > 0U)
218 {
219 BOARD_DEBUG_LOG("LPDDR4_GetRefreshRate: FAIL\n");
220 status = BOARD_FAIL;
221 break;
222 }
223 }
224 }
226 if (status == BOARD_SOK)
227 {
228 /* Configure interrupt router to route DDR Ctrl interrupt to Monitoring
229 * CPU
230 */
231 /* Request irq release for specified interrupt source */
232 irq_release_req.valid_params = TISCI_MSG_VALUE_RM_DST_ID_VALID
233 | TISCI_MSG_VALUE_RM_DST_HOST_IRQ_VALID;
234 irq_release_req.src_id = TISCI_DEV_DDR0;
235 irq_release_req.src_index = 0; /* First interrupt in DDR group is the DDR controller interrupt */
236 irq_release_req.dst_id = TISCI_DEV_MCU_R5FSS0_CORE0;
237 irq_release_req.dst_host_irq = CSLR_MCU_R5FSS0_CORE0_INTR_MAIN2MCU_LVL_INTRTR0_OUTL_63;
239 /* Call irq Release */
240 if (CSL_PASS != Sciclient_rmIrqRelease(&irq_release_req, BOARD_SCICLIENT_RESP_TIMEOUT))
241 {
242 /* Ignore if the release fails, as this is expected the first time the image is booted */
243 }
245 /* Request irq set for specified interrupt source */
246 irq_set_req.valid_params = TISCI_MSG_VALUE_RM_DST_ID_VALID
247 | TISCI_MSG_VALUE_RM_DST_HOST_IRQ_VALID;
248 irq_set_req.src_id = TISCI_DEV_DDR0;
249 irq_set_req.src_index = 0; /* First interrupt in DDR group is the DDR controller interrupt */
250 irq_set_req.dst_id = TISCI_DEV_MCU_R5FSS0_CORE0;
251 irq_set_req.dst_host_irq = CSLR_MCU_R5FSS0_CORE0_INTR_MAIN2MCU_LVL_INTRTR0_OUTL_63;
253 /* Call irq Set */
254 if (CSL_PASS != Sciclient_rmIrqSet(&irq_set_req, &resp, BOARD_SCICLIENT_RESP_TIMEOUT))
255 {
256 status = BOARD_FAIL;
257 }
258 }
260 if (status == BOARD_SOK)
261 {
263 /* Register DDR Control event handler */
264 Osal_RegisterInterrupt_initParams(&intrPrms);
266 intrPrms.corepacConfig.corepacEventNum = 0;
267 intrPrms.corepacConfig.intVecNum = CSLR_MCU_R5FSS0_CORE0_INTR_MAIN2MCU_LVL_INTRTR0_OUTL_63;
268 intrPrms.corepacConfig.arg = (uintptr_t)(&(gBoard_DDRThermalMgmtInstance.boardTempInterruptHandle));
269 intrPrms.corepacConfig.isrRoutine = &Board_DDRInterruptHandler;
271 /* Clear Interrupt */
272 Osal_ClearInterrupt(intrPrms.corepacConfig.corepacEventNum, intrPrms.corepacConfig.intVecNum);
274 /* Register interrupts */
275 osalRet = Osal_RegisterInterrupt(&intrPrms, &(gBoard_DDRThermalMgmtInstance.boardTempInterruptHandle));
276 if (osalRet != OSAL_INT_SUCCESS)
277 {
278 status = BOARD_FAIL;
279 }
280 }
282 if (status == BOARD_SOK)
283 {
284 /* Unmask only DDR thermal interrupt events */
285 interruptMask = (uint64_t)(0xffffffffffffffffU)
286 & (~(((((uint64_t)1U) << LPDDR4_TEMP_CHANGE)
287 | (((uint64_t)1U) << LPDDR4_TEMP_ALERT))));
288 LPDDR4_SetCtlInterruptMask(&(gBoard_DDRThermalMgmtInstance.boardRuntimeDDRPd), (const uint64_t *)(&interruptMask));
290 /* Enable DDR controller interrupt */
291 Osal_EnableInterrupt(intrPrms.corepacConfig.corepacEventNum, intrPrms.corepacConfig.intVecNum);
292 }
294 if (status == BOARD_SOK)
295 {
296 gBoard_DDRThermalMgmtInstance.appCallBackFunction = NULL;
297 if (callbackFunction != NULL)
298 {
299 /* Register callback function */
300 gBoard_DDRThermalMgmtInstance.appCallBackFunction = callbackFunction;
301 }
302 }
303 return status;
304 }
305 #endif /* BUILD_MCU1_0 */