diff --git a/pdk_j721s2_11_02_00_15/packages/ti/boot/sbl/soc/k3/sbl_ddr_ecc.h b/pdk_j721s2_11_02_00_15/packages/ti/boot/sbl/soc/k3/sbl_ddr_ecc.h new file mode 100644 index 0000000..a2406de --- /dev/null +++ b/pdk_j721s2_11_02_00_15/packages/ti/boot/sbl/soc/k3/sbl_ddr_ecc.h @@ -0,0 +1,157 @@ +/** + * \file sbl_ddr_ecc.h + * + * \brief This file contains function prototypes for DDR inline ECC initialization in SBL + * Provides DDR priming functionality using DRU for efficient memory initialization + * + */ + +/* + * Copyright (C) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef SBL_DDR_ECC_H +#define SBL_DDR_ECC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* ========================================================================== */ +/* Include Files */ +/* ========================================================================== */ + +#include +#include +#include +#include "sbl_log.h" + +/* ========================================================================== */ +/* Macros & Typedefs */ +/* ========================================================================== */ + +#define SBL_DRU_UTC_ID (UDMA_UTC_ID_MSMC_DRU0) +#define SBL_DRU_QUEUE_ID (CSL_DRU_QUEUE_ID_3) + +/* DDR region setting */ +#define DDR_ECC_START_ADDR0 (0x80000000U) +#define DDR_ECC_END_ADDR0 (0xBFFFFFFFU) +#define DDR_ECC_START_ADDR1 (0xC0000000U) +#define DDR_ECC_END_ADDR1 (0xFFFFFFFFU) +#define DDR_ECC_START_ADDR2 (0x880000000U) +#define DDR_ECC_END_ADDR2 (0x8E38E37FFU) +#define EMIF_DDR_START_ADDR_HIGH (0x880000000U) +#define EMIF_DDR_START_ADDR (0x80000000U) + +/* DDR priming parameters */ +#define SBL_DDR_PRIME_SRC_ADDR (0x70080000U) /* MSMC source buffer address */ +#define SBL_DDR_PRIME_LOW_START (0x80000000U) /* Low DDR start */ +#define SBL_DDR_PRIME_LOW_END (0xFFFFFFFFU) /* Low DDR end */ +#define SBL_DDR_PRIME_HIGH_START (0x880000000U) /* High DDR start */ +#define SBL_DDR_PRIME_HIGH_END (0x8FFFFFFFFU) /* High DDR end */ + +#define SBL_DDR_PRIME_BLOCK_SIZE (0x8000U) /* 32KB block size */ + +/* DRU TR loop parameters */ +#define SBL_DRU_TR_ICNT1 (0x1000U) /* icnt1 = 4096 */ + +/* ========================================================================== */ +/* Function Prototypes */ +/* ========================================================================== */ + +/** + * \brief Initialize DRU for data movement + * + * \param drvHndl UDMA driver handle + * + * \return 0 on success, -1 on failure + */ +int32_t SBL_druInit(Udma_DrvHandle drvHndl); + +/** + * \brief Deinitialize DRU + */ +void SBL_druDeInit(void); + +/** + * \brief Check if DRU initialization is done + * + * \return 1 if DRU is initialized, 0 otherwise + */ +uint8_t SBL_isDruInitDone(void); + +/** + * \brief Copy data using DRU + * + * \param dstAddr Destination address + * \param srcAddr Source address + * \param length Length of data to copy in bytes + * + * \return 0 on success, -1 on failure + */ +int32_t SBL_druCopyData(void *dstAddr, void *srcAddr, uint32_t length); + +/** + * \brief Prime low DDR (0x80000000 to 0xFFFFFFFF) for inline ECC + * Fills DDR memory regions with zeros to enable and initialize ECC codes + * + * \return 0 on success, -1 on failure + */ +int32_t SBL_druPrimeDDRLow(void); + +/** + * \brief Prime high DDR (0x880000000 to 0x8FFFFFFFF) for inline ECC + * Fills high DDR memory regions with zeros to enable and initialize ECC codes + * + * \return 0 on success, -1 on failure + */ +int32_t SBL_druPrimeDDRHigh(void); + +/** + * \brief Initialize DDR inline ECC configuration + * + * \return 0 on success, -1 on failure + */ +int32_t sbl_ddr_ecc_init(); + +/** + * \brief Enable DDR inline ECC checker + * + * \return 0 on success, -1 on failure + */ +int32_t sbl_ddr_ecc_enable(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/pdk_j721s2_11_02_00_15/packages/ti/boot/sbl/soc/k3/sbl_ddr_ecc.c b/pdk_j721s2_11_02_00_15/packages/ti/boot/sbl/soc/k3/sbl_ddr_ecc.c new file mode 100644 index 0000000..b8f0491 --- /dev/null +++ b/pdk_j721s2_11_02_00_15/packages/ti/boot/sbl/soc/k3/sbl_ddr_ecc.c @@ -0,0 +1,773 @@ +/* + * + * Copyright (c) 2021 Texas Instruments Incorporated + * + * All rights reserved not granted herein. + * + * Limited License. + * + * Texas Instruments Incorporated grants a world-wide, royalty-free, non-exclusive + * license under copyrights and patents it now or hereafter owns or controls to make, + * have made, use, import, offer to sell and sell ("Utilize") this software subject to the + * terms herein. With respect to the foregoing patent license, such license is granted + * solely to the extent that any such patent is necessary to Utilize the software alone. + * The patent license shall not apply to any combinations which include this software, + * other than combinations with devices manufactured by or for TI ("TI Devices"). + * No hardware patent is licensed hereunder. + * + * Redistributions must preserve existing copyright notices and reproduce this license + * (including the above copyright notice and the disclaimer and (if applicable) source + * code license limitations below) in the documentation and/or other materials provided + * with the distribution + * + * Redistribution and use in binary form, without modification, are permitted provided + * that the following conditions are met: + * + * * No reverse engineering, decompilation, or disassembly of this software is + * permitted with respect to any software provided in binary form. + * + * * any redistribution and use are licensed by TI for use only with TI Devices. + * + * * Nothing shall obligate TI to provide you with source code for the software + * licensed and provided to you in object code. + * + * If software source code is provided to you, modification and redistribution of the + * source code are permitted provided that the following conditions are met: + * + * * any redistribution and use of the source code, including any resulting derivative + * works, are licensed by TI for use only with TI Devices. + * + * * any redistribution and use of any object code compiled from the source code + * and any resulting derivative works, are licensed by TI for use only with TI Devices. + * + * Neither the name of Texas Instruments Incorporated nor the names of its suppliers + * + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * DISCLAIMER. + * + * THIS SOFTWARE IS PROVIDED BY TI AND TI'S LICENSORS "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TI AND TI'S LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/** + * \brief DDR Inline ECC Configuration and Initialization + * + * This module provides functionality to configure and initialize DDR inline ECC in SBL. + * It includes DDR priming using the Direct Read Unit (DRU) to efficiently initialize + * DDR memory with valid ECC codes. Inline ECC requires all DDR memory to be written + * with valid ECC before any read access. The module primes large DDR regions with zeros + * to generate and enable inline ECC checks for memory protection. + * + */ + +#include +#include +#include +#include +#include +#include "sbl_ddr_ecc.h" + +/* ========================================================================== */ +/* Macros & Typedefs */ +/* ========================================================================== */ + +/** + * \brief DRU TR packet descriptor memory. + * Size for one CSL_UdmapTR15 structure + */ +#define SBL_DRU_TR_SIZE (sizeof(CSL_UdmapTR15)) +/** \brief This ensures memory is aligned */ +#define SBL_DRU_TR_SIZE_ALIGN ((SBL_DRU_TR_SIZE + UDMA_CACHELINE_ALIGNMENT) & ~(UDMA_CACHELINE_ALIGNMENT - 1U)) + +/* ========================================================================== */ +/* Structure Declarations */ +/* ========================================================================== */ + +typedef struct +{ + struct Udma_ChObj chObj; + struct Udma_EventObj eventObj; + + Udma_ChHandle chHandle; + Udma_EventHandle eventHandle; + + Udma_DrvHandle drvHandle; + + uint8_t *trMem; + /**< Allocated TR memory pointer */ +} Sbl_DruChObj; + +typedef struct +{ + uint8_t initDone; + Udma_DrvHandle drvHandle; + Sbl_DruChObj chObj; +} Sbl_DruObj; + +/* ========================================================================== */ +/* Function Declarations */ +/* ========================================================================== */ + +static void sblDruInit(Sbl_DruObj *druObj, Udma_DrvHandle drvHndl); +static int32_t sblDruDeInit(Sbl_DruObj *druObj); + +static int32_t sblDruCreate(Sbl_DruObj *druObj); +static int32_t sblDruDelete(Sbl_DruObj *druObj); + +static void sblDruTrInit(Sbl_DruChObj *druChObj, void *srcAddr, void *dstAddr, uint64_t length); +static void sblDruWaitForCompletion(Sbl_DruChObj *druChObj); + +static void SBL_druCacheWb(const void *addr, uint32_t size); +static void SBL_druCacheInv(const void *addr, uint32_t size); + +static uint32_t sbl_get_ecc_addr(uint64_t addr); +static void sbl_config_ecc_ranges(CSL_EmifConfig *emifCfg); +static void sbl_config_ecc_ranges_swapped(CSL_EmifConfig *emifCfg); + +static void sblDruPrimeDDRRange(uint64_t startAddr, uint64_t endAddr); + +/* ========================================================================== */ +/* Global Variables */ +/* ========================================================================== */ + +/* + * DRU driver and channel objects + */ +Sbl_DruObj gSblDruObj; + +/* + * DRU TR Memory + */ +uint8_t gSblDruTrMem[SBL_DRU_TR_SIZE_ALIGN] __attribute__((aligned(UDMA_CACHELINE_ALIGNMENT))); + + +/* ========================================================================== */ +/* Function Definitions */ +/* ========================================================================== */ + +int32_t SBL_druInit(Udma_DrvHandle drvHndl) +{ + int32_t retVal = UDMA_SOK; + Sbl_DruObj *druObj = &gSblDruObj; + Udma_InitPrms initPrms; + uint32_t instId; + + memset(&gSblDruObj, 0x0, sizeof(gSblDruObj)); + + /* Initialize UDMA driver */ + instId = UDMA_INST_ID_MAIN_0; + UdmaInitPrms_init(instId, &initPrms); + retVal = Udma_init(drvHndl, &initPrms); + if(UDMA_SOK != retVal) + { + SBL_log(SBL_LOG_ERR, "[DRU] UDMA init failed!!\n"); + return -1; + } + + sblDruInit(druObj, drvHndl); + + retVal = sblDruCreate(druObj); + if(UDMA_SOK != retVal) + { + SBL_log(SBL_LOG_ERR, "[DRU] DRU create failed!!\n"); + Udma_deinit(drvHndl); + retVal = -1; + } + else + { + druObj->initDone = 1; + retVal = 0; + } + + return (retVal); +} + +uint8_t SBL_isDruInitDone(void) +{ + return (gSblDruObj.initDone); +} + +int32_t sbl_ddr_inline_ecc_config(CSL_emif_sscfgRegs *ddrCfgAddr) +{ + CSL_EmifConfig emifCfg; + int32_t cslRet; + int32_t retVal = 0; + + /* Configure ECC addresses and other configuration */ + emifCfg.bEnableMemoryECC = true; + emifCfg.bReadModifyWriteEnable = true; + emifCfg.bECCCheck = false; + emifCfg.bWriteAlloc = false; + emifCfg.ECCThreshold = 0x1U; + + /* Configure ECC ranges for all three DDR controllers */ + sbl_config_ecc_ranges(&emifCfg); + + cslRet = CSL_emifConfig(ddrCfgAddr, &emifCfg); + if(cslRet != CSL_PASS) + { + SBL_log(SBL_LOG_ERR, "CSL_emifConfig failed\n"); + retVal = -1; + } + + return retVal; +} + +int32_t sbl_ddr_inline_ecc_disable(CSL_emif_sscfgRegs *ddrCfgAddr) +{ + CSL_EmifConfig emifCfg; + int32_t cslRet; + int32_t retVal = 0; + + /* Configure ECC addresses and other configuration */ + emifCfg.bEnableMemoryECC = true; + emifCfg.bReadModifyWriteEnable = true; + emifCfg.bECCCheck = true; + emifCfg.bWriteAlloc = false; + emifCfg.ECCThreshold = 0x1U; + + /* Configure ECC ranges with swapped start/end for all three DDR controllers */ + sbl_config_ecc_ranges_swapped(&emifCfg); + + cslRet = CSL_emifConfig(ddrCfgAddr, &emifCfg); + if(cslRet != CSL_PASS) + { + SBL_log(SBL_LOG_ERR, "CSL_emifConfig failed\n"); + retVal = -1; + } + + return retVal; +} + +int32_t sbl_ddr_inline_ecc_checker_enable(CSL_emif_sscfgRegs *ddrCfgAddr) +{ + CSL_EmifConfig emifCfg; + int32_t cslRet; + int32_t retVal = 0; + + /* Configure ECC addresses and other configuration */ + emifCfg.bEnableMemoryECC = true; + emifCfg.bReadModifyWriteEnable = true; + emifCfg.bECCCheck = true; + emifCfg.bWriteAlloc = false; + emifCfg.ECCThreshold = 0x1U; + + cslRet = CSL_emifConfig(ddrCfgAddr, &emifCfg); + if(cslRet != CSL_PASS) + { + SBL_log(SBL_LOG_ERR, "CSL_emifConfig failed\n"); + retVal = -1; + } + + return retVal; +} + +int32_t sbl_ddr_inline_ecc_enable(CSL_emif_sscfgRegs *ddrCfgAddr) +{ + CSL_EmifConfig emifCfg; + int32_t cslRet; + int32_t retVal = 0; + + /* Configure ECC addresses and other configuration */ + emifCfg.bEnableMemoryECC = true; + emifCfg.bReadModifyWriteEnable = true; + emifCfg.bECCCheck = false; + emifCfg.bWriteAlloc = false; + emifCfg.ECCThreshold = 0x1U; + + /* Configure ECC ranges for all three DDR controllers */ + sbl_config_ecc_ranges(&emifCfg); + + cslRet = CSL_emifConfig(ddrCfgAddr, &emifCfg); + if(cslRet != CSL_PASS) + { + SBL_log(SBL_LOG_ERR, "CSL_emifConfig failed\n"); + retVal = -1; + } + + return retVal; +} + +int32_t sbl_ddr_ecc_init() +{ + int32_t retVal = 0; + + if(sbl_ddr_inline_ecc_config((CSL_emif_sscfgRegs *)(CSL_COMPUTE_CLUSTER0_DDR0_0_SS_CFG_BASE)) != CSL_PASS) + { + SBL_log(SBL_LOG_ERR, "sbl_ddr_ecc_init DDR0 config failed\n"); + retVal = -1; + } + + if(sbl_ddr_inline_ecc_config((CSL_emif_sscfgRegs *)(CSL_COMPUTE_CLUSTER0_DDR1_1_SS_CFG_BASE)) != CSL_PASS) + { + SBL_log(SBL_LOG_ERR, "sbl_ddr_ecc_init DDR1 config failed\n"); + retVal = -1; + } + + return retVal; +} + + +int32_t sbl_ddr_ecc_enable() +{ + int32_t retVal = 0; + + if(sbl_ddr_inline_ecc_checker_enable((CSL_emif_sscfgRegs *)(CSL_COMPUTE_CLUSTER0_DDR0_0_SS_CFG_BASE)) != CSL_PASS) + { + SBL_log(SBL_LOG_ERR, "sbl_ddr_ecc_enable DDR0 checker failed\n"); + retVal = -1; + } + + if(sbl_ddr_inline_ecc_checker_enable((CSL_emif_sscfgRegs *)(CSL_COMPUTE_CLUSTER0_DDR1_1_SS_CFG_BASE)) != CSL_PASS) + { + SBL_log(SBL_LOG_ERR, "sbl_ddr_ecc_enable DDR1 checker failed\n"); + retVal = -1; + } + + return retVal; +} + +void SBL_druDeInit(void) +{ + int32_t retVal; + Sbl_DruObj *druObj = &gSblDruObj; + Udma_DrvHandle drvHandle = druObj->drvHandle; + + retVal = sblDruDelete(druObj); + if(UDMA_SOK != retVal) + { + SBL_log(SBL_LOG_ERR, "[DRU] DRU delete failed!!\n"); + } + + retVal = sblDruDeInit(druObj); + if(UDMA_SOK != retVal) + { + SBL_log(SBL_LOG_ERR, "[DRU] DRU deinit failed!!\n"); + } + + /* Deinitialize UDMA driver */ + retVal = Udma_deinit(drvHandle); + if(UDMA_SOK != retVal) + { + SBL_log(SBL_LOG_ERR, "[DRU] UDMA deinit failed!!\n"); + } + + druObj->initDone = 0; +} + +int32_t SBL_druCopyData(void *dstAddr, void *srcAddr, uint32_t length) +{ + Sbl_DruObj *druObj = &gSblDruObj; + Sbl_DruChObj *druChObj; + + druChObj = &druObj->chObj; + + /* DRU transfer is used for larger transfers + * For smaller transfers, use memcpy */ + if (length >= SBL_DDR_PRIME_BLOCK_SIZE) + { + /* Initialize TR with source and destination addresses */ + sblDruTrInit(druChObj, srcAddr, dstAddr, length); + + /* Submit TR to DRU channel */ + Udma_chDruSubmitTr(druChObj->chHandle, (CSL_UdmapTR *)druChObj->trMem); + + /* Wait for transfer completion */ + sblDruWaitForCompletion(druChObj); + } + else + { + /* Use memcpy for small transfers */ + memcpy((void *)dstAddr, srcAddr, length); + } + + return 0; +} + +static uint32_t sbl_get_ecc_addr(uint64_t addr) +{ + if(addr >= EMIF_DDR_START_ADDR_HIGH) + { + return (addr - EMIF_DDR_START_ADDR_HIGH + EMIF_DDR_START_ADDR) >> 1; + } + else + { + return (addr - EMIF_DDR_START_ADDR) >> 1; + } +} + +static void sbl_config_ecc_ranges(CSL_EmifConfig *emifCfg) +{ + /* Configure ECC address ranges for all three DDR controllers */ + emifCfg->pMemEccCfg.startAddr[0] = sbl_get_ecc_addr(DDR_ECC_START_ADDR0); + emifCfg->pMemEccCfg.endAddr[0] = sbl_get_ecc_addr(DDR_ECC_END_ADDR0); + + emifCfg->pMemEccCfg.startAddr[1] = sbl_get_ecc_addr(DDR_ECC_START_ADDR1); + emifCfg->pMemEccCfg.endAddr[1] = sbl_get_ecc_addr(DDR_ECC_END_ADDR1); + + emifCfg->pMemEccCfg.startAddr[2] = sbl_get_ecc_addr(DDR_ECC_START_ADDR2); + emifCfg->pMemEccCfg.endAddr[2] = sbl_get_ecc_addr(DDR_ECC_END_ADDR2); +} + +static void sbl_config_ecc_ranges_swapped(CSL_EmifConfig *emifCfg) +{ + /* Configure ECC address ranges with swapped start/end (for disable) */ + emifCfg->pMemEccCfg.endAddr[0] = sbl_get_ecc_addr(DDR_ECC_START_ADDR0); + emifCfg->pMemEccCfg.startAddr[0] = sbl_get_ecc_addr(DDR_ECC_END_ADDR0); + + emifCfg->pMemEccCfg.endAddr[1] = sbl_get_ecc_addr(DDR_ECC_START_ADDR1); + emifCfg->pMemEccCfg.startAddr[1] = sbl_get_ecc_addr(DDR_ECC_END_ADDR1); + + emifCfg->pMemEccCfg.endAddr[2] = sbl_get_ecc_addr(DDR_ECC_START_ADDR2); + emifCfg->pMemEccCfg.startAddr[2] = sbl_get_ecc_addr(DDR_ECC_END_ADDR2); +} + +static void sblDruInit(Sbl_DruObj *druObj, Udma_DrvHandle drvHndl) +{ + Sbl_DruChObj *druChObj; + + druObj->drvHandle = drvHndl; + + druChObj = &druObj->chObj; + + druChObj->chHandle = &druChObj->chObj; + druChObj->eventHandle = NULL; + druChObj->drvHandle = drvHndl; + druChObj->trMem = &gSblDruTrMem[0u]; +} + +static int32_t sblDruDeInit(Sbl_DruObj *druObj) +{ + /* Release Driver Handle */ + druObj->drvHandle = NULL; + + return (0); +} + +static int32_t sblDruCreate(Sbl_DruObj *druObj) +{ + int32_t retVal = UDMA_SOK; + uint32_t chType; + Udma_ChPrms chPrms; + Udma_ChUtcPrms utcPrms; + Udma_EventHandle eventHandle; + Udma_EventPrms eventPrms; + Sbl_DruChObj *druChObj; + Udma_ChHandle chHandle; + Udma_DrvHandle drvHandle = druObj->drvHandle; + uint32_t numQueue, queId; + CSL_DruQueueConfig queueCfg; + + druChObj = &druObj->chObj; + chHandle = druChObj->chHandle; + + /* Clear channel object */ + memset(chHandle, 0x0, sizeof(struct Udma_ChObj)); + + /* Configure DRU queues */ + numQueue = Udma_druGetNumQueue(drvHandle, SBL_DRU_UTC_ID); + if(0U == numQueue) + { + SBL_log(SBL_LOG_ERR, "[DRU] Invalid queue number!!\n"); + retVal = UDMA_EFAIL; + } + + if(UDMA_SOK == retVal) + { + UdmaDruQueueConfig_init(&queueCfg); + for(queId = CSL_DRU_QUEUE_ID_0; queId < numQueue; queId++) + { + retVal = Udma_druQueueConfig(drvHandle, SBL_DRU_UTC_ID, queId, &queueCfg); + if(UDMA_SOK != retVal) + { + SBL_log(SBL_LOG_ERR, "[DRU] Queue config failed!!\n"); + break; + } + } + } + + if(UDMA_SOK == retVal) + { + /* Init channel parameters for UTC type */ + chType = UDMA_CH_TYPE_UTC; + UdmaChPrms_init(&chPrms, chType); + chPrms.utcId = SBL_DRU_UTC_ID; + + /* Ring not used in direct TR submission via DRU */ + chPrms.fqRingPrms.ringMem = NULL; + chPrms.cqRingPrms.ringMem = NULL; + chPrms.tdCqRingPrms.ringMem = NULL; + chPrms.fqRingPrms.elemCnt = 0U; + chPrms.cqRingPrms.elemCnt = 0U; + chPrms.tdCqRingPrms.elemCnt = 0U; + + /* Open UTC channel */ + retVal = Udma_chOpen(drvHandle, chHandle, chType, &chPrms); + if(UDMA_SOK != retVal) + { + SBL_log(SBL_LOG_ERR, "[DRU] Channel open failed!!\n"); + } + } + + if(UDMA_SOK == retVal) + { + /* Config UTC channel */ + UdmaChUtcPrms_init(&utcPrms); + utcPrms.druOwner = CSL_DRU_OWNER_DIRECT_TR; + utcPrms.druQueueId = SBL_DRU_QUEUE_ID; + retVal = Udma_chConfigUtc(chHandle, &utcPrms); + if(UDMA_SOK != retVal) + { + SBL_log(SBL_LOG_ERR, "[DRU] UTC channel config failed!!\n"); + } + } + + if(UDMA_SOK == retVal) + { + /* Register TR completion event for polling mode */ + eventHandle = &druChObj->eventObj; + UdmaEventPrms_init(&eventPrms); + eventPrms.eventType = UDMA_EVENT_TYPE_TR; + eventPrms.eventMode = UDMA_EVENT_MODE_SHARED; + eventPrms.chHandle = chHandle; + eventPrms.masterEventHandle = NULL; + eventPrms.eventCb = NULL; + retVal = Udma_eventRegister(drvHandle, eventHandle, &eventPrms); + if(UDMA_SOK != retVal) + { + SBL_log(SBL_LOG_ERR, "[DRU] Event register failed!!\n"); + } + else + { + druChObj->eventHandle = eventHandle; + } + } + + if(UDMA_SOK == retVal) + { + /* Channel enable */ + retVal = Udma_chEnable(chHandle); + if(UDMA_SOK != retVal) + { + SBL_log(SBL_LOG_ERR, "[DRU] Channel enable failed!!\n"); + } + } + + if(UDMA_SOK != retVal) + { + retVal = -1; + } + else + { + retVal = 0; + } + + return (retVal); +} + +static int32_t sblDruDelete(Sbl_DruObj *druObj) +{ + int32_t retVal = UDMA_SOK; + Sbl_DruChObj *druChObj; + Udma_ChHandle chHandle; + + druChObj = &druObj->chObj; + chHandle = druChObj->chHandle; + + retVal = Udma_chDisable(chHandle, UDMA_DEFAULT_CH_DISABLE_TIMEOUT); + if(UDMA_SOK != retVal) + { + SBL_log(SBL_LOG_ERR, "[DRU] Channel disable failed!!\n"); + } + + /* Unregister event */ + if(NULL != druChObj->eventHandle) + { + retVal += Udma_eventUnRegister(druChObj->eventHandle); + if(UDMA_SOK != retVal) + { + SBL_log(SBL_LOG_ERR, "[DRU] Event unregister failed!!\n"); + } + druChObj->eventHandle = NULL; + } + + retVal += Udma_chClose(chHandle); + if(UDMA_SOK != retVal) + { + SBL_log(SBL_LOG_ERR, "[DRU] Channel close failed!!\n"); + } + + if(UDMA_SOK != retVal) + { + retVal = -1; + } + else + { + retVal = 0; + } + + return (retVal); +} + +static void sblDruTrInit(Sbl_DruChObj *druChObj, void *srcAddr, void *dstAddr, uint64_t length) +{ + CSL_UdmapTR15 *pTr = (CSL_UdmapTR15 *)(druChObj->trMem); + uint64_t totalSize; + uint16_t icnt1, icnt2; + + /* Setup TR for 4D block move */ + pTr->flags = CSL_FMK(UDMAP_TR_FLAGS_TYPE, CSL_UDMAP_TR_FLAGS_TYPE_4D_BLOCK_MOVE) | + CSL_FMK(UDMAP_TR_FLAGS_STATIC, 0U) | + CSL_FMK(UDMAP_TR_FLAGS_EOL, 0U) | + CSL_FMK(UDMAP_TR_FLAGS_EVENT_SIZE, CSL_UDMAP_TR_FLAGS_EVENT_SIZE_COMPLETION) | + CSL_FMK(UDMAP_TR_FLAGS_TRIGGER0, CSL_UDMAP_TR_FLAGS_TRIGGER_NONE) | + CSL_FMK(UDMAP_TR_FLAGS_TRIGGER0_TYPE, CSL_UDMAP_TR_FLAGS_TRIGGER_TYPE_ALL) | + CSL_FMK(UDMAP_TR_FLAGS_TRIGGER1, CSL_UDMAP_TR_FLAGS_TRIGGER_NONE) | + CSL_FMK(UDMAP_TR_FLAGS_TRIGGER1_TYPE, CSL_UDMAP_TR_FLAGS_TRIGGER_TYPE_ALL) | + CSL_FMK(UDMAP_TR_FLAGS_CMD_ID, 0x25U) | + CSL_FMK(UDMAP_TR_FLAGS_SA_INDIRECT, 0U) | + CSL_FMK(UDMAP_TR_FLAGS_DA_INDIRECT, 0U) | + CSL_FMK(UDMAP_TR_FLAGS_EOP, 1U); + + /* Calculate loop counts: icnt0*icnt1*icnt2*icnt3 = length */ + totalSize = length / SBL_DDR_PRIME_BLOCK_SIZE; /* Divide by icnt0 */ + icnt1 = SBL_DRU_TR_ICNT1; /* 4096 */ + icnt2 = (uint16_t)(totalSize / icnt1); + + /* Source configuration - icnt0*icnt1*icnt2*icnt3 = length */ + pTr->icnt0 = SBL_DDR_PRIME_BLOCK_SIZE; /* 32KB block size */ + pTr->icnt1 = icnt1; /* 0x1000 (4096) */ + pTr->icnt2 = icnt2; /* calculated to reach total length */ + pTr->icnt3 = 1U; /* no loop in dim3 */ + pTr->dim1 = 0; /* Source address does not change - reuse buffer */ + pTr->dim2 = 0; /* Source address does not change */ + pTr->dim3 = 0; /* Source address does not change */ + pTr->addr = (uint64_t)srcAddr; + pTr->fmtflags = 0x00000000U; /* Linear addressing, 1 byte per elem */ + + /* Destination configuration - dicnt0*dicnt1*dicnt2*dicnt3 = length */ + pTr->dicnt0 = SBL_DDR_PRIME_BLOCK_SIZE; /* 32KB block size */ + pTr->dicnt1 = icnt1; /* 0x1000 (4096) */ + pTr->dicnt2 = icnt2; /* calculated to reach total length */ + pTr->dicnt3 = 1U; /* no loop in dim3 */ + pTr->ddim1 = (int32_t)SBL_DDR_PRIME_BLOCK_SIZE; /* Stride after icnt0 */ + pTr->ddim2 = (int32_t)(SBL_DDR_PRIME_BLOCK_SIZE * icnt1); /* Stride after icnt1 */ + pTr->ddim3 = (int32_t)(SBL_DDR_PRIME_BLOCK_SIZE * icnt1 * icnt2); /* Stride after icnt2 */ + pTr->daddr = (uint64_t)dstAddr; + + /* Writeback cache */ + SBL_druCacheWb(druChObj->trMem, SBL_DRU_TR_SIZE_ALIGN); + + return; +} + +static void sblDruWaitForCompletion(Sbl_DruChObj *druChObj) +{ + volatile uint64_t intrStatusReg; + + /* Poll for TR completion */ + while(1) + { + if(NULL != druChObj->eventHandle) + { + intrStatusReg = CSL_REG64_RD(druChObj->eventHandle->eventPrms.intrStatusReg); + if(intrStatusReg & druChObj->eventHandle->eventPrms.intrMask) + { + /* Clear interrupt status */ + CSL_REG64_WR(druChObj->eventHandle->eventPrms.intrClearReg, + druChObj->eventHandle->eventPrms.intrMask); + break; + } + } + } + + return; +} + +static void SBL_druCacheWb(const void *addr, uint32_t size) +{ + CacheP_wb(addr, size); + + return; +} + +static void SBL_druCacheInv(const void *addr, uint32_t size) +{ + CacheP_Inv(addr, size); + + return; +} + +static void sblDruPrimeDDRRange(uint64_t startAddr, uint64_t endAddr) +{ + uint64_t rangeSize; + uint8_t *srcBuf; + Sbl_DruObj *druObj = &gSblDruObj; + Sbl_DruChObj *druChObj; + + druChObj = &druObj->chObj; + srcBuf = (uint8_t *)SBL_DDR_PRIME_SRC_ADDR; + + /* Calculate range size to be primed */ + rangeSize = endAddr - startAddr + 1; + + /* Initialize source buffer with zeros for ECC priming */ + memset(srcBuf, 0, SBL_DDR_PRIME_BLOCK_SIZE); + SBL_druCacheWb(srcBuf, SBL_DDR_PRIME_BLOCK_SIZE); + + /* Setup TR with loop counters to prime entire DDR range with zeros + * Writing zeros initializes DDR with valid ECC codes for inline ECC */ + sblDruTrInit(druChObj, srcBuf, (void *)startAddr, rangeSize); + + /* Submit TR to DRU channel for efficient bulk data movement */ + Udma_chDruSubmitTr(druChObj->chHandle, (CSL_UdmapTR *)druChObj->trMem); + + /* Wait for DRU transfer completion */ + sblDruWaitForCompletion(druChObj); + + /* Invalidate destination cache to ensure data coherency */ + SBL_druCacheInv((const void *)startAddr, (uint32_t)rangeSize); + + return; +} + +int32_t SBL_druPrimeDDRLow(void) +{ + if(0 == SBL_isDruInitDone()) + { + SBL_log(SBL_LOG_ERR, "[DRU] DRU not initialized!!\n"); + return -1; + } + + SBL_log(SBL_LOG_MAX, "[DRU] Priming Low DDR (0x80000000 - 0xFFFFFFFF) for inline ECC...\n"); + sblDruPrimeDDRRange(SBL_DDR_PRIME_LOW_START, SBL_DDR_PRIME_LOW_END); + SBL_log(SBL_LOG_MAX, "[DRU] Low DDR priming complete.\n"); + + return 0; +} + +int32_t SBL_druPrimeDDRHigh(void) +{ + if(0 == SBL_isDruInitDone()) + { + SBL_log(SBL_LOG_ERR, "[DRU] DRU not initialized!!\n"); + return -1; + } + + SBL_log(SBL_LOG_MAX, "[DRU] Priming High DDR (0x880000000 - 0x8FFFFFFFF) for inline ECC...\n"); + sblDruPrimeDDRRange(SBL_DDR_PRIME_HIGH_START, SBL_DDR_PRIME_HIGH_END); + SBL_log(SBL_LOG_MAX, "[DRU] High DDR priming complete.\n"); + + return 0; +} diff --git a/pdk_j721s2_11_02_00_15/packages/ti/drv/sciclient/soc/V4/sciclient_defaultBoardcfg_rm.c b/pdk_j721s2_11_02_00_15/packages/ti/drv/sciclient/soc/V4/sciclient_defaultBoardcfg_rm.c index f094ee3..b5bc0ea 100755 --- a/pdk_j721s2_11_02_00_15/packages/ti/drv/sciclient/soc/V4/sciclient_defaultBoardcfg_rm.c +++ b/pdk_j721s2_11_02_00_15/packages/ti/drv/sciclient/soc/V4/sciclient_defaultBoardcfg_rm.c @@ -154,7 +154,7 @@ __attribute__(( aligned(128), section(".boardcfg_data") )) = .magic = TISCI_BOARDCFG_RM_RESASG_MAGIC_NUM, .size = (uint16_t) sizeof(struct tisci_boardcfg_rm_resasg), }, - .resasg_entries_size = 379 * sizeof(struct tisci_boardcfg_rm_resasg_entry), + .resasg_entries_size = 381 * sizeof(struct tisci_boardcfg_rm_resasg_entry), }, }, .resasg_entries = { @@ -1244,6 +1244,12 @@ __attribute__(( aligned(128), section(".boardcfg_data") )) = .start_resource = 101, .host_id = TISCI_HOST_ID_C7X_1_1, }, + { + .num_resource = 2, + .type = TISCI_RESASG_UTYPE (TISCI_DEV_NAVSS0_UDMAP_0, TISCI_RESASG_SUBTYPE_UDMAP_TX_ECHAN), + .start_resource = 113, + .host_id = TISCI_HOST_ID_MCU_0_R5_0, + }, { .num_resource = 2, .type = TISCI_RESASG_UTYPE (TISCI_DEV_NAVSS0_UDMAP_0, TISCI_RESASG_SUBTYPE_UDMAP_TX_ECHAN), @@ -1256,6 +1262,12 @@ __attribute__(( aligned(128), section(".boardcfg_data") )) = .start_resource = 115, .host_id = TISCI_HOST_ID_MAIN_0_R5_2, }, + { + .num_resource = 96, + .type = TISCI_RESASG_UTYPE (TISCI_DEV_NAVSS0_UDMAP_0, TISCI_RESASG_SUBTYPE_UDMAP_TX_ECHAN), + .start_resource = 117, + .host_id = TISCI_HOST_ID_MCU_0_R5_0, + }, { .num_resource = 96, .type = TISCI_RESASG_UTYPE (TISCI_DEV_NAVSS0_UDMAP_0, TISCI_RESASG_SUBTYPE_UDMAP_TX_ECHAN), diff --git a/pdk_j721s2_11_02_00_15/packages/ti/drv/sciclient/soc/V4/sciclient_defaultBoardcfg_tifs_rm.c b/pdk_j721s2_11_02_00_15/packages/ti/drv/sciclient/soc/V4/sciclient_defaultBoardcfg_tifs_rm.c index b9165c9..ed262ce 100644 --- a/pdk_j721s2_11_02_00_15/packages/ti/drv/sciclient/soc/V4/sciclient_defaultBoardcfg_tifs_rm.c +++ b/pdk_j721s2_11_02_00_15/packages/ti/drv/sciclient/soc/V4/sciclient_defaultBoardcfg_tifs_rm.c @@ -52,7 +52,7 @@ /* Global Variables */ /* ========================================================================== */ -#define BOARDCFG_TIFS_RM_RESASG_ENTRIES 317 +#define BOARDCFG_TIFS_RM_RESASG_ENTRIES 319 #if defined (BUILD_MCU1_0) || defined (SCICLIENT_MERGED) struct tisci_local_tifs_rm_boardcfg { @@ -1088,6 +1088,12 @@ __attribute__(( aligned(128), section(".boardcfg_data") )) = .start_resource = 101, .host_id = TISCI_HOST_ID_C7X_1_1, }, + { + .num_resource = 2, + .type = TISCI_RESASG_UTYPE (TISCI_DEV_NAVSS0_UDMAP_0, TISCI_RESASG_SUBTYPE_UDMAP_TX_ECHAN), + .start_resource = 113, + .host_id = TISCI_HOST_ID_MCU_0_R5_0, + }, { .num_resource = 2, .type = TISCI_RESASG_UTYPE (TISCI_DEV_NAVSS0_UDMAP_0, TISCI_RESASG_SUBTYPE_UDMAP_TX_ECHAN), @@ -1100,6 +1106,12 @@ __attribute__(( aligned(128), section(".boardcfg_data") )) = .start_resource = 115, .host_id = TISCI_HOST_ID_MAIN_0_R5_2, }, + { + .num_resource = 96, + .type = TISCI_RESASG_UTYPE (TISCI_DEV_NAVSS0_UDMAP_0, TISCI_RESASG_SUBTYPE_UDMAP_TX_ECHAN), + .start_resource = 117, + .host_id = TISCI_HOST_ID_MCU_0_R5_0, + }, { .num_resource = 96, .type = TISCI_RESASG_UTYPE (TISCI_DEV_NAVSS0_UDMAP_0, TISCI_RESASG_SUBTYPE_UDMAP_TX_ECHAN), diff --git a/pdk_j721s2_11_02_00_15/packages/ti/boot/sbl/build/sbl_lib.mk b/pdk_j721s2_11_02_00_15/packages/ti/boot/sbl/build/sbl_lib.mk index 0dff379..99f727d 100644 --- a/pdk_j721s2_11_02_00_15/packages/ti/boot/sbl/build/sbl_lib.mk +++ b/pdk_j721s2_11_02_00_15/packages/ti/boot/sbl/build/sbl_lib.mk @@ -102,6 +102,7 @@ SRCS_COMMON += sbl_vid_map.c ifeq ($(SBL_USE_DMA), yes) SRCS_COMMON += sbl_dma.c endif +SRCS_COMMON += sbl_ddr_ecc.c SRCS_ASM_COMMON += sbl_misc.asm SRCS_ASM_COMMON += sbl_init.asm diff --git a/pdk_j721s2_11_02_00_15/packages/ti/boot/sbl/board/k3/sbl_main.c b/pdk_j721s2_11_02_00_15/packages/ti/boot/sbl/board/k3/sbl_main.c index c7fe4de..45e8dab 100755 --- a/pdk_j721s2_11_02_00_15/packages/ti/boot/sbl/board/k3/sbl_main.c +++ b/pdk_j721s2_11_02_00_15/packages/ti/boot/sbl/board/k3/sbl_main.c @@ -47,6 +47,9 @@ #include "sbl_pbist.h" #endif +#include "sbl_ddr_ecc.h" +#include + /********************************************************************** ************************** Macros ************************************ **********************************************************************/ @@ -66,6 +69,7 @@ /********************************************************************** ************************** Global Variables ************************** **********************************************************************/ +static struct Udma_DrvObj gSblDdrPrimeUdmaDrvObj; extern sblProfileInfo_t sblProfileLog[MAX_PROFILE_LOG_ENTRIES]; extern uint32_t sblProfileLogIndx; extern uint32_t sblProfileLogOvrFlw; @@ -507,6 +511,38 @@ SBL_log(SBL_LOG_MAX,"done.\n"); /*Profile point after DRR init and before Ethernet Configuration*/ SBL_ADD_PROFILE_POINT; + /* Add after DDR initialization in main() */ + //#if defined(SBL_ENABLE_DDR_INLINE_ECC) + SBL_log(SBL_LOG_MAX, "Inline ECC iniitalzie ..."); + if(CSL_PASS != sbl_ddr_ecc_init()) + { + retVal = CSL_EFAIL; + SBL_log(SBL_LOG_ERR, "\n Failed to configure DDR Inline ECC Parameters !! \n"); + } + + SBL_log(SBL_LOG_MAX, "Priming DDR with DRU for inline ECC ..."); + if (SBL_druInit(&gSblDdrPrimeUdmaDrvObj) == 0) + { + SBL_druPrimeDDRLow(); + SBL_druPrimeDDRHigh(); + SBL_druDeInit(); + SBL_log(SBL_LOG_MAX, "DDR priming complete.\n"); + } + else + { + SBL_log(SBL_LOG_ERR, "Failed to initialize DRU for DDR priming!!\n"); + } + + SBL_log(SBL_LOG_MAX, "Enable DDR0 Inline ECC function ..."); + if(CSL_PASS != sbl_ddr_ecc_enable()) + { + retVal = CSL_EFAIL; + SBL_log(SBL_LOG_ERR, "\n Failed to enable Inline ECC ! \n"); + } + + //#endif + + #if defined(SBL_ENABLE_SERDES) SBL_log(SBL_LOG_MAX, "Initializing SERDES ..."); if (CSL_PASS != Board_init(BOARD_INIT_SERDES_PHY))