Can POWER_ENABLE_MOCI be deasserted upon request on iMX8QM?

I would like to deassert POWER_ENABLE_MOCI before going into sleep mode on my apalis iMX8QM to save additional power on my custom board. Is this possible? Would it require a PMIC firmware change?

On a future board-spin, I can use a GPIO and gate the peripheral power lines externally to the SOM, but I have existing boards in the field where this is not possible.

Is there anyway to turn off the peripheral power rails during sleep-mode?

The POWER_ENABLE_MOCI signal directly controlled by LDO3 output of PG8100 on board PIMIC. And yes, you have to modify System Controller Firmware.

I tried modifying the the board_lpm function in my SCFW board.c file (see “NEW” comments and PF8100_LDO3 references below), but this did not seem to have an affect on the current consumption. I tried setting the LDO3 mode to RUN_OFF_STBY_OFF and RUN_OFF_STBY_EN. I will add print statements and use the SCFW UART to see if this code is actually running. Any advice or input?

/*--------------------------------------------------------------------------*/
/* Set board power supplies when enter/exit low-power mode                  */
/*--------------------------------------------------------------------------*/
void board_lpm(sc_pm_power_mode_t mode)
{
    static uint32_t vdd_memc_mode = 0U;

    always_print("NEW: board_lpm\n");

    if (mode == SC_PM_PW_MODE_STBY)
    {
        /*
         * System standby (KS1) entry allows VDD_MEMC to be gated off.
         * Save current mode and switch off supply.
         */
        if (PMIC_GET_MODE(PMIC_1_ADDR, PF8100_SW5, &vdd_memc_mode)
            == SC_ERR_NONE)
        {
            (void) PMIC_SET_MODE(PMIC_1_ADDR, PF8100_SW5, SW_STBY_OFF
                | SW_RUN_OFF);
        }

        /* Turn off the peripheral power-rails when entering standby (controlled by PMIC LDO3) */
        always_print("NEW: turn off PF8100_LDO3\n");
        (void) PMIC_SET_MODE(PMIC_1_ADDR, PF8100_LDO3, RUN_OFF_STBY_EN);
    }
    else if (mode == SC_PM_PW_MODE_ON)
    {
        /* Turn on the peripheral power-rails when exiting standby (controlled by PMIC LDO3) */
        always_print("NEW: turn on PF8100_LDO3\n");
        (void) PMIC_SET_MODE(PMIC_1_ADDR, PF8100_LDO3, RUN_EN_STBY_OFF);

        /*
         * System standby (KS1) exit should switch on VDD_MEMC.  Restore
         * previous mode saved during KS1 entry.
         */
        if (vdd_memc_mode != 0U)
        {
            (void) PMIC_SET_MODE(PMIC_1_ADDR, PF8100_SW5, vdd_memc_mode);
        }
    }
    else
    {
        ; /* Intentional empty else */
    }
}

I connected the SCU-FW debug UART, and it doesn’t seem like the board_lpm function is running at all when I sleep/wake. None of my print statements are showing up in the debug-log.

This is what I run to sleep, which works, as there are significant power-savings:
echo deep > /sys/power/mem_sleep; echo mem > /sys/power/state

I was able to get my LDO3 set-mode commands to run upon entering/exiting sleep, but POWER_ENABLE_MOCI is staying at 3.3V, and I’m not seeing a reduction in power. I modified the board_trans_resource_power function in my SCUFW board.c file (see below).

/*--------------------------------------------------------------------------*/
/* Transition external board-level supply for board component               */
/*--------------------------------------------------------------------------*/
void board_trans_resource_power(sc_rm_idx_t idx, sc_rm_idx_t rsrc_idx,
    sc_pm_power_mode_t from_mode, sc_pm_power_mode_t to_mode)
{
    static uint32_t ldo3_mode = 0U;

    board_print(1, "board_trans_resource_power(%d, %s, %u, %u)\n", idx,
        rnames[rsrc_idx], from_mode, to_mode);

    /* Init PMIC */
    pmic_init();

    /* Process resource */
    if (pmic_ver.device_id != 0U)
    {
        sc_err_t err = SC_ERR_NONE;

        switch (idx)
        {
            case BRD_R_BOARD_R0 : /* Apalis ethernet PHY power rail */
                if (to_mode > SC_PM_PW_MODE_OFF)
                {
                    /* KSZ 9031 power-up sequence */
                    BRD_ERR(PMIC_SET_VOLTAGE(PMIC_0_ADDR, PF8100_LDO4,
                        3300, REG_RUN_MODE));
                    BRD_ERR(PMIC_SET_MODE(PMIC_0_ADDR, PF8100_LDO4,
                        RUN_EN_STBY_EN));

                    BRD_ERR(PMIC_SET_VOLTAGE(PMIC_1_ADDR, PF8100_SW7,
                        1200, REG_RUN_MODE));
                    BRD_ERR(PMIC_SET_MODE(PMIC_1_ADDR, PF8100_SW7,
                        RUN_EN_STBY_EN));
                }
                else
                {
                    /* KSZ 9031 power-down sequence */
                    BRD_ERR(PMIC_SET_MODE(PMIC_1_ADDR, PF8100_SW7,
                        RUN_OFF_STBY_OFF));

                    BRD_ERR(PMIC_SET_MODE(PMIC_0_ADDR, PF8100_LDO4,
                        RUN_OFF_STBY_OFF));
                }
                break;
            case BRD_R_BOARD_R1 : /* Apalis external RGMII interface in 3.3V */
                if (to_mode > SC_PM_PW_MODE_OFF)
                {
                    /*
                     * We set 5V here so the LDO1 runs in load switch (LS) mode
                     * so the output voltage follows exactly the input voltage
                     * that is the module supply voltage, 3.3V.
                     * This is needed because this LDO is fused to run in normal
                     * mode and not like PMIC_0_ADDR, PF8100_LDO4 in LS mode
                     */
                    BRD_ERR(PMIC_SET_VOLTAGE(PMIC_1_ADDR, PF8100_LDO1,
                        5000, REG_RUN_MODE));
                    BRD_ERR(PMIC_SET_MODE(PMIC_1_ADDR, PF8100_LDO1,
                        RUN_EN_STBY_EN));

                    /* Turn on the peripheral power-rails (controlled by PMIC LDO3) */
                    always_print("NEW: turn on PF8100_LDO3\n");
                    if (PMIC_GET_MODE(PMIC_1_ADDR, PF8100_LDO3, &ldo3_mode) == SC_ERR_NONE) {
                       always_print("ldo3_mode: 0x%x\n", ldo3_mode);
                    }
                    BRD_ERR(PMIC_SET_MODE(PMIC_1_ADDR, PF8100_LDO3, RUN_EN_STBY_EN));
                    if (PMIC_GET_MODE(PMIC_1_ADDR, PF8100_LDO3, &ldo3_mode) == SC_ERR_NONE) {
                       always_print("ldo3_mode: 0x%x\n", ldo3_mode);
                    }
                }
                else
                {
                    /* Turn off the peripheral power-rails when entering sleep (controlled by PMIC LDO3) */
                    if (to_mode == SC_PM_PW_MODE_OFF) {
                       always_print("NEW: turn off PF8100_LDO3\n");
                       if (PMIC_GET_MODE(PMIC_1_ADDR, PF8100_LDO3, &ldo3_mode) == SC_ERR_NONE) {
                          always_print("ldo3_mode: 0x%x\n", ldo3_mode);
                       }
                       BRD_ERR(PMIC_SET_MODE(PMIC_1_ADDR, PF8100_LDO3, RUN_OFF_STBY_OFF));
                       if (PMIC_GET_MODE(PMIC_1_ADDR, PF8100_LDO3, &ldo3_mode) == SC_ERR_NONE) {
                          always_print("ldo3_mode: 0x%x\n", ldo3_mode);
                       }
                    }

                    BRD_ERR(PMIC_SET_MODE(PMIC_1_ADDR, PF8100_LDO1,
                        RUN_OFF_STBY_OFF));
                }
                break;
            case BRD_R_BOARD_R2 : /* Apalis external RGMII interface in 1.8V */
                if (to_mode > SC_PM_PW_MODE_OFF)
                {
                    BRD_ERR(PMIC_SET_VOLTAGE(PMIC_1_ADDR, PF8100_LDO1,
                        1800, REG_RUN_MODE));
                    BRD_ERR(PMIC_SET_MODE(PMIC_1_ADDR, PF8100_LDO1,
                        RUN_EN_STBY_EN));
                }
                else
                {
                    BRD_ERR(PMIC_SET_MODE(PMIC_1_ADDR, PF8100_LDO1,
                        RUN_OFF_STBY_OFF));
                }
                break;
            case BRD_R_BOARD_R3 : /* Apalis external RGMII interface in 2.5V */
                if (to_mode > SC_PM_PW_MODE_OFF)
                {
                    BRD_ERR(PMIC_SET_VOLTAGE(PMIC_1_ADDR, PF8100_LDO1,
                        2500, REG_RUN_MODE));
                    BRD_ERR(PMIC_SET_MODE(PMIC_1_ADDR, PF8100_LDO1,
                        RUN_EN_STBY_EN));
                }
                else
                {
                    BRD_ERR(PMIC_SET_MODE(PMIC_1_ADDR, PF8100_LDO1,
                        RUN_OFF_STBY_OFF));
                }
                break;
            default :
                ; /* Intentional empty default */
                break;
        }
    }
}

The PMIC_SET_MODE operation on LDO3 appears to work, as when I read it back the value has changed. Here is the output log from the SCU-FW debug uart going into and out-of sleep:

board_trans_resource_power(4, BOARD_R1, 3, 0)
NEW: turn off PF8100_LDO3
ldo3_mode: 0x3
ldo3_mode: 0x0
ipc_err: bad service (1)
ipc_err: bad service (1)
ipc_err: bad service (1)
board_trans_resource_power(4, BOARD_R1, 0, 3)
NEW: turn on PF8100_LDO3
ldo3_mode: 0x0
ldo3_mode: 0x3

@alex.tx, can you confirm that it’s LDO3 that controls POWER_ENABLE_MOCI on Aplalis iMX8QuadMax SOMs? I tried setting LDO3 to all four modes (RUN_OFF_STBY_OFF, RUN_OFF_STBY_EN, RUN_EN_STBY_OFF, & RUN_EN_STBY_EN), but the voltage that I measure on the output of the SOM for POWER_ENABLE_MOCI is always 3.3V. Check my SCU-FW in the post above to see if I’m doing something wrong.

Also, I believe the PMIC for the iMX8QuadMax is the PF8100, not the PG8100.

Thanks,
Derek

@alex.tx, one more update. If I use the get_voltage function, I see that LDO3 is configured to 3.3V for both REG_RUN_MODE and REG_STBY_MODE. I’m confused between the these two modes from get_voltage (REG_RUN_MODE, REG_STBY_MODE) and the four ldo_mode_t modes (RUN_OFF_STBY_OFF, RUN_OFF_STBY_EN, RUN_EN_STBY_OFF, & RUN_EN_STBY_EN).

Yes, it was a typo. Please read PF8100
Yes , the POWER_ENABLE_MOCI signal is directly controlled by LDO3 output of PG8100 on board PIMIC. Please check a schematic snippets below:

I am in touch with a contact at NXP, and they want to be sure that my device is actually entering KS1 power-savings mode. They asked me to measure these voltages (see below). Are any of these exposed on the Toradex Apalis iMXQM SOM that I can probe?

VCC_MAIN
VCC_CPU1
VCC_CPU0
VCC_DDRIO0
VCC_1V8
VCC_GPU0
VCC_GPU1
VCC_MEMC
VCC_DDRIO1
VCC_3V3

vdd_main tp14, tp28
VDD_cpu1 tp16, tp29
vdd_cpu0 tp15, tp30
vdd_ddr0 TP13, TP31
vdd_gpu0 TP33
VDD_GPU1 TP34
VDD_MEMC TP12, TP35
VDD_ddr1 TP11, TP36

There are several 1.8V rails like +V1.8_SCU, +V1.8_SNVS etc. Which one you are looking for?

+V1.8_SNVS

Here are measurements that I made with the device in normal operating mode (see image below). I could not find TP35 (VCC_MEMC) in the diagram, unless it is the test-point in the upper-right corner, which I couldn’t quite read (can you clarify this?). Also, I measured TP40 & TP26, but I don’t know what those correspond to. Any additional clarification is appreciated!

+V1.8_SNVS - has no test points on Apalis iMX8 module

TP40 is BT_WKUP_HOST
TP35 is POWER_ENABLE_MOCI