AM2434: How can the Main and MCU domain be isolated?

Part Number: AM2434

Tool/software:

in Sitara AM2434 Safety Manual there is a description about "Physical Isolation of MCU domain from Main domain".

Each of these domains contain dedicated peripherals such
as GPIOs, I2C, UART, SPI, interconnect, and configuration logic. This makes sure that the M4F in the MCU
channel can execute independently using dedicated resources. After the AM64x device is boot up, the MCU
domain can be configured to be isolated from the Main domain. This is done by enabling clock gating isolation.

Our goal is to make sure that Main domain should not access the peripherals of MCU domain.

I also find an example mcu_plus_sdk_am243x/examples/drivers/safety/reset_isolation/reset_isolation_mcu_domain.c and the call of function SOC_enableResetIsolation(...) wirh the following paramenter.

    /* Disabling Main2MCU PSC. This would restrict the main domain from accessing
    MCU domain peripherals/registers. Care must be taken no Main domain cores access
    MCU domain registers after this */
    pscMain2MCUDisable = 1;

I try to integrate the code into out project in C++ and try to access GPIO pin from Main domain. It seems that the Isolation does not work. The GPIO can still be toggled.

Can You help me to find, what I do wrong. Or how it should be configured.

The class files are uploaded

SitaraMcuIsolation.cpp.txt
/*
 * SitaraMcuIsolation.cpp
 *
 *  Created on: 26.11.2024
 *      Author: zhih
 */
#include <sciopta.h>
#include "SitaraMcuIsolation.hpp"
#include "rat.h"

namespace balluff
{
namespace bni_safe
{
namespace pal
{
namespace sitara
{

SitaraMcuIsolation::SitaraMcuIsolation()
{
    util::SafeReturn status = util::SafeReturn::RET_ERROR;
    uint32_t         pscMain2MCUDisable, pscMCU2MainDisable, debugIsolationEnable;
    /* Disabling Main2MCU PSC. This would restrict the main domain from accessing
    MCU domain peripherals/registers. Care must be taken no Main domain cores access
    MCU domain registers after this */
    pscMain2MCUDisable = 1;
    /* Disabling MCU2Main PSC. This would restrict the MCU domain from accessing
    Main domain peripherals/registers. Care must be taken no MCU domain cores access
    Main domain registers after this */
    pscMCU2MainDisable = 0;
    /* Enabling debug isolation will restrict the JTAG access to MCU domain */
    debugIsolationEnable = 0;
    status = enableResetIsolation(pscMain2MCUDisable, pscMCU2MainDisable, debugIsolationEnable);
    kprintf(0, "SitaraMcuIsolation::SitaraMcuIsolation: status %x\n", status);
}

SitaraMcuIsolation::~SitaraMcuIsolation()
{
    // TODO Auto-generated destructor stub
}

util::SafeReturn SitaraMcuIsolation::enableResetIsolation(uint32_t main2McuIsolation, uint32_t mcu2MainIsolation,
                                                          uint32_t debugIsolationEnable)
{
    uint32_t         baseAddr = 0;
    util::SafeReturn status = util::SafeReturn::RET_OK;
    controlModuleUnlockMMR(6);
    controlModuleUnlockMMR(1);

    baseAddr = (uint32_t)AddrTranslateP_getLocalAddr(CSL_MCU_CTRL_MMR0_CFG0_BASE);

    /* Block MAIN domain reset: set bit 18 of CTRLMMR_RST_CTRL to 1.*/
    REG32_FINS(baseAddr + CSL_MCU_CTRL_MMR_CFG0_RST_CTRL, 0x0040000U, 0x00000012U, 1);

    /* Enable timeout gasket */
    REG32_FINS(baseAddr + CSL_MCU_CTRL_MMR_CFG0_MCU_MTOG_CTRL, 0x00008000U, 0x0000000FU, 1);

    /* Write a non zero value to Magic Word */
    REG32_WR(baseAddr + CSL_MCU_CTRL_MMR_CFG0_RST_MAGIC_WORD, 0x1);

    if (debugIsolationEnable == 1)
    {
        /* Enable debug Isolation */
        REG32_FINS(baseAddr + CSL_MCU_CTRL_MMR_CFG0_ISO_CTRL, 2, 1, 1);
    }

    /* Enable reset Isolation */
    REG32_FINS(baseAddr + CSL_MCU_CTRL_MMR_CFG0_ISO_CTRL, 1, 0, 1);

    /* Block DMSC to trigger reset of MCU domain: set bit 16 of CTRLMMR_RST_CTRL to 1.*/
    REG32_FINS(baseAddr + CSL_MCU_CTRL_MMR_CFG0_RST_CTRL, 0x00010000U, 0x00000010U, 1);

    if (main2McuIsolation == 1)
    {
        status = setPSCState(CSL_MCU_LPSC_MAIN2MCU, SOC_PSC_DISABLE);
    }

    if (status == util::SafeReturn::RET_OK)
    {
        if (mcu2MainIsolation == 1)
        {
            status = setPSCState(CSL_MCU_LPSC_MCU2MAIN, SOC_PSC_DISABLE);
        }
    }

    controlModuleLockMMR(6);
    controlModuleLockMMR(1);

    return status;
}


util::SafeReturn SitaraMcuIsolation::setPSCState(uint32_t moduleNum, uint32_t pscState) // 032
{
    util::SafeReturn status = util::SafeReturn::RET_OK;
    uint32_t         baseAddr = 0;
    uint32_t         loopCnt = 0;
    uint32_t         pdTransStatus;

    baseAddr = (uint32_t)AddrTranslateP_getLocalAddr(CSL_MCU_PSC0_BASE);

    if (status == util::SafeReturn::RET_OK)
    {

        /* get value of bits 0-5 of PSC0_MDSTAT Register*/
        if (REG32_FEXT(baseAddr + CSL_MCU_PSC0_MDSTAT, 0x0000003FU, 0x00000000U) == pscState)
        {
            ;
        }
        else
        {
            if (pscState == PSC_MODSTATE_ENABLE)
            {
                /* Power Domain Control: set bit NEXT to 1 */
                REG32_FINS(baseAddr + CSL_MCU_PSC0_PDCTL, 1, 0, 1);
            }

            /* Enable the clock for the module: Module Next State: set bits 0-4 of NEXT to 2 */
            REG32_FINS(baseAddr + CSL_MCU_PSC0_MDCTL, 0x1F, 0, pscState);

            /* Start the state transition */
            /* write 1 at PSC_PTCMD */
            REG32_WR(baseAddr + CSL_MCU_PSC0_PTCMD, 1);

            /* check pdTransStatus(Power Domain n Transition Command Status) until it is set */
            do
            {
                pdTransStatus = REG32_RD(baseAddr + CSL_MCU_PSC0_PTSTAT) & 1U;
                loopCnt++;
            } while (pdTransStatus && (loopCnt < PSC_TIMEOUT));

            if (pdTransStatus == 0)
            {
                status = util::SafeReturn::RET_OK;
            }
            else
            {
                status = util::SafeReturn::RET_ERROR;
            }
        }
    }

    return status;
}

void SitaraMcuIsolation::controlModuleLockMMR(uint32_t partition)
{
    uint32_t baseAddr;
    uint32_t kickAddr;

    baseAddr = (uint32_t)AddrTranslateP_getLocalAddr(CSL_MCU_CTRL_MMR0_CFG0_BASE);
    kickAddr = baseAddr + (0x1008 + 0x4000 * (partition));
    REG32_WR(kickAddr, KICK_LOCK_VAL); /* KICK 0 */
    kickAddr++;
    REG32_WR(kickAddr, KICK_LOCK_VAL); /* KICK 1 */


    return;
}

void SitaraMcuIsolation::controlModuleUnlockMMR(uint32_t partition)
{
    uint32_t baseAddr;
    uint32_t kickAddr;

    baseAddr = (uint32_t)AddrTranslateP_getLocalAddr(CSL_MCU_CTRL_MMR0_CFG0_BASE);
    kickAddr = baseAddr + (0x1008 + 0x4000 * (partition));
    REG32_WR(kickAddr, KICK0_UNLOCK_VAL); /* KICK 0 */
    kickAddr++;
    REG32_WR(kickAddr, KICK1_UNLOCK_VAL); /* KICK 1 */

    return;
}


} // namespace sitara

} // namespace pal

} // namespace bni_safe

} // namespace balluff
SitaraMcuIsolation.hpp.txt
/*
 * SitaraMcuIsolation.hpp
 *
 *  Created on: 26.11.2024
 *      Author: zhih
 */

#ifndef SITARAMCUISOLATION_HPP_
#define SITARAMCUISOLATION_HPP_

#include "CommonTypes.hpp"

namespace balluff
{
namespace bni_safe
{
namespace pal
{
namespace sitara
{

class SitaraMcuIsolation
{
  public:
    SitaraMcuIsolation();
    ~SitaraMcuIsolation();

  private:
    util::SafeReturn enableResetIsolation(uint32_t main2McuIsolation, uint32_t mcu2MainIsolation,
                                          uint32_t debugIsolationEnable);
    util::SafeReturn setPSCState(uint32_t moduleNum, uint32_t pscState);

    void controlModuleLockMMR(uint32_t partition);
    void controlModuleUnlockMMR(uint32_t partition);

    static uint32_t REG32_RD(uint32_t addr)
    {
        volatile uint32_t* const p = (volatile uint32_t*)addr;
        return (*p);
    }
    static void REG32_WR(uint32_t addr, uint32_t v)
    {
        volatile uint32_t* const p = (volatile uint32_t*)addr;
        *p = v;
        return;
    }

    static void REG32_FINS(uint32_t addr, uint32_t mask, uint32_t shift, uint32_t v)
    {
        uint32_t regVal = REG32_RD(addr);
        regVal = (regVal & ~(mask));
        regVal |= (v << shift) & mask;
        REG32_WR(addr, regVal);
        return;
    }

    static uint32_t REG32_FEXT(uint32_t addr, uint32_t mask, uint32_t shift)
    {
        uint32_t regVal = REG32_RD(addr);
        regVal = (regVal & mask) >> shift;
        return (regVal);
    }

    static constexpr uint32_t CSL_MCU_CTRL_MMR0_CFG0_BASE = 0x04500000U;
    static constexpr uint32_t CSL_MCU_CTRL_MMR_CFG0_MCU_MTOG_CTRL = 0x00004600U;
    static constexpr uint32_t CSL_MCU_CTRL_MMR_CFG0_RST_CTRL = 0x00018170U;
    static constexpr uint32_t CSL_MCU_CTRL_MMR_CFG0_RST_MAGIC_WORD = 0x0001817CU;
    static constexpr uint32_t CSL_MCU_CTRL_MMR_CFG0_ISO_CTRL = 0x00018180U;

    static constexpr uint32_t CSL_MCU_PSC0_BASE = 0x04000000U;
    static constexpr uint32_t CSL_MCU_PSC0_PTCMD = 0x00000120U;
    static constexpr uint32_t CSL_MCU_PSC0_PTSTAT = 0x00000128U;
    static constexpr uint32_t CSL_MCU_PSC0_PDCTL = 0x00000300U;
    static constexpr uint32_t CSL_MCU_PSC0_MDSTAT = 0x0000080CU;
    static constexpr uint32_t CSL_MCU_PSC0_MDCTL = 0x00000A00U;


    static constexpr uint32_t SOC_PSC_SYNCRESETDISABLE = 0x0U;
    static constexpr uint32_t SOC_PSC_SYNCRESET = 0x1U;
    static constexpr uint32_t SOC_PSC_DISABLE = 0x2U;
    static constexpr uint32_t SOC_PSC_ENABLE = 0x3U;

    /*
     *  MCU LPSC
     */
    static constexpr uint32_t CSL_MCU_LPSC_MAIN2MCU = 0x3U;
    static constexpr uint32_t CSL_MCU_LPSC_MCU2MAIN = 0x4U;


    /* PSC (Power Sleep Controller) timeout */
    static constexpr uint32_t PSC_TIMEOUT = 1000U;

    /* PSC (Power Sleep Controller) Domain enable */
    static constexpr uint32_t PSC_MODSTATE_ENABLE = 0x3U;

    /* define the unlock and lock values */
    static constexpr uint32_t KICK_LOCK_VAL = 0x00000000U;
    static constexpr uint32_t KICK0_UNLOCK_VAL = 0x68EF3490U;
    static constexpr uint32_t KICK1_UNLOCK_VAL = 0xD172BC5AU;
};

} // namespace sitara

} // namespace pal

} // namespace bni_safe

} // namespace balluff

#endif /* SITARAMCUISOLATION_HPP_ */

Best Regards

Haining Zhi

  • Hello Haining Zhi,

    I am looking at your queries and you may expect reply by EOD.

    Regards,

    Anil.

  • Hello Haining Zhi,

    I try to integrate the code into out project in C++ and try to access GPIO pin from Main domain. It seems that the Isolation does not work. The GPIO can still be toggled.

    With the above code, you can be able to access the MAIN domain peripherals from the MCU domain.

    And, you can't access the MCU domain peripheral from the MAIN domain.

    Please confirm which is the GPIO pin (MCU or MAIN ) you are toggling  ?

    Actually, if you isolate MCU core from the MAIN domain, then you are not supposed to use MAIN domain peripheral's  in the MCU domain and MCU domain peripherals in the MAIN domain.

    You need to integrate the same application that is available in the MCU+SDK and exactly it meets your requirements.

    If you set the  below flags , then SOC can't access the cross domain access.

    If you disable them and set it to 0, then SOC can access the cross domain access.

    pscMain2MCUDisable = 0;

    pscMCU2MainDisable = 0;

    Our goal is to make sure that Main domain should not access the peripherals of MCU domain.

    If above one is your requirement , then set the flags below .

    pscMain2MCUDisable = 1;

    pscMCU2MainDisable = 1;

    Regards,

    Anil.

  • Hello Anil,

    Please confirm which is the GPIO pin (MCU or MAIN ) you are toggling  ?

    The MCU_GPIO0_16 is toggled from R5F. It is connected to the LED on our board. The LED is still blinking, when pscMain2MCUDisable = 1;

    Best Regards

    Haining Zhi

  • Hello Haining Zhi,

    Can you please try the flags below and see whether you are able to control MCU GPIO from the MAIN domain or not ?

    pscMain2MCUDisable = 1;

    pscMCU2MainDisable = 1;

    The MCU_GPIO0_16 is toggled from R5F. It is connected to the LED on our board. The LED is still blinking, when pscMain2MCUDisable = 1;

    Even with the above settings, you are not supposed to access the MCU GPIO from R5F core .

    Please share your test procedure. As how you loaded M4F /R5F examples from CCS ?

    Regards,

    Anil. 

  • Hello Anil,

    it is the same with the both flags set to 1.

    Regards

    Haining

  • Hello Anil,

    I've also tried with TI-SDK example directly. It works well.

    anther question: is there difference between CSL_REG32_FINS and CSL_FINS by their functionality? It is the only changes in the function SOC_setPSCState().

    Is there any critical point of time to call the function SOC_enableResetIsolation()? Or it can be called anytime after startup?

    Regards

    Haining

  • Hello Haining,

    anther question: is there difference between CSL_REG32_FINS and CSL_FINS by their functionality? It is the only changes in the function SOC_setPSCState().

    Functionality wise, there is no difference and both are the same.

    But use the CSL_REG32_FINS macro because this macro is defined variable with volatile keyword.

    Is there any critical point of time to call the function SOC_enableResetIsolation()? Or it can be called anytime after startup?

    The good thing is that before the M4F core application runs, you can call the SOC_enableResetIsolation after all drivers init in M4F core.

    Regards,

    Anil.

  • Hello Antil,

    is it only needed to call the function of SOC_enableResetIsolation() for blocking the main2mcu isolation? Is there any other setup must be done?

    Regards

    Haining

  • Hello Haining,

    As I mentioned above, the MAIN2MCU PSC and MCU2MAIN PSC are disabled, then cross domain functionality does not work out.

    These changes are available in the SOC_enableResetIsolation API and other than this we are not doing changes in anywhere.

    If you integrate SOC_enableResetIsolation and resetReqIsr API's in your application, all Reset Isolation changes were taken and user no need to take any other changes.

    One more thing in the SBL we need to check the M4F core is Isolated or not if it is Isolated then we are not supposed to re init the M4F core clock configurations for every WarmReset. This is already taken care in SBL. So,  again users don't need to consider any other steps.

    Regards,
    Anil.

  • Hi,

    I'm not sure if I have understood this line right. What does the macro call of CSL_FEXTR here? To read the content of certain bits of the register? Or simply check the address of register? Because the "reg" is the address itself.

    pdTransStatus = CSL_FEXTR( baseAddr + CSL_PSC_PTSTAT(pwrDmnGrp), \
                                    pwrDmnNumInGrp, pwrDmnNumInGrp );

    /* the Field EXTract (Raw) macro */
    #define CSL_FEXTR(reg, msb, lsb)                                            \
        (((reg) >> (lsb)) & ((((uint32_t)1U) << ((msb) - (lsb) + ((uint32_t)1U))) - ((uint32_t)1U)))

    Regards

    Haining

  • Hello Haining,

    Yes, you are correct. We need to be supposed to pass an address content when we call the above API.

    Like as below,

    pdTransStatus = CSL_FEXTR(

    (*(volatile uint32_t *) ( baseAddr + CSL_PSC_PTSTAT(pwrDmnGrp) ) ), \

                                    pwrDmnNumInGrp, pwrDmnNumInGrp );

    please let me know if you face any problems with this MACRO ?

    I really wonder how we did not see any issues if we are using the same MACRO in the MCU+SDK.

    Regards,

    Anil.

  • Hello Anil,

    it was in the function SOC_setPSCState in the file ./source/drivers/soc/am64x_am243x/soc.c

    I don't know whether is also in the current version. Perhaps I'm using an old version of 9.0.0. But it make no problem for me.

    Regards

    Haining

  • Hello Haining,

    The above one is a bug only, and you don't get any failures, since when we are passing the address values to the macro, then every time you get a return value is 0. Please use the above suggestion method and internally I will raise the bug to fix this issue.

    Regards,

    Anil.