mirror of
https://github.com/raspberrypi/pico-sdk.git
synced 2026-03-14 21:19:43 +01:00
Add skips of data_copy in arm crt0
This commit is contained in:
parent
d9cf06ba33
commit
42f33036bd
5 changed files with 196 additions and 16 deletions
|
|
@ -205,14 +205,13 @@ static inline bool pstate_bitset_none_set(pstate_bitset_t *domains) {
|
|||
return bitset_equal(&domains->bitset, &none.bitset);
|
||||
}
|
||||
|
||||
static inline pstate_bitset_t pstate_bitset_from_powman_power_state(powman_power_state pstate) {
|
||||
pstate_bitset_t bitset;
|
||||
bitset_init(&bitset, pstate_bitset_t, POWMAN_POWER_DOMAIN_COUNT, pstate);
|
||||
return bitset;
|
||||
static inline pstate_bitset_t *pstate_bitset_from_powman_power_state(pstate_bitset_t *domains, powman_power_state pstate) {
|
||||
bitset_write_word(&domains->bitset, 0, pstate);
|
||||
return domains;
|
||||
}
|
||||
|
||||
static inline powman_power_state pstate_bitset_to_powman_power_state(pstate_bitset_t *pstate) {
|
||||
return pstate->bitset.words[0];
|
||||
static inline powman_power_state pstate_bitset_to_powman_power_state(pstate_bitset_t *domains) {
|
||||
return bitset_read_word(&domains->bitset, 0);
|
||||
}
|
||||
|
||||
/*! \brief Get the current power state
|
||||
|
|
|
|||
|
|
@ -15,6 +15,10 @@
|
|||
#include "boot/picobin.h"
|
||||
#include "pico/bootrom.h"
|
||||
|
||||
#if !PICO_RP2040
|
||||
#include "hardware/regs/powman.h"
|
||||
#endif
|
||||
|
||||
// PICO_CONFIG: PICO_CRT0_NEAR_CALLS, Whether calls from crt0 into the binary are near (<16M away) - ignored for PICO_COPY_TO_RAM, default=0, type=bool, group=pico_crt0
|
||||
#ifndef PICO_CRT0_NEAR_CALLS
|
||||
#define PICO_CRT0_NEAR_CALLS 0
|
||||
|
|
@ -478,6 +482,11 @@ _call_xip_setup:
|
|||
// In a NO_FLASH binary, don't perform .data etc copy, since it's loaded
|
||||
// in-place by the SRAM load. Still need to clear .bss
|
||||
#if !PICO_NO_FLASH
|
||||
#if LIB_PICO_LOW_POWER && !PICO_RP2040
|
||||
// Load previous power state into r6
|
||||
ldr r6, =(POWMAN_BASE+POWMAN_SCRATCH6_OFFSET)
|
||||
ldr r6, [r6]
|
||||
#endif
|
||||
adr r4, data_cpy_table
|
||||
|
||||
// assume there is at least one entry
|
||||
|
|
@ -485,6 +494,11 @@ _call_xip_setup:
|
|||
ldmia r4!, {r1-r3}
|
||||
cmp r1, #0
|
||||
beq 2f
|
||||
#if LIB_PICO_LOW_POWER && !PICO_RP2040
|
||||
bl data_cpy_check
|
||||
cmp r0, #1
|
||||
beq 1b
|
||||
#endif
|
||||
bl data_cpy
|
||||
b 1b
|
||||
2:
|
||||
|
|
@ -530,6 +544,54 @@ data_cpy:
|
|||
cmp r2, r3
|
||||
blo data_cpy_loop
|
||||
bx lr
|
||||
|
||||
#if LIB_PICO_LOW_POWER && !PICO_RP2040
|
||||
data_cpy_check:
|
||||
// uses r5 and r7 as scratch
|
||||
// uses the powman_power_state in r6
|
||||
// returns in r0
|
||||
mov r0, #0
|
||||
// First check start of copy (r2)
|
||||
mov r7, r2
|
||||
check_r7:
|
||||
ldr r5, =(SRAM_BASE >> 16)
|
||||
cmp r5, r7, lsr #16
|
||||
bgt check_xip_sram
|
||||
ldr r5, =(SRAM4_BASE >> 16)
|
||||
cmp r5, r7, lsr #16
|
||||
bgt check_sram0
|
||||
b check_sram1
|
||||
check_xip_sram:
|
||||
mov r5, #(1 << 2) // POWMAN_POWER_DOMAIN_XIP_CACHE
|
||||
and r5, r6
|
||||
cmp r5, #(1 << 2)
|
||||
beq skip
|
||||
b noskip
|
||||
check_sram0:
|
||||
mov r5, #(1 << 1) // POWMAN_POWER_DOMAIN_SRAM_BANK0
|
||||
and r5, r6
|
||||
cmp r5, #(1 << 1)
|
||||
beq skip
|
||||
b noskip
|
||||
check_sram1:
|
||||
mov r5, #(1 << 0) // POWMAN_POWER_DOMAIN_SRAM_BANK1
|
||||
and r5, r6
|
||||
cmp r5, #(1 << 0)
|
||||
beq skip
|
||||
b noskip
|
||||
skip:
|
||||
cmp r0, #1
|
||||
bne check_end
|
||||
bx lr
|
||||
check_end:
|
||||
add r0, #1
|
||||
// If start was skipped, check end of copy
|
||||
mov r7, r3
|
||||
b check_r7
|
||||
noskip:
|
||||
mov r0, #0
|
||||
bx lr
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Note the data copy table is still included for NO_FLASH builds, even though
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ int low_power_pstate_until_pin_state(uint gpio_pin, bool edge, bool high, pstate
|
|||
// Go to a pstate
|
||||
// Doesn't support powering down switched core domain
|
||||
int low_power_pstate_set(pstate_bitset_t *pstate);
|
||||
pstate_bitset_t low_power_pstate_get(void);
|
||||
pstate_bitset_t *low_power_pstate_get(pstate_bitset_t *pstate);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
|||
|
|
@ -500,15 +500,17 @@ int low_power_pstate_set(pstate_bitset_t *pstate) {
|
|||
return powman_set_power_state(pstate_bitset_to_powman_power_state(pstate));
|
||||
}
|
||||
|
||||
pstate_bitset_t low_power_pstate_get(void) {
|
||||
return pstate_bitset_from_powman_power_state(powman_get_power_state());
|
||||
pstate_bitset_t *low_power_pstate_get(pstate_bitset_t *pstate) {
|
||||
pstate_bitset_from_powman_power_state(pstate, powman_get_power_state());
|
||||
return pstate;
|
||||
}
|
||||
|
||||
int low_power_go_pstate(pstate_bitset_t *pstate, low_power_pstate_resume_func resume_func) {
|
||||
prepare_for_pstate_change();
|
||||
|
||||
// Configure the wakeup state
|
||||
pstate_bitset_t current_pstate = low_power_pstate_get();
|
||||
pstate_bitset_t current_pstate = pstate_bitset_none();
|
||||
low_power_pstate_get(¤t_pstate);
|
||||
bool valid_state = powman_configure_wakeup_state(pstate_bitset_to_powman_power_state(pstate), pstate_bitset_to_powman_power_state(¤t_pstate));
|
||||
if (!valid_state) {
|
||||
return PICO_ERROR_INVALID_STATE;
|
||||
|
|
@ -556,7 +558,8 @@ void __weak runtime_init_low_power_reboot_check(void) {
|
|||
if (powman_hw->chip_reset & POWMAN_CHIP_RESET_HAD_SWCORE_PD_BITS) {
|
||||
// we came from powman reboot, so execute the resume function
|
||||
if (powman_hw->scratch[7]) {
|
||||
pstate_bitset_t pstate = pstate_bitset_from_powman_power_state(powman_hw->scratch[6]);
|
||||
pstate_bitset_t pstate = pstate_bitset_none();
|
||||
pstate_bitset_from_powman_power_state(&pstate, powman_hw->scratch[6]);
|
||||
((low_power_pstate_resume_func)powman_hw->scratch[7])(&pstate);
|
||||
// clear the scratch registers
|
||||
powman_hw->scratch[6] = 0;
|
||||
|
|
|
|||
|
|
@ -30,9 +30,13 @@ bool repeater(repeating_timer_t *timer) {
|
|||
static bool came_from_pstate = false;
|
||||
static char powman_last_pwrup[100];
|
||||
static char powman_last_pstate[100];
|
||||
static char powman_last_pstate_val[10];
|
||||
|
||||
void pstate_resume_func(pstate_bitset_t *pstate) {
|
||||
came_from_pstate = true;
|
||||
memset(powman_last_pwrup, 0, sizeof(powman_last_pwrup));
|
||||
memset(powman_last_pstate, 0, sizeof(powman_last_pstate));
|
||||
memset(powman_last_pstate_val, 0, sizeof(powman_last_pstate_val));
|
||||
switch (powman_hw->last_swcore_pwrup) {
|
||||
// 0 = chip reset, for the source of the last reset see
|
||||
case 1 << 0: strcpy(powman_last_pwrup, "Chip reset"); break;
|
||||
|
|
@ -50,6 +54,8 @@ void pstate_resume_func(pstate_bitset_t *pstate) {
|
|||
if (pstate_bitset_is_set(pstate, POWMAN_POWER_DOMAIN_SRAM_BANK1)) strcat(powman_last_pstate, "SRAM_BANK1, ");
|
||||
if (pstate_bitset_none_set(pstate)) strcat(powman_last_pstate, "NONE, ");
|
||||
}
|
||||
|
||||
static volatile int my_number = 12345;
|
||||
#endif
|
||||
|
||||
int main() {
|
||||
|
|
@ -73,7 +79,13 @@ int main() {
|
|||
|
||||
if (came_from_pstate) {
|
||||
printf("Came from powerup %s with (%s) memory kept on - skipping to end\n", powman_last_pwrup, powman_last_pstate);
|
||||
goto post_pstate_timer;
|
||||
if (strstr(powman_last_pstate, "SRAM_BANK0") != NULL) {
|
||||
goto post_pstate_sram0_on;
|
||||
} else if (strstr(powman_last_pstate, "SRAM_BANK1") != NULL) {
|
||||
goto post_pstate_sram1_on;
|
||||
} else {
|
||||
goto post_pstate_sram_off;
|
||||
}
|
||||
}
|
||||
|
||||
pstate_bitset_t pstate;
|
||||
|
|
@ -88,6 +100,9 @@ int main() {
|
|||
struct timespec ts;
|
||||
int ret;
|
||||
|
||||
|
||||
|
||||
// exclusive sleep
|
||||
printf("Going to sleep for %d seconds via TIMER\n", SLEEP_TIME_S);
|
||||
|
||||
start_time = get_absolute_time();
|
||||
|
|
@ -102,6 +117,9 @@ int main() {
|
|||
printf("Doing %d second pause to prove timer running\n", SLEEP_TIME_S);
|
||||
busy_wait_ms(SLEEP_TIME_MS);
|
||||
|
||||
|
||||
|
||||
// non-exclusive sleep
|
||||
printf("Going to non-exclusive sleep for %d seconds via TIMER\n", SLEEP_TIME_S);
|
||||
|
||||
start_time = get_absolute_time();
|
||||
|
|
@ -116,6 +134,9 @@ int main() {
|
|||
printf("Doing %d second pause to prove timer running\n", SLEEP_TIME_S);
|
||||
busy_wait_ms(SLEEP_TIME_MS);
|
||||
|
||||
|
||||
|
||||
// dormant
|
||||
printf("Going DORMANT for %d seconds via AON TIMER\n", SLEEP_TIME_S);
|
||||
|
||||
// todo, ah; we should start the aon timer; still have to decide what to do about keeping them in sync
|
||||
|
|
@ -146,8 +167,98 @@ int main() {
|
|||
printf("Doing %d second pause to prove timer running\n", SLEEP_TIME_S);
|
||||
busy_wait_ms(SLEEP_TIME_MS);
|
||||
|
||||
|
||||
|
||||
// powman states
|
||||
#if !PICO_RP2040
|
||||
printf("Going to PSTATE for %d seconds\n", SLEEP_TIME_S);
|
||||
// pstate with sram0 on
|
||||
printf("Going to PSTATE with SRAM0 on for %d seconds\n", SLEEP_TIME_S);
|
||||
|
||||
if (my_number != 12345) {
|
||||
printf("ERROR: my_number is %d not 12345 - initialisation issue?\n", my_number);
|
||||
return -1;
|
||||
}
|
||||
my_number = 67890;
|
||||
|
||||
start_time = aon_timer_get_absolute_time();
|
||||
|
||||
wakeup_time = delayed_by_ms(start_time, SLEEP_TIME_MS);
|
||||
powman_hw->scratch[0] = to_us_since_boot(wakeup_time) & 0xFFFFFFFF;
|
||||
powman_hw->scratch[1] = to_us_since_boot(wakeup_time) >> 32;
|
||||
pstate = pstate_bitset_none();
|
||||
pstate_bitset_add(&pstate, POWMAN_POWER_DOMAIN_SRAM_BANK0);
|
||||
printf("pstate: %08x\n", pstate_bitset_to_powman_power_state(&pstate));
|
||||
ret = low_power_pstate_until_aon_timer(wakeup_time, &pstate, pstate_resume_func);
|
||||
|
||||
printf("%d low_power_pstate_until_aon_timer returned\n", ret);
|
||||
while (true) {
|
||||
printf("Waiting\n");
|
||||
busy_wait_ms(1000);
|
||||
}
|
||||
|
||||
post_pstate_sram0_on:
|
||||
// restore from scratch
|
||||
wakeup_time = from_us_since_boot((uint64_t)powman_hw->scratch[1] << 32 | (uint64_t)powman_hw->scratch[0]);
|
||||
diff = absolute_time_diff_us(wakeup_time, aon_timer_get_absolute_time());
|
||||
printf("Woken up now @%dus since target\n", (int)diff);
|
||||
if (diff < 0) {
|
||||
printf("WARNING: Woke up too soon - is this within the resolution of the aon timer?\n");
|
||||
}
|
||||
|
||||
if (my_number != 67890) {
|
||||
printf("ERROR: my_number is %d not 67890 - SRAM has been re-loaded\n", my_number);
|
||||
return -1;
|
||||
} else {
|
||||
printf("my_number in sram: %d\n", my_number);
|
||||
}
|
||||
|
||||
printf("Doing %d second pause to prove timer running\n", SLEEP_TIME_S);
|
||||
busy_wait_ms(SLEEP_TIME_MS);
|
||||
|
||||
|
||||
|
||||
// pstate with sram1 on
|
||||
printf("Going to PSTATE with SRAM1 on for %d seconds\n", SLEEP_TIME_S);
|
||||
|
||||
start_time = aon_timer_get_absolute_time();
|
||||
|
||||
wakeup_time = delayed_by_ms(start_time, SLEEP_TIME_MS);
|
||||
powman_hw->scratch[0] = to_us_since_boot(wakeup_time) & 0xFFFFFFFF;
|
||||
powman_hw->scratch[1] = to_us_since_boot(wakeup_time) >> 32;
|
||||
pstate = pstate_bitset_none();
|
||||
pstate_bitset_add(&pstate, POWMAN_POWER_DOMAIN_SRAM_BANK1);
|
||||
printf("pstate: %08x\n", pstate_bitset_to_powman_power_state(&pstate));
|
||||
ret = low_power_pstate_until_aon_timer(wakeup_time, &pstate, pstate_resume_func);
|
||||
|
||||
printf("%d low_power_pstate_until_aon_timer returned\n", ret);
|
||||
while (true) {
|
||||
printf("Waiting\n");
|
||||
busy_wait_ms(1000);
|
||||
}
|
||||
|
||||
post_pstate_sram1_on:
|
||||
// restore from scratch
|
||||
wakeup_time = from_us_since_boot((uint64_t)powman_hw->scratch[1] << 32 | (uint64_t)powman_hw->scratch[0]);
|
||||
diff = absolute_time_diff_us(wakeup_time, aon_timer_get_absolute_time());
|
||||
printf("Woken up now @%dus since target\n", (int)diff);
|
||||
if (diff < 0) {
|
||||
printf("WARNING: Woke up too soon - is this within the resolution of the aon timer?\n");
|
||||
}
|
||||
|
||||
if (my_number != 12345) {
|
||||
printf("ERROR: my_number is %d not 12345 - SRAM has not been re-loaded\n", my_number);
|
||||
return -1;
|
||||
} else {
|
||||
printf("my_number in sram: %d\n", my_number);
|
||||
}
|
||||
|
||||
printf("Doing %d second pause to prove timer running\n", SLEEP_TIME_S);
|
||||
busy_wait_ms(SLEEP_TIME_MS);
|
||||
|
||||
|
||||
|
||||
// pstate with sram off
|
||||
printf("Going to PSTATE with SRAM off for %d seconds\n", SLEEP_TIME_S);
|
||||
|
||||
start_time = aon_timer_get_absolute_time();
|
||||
|
||||
|
|
@ -163,17 +274,22 @@ int main() {
|
|||
busy_wait_ms(1000);
|
||||
}
|
||||
|
||||
post_pstate_timer:
|
||||
|
||||
post_pstate_sram_off:
|
||||
// restore from scratch
|
||||
wakeup_time = from_us_since_boot((uint64_t)powman_hw->scratch[1] << 32 | (uint64_t)powman_hw->scratch[0]);
|
||||
|
||||
diff = absolute_time_diff_us(wakeup_time, aon_timer_get_absolute_time());
|
||||
printf("Woken up now @%dus since target\n", (int)diff);
|
||||
if (diff < 0) {
|
||||
printf("WARNING: Woke up too soon - is this within the resolution of the aon timer?\n");
|
||||
}
|
||||
|
||||
if (my_number != 12345) {
|
||||
printf("ERROR: my_number is not 12345 - SRAM has not been re-loaded\n");
|
||||
return -1;
|
||||
} else {
|
||||
printf("my_number in sram: %d\n", my_number);
|
||||
}
|
||||
|
||||
printf("Doing %d second pause to prove timer running\n", SLEEP_TIME_S);
|
||||
busy_wait_ms(SLEEP_TIME_MS);
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue