10cda0865179fdcf52d384a07643d8f38b28ddf3
[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 <ti/csl/arch/csl_arch.h>
36 #include "board_ddr.h"
38 typedef struct Board_DDRThermalMgmtInstance_s
39 {
40     LPDDR4_Config      boardDDRCfg;
41     LPDDR4_PrivateData boardRuntimeDDRPd;
42     uint32_t           boardDDRInitRefreshRate[LPDDR4_FSP_2+1];
43     uint32_t           boardDDRTrasMax[LPDDR4_FSP_2+1];
44     HwiP_Handle        boardTempInterruptHandle;
45     Board_thermalMgmtCallbackFunction_t appCallBackFunction;
46     uint16_t           devIdCore;
47     uint16_t           devIdIr;
48 } Board_DDRThermalMgmtInstance_t;
50 #ifdef __cplusplus
51 #pragma DATA_SECTION(".data:BOARD_DDR_thermalManagement");
52 #else
53 #pragma DATA_SECTION(gBoard_DDRThermalMgmtInstance, ".data:BOARD_DDR_thermalManagement");
54 #endif
55 static Board_DDRThermalMgmtInstance_t gBoard_DDRThermalMgmtInstance;
57 /* Local defines */
58 #define BOARD_SCICLIENT_RESP_TIMEOUT 1000000
60 #ifdef __cplusplus
61 #pragma DATA_SECTION(".const:BOARD_DDR_thermalManagement");
62 #else
63 #pragma DATA_SECTION(gRefreshRateMultFactor, ".const:BOARD_DDR_thermalManagement");
64 #endif
65 /* Multiplication factors assumes scaling by 8 */
66 static const uint32_t gRefreshRateMultFactor[BOARD_MAX_TEMP_CHECK_REFRESH_RATE_VALUE+1] =
67 {
68     32U,  /* 4 x */
69     32U,  /* 4 x */
70     16U,  /* 2 x */
71     8U,   /* 1 x */
72     4U,   /* 0.5 x */
73     2U,   /* 0.25 x */
74     2U,   /* 0.25 x with derating */
75     2U,   /* 0.25 x with derating */
76 };
77 #ifdef __cplusplus
78 #pragma DATA_SECTION(".const:BOARD_DDR_thermalManagement");
79 #else
80 #pragma DATA_SECTION(gBoardDDRFSPNum, ".const:BOARD_DDR_thermalManagement");
81 #endif
83 static const LPDDR4_CtlFspNum gBoardDDRFSPNum[LPDDR4_FSP_2+1] =
84 {
85     LPDDR4_FSP_0,
86     LPDDR4_FSP_1,
87     LPDDR4_FSP_2,
88 };
90 #ifdef __cplusplus
91 #pragma CODE_SECTION(".text:BOARD_DDR_thermalManagement");
92 #else
93 #pragma CODE_SECTION(Board_updateRefreshRate, ".text:BOARD_DDR_thermalManagement");
94 #endif
96 void Board_updateRefreshRate(const LPDDR4_CtlFspNum fsNum, uint32_t refreshMultFactor)
97 {
98     uint32_t refreshRate;
99     uint32_t trasMax;
100     uint32_t status;
102     /* Calculate refresh rate */
103     refreshRate = (gBoard_DDRThermalMgmtInstance.boardDDRInitRefreshRate[fsNum] * refreshMultFactor) >> 3U;
104     trasMax = (gBoard_DDRThermalMgmtInstance.boardDDRTrasMax[fsNum] * refreshMultFactor) >> 3U;
106     /* Take action to update Refresh rate */
107     status = LPDDR4_SetRefreshRate(&(gBoard_DDRThermalMgmtInstance.boardRuntimeDDRPd), &fsNum, &refreshRate, &trasMax);
109     if (status > 0U)
110     {
111         BOARD_DEBUG_LOG("LPDDR4_GetRefreshRate: FAIL\n");
112         /* Add Assert if needed*/
113     }
116 #ifdef __cplusplus
117 #pragma CODE_SECTION(".text:BOARD_DDR_thermalManagement");
118 #else
119 #pragma CODE_SECTION(Board_DDRSetDevId, ".text:BOARD_DDR_thermalManagement");
120 #endif
122 static void Board_DDRSetDevId()
123
124     CSL_ArmR5CPUInfo info;
126     CSL_armR5GetCpuID(&info);
127     if (info.grpId == (uint32_t)CSL_ARM_R5_CLUSTER_GROUP_ID_0)
128     {
129         /* MCU SS Pulsar R5 SS */
130         /* For R5 cores in the MCU domain MAIN2MCU_LVL_INTRTR0 is the base interrupt to the VIM. */
131         gBoard_DDRThermalMgmtInstance.devIdIr   = TISCI_DEV_MAIN2MCU_LVL_INTRTR0;
132         gBoard_DDRThermalMgmtInstance.devIdCore = (info.cpuID == CSL_ARM_R5_CPU_ID_0)?
133                                                         TISCI_DEV_MCU_R5FSS0_CORE0:
134                                                         TISCI_DEV_MCU_R5FSS0_CORE1;
135     }
136     else if (info.grpId == (uint32_t)CSL_ARM_R5_CLUSTER_GROUP_ID_1)
137     {
138         /* MAIN SS Pulsar R5 SS0 */
139         gBoard_DDRThermalMgmtInstance.devIdIr   = TISCI_DEV_R5FSS0_INTROUTER0;
140         gBoard_DDRThermalMgmtInstance.devIdCore = (info.cpuID == CSL_ARM_R5_CPU_ID_0)?
141                                                         TISCI_DEV_R5FSS0_CORE0:
142                                                         TISCI_DEV_R5FSS0_CORE1;
143     }
144     else if (info.grpId == (uint32_t)CSL_ARM_R5_CLUSTER_GROUP_ID_2)
145     {
146         /* MAIN SS Pulsar R5 SS1 */
147         gBoard_DDRThermalMgmtInstance.devIdIr   = TISCI_DEV_R5FSS1_INTROUTER0;
148         gBoard_DDRThermalMgmtInstance.devIdCore = (info.cpuID == CSL_ARM_R5_CPU_ID_0)?
149                                                         TISCI_DEV_R5FSS1_CORE0:
150                                                         TISCI_DEV_R5FSS1_CORE1;
151     }
152     
153     return;
156 #ifdef __cplusplus
157 #pragma CODE_SECTION(".text:BOARD_DDR_thermalManagement");
158 #else
159 #pragma CODE_SECTION(Board_DDRGetIntNum, ".text:BOARD_DDR_thermalManagement");
160 #endif
162 static Board_STATUS Board_DDRGetIntNum(uint16_t *coreInterruptIdx)
164     Board_STATUS    status = BOARD_SOK;
165     uint16_t        irIntrIdx;
166     struct tisci_msg_rm_get_resource_range_resp res = {0};
167     struct tisci_msg_rm_get_resource_range_req  req = {0};
169     req.type           = gBoard_DDRThermalMgmtInstance.devIdIr;
170     req.subtype        = (uint8_t)TISCI_RESASG_SUBTYPE_IR_OUTPUT;
171     req.secondary_host = (uint8_t)TISCI_MSG_VALUE_RM_UNUSED_SECONDARY_HOST;
173     res.range_num = 0;
174     res.range_start = 0;
176     /* Get interrupt number range */
177     status =  Sciclient_rmGetResourceRange(
178                 &req,
179                 &res,
180                 SCICLIENT_SERVICE_WAIT_FOREVER);
181     if (CSL_PASS != status || res.range_num == 0) {
182         /* Try with HOST_ID_ALL */
183         req.type           = gBoard_DDRThermalMgmtInstance.devIdIr;
184         req.subtype        = (uint8_t)TISCI_RESASG_SUBTYPE_IR_OUTPUT;
185         req.secondary_host = TISCI_HOST_ID_ALL;
187         status = Sciclient_rmGetResourceRange(
188                 &req,
189                 &res,
190                 SCICLIENT_SERVICE_WAIT_FOREVER);
191     }
192     if ((CSL_PASS == status) && (res.range_num != 0))
193     {
194         /* Translate IR Idx to Core Interrupt Idx */
195         irIntrIdx = res.range_start;
196         status = Sciclient_rmIrqTranslateIrOutput(gBoard_DDRThermalMgmtInstance.devIdIr,
197                                                   irIntrIdx,
198                                                   gBoard_DDRThermalMgmtInstance.devIdCore,
199                                                   coreInterruptIdx);
200     }
201     else
202     {
203         status = BOARD_FAIL;
204     }
206     return status;
209 #ifdef __cplusplus
210 #pragma CODE_SECTION(".text:BOARD_DDR_thermalManagement");
211 #else
212 #pragma CODE_SECTION(Board_updateAllRefreshRate, ".text:BOARD_DDR_thermalManagement");
213 #endif
215 void Board_updateAllRefreshRate(uint32_t refreshMultFactor)
218     Board_updateRefreshRate(LPDDR4_FSP_0, refreshMultFactor);
219     Board_updateRefreshRate(LPDDR4_FSP_1, refreshMultFactor);
220     Board_updateRefreshRate(LPDDR4_FSP_2, refreshMultFactor);
223 #ifdef __cplusplus
224 #pragma CODE_SECTION(".text:BOARD_DDR_thermalManagement");
225 #else
226 #pragma CODE_SECTION(Board_DDRInterruptHandler, ".text:BOARD_DDR_thermalManagement");
227 #endif
228 /**
229  * \brief Interrupt handler for DDR events
230  *
231  * Handles DDR events including temperature change events.
232  *
233  * \return  BOARD_SOK in case of success or appropriate error code
234  *
235  */
236 void Board_DDRInterruptHandler(uintptr_t arg)
238     bool     irqStatus;
239     uint32_t regValue;
240     uint32_t status;
241     uint32_t tempCheckRefreshRateIndex;
242     
243     /* Get DDR interrupt status to check on thermal events */
244     LPDDR4_CheckCtlInterrupt (&(gBoard_DDRThermalMgmtInstance.boardRuntimeDDRPd), LPDDR4_TEMP_CHANGE, &irqStatus);
245     if (irqStatus)
246     {
247         /* Check Temp check register to check on the temperature change:
248          * Decide on refresh rate
249          */
250         /* Read Temp check register */
251         status = LPDDR4_ReadReg(&(gBoard_DDRThermalMgmtInstance.boardRuntimeDDRPd), LPDDR4_CTL_REGS,
252                                 LPDDR4__AUTO_TEMPCHK_VAL_0__REG_OFFSET,
253                                 &regValue);
254         if (status == 0U)
255         {
256             /* Calculate refresh rate index */
257             tempCheckRefreshRateIndex = ((regValue & LPDDR4__AUTO_TEMPCHK_VAL_0_MASK)
258                                          >>  LPDDR4__AUTO_TEMPCHK_VAL_0_SHIFT )
259                                         & LPDDR4__AUTO_TEMPCHK_OP0_MASK;
261             /* Adjust refresh rate */
262             Board_updateAllRefreshRate(gRefreshRateMultFactor[tempCheckRefreshRateIndex]);
263         
264             /* Call application callback function */
265             if (gBoard_DDRThermalMgmtInstance.appCallBackFunction != NULL)
266             {
267                 gBoard_DDRThermalMgmtInstance.appCallBackFunction((Board_DDRTempEventType)
268                                                                   (BOARD_DDR_TEMP_EVENT_LOW_TEMP_ALARM
269                                                                    + tempCheckRefreshRateIndex));
270             }
271         }
273         /* Ack interrupt */
274         LPDDR4_AckCtlInterrupt (&(gBoard_DDRThermalMgmtInstance.boardRuntimeDDRPd), LPDDR4_TEMP_CHANGE);
275     }
276     /* Get DDR interrupt status to check on alarm events */
277     LPDDR4_CheckCtlInterrupt (&(gBoard_DDRThermalMgmtInstance.boardRuntimeDDRPd), LPDDR4_TEMP_ALERT, &irqStatus);
278     if (irqStatus)
279     {
280         /* High or Low temperature alarm : call application callback */
281         if (gBoard_DDRThermalMgmtInstance.appCallBackFunction != NULL)
282         {
283             gBoard_DDRThermalMgmtInstance.appCallBackFunction(BOARD_DDR_TEMP_EVENT_TEMP_ALERT);
284         }
285         /* Ack interrupt */
286         LPDDR4_AckCtlInterrupt (&(gBoard_DDRThermalMgmtInstance.boardRuntimeDDRPd), LPDDR4_TEMP_ALERT);
287     }
289     /* NOTE: Code to handle other DDR events can be added here */
293 /**
294  * \brief DDR Temperature monitoring initialization function
295  *
296  * Configures and initializes DDR temperature handling.
297  * NOTE: This assumes that the DDR parameters are already have the thermal events
298  *       enabled in the DDR controller. This only handles software handling of the
299  *       thermal events
300  *
301  * \return  BOARD_SOK in case of success or appropriate error code 
302  *
303  */
304 Board_STATUS Board_DDRTempMonitoringInit(Board_thermalMgmtCallbackFunction_t callbackFunction)
306     Board_STATUS                status = BOARD_SOK;
307     OsalRegisterIntrParams_t    intrPrms;
308     OsalInterruptRetCode_e      osalRet;
309     uint64_t                    interruptMask;
310     uint32_t                    lpddrStatus;
311     uint32_t                    fspIndex;
312     uint16_t                    coreInterruptIdx;
313     
314     struct tisci_msg_rm_irq_release_req irq_release_req =
315     {
316         .ia_id          = 0,
317         .vint           = 0,
318         .global_event   = 0,
319         .vint_status_bit_index = 0,
320     };
321     struct tisci_msg_rm_irq_set_req irq_set_req =
322     {
323         .ia_id          = 0,
324         .vint           = 0,
325         .global_event   = 0,
326         .vint_status_bit_index = 0,
327     };
328     struct tisci_msg_rm_irq_set_resp resp;
330     /* Initialize LPDDR4 driver */
331     gBoard_DDRThermalMgmtInstance.boardDDRCfg.ctlBase = (struct LPDDR4_CtlRegs_s *)BOARD_DDR_CTL_CFG_BASE;
333     status = LPDDR4_Init(&(gBoard_DDRThermalMgmtInstance.boardRuntimeDDRPd), &(gBoard_DDRThermalMgmtInstance.boardDDRCfg));
335     if ((status > 0U) ||
336         (gBoard_DDRThermalMgmtInstance.boardRuntimeDDRPd.ctlBase != (struct LPDDR4_CtlRegs_s *)gBoard_DDRThermalMgmtInstance.boardDDRCfg.ctlBase))
337     {
338         BOARD_DEBUG_LOG("LPDDR4_Init: FAIL\n");
339         status = BOARD_FAIL;
340     }
342     if (status == BOARD_SOK)
343     {
344         /* Read and preserve the initial Refresh Rates as baseline */
345         for (fspIndex = 0; fspIndex <= LPDDR4_FSP_2; fspIndex++)
346         {
347             lpddrStatus = LPDDR4_GetRefreshRate(&(gBoard_DDRThermalMgmtInstance.boardRuntimeDDRPd), &gBoardDDRFSPNum[fspIndex],
348                                                 &(gBoard_DDRThermalMgmtInstance.boardDDRInitRefreshRate[gBoardDDRFSPNum[fspIndex]]),
349                                                 &(gBoard_DDRThermalMgmtInstance.boardDDRTrasMax[gBoardDDRFSPNum[fspIndex]]));
350             if (lpddrStatus > 0U)
351             {
352                 BOARD_DEBUG_LOG("LPDDR4_GetRefreshRate: FAIL\n");
353                 status = BOARD_FAIL;
354                 break;
355             }
356         }
357     }
358     
359     if (status == BOARD_SOK)
360     {
361         Board_DDRSetDevId();
362         /* Get the Core IRQ Idx */
363         status = Board_DDRGetIntNum(&coreInterruptIdx);
364     }
366     if (status == BOARD_SOK)
367     {
368         /* Configure interrupt router to route DDR Ctrl interrupt to Monitoring
369          * CPU
370          */
371         /* Request irq release for specified interrupt source */
372         irq_release_req.valid_params = TISCI_MSG_VALUE_RM_DST_ID_VALID
373                                        | TISCI_MSG_VALUE_RM_DST_HOST_IRQ_VALID;
374         irq_release_req.src_id = TISCI_DEV_DDR0;
375         irq_release_req.src_index = 0; /* First interrupt in DDR group is the DDR controller interrupt */
376         irq_release_req.dst_id = gBoard_DDRThermalMgmtInstance.devIdCore;
377         irq_release_req.dst_host_irq = coreInterruptIdx;
379         /* Call irq Release */
380         if (CSL_PASS != Sciclient_rmIrqRelease(&irq_release_req, BOARD_SCICLIENT_RESP_TIMEOUT))
381         {
382             /* Ignore if the release fails, as this is expected the first time the image is booted */
383         }
385         /* Request irq set for specified interrupt source */
386         irq_set_req.valid_params = TISCI_MSG_VALUE_RM_DST_ID_VALID
387                                    | TISCI_MSG_VALUE_RM_DST_HOST_IRQ_VALID;
388         irq_set_req.src_id = TISCI_DEV_DDR0;
389         irq_set_req.src_index = 0; /* First interrupt in DDR group is the DDR controller interrupt */
390         irq_set_req.dst_id = gBoard_DDRThermalMgmtInstance.devIdCore;
391         irq_set_req.dst_host_irq = coreInterruptIdx;
393         /* Call irq Set */
394         if (CSL_PASS != Sciclient_rmIrqSet(&irq_set_req, &resp, BOARD_SCICLIENT_RESP_TIMEOUT))
395         {
396             status = BOARD_FAIL;
397         }
398     }
400     if (status == BOARD_SOK)
401     {
403         /* Register DDR Control event handler */
404         Osal_RegisterInterrupt_initParams(&intrPrms); 
405         
406         intrPrms.corepacConfig.corepacEventNum  = 0;
407         intrPrms.corepacConfig.intVecNum        = coreInterruptIdx;
408         intrPrms.corepacConfig.arg              = (uintptr_t)(&(gBoard_DDRThermalMgmtInstance.boardTempInterruptHandle));
409         intrPrms.corepacConfig.isrRoutine       = &Board_DDRInterruptHandler;
411         /* Clear Interrupt */
412         Osal_ClearInterrupt(intrPrms.corepacConfig.corepacEventNum, intrPrms.corepacConfig.intVecNum);
414         /* Register interrupts */
415         osalRet = Osal_RegisterInterrupt(&intrPrms, &(gBoard_DDRThermalMgmtInstance.boardTempInterruptHandle));
416         if (osalRet != OSAL_INT_SUCCESS)
417         {
418             status = BOARD_FAIL;
419         }
420     }
422     if (status == BOARD_SOK)
423     {
424         /* Unmask only DDR thermal interrupt events */
425         interruptMask = (uint64_t)(0xffffffffffffffffU)
426                         & (~(((((uint64_t)1U) << LPDDR4_TEMP_CHANGE)
427                              | (((uint64_t)1U) << LPDDR4_TEMP_ALERT))));
428         LPDDR4_SetCtlInterruptMask(&(gBoard_DDRThermalMgmtInstance.boardRuntimeDDRPd), (const uint64_t *)(&interruptMask));
430         /* Enable DDR controller interrupt */
431         Osal_EnableInterrupt(intrPrms.corepacConfig.corepacEventNum, intrPrms.corepacConfig.intVecNum);
432     }
434     if (status == BOARD_SOK)
435     {
436         gBoard_DDRThermalMgmtInstance.appCallBackFunction = NULL;
437         if (callbackFunction != NULL)
438         {
439             /* Register callback function */
440             gBoard_DDRThermalMgmtInstance.appCallBackFunction = callbackFunction;
441         }
442     }
443     return status;