This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] AM6442:在 R5内核上启用 DRAM ECC

Guru**** 2482225 points
Other Parts Discussed in Thread: SYSCONFIG

请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1449525/am6442-enable-dram-ecc-on-r5-core

器件型号:AM6442
主题中讨论的其他器件:SysConfig

工具与软件:

你好

在我们的产品中、我们有 R5 Core0应用、它应该使用该 ECC 外设监控 DDR 存储器上的位翻转。 在我们的硬件上、我们使用引导流程、这样 u-boot 加载 Linux 内核、然后 R5内核端应用程序通过/lib/firmware.加载 使用此 ECC API 时会遇到一些问题

1. 尽快 DDR_enableInlineECC (true) 称为整个系统冻结、然后由看门狗重新启动

2.如果我使用 SDL_DPL_registerInterrupt (请参阅下面的代码) API、用于根据 TRM (DDR16SS0_DDRSS_DRAM_ECC_CORR_ERR_LVL_0和 DDR16SS0_DDRSS_DRAM_ECC_Uncorr_ERR_LVL_0)注册中断处理程序或中断6和69。Linux 系统仍有响应、但 R5代码侧的应用程序冻结。

我从名为 DDR_ECC_TEST_MAIN_ESM_am64x-sk_r5fss0-0_nortos_ti-arm-clang 的 MCU SDK 中尝试了示例、但该代码在本例中根本不起作用。 您能否查看该代码、并了解缺失或配置错误的内容?

第页 s 我们还根据本 教程在 u-boot 端上启用了 ECC

应用部件:

#define DDR16SS0_DDRSS_DRAM_ECC_CORR_ERR_LEVEL_0 6
#define DDR16SS0_DDRSS_DRAM_ECC_UNCORR_ERR_LEVEL_0 69


#define DDR_START_ADDR (0x80000000u)

/* Memory block for which ECC is calculated (256 Bytes) */
#define DDR_EMIF_ECC_MEM_BLOCK_SIZE       0x100
/* ECC data size per block (32 Bytes) */
#define DDR_EMIF_ECC_DATA_SIZE_PER_BLOCK  0x20

#define DDR_ECC_REGION0_START 0x20100000

#define DDR_MEM_ECC_TEST_ADDR               (DDR_START_ADDR + DDR_ECC_REGION0_START + DDR_EMIF_ECC_MEM_BLOCK_SIZE)

static pSDL_DPL_HwipHandle uncorrIntrHandle, corrIntrHandle;
static volatile uint32_t uncorrectableErrorFlag = false,correctableErrorFlag = false;

static uintptr_t DDRGetTranslatedAddress (uintptr_t memAddress)
{
    uint32_t memIndex;
    uintptr_t translatedMemAddr;

    memIndex = (memAddress - DDR_START_ADDR)/DDR_EMIF_ECC_MEM_BLOCK_SIZE;

    if ((memIndex & 0x1u) == 0)
    {
        translatedMemAddr = memAddress + ((memIndex)*DDR_EMIF_ECC_DATA_SIZE_PER_BLOCK);
    }
    else
    {
        translatedMemAddr = memAddress + ((memIndex+1u)*DDR_EMIF_ECC_DATA_SIZE_PER_BLOCK);
    }
    return  translatedMemAddr;
}

void ECC_UncorrectableErrorInterruptHandler(void * args)
{
    uncorrectableErrorFlag = true;
    DDR_clearECCError (DDR_ECC_2B_ERROR);
}

void ECC_CorrectableErrorInterruptHandler(void * args)
{
    correctableErrorFlag = true;
    DDR_clearECCError (DDR_ECC_1B_ERROR);
}

uint32_t RAM_ErrorDetectionInterruptInit()
{
    int32_t ret = SDL_PASS;

    DebugP_log("ECC Error interrupt registration\r\n");
    //if registering below interrupts is enabled application starts but freezes at moment when SDL_DPL_registerInterrupt is called
#if 1
    SDL_DPL_HwipParams intrParams = {
        .intNum      = DDR16SS0_DDRSS_DRAM_ECC_UNCORR_ERR_LEVEL_0,
        .callback    = &ECC_UncorrectableErrorInterruptHandler,
        .callbackArg = (uintptr_t)NULL
    };

    if((ret = SDL_DPL_registerInterrupt(&intrParams,(pSDL_DPL_HwipHandle*)&uncorrIntrHandle)) != SDL_PASS)
    {
        DebugP_log("ECC Uncorrectable Error interrupt registration failed! Error: %#x\r\n",ret);
        return ret;
    }

    intrParams.intNum = DDR16SS0_DDRSS_DRAM_ECC_CORR_ERR_LEVEL_0;
    intrParams.callback    = &ECC_CorrectableErrorInterruptHandler;
    intrParams.callbackArg = (uintptr_t)NULL;
    
    if((ret = SDL_DPL_registerInterrupt(&intrParams,(pSDL_DPL_HwipHandle*)&corrIntrHandle)) != SDL_PASS)
    {
        DebugP_log("ECC Correctable Error interrupt registration failed! Error: %#x\r\n",ret);
        return ret;
    }
#endif
    //enable 1 bit error interrupt
    //CSL_REG32_FINS(CSL_DDR16SS0_SS_CFG_BASE + CSL_EMIF_SSCFG_V2A_INT_SET_REG, EMIF_SSCFG_V2A_INT_SET_REG_ECC1BERR_EN,0x01);
    //HW_WR_FIELD32(CSL_DDR16SS0_SS_CFG_BASE + CSL_EMIF_SSCFG_V2A_INT_SET_REG, CSL_EMIF_SSCFG_V2A_INT_SET_REG_ECC1BERR_EN,0x01);
    //enable 2 bit error interrupt
    //CSL_REG32_FINS(CSL_DDR16SS0_SS_CFG_BASE + CSL_EMIF_SSCFG_V2A_INT_SET_REG, EMIF_SSCFG_V2A_INT_SET_REG_ECC2BERR_EN,0x01);
    //HW_WR_FIELD32(CSL_DDR16SS0_SS_CFG_BASE + CSL_EMIF_SSCFG_V2A_INT_SET_REG,CSL_EMIF_SSCFG_V2A_INT_SET_REG_ECC2BERR_EN,0x01);
    CSL_emifEnableECCInterrupts((CSL_emif_sscfgRegs*)CSL_DDR16SS0_SS_CFG_BASE,
                                                    CSL_EMIF_SSCFG_V2A_INT_SET_REG_ECC1BERR_EN_MASK
                                                    | CSL_EMIF_SSCFG_V2A_INT_SET_REG_ECCM1BERR_EN_MASK
                                                    | CSL_EMIF_SSCFG_V2A_INT_SET_REG_ECC2BERR_EN_MASK);
    return ret;
}

volatile uint32_t * translatedMemPtr = NULL;

static void printRegs()
{
     for(int i=0; i<=CSL_EMIF_SSCFG_ECC_2B_ERR_MSK_LOG_REG; i+=4)
     {
        uint32_t regValue = HW_RD_REG32(CSL_DDR16SS0_SS_CFG_BASE + i);
        DebugP_log("%d Reg: %#lx (offset: %#x) | value: %#lx\r\n",i,(long unsigned int)CSL_DDR16SS0_SS_CFG_BASE+i,i,(long unsigned int)regValue);
    }
}

uint32_t RAM_ErrorDetectionInit()
{
    DebugP_log("Initializing RAM error detection component\r\n");
    DDR_enableInlineECC (false);

    /*
    ECC 1-bit error threshold.
    The bridge will generate an interrupt when the ECC
    1-bit error count is equal to or greater than this threshold.
    A value of 0 will disable the generation of interrupt.
    */
    HW_WR_FIELD32(CSL_DDR16SS0_SS_CFG_BASE + CSL_EMIF_SSCFG_ECC_1B_ERR_THRSH_REG,CSL_EMIF_SSCFG_ECC_1B_ERR_THRSH_REG_ECC_1B_ERR_THRSH,0x01);

    DDR_clearECCError (DDR_ECC_ERR_ALL);

    RAM_ErrorDetectionInterruptInit();
    
    printRegs();

    //whole Linux system freezes when enabling ECC and then reboot occuring
    //DDR_enableInlineECC(true);

    /*
    Set 1 to enable ECC verification for read accesses when ecc_en=1.
    The value of this field is ignored when ecc_en=0.
    This bit must be set and kept static before using DDR.
    */
    //HW_WR_FIELD32(CSL_DDR16SS0_SS_CFG_BASE + CSL_EMIF_SSCFG_ECC_CTRL_REG,CSL_EMIF_SSCFG_ECC_CTRL_REG_ECC_CK,0x01);
#if 0
    uint32_t * testAddr = (uint32_t *) (DDR_MEM_ECC_TEST_ADDR);
    CacheP_wbInv ((void *)testAddr, 4, CacheP_TYPE_ALL);
    uint32_t memoryCellValue = *testAddr;
    /* Flip one bit to introduce error */
    memoryCellValue ^= 0x00010000u;
    /* Calculate translated address */
    translatedMemPtr = (volatile uint32_t *)(DDRGetTranslatedAddress ((uintptr_t)testAddr));

  /* Now corrupt the value */
    *(translatedMemPtr) = memoryCellValue;
    CacheP_wbInv ((void *)translatedMemPtr, 4, CacheP_TYPE_ALL);

    DDR_enableInlineECC(true);

    /* Invalidate cache */
    CacheP_inv ((void *)testAddr, 4, CacheP_TYPE_ALL);

    /* Read value to trigger error */
    memoryCellValue = *testAddr;
#endif
    return SDL_PASS;
}


SysConfig 器件:

esm1.$name                      = "CONFIG_ESM0";
esm1.esmNotifier.create(4);
esm1.esmNotifier[0].$name       = "CONFIG_ESM_NOTIFY0";
esm1.esmNotifier[0].errorNumber = 162;
esm1.esmNotifier[0].notify      = "ESM_Callback";
esm1.esmNotifier[1].$name       = "CONFIG_ESM_NOTIFY1";
esm1.esmNotifier[1].errorNumber = 112;
esm1.esmNotifier[1].setIntrPriorityLvl = "LOW";
esm1.esmNotifier[1].notify      = "DCC0_IntrErrHandler";
esm1.esmNotifier[2].$name              = "CONFIG_ESM_NOTIFY2";
esm1.esmNotifier[2].setIntrPriorityLvl = "LOW";
esm1.esmNotifier[2].errorNumber        = 69;
esm1.esmNotifier[2].notify             = "ECC_UncorrectableErrorInterruptHandler";
esm1.esmNotifier[3].$name              = "CONFIG_ESM_NOTIFY3";
esm1.esmNotifier[3].errorNumber        = 6;
esm1.esmNotifier[3].setIntrPriorityLvl = "LOW";
esm1.esmNotifier[3].notify             = "ECC_CorrectableErrorInterruptHandler";


BR

雅库布

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 TI 支持部门:

    是否有主题的更新?