lowRISC / opentitan

OpenTitan: Open source silicon root of trust
https://www.opentitan.org
Apache License 2.0
2.5k stars 745 forks source link

[prodc-integration] Normal Sleep Power Consumption High #22241

Open jettr opened 5 months ago

jettr commented 5 months ago

Description

We are noticing that the power draw while the chip is in normal sleep is around 13mW (3.95mA @ 3.3V). We are hoping to target the 6 - 8 mW range or better for normal sleep.

By normal sleep, I mean a sleep that retains SRAM contents and will wake up and start executing code from where it left off. Normal sleep is like a deeper WFI where there is no pending interrupt to process. We still want to wake up from normal sleep in a reasonable amount of time to handle incoming TPM communication from the AP (either on I2C or SPI bus).

What we are doing for normal sleep:

What else can we try to get the power consumption of normal sleep down to the 6-8 mW range or better?


For another data point: "deep sleep," i.e. sleep that must resume execution from ROM/ROM_EXT, power consumption looks good. It is around 600uW (0.20mA @ 3.33V).

johngt commented 5 months ago

@andreaskurth / @vogelpi - for power utilisation discussions

andreaskurth commented 5 months ago

Potentially related: https://github.com/lowRISC/opentitan/issues/22223

moidx commented 5 months ago

AI @jettr to disable entropy complex and measure power consumption to triage #22223. See reference: https://github.com/lowRISC/opentitan/blob/603430849d683ad52a5001fda5d81bbfaa437505/sw/device/lib/testing/entropy_testutils.c#L214.

This will turn off the TRNG request interface and should yield lower power consumption numbers.

vogelpi commented 5 months ago

When becoming active again, you should be able to just switch the MODULE_ENABLE fields in the main control registers of the EDNs, CSRNG and ENTROPY_SRC back on and don't need to undergo the full reconfiguration process. Currently, we don't provide a function in the testutils for that though.

In terms of latency, re-enabling ENTROPY_SRC and the TRNG will mean to repeat the startup health tests again and fill up the entropy buffer. This will take in the order of 5 - 10ms. To be sure it should maybe be experimentally verified (I can provide instructions for that). While waiting for the ENTROPY_SRC / TRNG to become online again, the processor can still run. It's just that crypto accelerators requiring randomness may be stalled for a while.

jettr commented 5 months ago

Disabling the entropy complex did reduce power consumption in normal sleep! The power consumption drops to 9mW (2.71mA @ 3.3V). I didn't try re-enabling the entropy sources or do crypto in my tests.

I performed

EDN0.stop();
EDN1.stop();
csrng_stop();
entropy_src_stop();

before the normal sleep where those resolve to

    impl Edn {
        pub fn stop(&self) {
            self.register
                .ctrl
                .modify(CTRL::CMD_FIFO_RST.val(multibit::size_4bit::TRUE));
            self.register.ctrl.set(0x9999);
        }
    }

    pub unsafe fn csrng_stop() {
        StaticRef::new(CSRNG_BASE_ADDR as *const CsrngRegisters).ctrl.set(0x0999);
    }

    pub unsafe fn entropy_src_stop() {
        let register = StaticRef::new(ENTROPY_SRC_BASE_ADDR as *const EntropySrcRegisters);
        register.module_enable.set(0x9);
        register.entropy_control.set(0x99);
        register.conf.set(0x2649999);
        register.health_test_windows.set(0x600200);
        register.alert_threshold.set(0xfffd0002);
    }

This is good new and seems like something we can use. Is there any other IP block we can disable to get another 2 - 3 mW savings?

vogelpi commented 5 months ago

Thanks for the feedback @jettr ! This is good news. Could please try to only disable the ENTROPY_SRC, i.e., just do a entropy_src_stop()? My expectation would be that this alone should be sufficient to reach 9mA. If you use the function dif_entropy_src_set_enabled() instead of entropy_src_stop() you also re-enable the ENTROPY_SRC with the same settings in an attempt to resume. In contrast, the stop function clears some of the settings.

As for further things to try out: Reading the documentation of the register you referenced above. I would suggest to use the following:

Apart from that, you also have the option to disable individual clocks via clkmgr. However, I don't know how this interacts with above settings.

Another analog part you may want to disable is the ADC, see adc_en_ctl.

jettr commented 5 months ago

Could please try to only disable the ENTROPY_SRC, i.e., just do a entropy_src_stop()? My expectation would be that this alone should be sufficient to reach 9mW.

You are correct. It appears that the only entropy_src_stop() reduces the power consumption.

If you use the function dif_entropy_src_set_enabled() instead of entropy_src_stop() you also re-enable the ENTROPY_SRC with the same settings in an attempt to resume.

When I only use entropy_src_set_enabled and none of the other methods we have been experimenting with in the following way:

entropy_src_set_enabled(false);
rv32i::support::wfi();
entropy_src_set_enabled(true);

I actually get even lower normal sleep power: 8.8mW (2.66mA * 3.3V), but not by that much. This also seems like it is a better choice we as don't have to go through health checks etc again on normal sleep resume.

As for the PMU Control register: I am already using MAIN_PD_N as the only bit that is set when entering normal sleep. And if I remove even that, then the chips goes into deep sleep (which is desirable in different sleep scenarios).

Apart from that, you also have the option to disable individual clocks via clkmgr

We haven't done too much of that yet. That is something we will explore too. Thank you.

Another analog part you may want to disable is the ADC

We do need to ADC to be monitoring for a cable insertion during normal/deep sleep so we can't fully disable it, but I do hope that we can make full use of the lower power mode that it offers.

andreaskurth commented 4 months ago

Related to high entropy consumption

vogelpi commented 4 months ago

@jettr We've found out today that keymgr doesn't behave ideally in terms of entropy consumption (see https://github.com/lowRISC/opentitan/issues/22819). We're now discussing a hardware fix for that. In the meantime, and in particular for the engineering sample, software should set the reseed interval register to the maximum value. It's a 16-bit register, so the max reseed interval is something like 65535. It's not ideal but should already be much better than the default 256. You may want to try this out on the chip and re-measure power.

jettr commented 4 months ago

Thanks for the heads up! We will want to re-measure power for A1, but it should have this change.

andreaskurth commented 4 months ago

@jettr: With the relaxed keymgr reseed configuration, does the power consumption of ES match the expectation / requirements?

jettr commented 4 months ago

I saw a small power different when I set reseed interval register to 0xFFFF. The normal sleep current for this round of testing started at ~4.26mA and dropped to ~4.07mA with the change. Looks like only about 630uW of power savings.

vogelpi commented 4 months ago

Thanks @jettr for getting back with additional results. It's less than I expected but on the other hand, keymgr is still triggering a reseed (CSRNG operation) every 0.5ms with this new setting. I think there is not much more that can be done for ES on the entropy complex front.

jettr commented 4 months ago

That's okay, we will just need to re-measure power with the A1 silicon :)

andreaskurth commented 4 months ago

Disabling input for unused pins should help as well with reducing power consumption. That will be supported for most pins in A1

andreaskurth commented 3 months ago

@johngt Please add this to PROD SiVal

matutem commented 1 month ago

@jettr did you try disabling the various CONTROL.*CLK_EN?

jettr commented 4 weeks ago

@jettr did you try disabling the various CONTROL.*CLK_EN?

Yes, I performed all of this normal sleep testing with all of the CONTROL.*CLK_EN bits set to 0. The only enabled bits on the CONTROL register are CONTROL::LOW_POWER_HINT + CONTROL::MAIN_PD_N