diff --git a/.gitignore b/.gitignore index a9a6e8c09..b5e6eaa98 100644 --- a/.gitignore +++ b/.gitignore @@ -43,7 +43,6 @@ sw/linker/link.ld sw/linker/link_flash_exec.ld sw/linker/link_flash_load.ld sw/device/lib/drivers/power_manager/power_manager_regs.h -sw/device/lib/drivers/power_manager/power_manager.h sw/device/lib/drivers/pad_control/pad_control_regs.h sw/device/lib/drivers/**/*_structs.h diff --git a/Makefile b/Makefile index 0b80c28fb..75307dde7 100644 --- a/Makefile +++ b/Makefile @@ -94,7 +94,6 @@ mcu-gen: $(PYTHON) util/mcu_gen.py --cfg $(MCU_CFG) --pads_cfg $(PAD_CFG) --outdir hw/ip/power_manager/rtl --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --external_domains $(EXTERNAL_DOMAINS) --pkg-sv hw/ip/power_manager/data/power_manager.sv.tpl $(PYTHON) util/mcu_gen.py --cfg $(MCU_CFG) --pads_cfg $(PAD_CFG) --outdir hw/ip/power_manager/data --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --external_domains $(EXTERNAL_DOMAINS) --pkg-sv hw/ip/power_manager/data/power_manager.hjson.tpl bash -c "cd hw/ip/power_manager; source power_manager_gen.sh; cd ../../../" - $(PYTHON) util/mcu_gen.py --cfg mcu_cfg.hjson --pads_cfg $(PAD_CFG) --outdir sw/device/lib/drivers/power_manager --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --external_domains $(EXTERNAL_DOMAINS) --pkg-sv sw/device/lib/drivers/power_manager/data/power_manager.h.tpl $(PYTHON) util/mcu_gen.py --cfg mcu_cfg.hjson --pads_cfg $(PAD_CFG) --outdir hw/system/pad_control/data --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --external_pads $(EXT_PAD_CFG) --pkg-sv hw/system/pad_control/data/pad_control.hjson.tpl $(PYTHON) util/mcu_gen.py --cfg mcu_cfg.hjson --pads_cfg $(PAD_CFG) --outdir hw/system/pad_control/rtl --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --external_pads $(EXT_PAD_CFG) --pkg-sv hw/system/pad_control/rtl/pad_control.sv.tpl bash -c "cd hw/system/pad_control; source pad_control_gen.sh; cd ../../../" diff --git a/sw/applications/example_clock_gating/main.c b/sw/applications/example_clock_gating/main.c index 958e04921..a20095ddf 100644 --- a/sw/applications/example_clock_gating/main.c +++ b/sw/applications/example_clock_gating/main.c @@ -23,39 +23,36 @@ #define PRINTF(...) #endif -static power_manager_t power_manager; - int main(int argc, char *argv[]) { // Setup power_manager - mmio_region_t power_manager_reg = mmio_region_from_addr(POWER_MANAGER_START_ADDRESS); - power_manager.base_addr = power_manager_reg; + power_manager_init(NULL); // Clock-gating the peripheral subsystem - mmio_region_write32(power_manager.base_addr, (ptrdiff_t)(POWER_MANAGER_PERIPH_CLK_GATE_REG_OFFSET), 0x1); + clock_gate_periph(kOff_e); // Clock-gating ram-banks // We probably should not clockgate the bank where our RAM resides for(uint32_t i = 2; i < MEMORY_BANKS; ++i) - mmio_region_write32(power_manager.base_addr, (ptrdiff_t)(power_manager_ram_map[i].clk_gate), 0x1); + clock_gate_ram_block(i,kOff_e); // Clock-gating external subsystems for(uint32_t i = 0; i < EXTERNAL_DOMAINS; ++i) - mmio_region_write32(power_manager.base_addr, (ptrdiff_t)(power_manager_external_map[i].clk_gate), 0x1); + clock_gate_external(i,kOff_e); // Wait some time for (int i=0; i<100; i++) asm volatile("nop;"); // Enabling the peripheral subsystem - mmio_region_write32(power_manager.base_addr, (ptrdiff_t)(POWER_MANAGER_PERIPH_CLK_GATE_REG_OFFSET), 0x0); + clock_gate_periph(kOn_e); // Enabling ram-banks for(uint32_t i = 2; i < MEMORY_BANKS; ++i) - mmio_region_write32(power_manager.base_addr, (ptrdiff_t)(power_manager_ram_map[i].clk_gate), 0x0); + clock_gate_ram_block(i,kOn_e); // Enabling external subsystems for(uint32_t i = 0; i < EXTERNAL_DOMAINS; ++i) - mmio_region_write32(power_manager.base_addr, (ptrdiff_t)(power_manager_external_map[i].clk_gate), 0x0); + clock_gate_external(i,kOn_e); /* write something to stdout */ PRINTF("Success.\n\r"); diff --git a/sw/applications/example_power_gating_core/main.c b/sw/applications/example_power_gating_core/main.c index da7d84486..9d91488cd 100644 --- a/sw/applications/example_power_gating_core/main.c +++ b/sw/applications/example_power_gating_core/main.c @@ -39,7 +39,6 @@ static rv_timer_t timer_0_1; static rv_timer_t timer_2_3; static const uint64_t kTickFreqHz = 1000 * 1000; // 1 MHz -static power_manager_t power_manager; #ifndef TARGET_PYNQ_Z2 #define GPIO_TB_OUT 30 @@ -51,9 +50,7 @@ int main(int argc, char *argv[]) { // Setup power_manager - mmio_region_t power_manager_reg = mmio_region_from_addr(POWER_MANAGER_START_ADDRESS); - power_manager.base_addr = power_manager_reg; - power_manager_counters_t power_manager_cpu_counters; + power_manager_init(NULL); //counters uint32_t reset_off, reset_on, switch_off, switch_on, iso_off, iso_on; @@ -94,7 +91,7 @@ int main(int argc, char *argv[]) reset_on = switch_on + 20; //give 20 cycles to emulate the turn on time, this number depends on technology and here it is just a random number iso_on = reset_on + 5; - if (power_gate_counters_init(&power_manager_cpu_counters, reset_off, reset_on, switch_off, switch_on, iso_off, iso_on, 0, 0) != kPowerManagerOk_e) + if (power_gate_counters_init(reset_off, reset_on, switch_off, switch_on, iso_off, iso_on, 0, 0) != kPowerManagerOk_e) { PRINTF("Error: power manager fail. Check the reset and powergate counters value\n\r"); return EXIT_FAILURE; @@ -107,7 +104,7 @@ int main(int argc, char *argv[]) rv_timer_counter_set_enabled(&timer_0_1, 0, kRvTimerEnabled); CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); - if (power_gate_core(&power_manager, kTimer_0_pm_e, &power_manager_cpu_counters) != kPowerManagerOk_e) + if (power_gate_core(kTimer_0_pm_e) != kPowerManagerOk_e) { PRINTF("Error: power manager fail.\n\r"); return EXIT_FAILURE; @@ -121,7 +118,7 @@ int main(int argc, char *argv[]) rv_timer_counter_set_enabled(&timer_0_1, 1, kRvTimerEnabled); CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); - if (power_gate_core(&power_manager, kTimer_1_pm_e, &power_manager_cpu_counters) != kPowerManagerOk_e) + if (power_gate_core(kTimer_1_pm_e) != kPowerManagerOk_e) { PRINTF("Error: power manager fail.\n\r"); return EXIT_FAILURE; @@ -135,7 +132,7 @@ int main(int argc, char *argv[]) rv_timer_counter_set_enabled(&timer_2_3, 0, kRvTimerEnabled); CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); - if (power_gate_core(&power_manager, kTimer_2_pm_e, &power_manager_cpu_counters) != kPowerManagerOk_e) + if (power_gate_core(kTimer_2_pm_e) != kPowerManagerOk_e) { PRINTF("Error: power manager fail.\n\r"); return EXIT_FAILURE; @@ -149,7 +146,7 @@ int main(int argc, char *argv[]) rv_timer_counter_set_enabled(&timer_2_3, 1, kRvTimerEnabled); CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); - if (power_gate_core(&power_manager, kTimer_3_pm_e, &power_manager_cpu_counters) != kPowerManagerOk_e) + if (power_gate_core(kTimer_3_pm_e) != kPowerManagerOk_e) { PRINTF("Error: power manager fail.\n\r"); return EXIT_FAILURE; @@ -171,7 +168,7 @@ int main(int argc, char *argv[]) gpio_write(GPIO_TB_OUT, true); CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); - if (power_gate_core(&power_manager, kPlic_pm_e, &power_manager_cpu_counters) != kPowerManagerOk_e) + if (power_gate_core(kPlic_pm_e) != kPowerManagerOk_e) { PRINTF("Error: power manager fail.\n\r"); return EXIT_FAILURE; diff --git a/sw/applications/example_power_gating_external/main.c b/sw/applications/example_power_gating_external/main.c index 1ffc90c4d..93caa5342 100644 --- a/sw/applications/example_power_gating_external/main.c +++ b/sw/applications/example_power_gating_external/main.c @@ -23,38 +23,33 @@ #define PRINTF(...) #endif -static power_manager_t power_manager; - int main(int argc, char *argv[]) { // Setup power_manager - mmio_region_t power_manager_reg = mmio_region_from_addr(POWER_MANAGER_START_ADDRESS); - power_manager.base_addr = power_manager_reg; - - power_manager_counters_t power_manager_external_counters; + power_manager_init(NULL); // Init ram block 2's counters - if (power_gate_counters_init(&power_manager_external_counters, 30, 30, 30, 30, 30, 30, 0, 0) != kPowerManagerOk_e) + if (power_gate_counters_init(30, 30, 30, 30, 30, 30, 0, 0) != kPowerManagerOk_e) { PRINTF("Error: power manager fail. Check the reset and powergate counters value\n\r"); return EXIT_FAILURE; } // Power off external domain - if (power_gate_external(&power_manager, 0, kOff_e, &power_manager_external_counters) != kPowerManagerOk_e) + if (power_gate_external(0, kOff_e) != kPowerManagerOk_e) { PRINTF("Error: power manager fail.\n\r"); return EXIT_FAILURE; } // Check that the external domain is actually OFF - while(!external_power_domain_is_off(&power_manager, 0)); + while(!external_power_domain_is_off(0)); // Wait some time for (int i=0; i<100; i++) asm volatile("nop"); // Power on external domain - if (power_gate_external(&power_manager, 0, kOn_e, &power_manager_external_counters) != kPowerManagerOk_e) + if (power_gate_external(0, kOn_e) != kPowerManagerOk_e) { PRINTF("Error: power manager fail.\n\r"); return EXIT_FAILURE; diff --git a/sw/applications/example_power_gating_periph/main.c b/sw/applications/example_power_gating_periph/main.c index fb51e1c73..b464300b8 100644 --- a/sw/applications/example_power_gating_periph/main.c +++ b/sw/applications/example_power_gating_periph/main.c @@ -23,38 +23,33 @@ #define PRINTF(...) #endif -static power_manager_t power_manager; - int main(int argc, char *argv[]) { // Setup power_manager - mmio_region_t power_manager_reg = mmio_region_from_addr(POWER_MANAGER_START_ADDRESS); - power_manager.base_addr = power_manager_reg; - - power_manager_counters_t power_manager_periph_counters; + power_manager_init(NULL); // Init peripheral_subsystem's counters - if (power_gate_counters_init(&power_manager_periph_counters, 30, 30, 30, 30, 30, 30, 0, 0) != kPowerManagerOk_e) + if (power_gate_counters_init(30, 30, 30, 30, 30, 30, 0, 0) != kPowerManagerOk_e) { PRINTF("Error: power manager fail. Check the reset and powergate counters value\n\r"); return EXIT_FAILURE; } // Power off peripheral_subsystem domain - if (power_gate_periph(&power_manager, kOff_e, &power_manager_periph_counters) != kPowerManagerOk_e) + if (power_gate_periph(kOff_e) != kPowerManagerOk_e) { PRINTF("Error: power manager fail.\n\r"); return EXIT_FAILURE; } // Check that the peripheral_subsystem domain is actually OFF - while(!periph_power_domain_is_off(&power_manager)); + while(!periph_power_domain_is_off()); // Wait some time for (int i=0; i<100; i++) asm volatile("nop;"); // Power on peripheral_subsystem domain - if (power_gate_periph(&power_manager, kOn_e, &power_manager_periph_counters) != kPowerManagerOk_e) + if (power_gate_periph(kOn_e) != kPowerManagerOk_e) { PRINTF("Error: power manager fail.\n\r"); return EXIT_FAILURE; diff --git a/sw/applications/example_power_gating_ram_blocks/main.c b/sw/applications/example_power_gating_ram_blocks/main.c index fe6734037..59bf333ee 100644 --- a/sw/applications/example_power_gating_ram_blocks/main.c +++ b/sw/applications/example_power_gating_ram_blocks/main.c @@ -23,40 +23,35 @@ #define PRINTF(...) #endif -static power_manager_t power_manager; - int main(int argc, char *argv[]) { #if MEMORY_BANKS > 2 // Setup power_manager - mmio_region_t power_manager_reg = mmio_region_from_addr(POWER_MANAGER_START_ADDRESS); - power_manager.base_addr = power_manager_reg; - - power_manager_counters_t power_manager_ram_blocks_counters; + power_manager_init(NULL); // Init ram block 2's counters - if (power_gate_counters_init(&power_manager_ram_blocks_counters, 30, 30, 30, 30, 30, 30, 0, 0) != kPowerManagerOk_e) + if (power_gate_counters_init(30, 30, 30, 30, 30, 30, 0, 0) != kPowerManagerOk_e) { PRINTF("Error: power manager fail. Check the reset and powergate counters value\n\r"); return EXIT_FAILURE; } // Power off ram block 2 domain - if (power_gate_ram_block(&power_manager, 2, kOff_e, &power_manager_ram_blocks_counters) != kPowerManagerOk_e) + if (power_gate_ram_block(2, kOff_e) != kPowerManagerOk_e) { PRINTF("Error: power manager fail.\n\r"); return EXIT_FAILURE; } // Check that the ram block 2 domain is actually OFF - while(!ram_block_power_domain_is_off(&power_manager, 2)); + while(!ram_block_power_domain_is_off(2)); // Wait some time for (int i=0; i<100; i++) asm volatile("nop"); // Power on ram block 2 domain - if (power_gate_ram_block(&power_manager, 2, kOn_e, &power_manager_ram_blocks_counters) != kPowerManagerOk_e) + if (power_gate_ram_block(2, kOn_e) != kPowerManagerOk_e) { PRINTF("Error: power manager fail.\n\r"); return EXIT_FAILURE; diff --git a/sw/applications/example_set_retentive_ram_blocks/main.c b/sw/applications/example_set_retentive_ram_blocks/main.c index cde898ad8..417f5f30e 100644 --- a/sw/applications/example_set_retentive_ram_blocks/main.c +++ b/sw/applications/example_set_retentive_ram_blocks/main.c @@ -23,26 +23,21 @@ #define PRINTF(...) #endif -static power_manager_t power_manager; - int main(int argc, char *argv[]) { #if MEMORY_BANKS > 2 // Setup power_manager - mmio_region_t power_manager_reg = mmio_region_from_addr(POWER_MANAGER_START_ADDRESS); - power_manager.base_addr = power_manager_reg; - - power_manager_counters_t power_manager_ram_blocks_counters; + power_manager_init(NULL); // Init ram block 2's counters - if (power_gate_counters_init(&power_manager_ram_blocks_counters, 0, 0, 0, 0, 0, 0, 30, 30) != kPowerManagerOk_e) + if (power_gate_counters_init(0, 0, 0, 0, 0, 0, 30, 30) != kPowerManagerOk_e) { PRINTF("Error: power manager fail. Check the reset and powergate counters value\n\r"); return EXIT_FAILURE; } // Set retention mode on for ram block 2 domain - if (power_gate_ram_block(&power_manager, 2, kRetOn_e, &power_manager_ram_blocks_counters) != kPowerManagerOk_e) + if (power_gate_ram_block(2, kRetOn_e) != kPowerManagerOk_e) { PRINTF("Error: power manager fail.\n\r"); return EXIT_FAILURE; @@ -52,7 +47,7 @@ int main(int argc, char *argv[]) for (int i=0; i<100; i++) asm volatile("nop"); // Set retention mode off for ram block 2 domain - if (power_gate_ram_block(&power_manager, 2, kRetOff_e, &power_manager_ram_blocks_counters) != kPowerManagerOk_e) + if (power_gate_ram_block(2, kRetOff_e) != kPowerManagerOk_e) { PRINTF("Error: power manager fail.\n\r"); return EXIT_FAILURE; diff --git a/sw/applications/example_set_retentive_ram_blocks_external/main.c b/sw/applications/example_set_retentive_ram_blocks_external/main.c index 7b4555910..1a8489fdd 100644 --- a/sw/applications/example_set_retentive_ram_blocks_external/main.c +++ b/sw/applications/example_set_retentive_ram_blocks_external/main.c @@ -23,25 +23,20 @@ #define PRINTF(...) #endif -static power_manager_t power_manager; - int main(int argc, char *argv[]) { // Setup power_manager - mmio_region_t power_manager_reg = mmio_region_from_addr(POWER_MANAGER_START_ADDRESS); - power_manager.base_addr = power_manager_reg; - - power_manager_counters_t power_manager_external_ram_blocks_counters; + power_manager_init(NULL); // Init external ram block 0's counters - if (power_gate_counters_init(&power_manager_external_ram_blocks_counters, 0, 0, 0, 0, 0, 0, 30, 30) != kPowerManagerOk_e) + if (power_gate_counters_init(0, 0, 0, 0, 0, 0, 30, 30) != kPowerManagerOk_e) { PRINTF("Error: power manager fail. Check the reset and powergate counters value\n\r"); return EXIT_FAILURE; } // Set retention mode on for external ram block 0 - if (power_gate_external(&power_manager, 0, kRetOn_e, &power_manager_external_ram_blocks_counters) != kPowerManagerOk_e) + if (power_gate_external(0, kRetOn_e) != kPowerManagerOk_e) { PRINTF("Error: power manager fail.\n\r"); return EXIT_FAILURE; @@ -51,7 +46,7 @@ int main(int argc, char *argv[]) for (int i=0; i<100; i++) asm volatile("nop"); // Set retention mode off for external ram block 0 - if (power_gate_external(&power_manager, 0, kRetOff_e, &power_manager_external_ram_blocks_counters) != kPowerManagerOk_e) + if (power_gate_external(0, kRetOff_e) != kPowerManagerOk_e) { PRINTF("Error: power manager fail.\n\r"); return EXIT_FAILURE; diff --git a/sw/applications/example_spi_host_dma_power_gate/main.c b/sw/applications/example_spi_host_dma_power_gate/main.c index 6f80e5b41..1465be0bb 100644 --- a/sw/applications/example_spi_host_dma_power_gate/main.c +++ b/sw/applications/example_spi_host_dma_power_gate/main.c @@ -48,8 +48,6 @@ volatile int8_t dma_intr_flag; int8_t core_sleep_flag; spi_host_t spi_host; -static power_manager_t power_manager; - void dma_intr_handler_trans_done(void) { PRINTF("Non-weak implementation of a DMA interrupt\n\r"); @@ -102,11 +100,10 @@ int main(int argc, char *argv[]) #endif // Setup power_manager - mmio_region_t power_manager_reg = mmio_region_from_addr(POWER_MANAGER_START_ADDRESS); - power_manager.base_addr = power_manager_reg; - power_manager_counters_t power_manager_cpu_counters; + power_manager_init(NULL); + // Init cpu_subsystem's counters - if (power_gate_counters_init(&power_manager_cpu_counters, 300, 300, 300, 300, 300, 300, 0, 0) != kPowerManagerOk_e) + if (power_gate_counters_init(300, 300, 300, 300, 300, 300, 0, 0) != kPowerManagerOk_e) { PRINTF("Error: power manager fail. Check the reset and powergate counters value\n\r"); return EXIT_FAILURE; @@ -279,7 +276,7 @@ int main(int argc, char *argv[]) // Power gate core and wait for fast DMA interrupt CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); if(dma_intr_flag == 0) { - if (power_gate_core(&power_manager, kDma_pm_e, &power_manager_cpu_counters) != kPowerManagerOk_e) + if (power_gate_core(kDma_pm_e) != kPowerManagerOk_e) { PRINTF("Error: power manager fail.\n\r"); return EXIT_FAILURE; diff --git a/sw/device/lib/drivers/power_manager/data/power_manager.h.tpl b/sw/device/lib/drivers/power_manager/data/power_manager.h.tpl deleted file mode 100644 index 7f0d939ea..000000000 --- a/sw/device/lib/drivers/power_manager/data/power_manager.h.tpl +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright 2022 OpenHW Group -// Solderpad Hardware License, Version 2.1, see LICENSE.md for details. -// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 - -#ifndef _POWER_MANAGER_H_ -#define _POWER_MANAGER_H_ - -#include -#include - -#include "mmio.h" -#include "power_manager_regs.h" - - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Results. - */ -typedef enum power_manager_result { - kPowerManagerOk_e = 0, - kPowerManagerError_e = 1, -} power_manager_result_t; - - -/** - * Domain states. - */ -typedef enum power_manager_sel_state { - kOn_e = 0, - kOff_e = 1, - kRetOn_e = 2, - kRetOff_e = 3, -} power_manager_sel_state_t; - -/** - * Interrupt source. - */ -typedef enum power_manager_sel_intr { - kTimer_0_pm_e = 0, - kPlic_pm_e = 1, - kTimer_1_pm_e = 2, - kTimer_2_pm_e = 3, - kTimer_3_pm_e = 4, - kDma_pm_e = 5, - kSpi_pm_e = 6, - kSpiFlash_pm_e = 7, - kGpio_0_pm_e = 8, - kGpio_1_pm_e = 9, - kGpio_2_pm_e = 10, - kGpio_3_pm_e = 11, - kGpio_4_pm_e = 12, - kGpio_5_pm_e = 13, - kGpio_6_pm_e = 14, - kGpio_7_pm_e = 15, - kExt_0_pm_e = 16, - kExt_1_pm_e = 17, - kExt_2_pm_e = 18, - kExt_3_pm_e = 19, -} power_manager_sel_intr_t; - -/** - * Monitor signals. - */ -typedef struct monitor_signals { - uint32_t kSwitch_e; - uint32_t kIso_e; - uint32_t kReset_e; -} monitor_signals_t; - -/** - * Initialization parameters for POWER MANAGER. - * - */ -typedef struct power_manager { - /** - * The base address for the power_manager hardware registers. - */ - mmio_region_t base_addr; -} power_manager_t; - -typedef struct power_manager_counters { - /** - * The counter to set and unset the reset and switch of the CPU. - */ - uint32_t reset_off; - uint32_t reset_on; - uint32_t switch_off; - uint32_t switch_on; - uint32_t iso_off; - uint32_t iso_on; - uint32_t retentive_off; - uint32_t retentive_on; -} power_manager_counters_t; - -typedef struct power_manager_ram_map_t { - uint32_t clk_gate; - uint32_t power_gate_ack; - uint32_t switch_off; - uint32_t wait_ack_switch; - uint32_t iso; - uint32_t retentive; - uint32_t monitor_power_gate; -} power_manager_ram_map_t; - -static power_manager_ram_map_t power_manager_ram_map[${ram_numbanks}] = { -% for bank in range(ram_numbanks): - (power_manager_ram_map_t) { - .clk_gate = POWER_MANAGER_RAM_${bank}_CLK_GATE_REG_OFFSET, - .power_gate_ack = POWER_MANAGER_POWER_GATE_RAM_BLOCK_${bank}_ACK_REG_OFFSET, - .switch_off = POWER_MANAGER_RAM_${bank}_SWITCH_REG_OFFSET, - .wait_ack_switch = POWER_MANAGER_RAM_${bank}_WAIT_ACK_SWITCH_ON_REG_OFFSET, - .iso = POWER_MANAGER_RAM_${bank}_ISO_REG_OFFSET, - .retentive = POWER_MANAGER_RAM_${bank}_RETENTIVE_REG_OFFSET, - .monitor_power_gate = POWER_MANAGER_MONITOR_POWER_GATE_RAM_BLOCK_${bank}_REG_OFFSET - }, -% endfor -}; - -typedef struct power_manager_external_map_t { - uint32_t clk_gate; - uint32_t power_gate_ack; - uint32_t reset; - uint32_t switch_off; - uint32_t wait_ack_switch; - uint32_t iso; - uint32_t retentive; - uint32_t monitor_power_gate; -} power_manager_external_map_t; - -static power_manager_external_map_t power_manager_external_map[${external_domains}] = { -% for ext in range(external_domains): - (power_manager_external_map_t) { - .clk_gate = POWER_MANAGER_EXTERNAL_${ext}_CLK_GATE_REG_OFFSET, - .power_gate_ack = POWER_MANAGER_POWER_GATE_EXTERNAL_${ext}_ACK_REG_OFFSET, - .reset = POWER_MANAGER_EXTERNAL_${ext}_RESET_REG_OFFSET, - .switch_off = POWER_MANAGER_EXTERNAL_${ext}_SWITCH_REG_OFFSET, - .wait_ack_switch = POWER_MANAGER_EXTERNAL_${ext}_WAIT_ACK_SWITCH_ON_REG_OFFSET, - .iso = POWER_MANAGER_EXTERNAL_${ext}_ISO_REG_OFFSET, - .retentive = POWER_MANAGER_EXTERNAL_RAM_${ext}_RETENTIVE_REG_OFFSET, - .monitor_power_gate = POWER_MANAGER_MONITOR_POWER_GATE_EXTERNAL_${ext}_REG_OFFSET, - }, -% endfor -}; - -power_manager_result_t power_gate_counters_init(power_manager_counters_t* counters, uint32_t reset_off, uint32_t reset_on, uint32_t switch_off, uint32_t switch_on, uint32_t iso_off, uint32_t iso_on, uint32_t retentive_off, uint32_t retentive_on); - -power_manager_result_t power_gate_core(const power_manager_t *power_manager, power_manager_sel_intr_t sel_intr, power_manager_counters_t* cpu_counters); - -power_manager_result_t power_gate_periph(const power_manager_t *power_manager, power_manager_sel_state_t sel_state, power_manager_counters_t* periph_counters); - -power_manager_result_t power_gate_ram_block(const power_manager_t *power_manager, uint32_t sel_block, power_manager_sel_state_t sel_state, power_manager_counters_t* ram_block_counters); - -power_manager_result_t power_gate_external(const power_manager_t *power_manager, uint32_t sel_external, power_manager_sel_state_t sel_state, power_manager_counters_t* external_counters); - -uint32_t periph_power_domain_is_off(const power_manager_t *power_manager); - -uint32_t ram_block_power_domain_is_off(const power_manager_t *power_manager, uint32_t sel_block); - -uint32_t external_power_domain_is_off(const power_manager_t *power_manager, uint32_t sel_external); - -monitor_signals_t monitor_power_gate_core(const power_manager_t *power_manager); - -monitor_signals_t monitor_power_gate_periph(const power_manager_t *power_manager); - -monitor_signals_t monitor_power_gate_ram_block(const power_manager_t *power_manager, uint32_t sel_block); - -monitor_signals_t monitor_power_gate_external(const power_manager_t *power_manager, uint32_t sel_external); - - -#ifdef __cplusplus -} -#endif - -#endif // _POWER_MANAGER_H_ diff --git a/sw/device/lib/drivers/power_manager/power_manager.c b/sw/device/lib/drivers/power_manager/power_manager.c index 4a9c37a85..d11452ab9 100644 --- a/sw/device/lib/drivers/power_manager/power_manager.c +++ b/sw/device/lib/drivers/power_manager/power_manager.c @@ -1,449 +1,742 @@ -// Copyright 2022 OpenHW Group -// Solderpad Hardware License, Version 2.1, see LICENSE.md for details. -// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 - -#include "power_manager.h" - -#include -#include - -#include "mmio.h" - -#include "core_v_mini_mcu.h" - -#include "power_manager_regs.h" // Generated. - -#include "x-heep.h" - - -void __attribute__ ((noinline)) power_gate_core_asm() -{ - asm volatile ( - - // write POWER_GATE_CORE[0] = 1 - "lui a0, %[base_address_20bit]\n" - "li a1, 1\n" - "sw a1, %[power_manager_power_gate_core_reg_offset](a0)\n" - - // write WAKEUP_STATE[0] = 1 - "sw a1, %[power_manager_wakeup_state_reg_offset](a0)\n" : : \ - \ - [base_address_20bit] "i" (POWER_MANAGER_START_ADDRESS >> 12), \ - [power_manager_power_gate_core_reg_offset] "i" (POWER_MANAGER_POWER_GATE_CORE_REG_OFFSET), \ - [power_manager_wakeup_state_reg_offset] "i" (POWER_MANAGER_WAKEUP_STATE_REG_OFFSET) : "a0", "a1" \ - ); - - asm volatile ( - - // write registers - "la a0, __power_manager_start\n" - "sw x1, 0(a0)\n" - "sw x2, 4(a0)\n" - "sw x3, 8(a0)\n" - "sw x4, 12(a0)\n" - "sw x5, 16(a0)\n" - "sw x6, 20(a0)\n" - "sw x7, 24(a0)\n" - "sw x8, 28(a0)\n" - "sw x9, 32(a0)\n" - "sw x10, 36(a0)\n" - "sw x11, 40(a0)\n" - "sw x12, 44(a0)\n" - "sw x13, 48(a0)\n" - "sw x14, 52(a0)\n" - "sw x15, 56(a0)\n" - "sw x16, 60(a0)\n" - "sw x17, 64(a0)\n" - "sw x18, 68(a0)\n" - "sw x19, 72(a0)\n" - "sw x20, 76(a0)\n" - "sw x21, 80(a0)\n" - "sw x22, 88(a0)\n" - "sw x23, 92(a0)\n" - "sw x24, 96(a0)\n" - "sw x25, 100(a0)\n" - "sw x26, 104(a0)\n" - "sw x27, 108(a0)\n" - "sw x28, 112(a0)\n" - "sw x29, 116(a0)\n" - "sw x30, 120(a0)\n" - "sw x31, 124(a0)\n" - //csr - "csrr a1, mstatus\n" - "sw a1, 128(a0)\n" - "csrr a1, mie\n" - "sw a1, 132(a0)\n" - "csrr a1, mtvec\n" - "sw a1, 136(a0)\n" - "csrr a1, mscratch\n" - "sw a1, 140(a0)\n" - "csrr a1, mepc\n" - "sw a1, 144(a0)\n" - "csrr a1, mcause\n" - "sw a1, 148(a0)\n" - "csrr a1, mtval\n" - "sw a1, 152(a0)\n" - "csrr a1, mcycle\n" - "sw a1, 156(a0)\n" - "csrr a1, minstret\n" - "sw a1, 160(a0)\n" : : : "a0", "a1" \ - ); - - asm volatile ( - - // write RESTORE_ADDRESS[31:0] = PC - "lui a0, %[base_address_20bit]\n" - "la a1, wakeup\n" - "sw a1, %[power_manager_restore_address_reg_offset](a0)\n" - - // wait for interrupt - "wfi\n" - - // ---------------------------- - // power-gate - // ---------------------------- - - // ---------------------------- - // wake-up - // ---------------------------- - - // write POWER_GATE_CORE[0] = 0 - "wakeup:" - "lui a0, %[base_address_20bit]\n" - "sw x0, %[power_manager_power_gate_core_reg_offset](a0)\n" - - // write WAKEUP_STATE[0] = 0 - "sw x0, %[power_manager_wakeup_state_reg_offset](a0)\n" - - // write RESTORE_ADDRESS[31:0] = 0 - "sw x0, %[power_manager_restore_address_reg_offset](a0)\n" : : \ - \ - [base_address_20bit] "i" (POWER_MANAGER_START_ADDRESS >> 12), \ - [power_manager_power_gate_core_reg_offset] "i" (POWER_MANAGER_POWER_GATE_CORE_REG_OFFSET), \ - [power_manager_wakeup_state_reg_offset] "i" (POWER_MANAGER_WAKEUP_STATE_REG_OFFSET), \ - [power_manager_restore_address_reg_offset] "i" (POWER_MANAGER_RESTORE_ADDRESS_REG_OFFSET) : "a0", "a1" \ - ); - - asm volatile ( - - // write CORE_REG_Xn[31:0] = Xn - "la a0, __power_manager_start\n" - //one of the following load is gonna overwrite a0, but a0 was already stored before to the right value - "lw x1, 0(a0)\n" - "lw x2, 4(a0)\n" - "lw x3, 8(a0)\n" - "lw x4, 12(a0)\n" - "lw x5, 16(a0)\n" - "lw x6, 20(a0)\n" - "lw x7, 24(a0)\n" - "lw x8, 28(a0)\n" - "lw x9, 32(a0)\n" - "lw x10, 36(a0)\n" - "lw x11, 40(a0)\n" - "lw x12, 44(a0)\n" - "lw x13, 48(a0)\n" - "lw x14, 52(a0)\n" - "lw x15, 56(a0)\n" - "lw x16, 60(a0)\n" - "lw x17, 64(a0)\n" - "lw x18, 68(a0)\n" - "lw x19, 72(a0)\n" - "lw x20, 76(a0)\n" - "lw x21, 80(a0)\n" - "lw x22, 88(a0)\n" - "lw x23, 92(a0)\n" - "lw x24, 96(a0)\n" - "lw x25, 100(a0)\n" - "lw x26, 104(a0)\n" - "lw x27, 108(a0)\n" - "lw x28, 112(a0)\n" - "lw x29, 116(a0)\n" - "lw x30, 120(a0)\n" - "lw x31, 124(a0)\n" - //csr - "lw a1, 128(a0)\n" - "csrw mstatus, a1\n" - "lw a1, 132(a0)\n" - "csrw mie, a1\n" - "lw a1, 136(a0)\n" - "csrw mtvec, a1\n" - "lw a1, 140(a0)\n" - "csrw mscratch, a1\n" - "lw a1, 144(a0)\n" - "csrw mepc, a1\n" - "lw a1, 148(a0)\n" - "csrw mcause, a1\n" - "lw a1, 152(a0)\n" - "csrw mtval, a1\n" - "lw a1, 156(a0)\n" - "csrw mcycle, a1\n" - "lw a1, 160(a0)\n" - "csrw minstret, a1\n": : : "a0", "a1" \ - ); - - return; -} - -power_manager_result_t __attribute__ ((noinline)) power_gate_core(const power_manager_t *power_manager, power_manager_sel_intr_t sel_intr, power_manager_counters_t* cpu_counter) -{ - uint32_t reg = 0; - - // set counters - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(POWER_MANAGER_CPU_RESET_ASSERT_COUNTER_REG_OFFSET), cpu_counter->reset_off); - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(POWER_MANAGER_CPU_RESET_DEASSERT_COUNTER_REG_OFFSET), cpu_counter->reset_on); - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(POWER_MANAGER_CPU_SWITCH_OFF_COUNTER_REG_OFFSET), cpu_counter->switch_off); - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(POWER_MANAGER_CPU_SWITCH_ON_COUNTER_REG_OFFSET), cpu_counter->switch_on); - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(POWER_MANAGER_CPU_ISO_OFF_COUNTER_REG_OFFSET), cpu_counter->iso_off); - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(POWER_MANAGER_CPU_ISO_ON_COUNTER_REG_OFFSET), cpu_counter->iso_on); - - // enable wakeup timers - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(POWER_MANAGER_EN_WAIT_FOR_INTR_REG_OFFSET), 1 << sel_intr); - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(POWER_MANAGER_INTR_STATE_REG_OFFSET), 0x0); - - // enable wait for SWITCH ACK - #ifdef TARGET_PYNQ_Z2 - reg = bitfield_bit32_write(reg, POWER_MANAGER_CPU_WAIT_ACK_SWITCH_ON_COUNTER_CPU_WAIT_ACK_SWITCH_ON_COUNTER_BIT, 0x0); - #else - reg = bitfield_bit32_write(reg, POWER_MANAGER_CPU_WAIT_ACK_SWITCH_ON_COUNTER_CPU_WAIT_ACK_SWITCH_ON_COUNTER_BIT, 0x1); - #endif - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(POWER_MANAGER_CPU_WAIT_ACK_SWITCH_ON_COUNTER_REG_OFFSET), reg); - - power_gate_core_asm(); - - // clean up states - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(POWER_MANAGER_EN_WAIT_FOR_INTR_REG_OFFSET), 0x0); - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(POWER_MANAGER_INTR_STATE_REG_OFFSET), 0x0); - - // stop counters - reg = 0; - reg = bitfield_bit32_write(reg, POWER_MANAGER_CPU_COUNTERS_STOP_CPU_RESET_ASSERT_STOP_BIT_COUNTER_BIT, true); - reg = bitfield_bit32_write(reg, POWER_MANAGER_CPU_COUNTERS_STOP_CPU_RESET_DEASSERT_STOP_BIT_COUNTER_BIT, true); - reg = bitfield_bit32_write(reg, POWER_MANAGER_CPU_COUNTERS_STOP_CPU_SWITCH_OFF_STOP_BIT_COUNTER_BIT, true); - reg = bitfield_bit32_write(reg, POWER_MANAGER_CPU_COUNTERS_STOP_CPU_SWITCH_ON_STOP_BIT_COUNTER_BIT, true); - reg = bitfield_bit32_write(reg, POWER_MANAGER_CPU_COUNTERS_STOP_CPU_ISO_OFF_STOP_BIT_COUNTER_BIT, true); - reg = bitfield_bit32_write(reg, POWER_MANAGER_CPU_COUNTERS_STOP_CPU_ISO_ON_STOP_BIT_COUNTER_BIT, true); - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(POWER_MANAGER_CPU_COUNTERS_STOP_REG_OFFSET), reg); - - return kPowerManagerOk_e; -} - -power_manager_result_t __attribute__ ((noinline)) power_gate_periph(const power_manager_t *power_manager, power_manager_sel_state_t sel_state, power_manager_counters_t* periph_counters) -{ - uint32_t reg = 0; - - #ifdef TARGET_PYNQ_Z2 - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(POWER_MANAGER_PERIPH_WAIT_ACK_SWITCH_ON_REG_OFFSET), 0x0); - #else - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(POWER_MANAGER_PERIPH_WAIT_ACK_SWITCH_ON_REG_OFFSET), 0x1); - #endif - - if (sel_state == kOn_e) - { - for (int i=0; iswitch_on; i++) asm volatile ("nop\n;"); - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(POWER_MANAGER_PERIPH_SWITCH_REG_OFFSET), 0x0); - for (int i=0; iiso_off; i++) asm volatile ("nop\n;"); - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(POWER_MANAGER_PERIPH_ISO_REG_OFFSET), 0x0); - for (int i=0; ireset_off; i++) asm volatile ("nop\n;"); - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(POWER_MANAGER_PERIPH_RESET_REG_OFFSET), 0x0); - } - else - { - for (int i=0; iiso_on; i++) asm volatile ("nop\n;"); - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(POWER_MANAGER_PERIPH_ISO_REG_OFFSET), 0x1); - for (int i=0; iswitch_off; i++) asm volatile ("nop\n;"); - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(POWER_MANAGER_PERIPH_SWITCH_REG_OFFSET), 0x1); - for (int i=0; ireset_on; i++) asm volatile ("nop\n;"); - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(POWER_MANAGER_PERIPH_RESET_REG_OFFSET), 0x1); - } - - return kPowerManagerOk_e; -} - -power_manager_result_t __attribute__ ((noinline)) power_gate_ram_block(const power_manager_t *power_manager, uint32_t sel_block, power_manager_sel_state_t sel_state, power_manager_counters_t* ram_block_counters) -{ - uint32_t reg = 0; - - if (sel_state == kOn_e) - { - #ifdef TARGET_PYNQ_Z2 - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_ram_map[sel_block].wait_ack_switch), 0x0); - #else - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_ram_map[sel_block].wait_ack_switch), 0x1); - #endif - for (int i=0; iswitch_on; i++) asm volatile ("nop\n;"); - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_ram_map[sel_block].switch_off), 0x0); - for (int i=0; iiso_off; i++) asm volatile ("nop\n;"); - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_ram_map[sel_block].iso), 0x0); - } - else if (sel_state == kOff_e) - { - #ifdef TARGET_PYNQ_Z2 - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_ram_map[sel_block].wait_ack_switch), 0x0); - #else - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_ram_map[sel_block].wait_ack_switch), 0x1); - #endif - for (int i=0; iiso_on; i++) asm volatile ("nop\n;"); - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_ram_map[sel_block].iso), 0x1); - for (int i=0; iswitch_off; i++) asm volatile ("nop\n;"); - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_ram_map[sel_block].switch_off), 0x1); - } - else if (sel_state == kRetOn_e) - { - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_ram_map[sel_block].wait_ack_switch), 0x0); - for (int i=0; iretentive_on; i++) asm volatile ("nop\n;"); - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_ram_map[sel_block].retentive), 0x1); - } - else - { - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_ram_map[sel_block].wait_ack_switch), 0x0); - for (int i=0; iretentive_off; i++) asm volatile ("nop\n;"); - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_ram_map[sel_block].retentive), 0x0); - } - - return kPowerManagerOk_e; -} - -power_manager_result_t __attribute__ ((noinline)) power_gate_external(const power_manager_t *power_manager, uint32_t sel_external, power_manager_sel_state_t sel_state, power_manager_counters_t* external_counters) -{ - uint32_t reg = 0; - - if (sel_state == kOn_e) - { - #ifdef TARGET_PYNQ_Z2 - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_external_map[sel_external].wait_ack_switch), 0x0); - #else - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_external_map[sel_external].wait_ack_switch), 0x1); - #endif - for (int i=0; iswitch_on; i++) asm volatile ("nop\n;"); - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_external_map[sel_external].switch_off), 0x0); - for (int i=0; iiso_off; i++) asm volatile ("nop\n;"); - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_external_map[sel_external].iso), 0x0); - for (int i=0; ireset_off; i++) asm volatile ("nop\n;"); - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_external_map[sel_external].reset), 0x0); - } - else if (sel_state == kOff_e) - { - #ifdef TARGET_PYNQ_Z2 - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_external_map[sel_external].wait_ack_switch), 0x0); - #else - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_external_map[sel_external].wait_ack_switch), 0x1); - #endif - for (int i=0; iiso_on; i++) asm volatile ("nop\n;"); - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_external_map[sel_external].iso), 0x1); - for (int i=0; iswitch_off; i++) asm volatile ("nop\n;"); - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_external_map[sel_external].switch_off), 0x1); - for (int i=0; ireset_on; i++) asm volatile ("nop\n;"); - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_external_map[sel_external].reset), 0x1); - } - else if (sel_state == kRetOn_e) - { - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_external_map[sel_external].wait_ack_switch), 0x0); - for (int i=0; iretentive_on; i++) asm volatile ("nop\n;"); - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_external_map[sel_external].retentive), 0x1); - } - else - { - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_external_map[sel_external].wait_ack_switch), 0x0); - for (int i=0; iretentive_off; i++) asm volatile ("nop\n;"); - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_external_map[sel_external].retentive), 0x0); - } - - return kPowerManagerOk_e; -} - -uint32_t periph_power_domain_is_off(const power_manager_t *power_manager) -{ - uint32_t switch_state; - - switch_state = mmio_region_read32(power_manager->base_addr, (ptrdiff_t)(POWER_MANAGER_POWER_GATE_PERIPH_ACK_REG_OFFSET)); - - return switch_state == 0; -} - -uint32_t ram_block_power_domain_is_off(const power_manager_t *power_manager, uint32_t sel_block) -{ - uint32_t switch_state; - - switch_state = mmio_region_read32(power_manager->base_addr, (ptrdiff_t)(power_manager_ram_map[sel_block].power_gate_ack)); - - return switch_state == 0; -} - -uint32_t external_power_domain_is_off(const power_manager_t *power_manager, uint32_t sel_external) -{ - uint32_t switch_state; - - switch_state = mmio_region_read32(power_manager->base_addr, (ptrdiff_t)(power_manager_external_map[sel_external].power_gate_ack)); - - return switch_state == 0; -} - -power_manager_result_t power_gate_counters_init(power_manager_counters_t* counters, uint32_t reset_off, uint32_t reset_on, uint32_t switch_off, uint32_t switch_on, uint32_t iso_off, uint32_t iso_on, uint32_t retentive_off, uint32_t retentive_on) -{ - counters->reset_off = reset_off; - counters->reset_on = reset_on; - counters->switch_off = switch_off; - counters->switch_on = switch_on; - counters->iso_off = iso_off; - counters->iso_on = iso_on; - counters->retentive_off = retentive_off; - counters->retentive_on = retentive_on; - - return kPowerManagerOk_e; -} - -monitor_signals_t monitor_power_gate_core(const power_manager_t *power_manager) -{ - uint32_t reg = 0; - monitor_signals_t monitor_signals; - - reg = mmio_region_read32(power_manager->base_addr, (ptrdiff_t)POWER_MANAGER_MONITOR_POWER_GATE_CORE_REG_OFFSET); - - monitor_signals.kSwitch_e = reg & 0x1; - monitor_signals.kIso_e = (reg & 0x2) >> 1; - monitor_signals.kReset_e = (reg & 0x4) >> 2; - - return monitor_signals; -} - -monitor_signals_t monitor_power_gate_periph(const power_manager_t *power_manager) -{ - uint32_t reg = 0; - monitor_signals_t monitor_signals; - - reg = mmio_region_read32(power_manager->base_addr, (ptrdiff_t)POWER_MANAGER_MONITOR_POWER_GATE_PERIPH_REG_OFFSET); - - monitor_signals.kSwitch_e = reg & 0x1; - monitor_signals.kIso_e = (reg & 0x2) >> 1; - monitor_signals.kReset_e = (reg & 0x4) >> 2; - - return monitor_signals; -} - -monitor_signals_t monitor_power_gate_ram_block(const power_manager_t *power_manager, uint32_t sel_block) -{ - uint32_t reg = 0; - monitor_signals_t monitor_signals; - - reg = mmio_region_read32(power_manager->base_addr, (ptrdiff_t)(power_manager_ram_map[sel_block].monitor_power_gate)); - - monitor_signals.kSwitch_e = reg & 0x1; - monitor_signals.kIso_e = (reg & 0x2) >> 1; - monitor_signals.kReset_e = 0x1; - - return monitor_signals; -} - -monitor_signals_t monitor_power_gate_external(const power_manager_t *power_manager, uint32_t sel_external) -{ - uint32_t reg = 0; - monitor_signals_t monitor_signals; - - reg = mmio_region_read32(power_manager->base_addr, (ptrdiff_t)(power_manager_external_map[sel_external].monitor_power_gate)); - - monitor_signals.kSwitch_e = reg & 0x1; - monitor_signals.kIso_e = (reg & 0x2) >> 1; - monitor_signals.kReset_e = (reg & 0x4) >> 2; - - return monitor_signals; -} +/* + ******************* +******************************* C SOURCE FILE ******************************* +** ******************* ** +** ** +** project : X-HEEP ** +** filename : power_manager.c ** +** version : 1 ** +** date : 22/08/23 ** +** ** +***************************************************************************** +** ** +** Copyright (c) EPFL contributors. ** +** All rights reserved. ** +** ** +***************************************************************************** + +VERSION HISTORY: +---------------- +Version : 1 +Date : -/-/- +Revised by : - +Description : Original version + +*/ + +/***************************************************************************/ +/***************************************************************************/ + +/** +* @file power_manager.c +* @date 22/08/23 +* @brief The Power Manager driver to set up and use the power manager +* peripheral +* +* X-HEEP power domains (take from paper) +*/ + +/****************************************************************************/ +/** **/ +/* MODULES USED */ +/** **/ +/****************************************************************************/ + +#include "power_manager.h" // Generated + +#include "bitfield.h" + +#include "power_manager_regs.h" // Generated + +#include "x-heep.h" + +/****************************************************************************/ +/** **/ +/* DEFINITIONS AND MACROS */ +/** **/ +/****************************************************************************/ + +/****************************************************************************/ +/** **/ +/* TYPEDEFS AND STRUCTURES */ +/** **/ +/****************************************************************************/ + +/** + * + * + * + */ +typedef struct power_manager_counters { + /** + * The counter to set and unset the reset and switch of the CPU. + */ + uint32_t reset_off; + /** + * + * + * + */ + uint32_t reset_on; + /** + * + * + * + */ + uint32_t switch_off; + /** + * + * + * + */ + uint32_t switch_on; + /** + * + * + * + */ + uint32_t iso_off; + /** + * + * + * + */ + uint32_t iso_on; + /** + * + * + * + */ + uint32_t retentive_off; + /** + * + * + * + */ + uint32_t retentive_on; +} power_manager_counters_t; + +/** + * @todo completely wrong, copy paste from DMA + * Interrupts must be enabled in the INTERRUPT register of the DMA. + * Only one at a time. In case more than one is interrupt is to be triggered, + * at the same time (last byte of a transaction of size multiple of the window + * size) only the lowest ID is triggered. + */ +typedef enum +{ + INTR_EN_NONE = 0x0, /*!< No interrupts should be triggered. */ + INTR_EN_TRANS_DONE = 0x1, /*!< The TRANS_DONE interrupt is a fast + interrupt that is triggered once the whole transaction has finished. */ + INTR_EN_WINDOW_DONE = 0x2, /*!< The WINDOW_DONE interrupt is a PLIC + interrupt that is triggered every given number of bytes (set in the + transaction configuration as win_du). */ + INTR_EN__size, +} inter_en_t; + +/****************************************************************************/ +/** **/ +/* PROTOTYPES OF LOCAL FUNCTIONS */ +/** **/ +/****************************************************************************/ + +/****************************************************************************/ +/** **/ +/* EXPORTED VARIABLES */ +/** **/ +/****************************************************************************/ + +/****************************************************************************/ +/** **/ +/* GLOBAL VARIABLES */ +/** **/ +/****************************************************************************/ + +/** + * Control Block (CB) of the power manager peripheral. + * Has variables and constant necessary/useful for its control. + */ +static struct +{ + /** + * Flag to lower as soon as a transaction is launched, and raised by the + * interrupt handler once it has finished. Only used when the end event is + * set to INTR_WAIT. + */ + uint8_t intrFlag; + + /** + * memory mapped structure of a power manager. + */ + power_manager *peri; + + /** + * memory mapped structure of a power manager. + */ + power_manager_counters_t counters; + +}power_manager_cb; + +/****************************************************************************/ +/** **/ +/* EXPORTED FUNCTIONS */ +/** **/ +/****************************************************************************/ + +void power_manager_init( power_manager *peri ) +{ + /* + * If a power_manager peripheral was provided, use that one, otherwise use the + * integrated one. + */ + power_manager_cb.peri = peri ? peri : power_manager_peri; + + /* Clear all values in the power_manager registers. */ + /** + * @todo check register initializaton + * */ + // power_manager_cb.peri->WAKEUP_STATE = 0; + // power_manager_cb.peri->RESTORE_ADDRESS = 0; + // power_manager_cb.peri->EN_WAIT_FOR_INTR = 0; + // power_manager_cb.peri->INTR_STATE = 0; + // power_manager_cb.peri->POWER_GATE_CORE = 0; + // power_manager_cb.peri->POWER_GATE_CORE_ACK = 0; + // power_manager_cb.peri->CPU_RESET_ASSERT_COUNTER = 0; + // power_manager_cb.peri->CPU_RESET_DEASSERT_COUNTER = 0; + // power_manager_cb.peri->CPU_SWITCH_OFF_COUNTER = 0; + // power_manager_cb.peri->CPU_SWITCH_ON_COUNTER = 0; + // power_manager_cb.peri->CPU_WAIT_ACK_SWITCH_ON_COUNTER = 0; + // power_manager_cb.peri->CPU_ISO_OFF_COUNTER = 0; + // power_manager_cb.peri->CPU_ISO_ON_COUNTER = 0; + // power_manager_cb.peri->CPU_COUNTERS_STOP = 0; + // power_manager_cb.peri->POWER_GATE_PERIPH_ACK = 0; + // power_manager_cb.peri->PERIPH_RESET = 0; + // power_manager_cb.peri->PERIPH_SWITCH = 0; + // power_manager_cb.peri->PERIPH_WAIT_ACK_SWITCH_ON = 0; + // power_manager_cb.peri->PERIPH_ISO = 0; + // power_manager_cb.peri->PERIPH_CLK_GATE = 0; + // power_manager_cb.peri->RAM_0_CLK_GATE = 0; + // power_manager_cb.peri->POWER_GATE_RAM_BLOCK_0_ACK = 0; + // power_manager_cb.peri->RAM_0_SWITCH = 0; + // power_manager_cb.peri->RAM_0_WAIT_ACK_SWITCH_ON = 0; + // power_manager_cb.peri->RAM_0_ISO = 0; + // power_manager_cb.peri->RAM_0_RETENTIVE = 0; + // power_manager_cb.peri->RAM_1_CLK_GATE = 0; + // power_manager_cb.peri->POWER_GATE_RAM_BLOCK_1_ACK = 0; + // power_manager_cb.peri->RAM_1_SWITCH = 0; + // power_manager_cb.peri->RAM_1_WAIT_ACK_SWITCH_ON = 0; + // power_manager_cb.peri->RAM_1_ISO = 0; + // power_manager_cb.peri->RAM_1_RETENTIVE = 0; + // power_manager_cb.peri->MONITOR_POWER_GATE_CORE = 0; + // power_manager_cb.peri->MONITOR_POWER_GATE_PERIPH = 0; + // power_manager_cb.peri->MONITOR_POWER_GATE_RAM_BLOCK_0 = 0; + // power_manager_cb.peri->MONITOR_POWER_GATE_RAM_BLOCK_1 = 0; + // power_manager_cb.peri->MASTER_CPU_FORCE_SWITCH_OFF = 0; + // power_manager_cb.peri->MASTER_CPU_FORCE_SWITCH_ON = 0; + // power_manager_cb.peri->MASTER_CPU_FORCE_RESET_ASSERT = 0; + // power_manager_cb.peri->MASTER_CPU_FORCE_RESET_DEASSERT = 0; + // power_manager_cb.peri->MASTER_CPU_FORCE_ISO_OFF = 0; + // power_manager_cb.peri->MASTER_CPU_FORCE_ISO_ON = 0; +} + +power_manager_result_t __attribute__ ((noinline)) clock_gate_periph(power_manager_sel_state_t sel_state){ + if (sel_state == kOn_e) + { + power_manager_cb.peri->PERIPH_CLK_GATE = 0x0; + } + else + { + power_manager_cb.peri->PERIPH_CLK_GATE = 0x1; + } + + return kPowerManagerOk_e; +} + +power_manager_result_t __attribute__ ((noinline)) clock_gate_ram_block(uint32_t sel_block, power_manager_sel_state_t sel_state){ + if (sel_state == kOn_e) + { + *((uint32_t *)&power_manager_cb.peri->RAM_0_CLK_GATE + sel_block*6) = 0x0; + } + else + { + *((uint32_t *)&power_manager_cb.peri->RAM_0_CLK_GATE + sel_block*6) = 0x1; + } + + return kPowerManagerOk_e; +} + +power_manager_result_t __attribute__ ((noinline)) clock_gate_external(uint32_t sel_external, power_manager_sel_state_t sel_state){ + + if (sel_external >= EXTERNAL_DOMAINS){ + // Sanity check on the number of external domains available. Return with an error if the external domain accessed is greater than the number of external domains avaliable + return kPowerManagerError_e; + }else{ + #if EXTERNAL_DOMAINS > 0 + + if (sel_state == kOn_e) + { + *((uint32_t *)&power_manager_cb.peri->EXTERNAL_0_CLK_GATE + sel_external*7) = 0x0; + } + else + { + *((uint32_t *)&power_manager_cb.peri->EXTERNAL_0_CLK_GATE + sel_external*7) = 0x1; + } + + #endif + } + + return kPowerManagerOk_e; +} + +void __attribute__ ((noinline)) power_gate_core_asm() +{ + asm volatile ( + + // write POWER_GATE_CORE[0] = 1 + "lui a0, %[base_address_20bit]\n" + "li a1, 1\n" + "sw a1, %[power_manager_power_gate_core_reg_offset](a0)\n" + + // write WAKEUP_STATE[0] = 1 + "sw a1, %[power_manager_wakeup_state_reg_offset](a0)\n" : : \ + \ + [base_address_20bit] "i" (POWER_MANAGER_START_ADDRESS >> 12), \ + [power_manager_power_gate_core_reg_offset] "i" (POWER_MANAGER_POWER_GATE_CORE_REG_OFFSET), \ + [power_manager_wakeup_state_reg_offset] "i" (POWER_MANAGER_WAKEUP_STATE_REG_OFFSET) : "a0", "a1" \ + ); + + asm volatile ( + + // write registers + "la a0, __power_manager_start\n" + "sw x1, 0(a0)\n" + "sw x2, 4(a0)\n" + "sw x3, 8(a0)\n" + "sw x4, 12(a0)\n" + "sw x5, 16(a0)\n" + "sw x6, 20(a0)\n" + "sw x7, 24(a0)\n" + "sw x8, 28(a0)\n" + "sw x9, 32(a0)\n" + "sw x10, 36(a0)\n" + "sw x11, 40(a0)\n" + "sw x12, 44(a0)\n" + "sw x13, 48(a0)\n" + "sw x14, 52(a0)\n" + "sw x15, 56(a0)\n" + "sw x16, 60(a0)\n" + "sw x17, 64(a0)\n" + "sw x18, 68(a0)\n" + "sw x19, 72(a0)\n" + "sw x20, 76(a0)\n" + "sw x21, 80(a0)\n" + "sw x22, 88(a0)\n" + "sw x23, 92(a0)\n" + "sw x24, 96(a0)\n" + "sw x25, 100(a0)\n" + "sw x26, 104(a0)\n" + "sw x27, 108(a0)\n" + "sw x28, 112(a0)\n" + "sw x29, 116(a0)\n" + "sw x30, 120(a0)\n" + "sw x31, 124(a0)\n" + //csr + "csrr a1, mstatus\n" + "sw a1, 128(a0)\n" + "csrr a1, mie\n" + "sw a1, 132(a0)\n" + "csrr a1, mtvec\n" + "sw a1, 136(a0)\n" + "csrr a1, mscratch\n" + "sw a1, 140(a0)\n" + "csrr a1, mepc\n" + "sw a1, 144(a0)\n" + "csrr a1, mcause\n" + "sw a1, 148(a0)\n" + "csrr a1, mtval\n" + "sw a1, 152(a0)\n" + "csrr a1, mcycle\n" + "sw a1, 156(a0)\n" + "csrr a1, minstret\n" + "sw a1, 160(a0)\n" : : : "a0", "a1" \ + ); + + asm volatile ( + + // write RESTORE_ADDRESS[31:0] = PC + "lui a0, %[base_address_20bit]\n" + "la a1, wakeup\n" + "sw a1, %[power_manager_restore_address_reg_offset](a0)\n" + + // wait for interrupt + "wfi\n" + + // ---------------------------- + // power-gate + // ---------------------------- + + // ---------------------------- + // wake-up + // ---------------------------- + + // write POWER_GATE_CORE[0] = 0 + "wakeup:" + "lui a0, %[base_address_20bit]\n" + "sw x0, %[power_manager_power_gate_core_reg_offset](a0)\n" + + // write WAKEUP_STATE[0] = 0 + "sw x0, %[power_manager_wakeup_state_reg_offset](a0)\n" + + // write RESTORE_ADDRESS[31:0] = 0 + "sw x0, %[power_manager_restore_address_reg_offset](a0)\n" : : \ + \ + [base_address_20bit] "i" (POWER_MANAGER_START_ADDRESS >> 12), \ + [power_manager_power_gate_core_reg_offset] "i" (POWER_MANAGER_POWER_GATE_CORE_REG_OFFSET), \ + [power_manager_wakeup_state_reg_offset] "i" (POWER_MANAGER_WAKEUP_STATE_REG_OFFSET), \ + [power_manager_restore_address_reg_offset] "i" (POWER_MANAGER_RESTORE_ADDRESS_REG_OFFSET) : "a0", "a1" \ + ); + + asm volatile ( + + // write CORE_REG_Xn[31:0] = Xn + "la a0, __power_manager_start\n" + //one of the following load is gonna overwrite a0, but a0 was already stored before to the right value + "lw x1, 0(a0)\n" + "lw x2, 4(a0)\n" + "lw x3, 8(a0)\n" + "lw x4, 12(a0)\n" + "lw x5, 16(a0)\n" + "lw x6, 20(a0)\n" + "lw x7, 24(a0)\n" + "lw x8, 28(a0)\n" + "lw x9, 32(a0)\n" + "lw x10, 36(a0)\n" + "lw x11, 40(a0)\n" + "lw x12, 44(a0)\n" + "lw x13, 48(a0)\n" + "lw x14, 52(a0)\n" + "lw x15, 56(a0)\n" + "lw x16, 60(a0)\n" + "lw x17, 64(a0)\n" + "lw x18, 68(a0)\n" + "lw x19, 72(a0)\n" + "lw x20, 76(a0)\n" + "lw x21, 80(a0)\n" + "lw x22, 88(a0)\n" + "lw x23, 92(a0)\n" + "lw x24, 96(a0)\n" + "lw x25, 100(a0)\n" + "lw x26, 104(a0)\n" + "lw x27, 108(a0)\n" + "lw x28, 112(a0)\n" + "lw x29, 116(a0)\n" + "lw x30, 120(a0)\n" + "lw x31, 124(a0)\n" + //csr + "lw a1, 128(a0)\n" + "csrw mstatus, a1\n" + "lw a1, 132(a0)\n" + "csrw mie, a1\n" + "lw a1, 136(a0)\n" + "csrw mtvec, a1\n" + "lw a1, 140(a0)\n" + "csrw mscratch, a1\n" + "lw a1, 144(a0)\n" + "csrw mepc, a1\n" + "lw a1, 148(a0)\n" + "csrw mcause, a1\n" + "lw a1, 152(a0)\n" + "csrw mtval, a1\n" + "lw a1, 156(a0)\n" + "csrw mcycle, a1\n" + "lw a1, 160(a0)\n" + "csrw minstret, a1\n": : : "a0", "a1" \ + ); + + return; +} + +power_manager_result_t __attribute__ ((noinline)) power_gate_core(power_manager_sel_intr_t sel_intr) +{ + // set counters + power_manager_cb.peri->CPU_RESET_ASSERT_COUNTER = power_manager_cb.counters.reset_off; + power_manager_cb.peri->CPU_RESET_DEASSERT_COUNTER = power_manager_cb.counters.reset_on; + power_manager_cb.peri->CPU_SWITCH_OFF_COUNTER = power_manager_cb.counters.switch_off; + power_manager_cb.peri->CPU_SWITCH_ON_COUNTER = power_manager_cb.counters.switch_on; + power_manager_cb.peri->CPU_ISO_OFF_COUNTER = power_manager_cb.counters.iso_off; + power_manager_cb.peri->CPU_ISO_ON_COUNTER = power_manager_cb.counters.iso_on; + + // enable wakeup timers + power_manager_cb.peri->EN_WAIT_FOR_INTR = 1 << sel_intr; + power_manager_cb.peri->INTR_STATE = 0x0; + + // enable wait for SWITCH ACK + #ifdef TARGET_PYNQ_Z2 + power_manager_cb.peri->CPU_WAIT_ACK_SWITCH_ON_COUNTER = bitfield_bit32_write(power_manager_cb.peri->CPU_WAIT_ACK_SWITCH_ON_COUNTER, POWER_MANAGER_CPU_WAIT_ACK_SWITCH_ON_COUNTER_CPU_WAIT_ACK_SWITCH_ON_COUNTER_BIT, false); + #else + power_manager_cb.peri->CPU_WAIT_ACK_SWITCH_ON_COUNTER = bitfield_bit32_write(power_manager_cb.peri->CPU_WAIT_ACK_SWITCH_ON_COUNTER, POWER_MANAGER_CPU_WAIT_ACK_SWITCH_ON_COUNTER_CPU_WAIT_ACK_SWITCH_ON_COUNTER_BIT, true); + #endif + + asm volatile ("nop\n;"); // Necessary in SIM to swith on/off the ack signal + power_gate_core_asm(); + + // clean up states + power_manager_cb.peri->EN_WAIT_FOR_INTR = 0x0; + power_manager_cb.peri->INTR_STATE = 0x0; + + // stop counters + power_manager_cb.peri->CPU_COUNTERS_STOP = bitfield_bit32_write(power_manager_cb.peri->CPU_COUNTERS_STOP, POWER_MANAGER_CPU_COUNTERS_STOP_CPU_RESET_ASSERT_STOP_BIT_COUNTER_BIT, true); + power_manager_cb.peri->CPU_COUNTERS_STOP = bitfield_bit32_write(power_manager_cb.peri->CPU_COUNTERS_STOP, POWER_MANAGER_CPU_COUNTERS_STOP_CPU_RESET_DEASSERT_STOP_BIT_COUNTER_BIT, true); + power_manager_cb.peri->CPU_COUNTERS_STOP = bitfield_bit32_write(power_manager_cb.peri->CPU_COUNTERS_STOP, POWER_MANAGER_CPU_COUNTERS_STOP_CPU_SWITCH_OFF_STOP_BIT_COUNTER_BIT, true); + power_manager_cb.peri->CPU_COUNTERS_STOP = bitfield_bit32_write(power_manager_cb.peri->CPU_COUNTERS_STOP, POWER_MANAGER_CPU_COUNTERS_STOP_CPU_SWITCH_ON_STOP_BIT_COUNTER_BIT, true); + power_manager_cb.peri->CPU_COUNTERS_STOP = bitfield_bit32_write(power_manager_cb.peri->CPU_COUNTERS_STOP, POWER_MANAGER_CPU_COUNTERS_STOP_CPU_ISO_OFF_STOP_BIT_COUNTER_BIT, true); + power_manager_cb.peri->CPU_COUNTERS_STOP = bitfield_bit32_write(power_manager_cb.peri->CPU_COUNTERS_STOP, POWER_MANAGER_CPU_COUNTERS_STOP_CPU_ISO_ON_STOP_BIT_COUNTER_BIT, true); + + return kPowerManagerOk_e; +} + +power_manager_result_t __attribute__ ((noinline)) power_gate_periph(power_manager_sel_state_t sel_state) +{ + #ifdef TARGET_PYNQ_Z2 + power_manager_cb.peri->PERIPH_WAIT_ACK_SWITCH_ON = 0x0; + #else + power_manager_cb.peri->PERIPH_WAIT_ACK_SWITCH_ON = 0x1; + #endif + + if (sel_state == kOn_e) + { + for (int i=0; iPERIPH_SWITCH = 0x0; + for (int i=0; iPERIPH_ISO = 0x0; + for (int i=0; iPERIPH_RESET = 0x0; + } + else + { + for (int i=0; iPERIPH_ISO = 0x1; + for (int i=0; iPERIPH_SWITCH = 0x1; + for (int i=0; iPERIPH_RESET = 0x1; + } + + return kPowerManagerOk_e; +} + +power_manager_result_t __attribute__ ((noinline)) power_gate_ram_block(uint32_t sel_block, power_manager_sel_state_t sel_state) +{ + if (sel_block >= MEMORY_BANKS){ + // Sanity check on the number of banks available. Return with an error if the bank accessed is greater than the number of banks avaliable + return kPowerManagerError_e; + }else{ + if (sel_state == kOn_e) + { + #ifdef TARGET_PYNQ_Z2 + *((uint32_t *)&power_manager_cb.peri->RAM_0_WAIT_ACK_SWITCH_ON + sel_block*6) = 0x0; + #else + *((uint32_t *)&power_manager_cb.peri->RAM_0_WAIT_ACK_SWITCH_ON + sel_block*6) = 0x1; + #endif + for (int i=0; iRAM_0_SWITCH + sel_block*6) = 0x0; + for (int i=0; iRAM_0_ISO + sel_block*6) = 0x0; + } + else if (sel_state == kOff_e) + { + #ifdef TARGET_PYNQ_Z2 + *((uint32_t *)&power_manager_cb.peri->RAM_0_WAIT_ACK_SWITCH_ON + sel_block*6) = 0x0; + #else + *((uint32_t *)&power_manager_cb.peri->RAM_0_WAIT_ACK_SWITCH_ON + sel_block*6) = 0x1; + #endif + for (int i=0; iRAM_0_ISO + sel_block*6) = 0x1; + for (int i=0; iRAM_0_SWITCH + sel_block*6) = 0x1; + } + else if (sel_state == kRetOn_e) + { + *((uint32_t *)&power_manager_cb.peri->RAM_0_WAIT_ACK_SWITCH_ON + sel_block*6) = 0x0; + for (int i=0; iRAM_0_RETENTIVE + sel_block*6) = 0x1; + } + else + { + *((uint32_t *)&power_manager_cb.peri->RAM_0_WAIT_ACK_SWITCH_ON + sel_block*6) = 0x0; + for (int i=0; iRAM_0_RETENTIVE + sel_block*6) = 0x0; + } + + return kPowerManagerOk_e; + } + +} + +power_manager_result_t __attribute__ ((noinline)) power_gate_external(uint32_t sel_external, power_manager_sel_state_t sel_state) +{ + if (sel_external >= EXTERNAL_DOMAINS){ + // Sanity check on the number of external domains available. Return with an error if the external domain accessed is greater than the number of external domains avaliable + return kPowerManagerError_e; + }else{ + #if EXTERNAL_DOMAINS > 0 + + if (sel_state == kOn_e) + { + #ifdef TARGET_PYNQ_Z2 + *((uint32_t *)&power_manager_cb.peri->EXTERNAL_0_WAIT_ACK_SWITCH_ON + sel_external*7) = 0x0; + #else + *((uint32_t *)&power_manager_cb.peri->EXTERNAL_0_WAIT_ACK_SWITCH_ON + sel_external*7) = 0x1; + #endif + for (int i=0; iEXTERNAL_0_SWITCH + sel_external*7) = 0x0; + for (int i=0; iEXTERNAL_0_ISO + sel_external*7) = 0x0; + for (int i=0; iEXTERNAL_0_RESET + sel_external*7) = 0x0; + } + else if (sel_state == kOff_e) + { + #ifdef TARGET_PYNQ_Z2 + *((uint32_t *)&power_manager_cb.peri->EXTERNAL_0_WAIT_ACK_SWITCH_ON + sel_external*7) = 0x0; + #else + *((uint32_t *)&power_manager_cb.peri->EXTERNAL_0_WAIT_ACK_SWITCH_ON + sel_external*7) = 0x1; + #endif + for (int i=0; iEXTERNAL_0_ISO + sel_external*7) = 0x1; + for (int i=0; iEXTERNAL_0_SWITCH + sel_external*7) = 0x1; + for (int i=0; iEXTERNAL_0_RESET + sel_external*7) = 0x1; + } + else if (sel_state == kRetOn_e) + { + *((uint32_t *)&power_manager_cb.peri->EXTERNAL_0_WAIT_ACK_SWITCH_ON + sel_external*7) = 0x0; + for (int i=0; iEXTERNAL_RAM_0_RETENTIVE + sel_external*7) = 0x1; + } + else + { + *((uint32_t *)&power_manager_cb.peri->EXTERNAL_0_WAIT_ACK_SWITCH_ON + sel_external*7) = 0x0; + for (int i=0; iEXTERNAL_RAM_0_RETENTIVE + sel_external*7) = 0x0; + } + + return kPowerManagerOk_e; + + #endif + } +} + +uint32_t periph_power_domain_is_off() +{ + uint32_t switch_state; + + switch_state = power_manager_cb.peri->POWER_GATE_PERIPH_ACK; + + return switch_state == 0; +} + +uint32_t ram_block_power_domain_is_off(uint32_t sel_block) +{ + uint32_t switch_state; + + switch_state = *((uint32_t *)&power_manager_cb.peri->POWER_GATE_RAM_BLOCK_0_ACK + sel_block*6); + + return switch_state == 0; +} + +uint32_t external_power_domain_is_off(uint32_t sel_external) +{ + #if EXTERNAL_DOMAINS > 0 + uint32_t switch_state; + + switch_state = *((uint32_t *)&power_manager_cb.peri->POWER_GATE_EXTERNAL_0_ACK + sel_external*7); + + return switch_state == 0; + #endif +} + +power_manager_result_t power_gate_counters_init(uint32_t reset_off, uint32_t reset_on, uint32_t switch_off, uint32_t switch_on, uint32_t iso_off, uint32_t iso_on, uint32_t retentive_off, uint32_t retentive_on) +{ + power_manager_cb.counters.reset_off = reset_off; + power_manager_cb.counters.reset_on = reset_on; + power_manager_cb.counters.switch_off = switch_off; + power_manager_cb.counters.switch_on = switch_on; + power_manager_cb.counters.iso_off = iso_off; + power_manager_cb.counters.iso_on = iso_on; + power_manager_cb.counters.retentive_off = retentive_off; + power_manager_cb.counters.retentive_on = retentive_on; + + return kPowerManagerOk_e; +} + +monitor_signals_t monitor_power_gate_core() +{ + uint32_t reg = 0; + monitor_signals_t monitor_signals; + + reg = power_manager_cb.peri->MONITOR_POWER_GATE_CORE; + + monitor_signals.kSwitch_e = reg & 0x1; + monitor_signals.kIso_e = (reg & 0x2) >> 1; + monitor_signals.kReset_e = (reg & 0x4) >> 2; + + return monitor_signals; +} + +monitor_signals_t monitor_power_gate_periph() +{ + uint32_t reg = 0; + monitor_signals_t monitor_signals; + + reg = power_manager_cb.peri->MONITOR_POWER_GATE_PERIPH; + + monitor_signals.kSwitch_e = reg & 0x1; + monitor_signals.kIso_e = (reg & 0x2) >> 1; + monitor_signals.kReset_e = (reg & 0x4) >> 2; + + return monitor_signals; +} + +monitor_signals_t monitor_power_gate_ram_block(uint32_t sel_block) +{ + uint32_t reg = 0; + monitor_signals_t monitor_signals; + + reg = *((uint32_t *)&power_manager_cb.peri->MONITOR_POWER_GATE_RAM_BLOCK_0 + sel_block); + + monitor_signals.kSwitch_e = reg & 0x1; + monitor_signals.kIso_e = (reg & 0x2) >> 1; + monitor_signals.kReset_e = 0x1; + + return monitor_signals; +} + +monitor_signals_t monitor_power_gate_external(uint32_t sel_external) +{ + #if EXTERNAL_DOMAINS > 0 + uint32_t reg = 0; + monitor_signals_t monitor_signals; + + reg = *((uint32_t *)&power_manager_cb.peri->MONITOR_POWER_GATE_EXTERNAL_0 + sel_external); + + monitor_signals.kSwitch_e = reg & 0x1; + monitor_signals.kIso_e = (reg & 0x2) >> 1; + monitor_signals.kReset_e = (reg & 0x4) >> 2; + + return monitor_signals; + #endif +} + +/****************************************************************************/ +/** **/ +/* LOCAL FUNCTIONS */ +/** **/ +/****************************************************************************/ + +/****************************************************************************/ +/** **/ +/* EOF */ +/** **/ +/****************************************************************************/ diff --git a/sw/device/lib/drivers/power_manager/power_manager.h b/sw/device/lib/drivers/power_manager/power_manager.h new file mode 100644 index 000000000..57975927e --- /dev/null +++ b/sw/device/lib/drivers/power_manager/power_manager.h @@ -0,0 +1,430 @@ +/* + ******************* +******************************* H SOURCE FILE ******************************* +** ******************* ** +** ** +** project : X-HEEP ** +** filename : power_manager.h ** +** version : 1 ** +** date : 22/08/23 ** +** ** +***************************************************************************** +** ** +** Copyright (c) EPFL contributors. ** +** All rights reserved. ** +** ** +***************************************************************************** + +VERSION HISTORY: +---------------- +Version : 1 +Date : -/-/- +Revised by : - +Description : Original version + +*/ + +/** + * @todo + * Create enums for modes and interrupts + * remove unnecesary structs + * initilization slave registers + * review headers + * Different counters for each peripheral + * Test all external examples in questa and fpga + * Test dma-power-gate in questa and fpga + * Add to dma power gate cannot execute in verilator + * Check clock gate in the simultion +*/ + +/** + * @todo sanity checks - assert or error? +*/ + +/***************************************************************************/ +/***************************************************************************/ + +/** +* @file power_manager.h +* @date 22/08/23 +* @brief The Power Manager driver to set up and use the power manager +* peripheral +* +* X-HEEP power domains (take from paper) +*/ + +#ifndef _POWER_MANAGER_H_ +#define _POWER_MANAGER_H_ + +/****************************************************************************/ +/** **/ +/** MODULES USED **/ +/** **/ +/****************************************************************************/ + +#include +#include + +#include "power_manager_regs.h" // Generated +#include "power_manager_structs.h" // Generated + +/****************************************************************************/ +/** **/ +/** DEFINITIONS AND MACROS **/ +/** **/ +/****************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +/****************************************************************************/ +/** **/ +/** TYPEDEFS AND STRUCTURES **/ +/** **/ +/****************************************************************************/ + +/** + * Error return for power manager init counters functions + * + * This enum describes the return type from power manager HAL functions + */ +typedef enum power_manager_result { + /* + * Ok return status (no error) + */ + kPowerManagerOk_e = 0, + /* + * Error return value + */ + kPowerManagerError_e = 1, +} power_manager_result_t; + + +/** + * Domain states. + * + * + */ +typedef enum power_manager_sel_state { + /** + * + */ + kOn_e = 0, + /** + * + */ + kOff_e = 1, + /** + * + */ + kRetOn_e = 2, + /** + * + */ + kRetOff_e = 3, +} power_manager_sel_state_t; + +/** + * Interrupt source. + * + * + */ +typedef enum power_manager_sel_intr { + /** + * + */ + kTimer_0_pm_e = 0, + /** + * + */ + kPlic_pm_e = 1, + /** + * + */ + kTimer_1_pm_e = 2, + /** + * + */ + kTimer_2_pm_e = 3, + /** + * + */ + kTimer_3_pm_e = 4, + /** + * + */ + kDma_pm_e = 5, + /** + * + */ + kSpi_pm_e = 6, + /** + * + */ + kSpiFlash_pm_e = 7, + /** + * + */ + kGpio_0_pm_e = 8, + /** + * + */ + kGpio_1_pm_e = 9, + /** + * + */ + kGpio_2_pm_e = 10, + /** + * + */ + kGpio_3_pm_e = 11, + /** + * + */ + kGpio_4_pm_e = 12, + /** + * + */ + kGpio_5_pm_e = 13, + /** + * + */ + kGpio_6_pm_e = 14, + /** + * + */ + kGpio_7_pm_e = 15, + /** + * + */ + kExt_0_pm_e = 16, + /** + * + */ + kExt_1_pm_e = 17, + /** + * + */ + kExt_2_pm_e = 18, + /** + * + */ + kExt_3_pm_e = 19, +} power_manager_sel_intr_t; + +/** + * Monitor signals. + * + * + */ +typedef struct monitor_signals { + /** + * + */ + uint32_t kSwitch_e; + /** + * + */ + uint32_t kIso_e; + /** + * + */ + uint32_t kReset_e; +} monitor_signals_t; + +/****************************************************************************/ +/** **/ +/** EXPORTED VARIABLES **/ +/** **/ +/****************************************************************************/ + +/****************************************************************************/ +/** **/ +/** EXPORTED FUNCTIONS **/ +/** **/ +/****************************************************************************/ + +/** + *@brief Initialize all Power Manager configuration registers to a safe default state. + * It can be called anytime to reset the Power Manager control block. @todo + * @param peri Pointer to a register address following the power_manager structure. By + * default (peri == NULL), the integrated power_manager will be used. + */ +void power_manager_init( power_manager *peri ); + +/** + * Creates a new handle + * + * This function does not actuate the hardware. + * + * @param reset_off + * @param reset_on + * @param switch_off + * @param switch_on + * @param iso_off + * @param iso_on + * @param retentive_off + * @param retentive_on + * @return The result of the operation. + */ +power_manager_result_t power_gate_counters_init(uint32_t reset_off, uint32_t reset_on, uint32_t switch_off, uint32_t switch_on, uint32_t iso_off, uint32_t iso_on, uint32_t retentive_off, uint32_t retentive_on); + +/** + * + * + * + * + * @param sel_state + * @return The result of the operation. + */ +power_manager_result_t clock_gate_periph(power_manager_sel_state_t sel_state); + +/** + * + * + * + * + * @param sel_block + * @param sel_state + * @return The result of the operation. + */ +power_manager_result_t clock_gate_ram_block(uint32_t sel_block, power_manager_sel_state_t sel_state); + +/** + * + * + * + * + * @param sel_external + * @param sel_state + * @return The result of the operation. + */ +power_manager_result_t clock_gate_external(uint32_t sel_external, power_manager_sel_state_t sel_state); + +/** + * + * + * + * + * @param sel_intr + * @return The result of the operation. + */ +power_manager_result_t power_gate_core(power_manager_sel_intr_t sel_intr); + +/** + * + * + * + * + * @param sel_state + * @return The result of the operation. + */ +power_manager_result_t power_gate_periph(power_manager_sel_state_t sel_state); + +/** + * + * + * + * + * @param sel_block + * @param sel_state + * @return The result of the operation: 0 for success, 1 if trying to access innexistant RAM + */ +power_manager_result_t power_gate_ram_block(uint32_t sel_block, power_manager_sel_state_t sel_state); + +/** + * + * + * + * + * @param sel_external + * @param sel_state + * @return The result of the operation. + */ +power_manager_result_t power_gate_external(uint32_t sel_external, power_manager_sel_state_t sel_state); + +/** + * + * + * + * + * @return The result of the operation. + */ +uint32_t periph_power_domain_is_off(); + +/** + * + * + * + * + * @param sel_block + * @return The result of the operation. + */ +uint32_t ram_block_power_domain_is_off(uint32_t sel_block); + +/** + * + * + * + * + * @param sel_external + * @return The result of the operation. + */ +uint32_t external_power_domain_is_off(uint32_t sel_external); + +/** + * + * + * + * + * @return The result of the operation. + */ +monitor_signals_t monitor_power_gate_core(); + +/** + * + * + * + * + * @return The result of the operation. + */ +monitor_signals_t monitor_power_gate_periph(); + +/** + * + * + * + * + * @param sel_block + * @return The result of the operation. + */ +monitor_signals_t monitor_power_gate_ram_block(uint32_t sel_block); + +/** + * + * + * + * + * @param sel_external + * @return The result of the operation. + */ +monitor_signals_t monitor_power_gate_external(uint32_t sel_external); + +/****************************************************************************/ +/** **/ +/** INLINE FUNCTIONS **/ +/** **/ +/****************************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif // _POWER_MANAGER_H_ + +/****************************************************************************/ +/** **/ +/** EOF **/ +/** **/ +/****************************************************************************/