c193069885a7425247c9cc4dcd1bb443e5a4511c
[processor-sdk/pdk.git] / packages / ti / board / src / j721e_evm / board_ddrtempmonitor.c
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)
107     bool     irqStatus;
108     uint32_t regValue;
109     uint32_t status;
110     uint32_t tempCheckRefreshRateIndex;
111     
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                                 &regValue);
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]);
132         
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 */
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)
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;
181     
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     }
225     
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); 
265         
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;
305 #endif /* BUILD_MCU1_0 */