J721EXSOMXEVM: Using LPM Demo PMIC Functions in IPC Demo

Part Number: J721EXSOMXEVM

Tool/software:

My goal is to use the MCU to turn off the MAIN domain power. I do not need to turn MAIN back on, only off. I also have a requirement of using the generic U-Boot development boot flow. I cannot use the BootApp tertiary boot flow. This is why I didn't try using the LPM demo (which requires the BootApp boot flow) and tried using another demo instead.

I tried using the IPC demo FreeRTOS on the MCU1_0 as a starting point and then tried modifying it to call the necessary PMIC functions from the LPM demo. I have pasted the code for my modified demo. I had to make some makefile changes as well as some other minor modifications to be able to include and link the necessary functions.

My code change is extremely simple. All I did was create a new RTOS task and call the following functions:

Lpm_pmicInit();
Lpm_vtmMaxOutrgAlertDisableForTmpSens1to4();
Lpm_activeToMcuSwitch();

Here is my full code:

/*
 *  Copyright (c) Texas Instruments Incorporated 2018-2023
 *  All rights reserved.
 *
 *  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.
 */

/**
 *  \file main_tirtos.c
 *
 *  \brief Main file for TI-RTOS build
 */

/* ========================================================================== */
/*                             Include Files                                  */
/* ========================================================================== */

#include <stdio.h>
#include <stdint.h>
#include <string.h>

#include <ti/drv/ipc/examples/common/src/ipc_setup.h>

#include <ti/osal/osal.h>
#include <ti/osal/TaskP.h>

#include "ipc_utils.h"
#include <ti/csl/csl_types.h>
#if defined (BUILD_C7X)
#include <ti/csl/soc.h>
#include <ti/csl/csl_clec.h>
#include <ti/csl/arch/csl_arch.h>

#include <ti/osal/soc/osal_soc.h>

#if (defined (FREERTOS))
#include "Hwi.h"
#include "Mmu.h"
#elif (defined (SAFERTOS))
#include "Mmu.h"
#endif
#endif

#include <ti/drv/sciclient/sciclient.h>
#include <ti/board/board.h>

#if (defined (BUILD_MCU1_0) && (defined (SOC_J721E) || defined (SOC_J7200) || defined (SOC_J721S2) || defined (SOC_J784S4)))
#include <ti/drv/sciclient/src/sciclient/sciclient_priv.h>
#include <ti/drv/sciclient/sciserver_tirtos.h>
#endif

/* This needs to be enabled only for negative test cases */
#ifdef IPC_NEGATIVE_TEST
#include <ti/drv/ipc/examples/rtos/ipc_negative_test/ipc_neg_setup.h>
#endif

/* This needs to be enabled only for extended test cases */
#ifdef IPC_EXTENDED_TEST
#include <ti/drv/ipc/examples/rtos/ipc_extended_test.h>
#endif

// new 11/8
// #include <ti/drv/lpm/lpm.h>
#include <ti/drv/lpm/include/lpm_pmic.h>


/* ========================================================================== */
/*                           Macros & Typedefs                                */
/* ========================================================================== */

#define APP_TSK_STACK_MAIN              (32U * 1024U)
/**< Test application stack size */

#if (defined (BUILD_MCU1_0) && (defined (SOC_J721E) || defined (SOC_J7200) || defined (SOC_J721S2) || defined (SOC_J784S4)))
/**< SCI Server Init Task stack size */
#define APP_SCISERVER_INIT_TSK_STACK        (32U * 1024U)
/* SCI Server Init Task Priority - must be higher than High priority Sciserver task */
#define IPC_INIT_SCISERVER_TASK_PRI         (6)
#endif

/* High Priority for SCI Server - must be higher than Low priority task */
#define IPC_SETUP_SCISERVER_TASK_PRI_HIGH   (5)
/*
 * Low Priority for SCI Server - must be higher than IPC echo test tasks
 * to prevent delay in handling Sciserver requests when test is performing
 * multicore ping/pong.
 */
#define IPC_SETUP_SCISERVER_TASK_PRI_LOW    (4)

// new 11/8
#define TEST_SHUTDOWN_TASK_PRIORITY         (3)
#define TEST_SHUTDOWN_STACK_SIZE            (64U * 1024U)

/* ========================================================================== */
/*                         Structure Declarations                             */
/* ========================================================================== */

/* None */

/* ========================================================================== */
/*                          Function Declarations                             */
/* ========================================================================== */

static void taskFxn(void* a0, void* a1);
// new 11/8
static void TestShutdown(void *arg0, void *arg1);
volatile uint8_t sci_init_done = false;


#if (defined (BUILD_MCU1_0) && (defined (SOC_J721E) || defined (SOC_J7200) || defined (SOC_J721S2) || defined (SOC_J784S4)))
void Ipc_setupSciServer(void *arg0, void *arg1);
/**< Initialize SCI Server, to process RM/PM Requests by other cores */
#endif

/* ========================================================================== */
/*                            Global Variables                                */
/* ========================================================================== */

/* Test application stack */
/* For SafeRTOS on R5F with FFI Support, task stack should be aligned to the stack size */
#if defined(SAFERTOS) && defined (BUILD_MCU)
static uint8_t  gAppTskStackMain[APP_TSK_STACK_MAIN]
__attribute__ ((aligned(APP_TSK_STACK_MAIN)));
#else
static uint8_t  gAppTskStackMain[APP_TSK_STACK_MAIN]
__attribute__ ((aligned(8192)));
#endif

/* Variable to check if ipc_boardInit has completed or not*/
uint8_t  gBoardinit=0;

#if (defined (BUILD_MCU1_0) && (defined (SOC_J721E) || defined (SOC_J7200) || defined (SOC_J721S2) || defined (SOC_J784S4)))
/* Sciserver Init TAsk stack */
#if defined(SAFERTOS)
static uint8_t  gSciserverInitTskStack[APP_SCISERVER_INIT_TSK_STACK]
__attribute__ ((aligned(APP_SCISERVER_INIT_TSK_STACK)));
#else
static uint8_t  gSciserverInitTskStack[APP_SCISERVER_INIT_TSK_STACK]
__attribute__ ((aligned(8192)));
#endif
extern Sciclient_ServiceHandle_t gSciclientHandle;
#endif

// new 11/8
static uint8_t gTestShutdownStack[TEST_SHUTDOWN_STACK_SIZE] __attribute__((aligned(32)));

/* ========================================================================== */
/*                          Function Definitions                              */
/* ========================================================================== */


void ipc_initSciclient()
{
    int32_t ret = CSL_PASS;
    Sciclient_ConfigPrms_t        config;

    /* Now reinitialize it as default parameter */
    ret = Sciclient_configPrmsInit(&config);
    if (ret != CSL_PASS)
    {
        App_printf("Sciclient_configPrmsInit Failed\n");
    }

#if (defined (BUILD_MCU1_0) && (defined (SOC_J721E) || defined (SOC_J7200) || defined (SOC_J721S2) || defined (SOC_J784S4)))
    if (ret == CSL_PASS)
    {
        ret = Sciclient_boardCfgParseHeader(
            (uint8_t *)SCISERVER_COMMON_X509_HEADER_ADDR,
            &config.inPmPrms, &config.inRmPrms);
        if (ret != CSL_PASS)
        {
            App_printf("Sciclient_boardCfgParseHeader Failed\n");
        }
    }
#endif

    if (ret == CSL_PASS)
    {
        ret = Sciclient_init(&config);
        if (ret != CSL_PASS)
        {
            App_printf("Sciclient_init Failed\n");
        }
#if (defined (BUILD_MCU1_0) && (defined (SOC_J721E) || defined (SOC_J7200) || defined (SOC_J721S2) || defined (SOC_J784S4)))
        if (gSciclientHandle.rmBoardConfigComplete == SCICLIENT_FT_PASS)
        {
            App_printf("Sciclient_boardCfgRm init Passed\n");
        }
        else
        {
            App_printf("Sciclient_boardCfgRm init FAILED!\n");
        }
#endif
    }
}

void ipc_boardInit()
{
    Board_initCfg           boardCfg;

    boardCfg = BOARD_INIT_UART_STDIO;
#if defined(A72_LINUX_OS)
    /* Configure UART TX pinmux only. Linux doesn't support full pinmux config */
    Board_uartTxPinmuxConfig();
#else
    boardCfg |= BOARD_INIT_PINMUX_CONFIG;
#endif

    Board_init(boardCfg);

    /* Mark Board_init() has been called */
    gBoardinit = 1;
}

int main(void)
{
    TaskP_Handle task;
    TaskP_Params taskParams;



#if defined ECHO_TEST_BTCM && defined FREERTOS && defined BUILD_MCU
    /* Relocate FreeRTOS Reset Vectors from BTCM*/
    void _freertosresetvectors (void);
    memcpy((void *)0x0, (void *)_freertosresetvectors, 0x40);
#endif

#if defined ECHO_TEST_BTCM && defined SAFERTOS && defined BUILD_MCU
    /* Relocate FreeRTOS Reset Vectors from BTCM*/
    void _axSafeRTOSresetVectors (void);
    memcpy((void *)0x0, (void *)_axSafeRTOSresetVectors, 0x40);
#endif

    /*  This should be called before any other OS calls (like Task creation, OS_start, etc..) */
    OS_init();

    /* Initialize the task params */
    TaskP_Params_init(&taskParams);
    /* Set the task priority higher than the default priority (1) */
    taskParams.priority = 2;
    taskParams.stack        = gAppTskStackMain;
    taskParams.stacksize    = sizeof (gAppTskStackMain);

    task = TaskP_create(&taskFxn, &taskParams);
    if(NULL == task)
    {
        OS_stop();
    }

    // new 11/8
    /* Configure and create the TestShutdown task */
    TaskP_Params_init(&taskParams);
    taskParams.priority = TEST_SHUTDOWN_TASK_PRIORITY;
    taskParams.stack = gTestShutdownStack;
    taskParams.stacksize = sizeof (gTestShutdownStack);

    task = TaskP_create(&TestShutdown, &taskParams);
    if(NULL == task)
    {
        OS_stop();
    }

    OS_start();    /* does not return */

    return(0);
}

static void taskFxn(void* a0, void* a1)
{

    /* Initialize SCI Client - It must be called before board init */
    ipc_initSciclient();
    /* IPC Board Init should be done only for MCU1_0 for Linux,
     * unconditionally for RTOS
     */
#if defined(A72_LINUX_OS) && defined(BUILD_MCU1_0)
    ipc_boardInit();
#elif !defined(A72_LINUX_OS)
    ipc_boardInit();
#endif

#if (defined (BUILD_MCU1_0) && (defined (SOC_J721E) || defined (SOC_J7200) || defined (SOC_J721S2) || defined (SOC_J784S4)))
    TaskP_Handle sciserverInitTask;
    TaskP_Params sciserverInitTaskParams;

    /* Initialize SCI Client Server */
    TaskP_Params_init(&sciserverInitTaskParams);
    sciserverInitTaskParams.priority     = IPC_INIT_SCISERVER_TASK_PRI;
    sciserverInitTaskParams.stack        = gSciserverInitTskStack;
    sciserverInitTaskParams.stacksize    = sizeof (gSciserverInitTskStack);

    sciserverInitTask = TaskP_create(&Ipc_setupSciServer, &sciserverInitTaskParams);
    if(NULL == sciserverInitTask)
    {
        OS_stop();
    }
#endif

#if defined (_TMS320C6X)
#if defined (FREERTOS) || defined (SAFERTOS)
    ipc_cacheMarInit();
#endif
#endif

#if defined IPC_NEGATIVE_TEST
    Ipc_echo_neg_test();
#elif IPC_EXTENDED_TEST
    IpcApp_echoExtTest();
#else
    Ipc_echo_test();
#endif

    // TaskP_Handle task;
    // TaskP_Params taskParams;
    // /* Configure and create the TestShutdown task */
    // TaskP_Params_init(&taskParams);
    // taskParams.priority = TEST_SHUTDOWN_TASK_PRIORITY;
    // taskParams.stack = gTestShutdownStack;
    // taskParams.stacksize = sizeof (gTestShutdownStack);

    // task = TaskP_create(&TestShutdown, &taskParams);
    // if(NULL == task)
    // {
    //     OS_stop();
    // }

}

#if defined(BUILD_C7X)
void InitMmu(void)
{
    IpcInitMmu(FALSE);
    IpcInitMmu(TRUE);
    OsalCfgClecAccessCtrl(false);

}
#endif

#if defined(BUILD_MPU)
extern void Osal_initMmuDefault(void);
void InitMmu(void)
{
    Osal_initMmuDefault();
}
#endif

#if (defined (BUILD_MCU1_0) && (defined (SOC_J721E) || defined (SOC_J7200) || defined (SOC_J721S2) || defined (SOC_J784S4)))
void Ipc_setupSciServer(void *arg0, void *arg1)
{

    Sciserver_TirtosCfgPrms_t appPrms;
    int32_t ret = CSL_PASS;
    char *version_str = NULL;
    char *rmpmhal_version_str = NULL;

    ret = Sciserver_tirtosInitPrms_Init(&appPrms);

    appPrms.taskPriority[SCISERVER_TASK_USER_LO] =
                                            IPC_SETUP_SCISERVER_TASK_PRI_LOW;
    appPrms.taskPriority[SCISERVER_TASK_USER_HI] =
                                            IPC_SETUP_SCISERVER_TASK_PRI_HIGH;

    if (ret == CSL_PASS)
    {
        ret = Sciserver_tirtosInit(&appPrms);
    }

    version_str = Sciserver_getVersionStr();
    rmpmhal_version_str = Sciserver_getRmPmHalVersionStr();
    App_printf("DM Built On: %s %s\n", __DATE__, __TIME__);
    // new
    App_printf("Amazon Test");
    App_printf("Sciserver Version: %s\n", version_str);
    App_printf("RM_PM_HAL Version: %s\n", rmpmhal_version_str);

    if (ret == CSL_PASS)
    {
        App_printf("Starting Sciserver..... PASSED\n");
    }
    else
    {
        App_printf("Starting Sciserver..... FAILED\n");
    }

    // TODO: added
    sci_init_done = true;

    return;
}
#endif

// new 11/8
void TestShutdown(void *arg0, void *arg1)
{
    while(!sci_init_done) {
        // do nothing
        TaskP_sleep(10); 
    }
    //TaskP_sleep(10000); 


    Lpm_pmicInit();
    App_printf("PMIC Init done.\n");

    uint32_t status = 0;

    /* Before entering MCU_ONLY mode we need to disable all VTM temp sensors in
       the MAIN domain - VTM_TMPSENS1-4 */
    /* Disabling the VTM MAXT_OUTRG_ALERT_THR */
    Lpm_vtmMaxOutrgAlertDisableForTmpSens1to4();
    App_printf("Temp sensors disabled.\n");
    TaskP_sleepInMsecs(1000);

    /* Change state from ACTIVE to MCU ONLY */
    if (0 == status)
    {
         App_printf("ACTIVE -> MCU ONLY MODE\n");
         /* The status is dummy currently */
         status = Lpm_activeToMcuSwitch();
         App_printf("ACTIVE -> MCU ONLY MODE DONE\n");
     }
     else
     {
         App_printf(">> ERROR :: Status not correct!!!\n");
     }

     App_printf("STATE INFO :: NOW IN MCU ONLY MODE!\n");

}

I thought that this would be enough to get it to work but the code does not function as expected. It runs as expected until Lpm_activeToMcuSwitch() and then it hangs at that function call. I tried to look into it and it seems that it's hanging on a specific I2C command inside lpm_pmic.c

    /* Clear INT_STARTUP */
    dataToSlave[0] = 0x65;
    dataToSlave[1] = 0x02;
    Lpm_setupI2CTransfer(gLpmPmicI2cHandle, 0x48, dataToSlave, 2, NULL, 0);

Is it possible to run these LPM demo commands from the IPC demo? Thank you.

  • Hi,

    My goal is to use the MCU to turn off the MAIN domain power. I do not need to turn MAIN back on, only off

    Please find the attached API for turning off  Main Core, let us know if this helps.

    Board_moduleClockDisable(TISCI_DEV_A72SS0_CORE0); // Power off A72_0 CORE by disabling its clock
    Board_moduleClockDisable(TISCI_DEV_R5FSS0_CORE0); // Power off MCU2_0 CORE by disabling its clock
    

    Regards,

    Karthik

  • Thanks for this idea. I should add that the reason I'm trying to turn off the MAIN domain is because I'm trying to save power and only have the MCU on. I tried the commands you provided but I don't see the current draw decrease.

    But since I need U-Boot I need to stick with generic demos and not use the LPM demo (MCU Only mode) because that does not support U-Boot. I tried using the PMIC commands taken from the LPM demo to use in the IPC demo (as a simple demo starting point). Trying this hangs here in Lpm_pmicStateChangeActiveToMCUOnly():

     /* Clear INT_STARTUP */
        dataToSlave[0] = 0x65;
        dataToSlave[1] = 0x02;
        Lpm_setupI2CTransfer(gLpmPmicI2cHandle, 0x48, dataToSlave, 2, NULL, 0);
        /*AppUtils_PrintfAppUtils_Printf(MSG_NORMAL, MSG_APP_NAME "Write INT_STARTUP = 0x%x\n", dataToSlave[1]);*/
        App_printf("Write INT_STARTUP = 0x%x\n", dataToSlave[1]);

    We think it might be due to the fact that the IPC demo executes from DDR and the PMIC commands might be turning off DDR, therefore halting execution. Do you have any other suggestions for how to get this to work or how to decrease the power of the MAIN domain?

    I also tried just running the shutdown and poweroff command on Linux but unfortunately this also stopped execution of the MCU. We believe this effect is also due to the shutdown command turning off DDR where the MCU is executing from. Thanks!

  • Hi,

    Thanks for this idea. I should add that the reason I'm trying to turn off the MAIN domain is because I'm trying to save power and only have the MCU on. I tried the commands you provided but I don't see the current draw decrease.

    Please provide more details on the procedure you use to determine  the main core current does not decrease.

    But since I need U-Boot I need to stick with generic demos and not use the LPM demo (MCU Only mode) because that does not support U-Boot. I tried using the PMIC commands taken from the LPM demo to use in the IPC demo (as a simple demo starting point). Trying this hangs here in Lpm_pmicStateChangeActiveToMCUOnly():

    Could you please refer this thread https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1427180/j721exsomxevm-pdk-low-power-manager-demo-linux-boot-errors let us know if this helps.

    Regards,

    Karthik

  • My power supply that I'm using to power the board shows the current draw. The current draw is the same before and after running the function that stops the A72 clocks (I tried stopping both A72 clocks).

    You have referred me to my previous post :)