diff --git a/bootloader/main.c b/bootloader/main.c index 12566ce..095f4bc 100644 --- a/bootloader/main.c +++ b/bootloader/main.c @@ -1302,7 +1302,8 @@ void ipl_main() while (true) tui_do_menu(&menu_top); - + + // Halt BPMP if we managed to get out of execution. while (true) - ; + bpmp_halt(); } diff --git a/bootloader/soc/bpmp.c b/bootloader/soc/bpmp.c index 1794696..cc20d89 100644 --- a/bootloader/soc/bpmp.c +++ b/bootloader/soc/bpmp.c @@ -216,3 +216,37 @@ void bpmp_clk_rate_set(bpmp_freq_t fid) } } +// The following functions halt BPMP to reduce power while sleeping. +// They are not as accurate as RTC at big values but they guarantee time+ delay. +void bpmp_usleep(u32 us) +{ + u32 delay; + + // Each iteration takes 1us. + while (us) + { + delay = (us > HALT_COP_MAX_CNT) ? HALT_COP_MAX_CNT : us; + us -= delay; + + FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_USEC | delay; + } +} + +void bpmp_msleep(u32 ms) +{ + u32 delay; + + // Iteration time is variable. ~200 - 1000us. + while (ms) + { + delay = (ms > HALT_COP_MAX_CNT) ? HALT_COP_MAX_CNT : ms; + ms -= delay; + + FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_MSEC | delay; + } +} + +void bpmp_halt() +{ + FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_JTAG; +} diff --git a/bootloader/soc/bpmp.h b/bootloader/soc/bpmp.h index 5c8f14b..b45ab7a 100644 --- a/bootloader/soc/bpmp.h +++ b/bootloader/soc/bpmp.h @@ -47,5 +47,8 @@ void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply); void bpmp_mmu_enable(); void bpmp_mmu_disable(); void bpmp_clk_rate_set(bpmp_freq_t fid); +void bpmp_usleep(u32 us); +void bpmp_msleep(u32 ms); +void bpmp_halt(); #endif diff --git a/bootloader/soc/cluster.h b/bootloader/soc/cluster.h index 5cecd19..428c046 100644 --- a/bootloader/soc/cluster.h +++ b/bootloader/soc/cluster.h @@ -19,19 +19,6 @@ #include "../utils/types.h" -/*! Flow controller registers. */ -#define FLOW_CTLR_HALT_CPU0_EVENTS 0x0 -#define FLOW_CTLR_HALT_CPU1_EVENTS 0x14 -#define FLOW_CTLR_HALT_CPU2_EVENTS 0x1C -#define FLOW_CTLR_HALT_CPU3_EVENTS 0x24 -#define FLOW_CTLR_HALT_COP_EVENTS 0x4 -#define FLOW_CTLR_CPU0_CSR 0x8 -#define FLOW_CTLR_CPU1_CSR 0x18 -#define FLOW_CTLR_CPU2_CSR 0x20 -#define FLOW_CTLR_CPU3_CSR 0x28 -#define FLOW_CTLR_RAM_REPAIR 0x40 -#define FLOW_CTLR_BPMP_CLUSTER_CONTROL 0x98 - void cluster_boot_cpu0(u32 entry); #endif diff --git a/bootloader/soc/t210.h b/bootloader/soc/t210.h index 1a9ef3f..d5a526b 100644 --- a/bootloader/soc/t210.h +++ b/bootloader/soc/t210.h @@ -189,4 +189,24 @@ #define EMC_HEKA_UPD (1 << 30) #define EMC_SEPT_RUN (1 << 31) +/*! Flow controller registers. */ +#define FLOW_CTLR_HALT_COP_EVENTS 0x4 +#define HALT_COP_SEC (1 << 23) +#define HALT_COP_MSEC (1 << 24) +#define HALT_COP_USEC (1 << 25) +#define HALT_COP_JTAG (1 << 28) +#define HALT_COP_WAIT_EVENT (1 << 30) +#define HALT_COP_WAIT_IRQ (1 << 31) +#define HALT_COP_MAX_CNT 0xFF +#define FLOW_CTLR_HALT_CPU0_EVENTS 0x0 +#define FLOW_CTLR_HALT_CPU1_EVENTS 0x14 +#define FLOW_CTLR_HALT_CPU2_EVENTS 0x1C +#define FLOW_CTLR_HALT_CPU3_EVENTS 0x24 +#define FLOW_CTLR_CPU0_CSR 0x8 +#define FLOW_CTLR_CPU1_CSR 0x18 +#define FLOW_CTLR_CPU2_CSR 0x20 +#define FLOW_CTLR_CPU3_CSR 0x28 +#define FLOW_CTLR_RAM_REPAIR 0x40 +#define FLOW_CTLR_BPMP_CLUSTER_CONTROL 0x98 + #endif diff --git a/bootloader/utils/util.c b/bootloader/utils/util.c index 4bdc1ff..8833feb 100644 --- a/bootloader/utils/util.c +++ b/bootloader/utils/util.c @@ -24,6 +24,8 @@ #include "../soc/pmc.h" #include "../soc/t210.h" +#define USE_RTC_TIMER + extern void sd_unmount(); u32 get_tmr_s() @@ -35,7 +37,7 @@ u32 get_tmr_ms() { // The registers must be read with the following order: // RTC_MILLI_SECONDS (0x10) -> RTC_SHADOW_SECONDS (0xC) - return (RTC(APBDEV_RTC_MILLI_SECONDS) | (RTC(APBDEV_RTC_SHADOW_SECONDS) << 10)); + return (RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000)); } u32 get_tmr_us() @@ -43,19 +45,28 @@ u32 get_tmr_us() return TMR(TIMERUS_CNTR_1US); //TIMERUS_CNTR_1US } -void msleep(u32 milliseconds) +void msleep(u32 ms) { - u32 start = RTC(APBDEV_RTC_MILLI_SECONDS) | (RTC(APBDEV_RTC_SHADOW_SECONDS) << 10); - while (((RTC(APBDEV_RTC_MILLI_SECONDS) | (RTC(APBDEV_RTC_SHADOW_SECONDS) << 10)) - start) <= milliseconds) +#ifdef USE_RTC_TIMER + u32 start = RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000); + // Casting to u32 is important! + while (((u32)(RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000)) - start) <= ms) ; +#else + bpmp_msleep(ms); +#endif } -void usleep(u32 microseconds) +void usleep(u32 us) { +#ifdef USE_RTC_TIMER u32 start = TMR(TIMERUS_CNTR_1US); // Casting to u32 is important! - while ((u32)(TMR(TIMERUS_CNTR_1US) - start) <= microseconds) + while ((u32)(TMR(TIMERUS_CNTR_1US) - start) <= us) ; +#else + bpmp_usleep(us); +#endif } void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops) @@ -76,7 +87,6 @@ void panic(u32 val) while (true) usleep(1); - } void reboot_normal() @@ -100,7 +110,7 @@ void reboot_rcm() PMC(APBDEV_PMC_CNTRL) |= PMC_CNTRL_MAIN_RST; while (true) - usleep(1); + bpmp_halt(); } void power_off() @@ -114,5 +124,5 @@ void power_off() i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_PWR_OFF); while (true) - usleep(1); + bpmp_halt(); } diff --git a/bootloader/utils/util.h b/bootloader/utils/util.h index ae736dd..3a81e55 100644 --- a/bootloader/utils/util.h +++ b/bootloader/utils/util.h @@ -46,8 +46,8 @@ typedef struct _nyx_storage_t u32 get_tmr_us(); u32 get_tmr_ms(); u32 get_tmr_s(); -void usleep(u32 ticks); -void msleep(u32 milliseconds); +void usleep(u32 us); +void msleep(u32 ms); void panic(u32 val); void reboot_normal(); void reboot_rcm(); diff --git a/nyx/nyx_gui/nyx.c b/nyx/nyx_gui/nyx.c index 941bac0..1144f5d 100644 --- a/nyx/nyx_gui/nyx.c +++ b/nyx/nyx_gui/nyx.c @@ -358,6 +358,7 @@ void load_saved_configuration() void nyx_init_load_res() { bpmp_mmu_enable(); + bpmp_clk_rate_set(BPMP_CLK_SUPER_BOOST); // Set bootloader's default configuration. set_default_configuration(); @@ -385,8 +386,6 @@ void nyx_init_load_res() sd_unmount(false); h_cfg.rcm_patched = fuse_check_patched_rcm(); - - bpmp_clk_rate_set(BPMP_CLK_SUPER_BOOST); } #define IPL_STACK_TOP 0x90010000 @@ -424,6 +423,7 @@ void ipl_main() nyx_load_and_run(); + // Halt BPMP if we managed to get out of execution. while (true) - ; + bpmp_halt(); } diff --git a/nyx/nyx_gui/soc/bpmp.c b/nyx/nyx_gui/soc/bpmp.c index b5a8f07..45a4a0c 100644 --- a/nyx/nyx_gui/soc/bpmp.c +++ b/nyx/nyx_gui/soc/bpmp.c @@ -219,4 +219,39 @@ void bpmp_clk_rate_set(bpmp_freq_t fid) } } +// The following functions halt BPMP to reduce power while sleeping. +// They are not as accurate as RTC at big values but they guarantee time+ delay. +void bpmp_usleep(u32 us) +{ + u32 delay; + + // Each iteration takes 1us. + while (us) + { + delay = (us > HALT_COP_MAX_CNT) ? HALT_COP_MAX_CNT : us; + us -= delay; + + FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_USEC | delay; + } +} + +void bpmp_msleep(u32 ms) +{ + u32 delay; + + // Iteration time is variable. ~200 - 1000us. + while (ms) + { + delay = (ms > HALT_COP_MAX_CNT) ? HALT_COP_MAX_CNT : ms; + ms -= delay; + + FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_MSEC | delay; + } +} + +void bpmp_halt() +{ + FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_JTAG; +} + #pragma GCC pop_options diff --git a/nyx/nyx_gui/soc/bpmp.h b/nyx/nyx_gui/soc/bpmp.h index 5c8f14b..b45ab7a 100644 --- a/nyx/nyx_gui/soc/bpmp.h +++ b/nyx/nyx_gui/soc/bpmp.h @@ -47,5 +47,8 @@ void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply); void bpmp_mmu_enable(); void bpmp_mmu_disable(); void bpmp_clk_rate_set(bpmp_freq_t fid); +void bpmp_usleep(u32 us); +void bpmp_msleep(u32 ms); +void bpmp_halt(); #endif diff --git a/nyx/nyx_gui/soc/cluster.h b/nyx/nyx_gui/soc/cluster.h index 5cecd19..428c046 100644 --- a/nyx/nyx_gui/soc/cluster.h +++ b/nyx/nyx_gui/soc/cluster.h @@ -19,19 +19,6 @@ #include "../utils/types.h" -/*! Flow controller registers. */ -#define FLOW_CTLR_HALT_CPU0_EVENTS 0x0 -#define FLOW_CTLR_HALT_CPU1_EVENTS 0x14 -#define FLOW_CTLR_HALT_CPU2_EVENTS 0x1C -#define FLOW_CTLR_HALT_CPU3_EVENTS 0x24 -#define FLOW_CTLR_HALT_COP_EVENTS 0x4 -#define FLOW_CTLR_CPU0_CSR 0x8 -#define FLOW_CTLR_CPU1_CSR 0x18 -#define FLOW_CTLR_CPU2_CSR 0x20 -#define FLOW_CTLR_CPU3_CSR 0x28 -#define FLOW_CTLR_RAM_REPAIR 0x40 -#define FLOW_CTLR_BPMP_CLUSTER_CONTROL 0x98 - void cluster_boot_cpu0(u32 entry); #endif diff --git a/nyx/nyx_gui/soc/t210.h b/nyx/nyx_gui/soc/t210.h index 1b11d72..5aa266f 100644 --- a/nyx/nyx_gui/soc/t210.h +++ b/nyx/nyx_gui/soc/t210.h @@ -188,4 +188,24 @@ #define EMC_HEKA_UPD (1 << 30) #define EMC_SEPT_RUN (1 << 31) +/*! Flow controller registers. */ +#define FLOW_CTLR_HALT_COP_EVENTS 0x4 +#define HALT_COP_SEC (1 << 23) +#define HALT_COP_MSEC (1 << 24) +#define HALT_COP_USEC (1 << 25) +#define HALT_COP_JTAG (1 << 28) +#define HALT_COP_WAIT_EVENT (1 << 30) +#define HALT_COP_WAIT_IRQ (1 << 31) +#define HALT_COP_MAX_CNT 0xFF +#define FLOW_CTLR_HALT_CPU0_EVENTS 0x0 +#define FLOW_CTLR_HALT_CPU1_EVENTS 0x14 +#define FLOW_CTLR_HALT_CPU2_EVENTS 0x1C +#define FLOW_CTLR_HALT_CPU3_EVENTS 0x24 +#define FLOW_CTLR_CPU0_CSR 0x8 +#define FLOW_CTLR_CPU1_CSR 0x18 +#define FLOW_CTLR_CPU2_CSR 0x20 +#define FLOW_CTLR_CPU3_CSR 0x28 +#define FLOW_CTLR_RAM_REPAIR 0x40 +#define FLOW_CTLR_BPMP_CLUSTER_CONTROL 0x98 + #endif diff --git a/nyx/nyx_gui/utils/util.c b/nyx/nyx_gui/utils/util.c index 6ec67a3..b1c5161 100644 --- a/nyx/nyx_gui/utils/util.c +++ b/nyx/nyx_gui/utils/util.c @@ -23,6 +23,8 @@ #include "../soc/pmc.h" #include "../soc/t210.h" +#define USE_RTC_TIMER + extern void sd_unmount(bool deinit); u32 get_tmr_s() @@ -34,7 +36,7 @@ u32 get_tmr_ms() { // The registers must be read with the following order: // RTC_MILLI_SECONDS (0x10) -> RTC_SHADOW_SECONDS (0xC) - return (RTC(APBDEV_RTC_MILLI_SECONDS) | (RTC(APBDEV_RTC_SHADOW_SECONDS) << 10)); + return (RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000)); } u32 get_tmr_us() @@ -42,19 +44,28 @@ u32 get_tmr_us() return TMR(TIMERUS_CNTR_1US); //TIMERUS_CNTR_1US } -void msleep(u32 milliseconds) +void msleep(u32 ms) { - u32 start = RTC(APBDEV_RTC_MILLI_SECONDS) | (RTC(APBDEV_RTC_SHADOW_SECONDS) << 10); - while (((RTC(APBDEV_RTC_MILLI_SECONDS) | (RTC(APBDEV_RTC_SHADOW_SECONDS) << 10)) - start) <= milliseconds) +#ifdef USE_RTC_TIMER + u32 start = RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000); + // Casting to u32 is important! + while (((u32)(RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000)) - start) <= ms) ; +#else + bpmp_msleep(ms); +#endif } -void usleep(u32 microseconds) +void usleep(u32 us) { +#ifdef USE_RTC_TIMER u32 start = TMR(TIMERUS_CNTR_1US); // Casting to u32 is important! - while ((u32)(TMR(TIMERUS_CNTR_1US) - start) <= microseconds) + while ((u32)(TMR(TIMERUS_CNTR_1US) - start) <= us) ; +#else + bpmp_usleep(us); +#endif } void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops) @@ -75,7 +86,6 @@ void panic(u32 val) while (true) usleep(1); - } void reboot_normal() @@ -99,7 +109,7 @@ void reboot_rcm() PMC(APBDEV_PMC_CNTRL) |= PMC_CNTRL_MAIN_RST; while (true) - usleep(1); + bpmp_halt(); } void power_off() @@ -110,5 +120,5 @@ void power_off() i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_PWR_OFF); while (true) - usleep(1); + bpmp_halt(); } diff --git a/nyx/nyx_gui/utils/util.h b/nyx/nyx_gui/utils/util.h index ae736dd..3a81e55 100644 --- a/nyx/nyx_gui/utils/util.h +++ b/nyx/nyx_gui/utils/util.h @@ -46,8 +46,8 @@ typedef struct _nyx_storage_t u32 get_tmr_us(); u32 get_tmr_ms(); u32 get_tmr_s(); -void usleep(u32 ticks); -void msleep(u32 milliseconds); +void usleep(u32 us); +void msleep(u32 ms); void panic(u32 val); void reboot_normal(); void reboot_rcm();