1/* Copyright (c) 2022 Intel Corporation 2 * SPDX-License-Identifier: Apache-2.0 3 */ 4 5#include "asm_memory_management.h" 6 7 .section .text, "ax" 8 .align 64 9power_down_literals: 10 .literal_position 11ipc_flag: 12 .word 0x80000000 // IPC_DIPCTDR_BUSY 13sram_dis_loop_cnt: 14 .word 4096 15 16 .global power_down 17 .type power_down, @function 18 19 /** 20 * @brief Perform power down. 21 * 22 * Depending on arguments, memories are switched off. 23 * 24 * @param A2 - argument for LPSRAM 25 * @param A3 - argument for HPSRAM 26 * @param A4 - send response to ipc 27 */ 28 29#define IPC_HOST_BASE 0x00073000 30#define b_disable_lpsram a2 31#define b_disable_hpsram a3 32#define b_ipc_response a4 33#define temp_reg0 a6 34#define temp_reg1 a7 35#define temp_reg2 a8 36#define temp_reg3 a9 37#define temp_reg4 a10 38#define temp_reg5 a11 39#define temp_reg6 a12 40#define p_ipc_regs a13 41#define u32_ipc_response_mask a14 42#define pfl_reg a15 43 44power_down: 45 entry sp, 32 46 /** 47 * effectively executes: 48 * xthal_dcache_region_lock(&literals, 128); 49 * xthal_icache_region_lock(&powerdown, 256); 50 */ 51 movi pfl_reg, power_down_literals 52 dpfl pfl_reg, 0 53 dpfl pfl_reg, 64 54 55 movi pfl_reg, power_down 56 ipfl pfl_reg, 0 57 ipfl pfl_reg, 64 58 ipfl pfl_reg, 128 59 ipfl pfl_reg, 192 60 61 /* move some values to registries before switching off whole memory */ 62 /* load address of DIPCTDR register */ 63 movi p_ipc_regs, IPC_HOST_BASE 64 movi u32_ipc_response_mask, 0x20000000 65#if CONFIG_XTENSA_MMU 66 /** 67 * Preload the IPC register to ensure the TLB entry is present. 68 * This addresses an issue on platforms with an MMU where a 69 * LoadStoreTLBMissCause exception occurs when accessing hardware 70 * registers during the power-down process. By preloading the IPC 71 * register, we ensure that the necessary TLB entry is available, 72 * preventing a double exception (LoadStoreTLBMissCause followed by 73 * InstrPIFDataErrorCause) when accessing the IPC register after 74 * HPSRAM is powered down. 75 * 76 * Two solutions were considered: 77 * 1. Use TLB way9 to lock IPC MMIO registers (Zephyr PR80333) 78 * 2. Manually force TLB entry to be fetched in power_down (this solution) 79 * 80 * The decision was made to proceed with this solution due to its 81 * simplicity and directness, despite the potential performance benefits 82 * of the TLB way9 approach. The TLB way9 approach would also reserve 83 * way9, potentially limiting its use for other purposes in the future. 84 */ 85 l32i pfl_reg, p_ipc_regs, 0 86#endif 87 88_PD_DISABLE_LPSRAM: 89/** 90 * effectively executes: 91 * if (b_disable_lpsram) { 92 * ace_lpsram_power_down_entire(); 93 * } 94 */ 95 beqz b_disable_lpsram, _PD_DISABLE_HPSRAM 96 m_ace_lpsram_power_down_entire temp_reg0, temp_reg1, temp_reg2, temp_reg3 97 98_PD_DISABLE_HPSRAM: 99/** 100 * effectively executes: 101 * if (b_disable_hpsram) { 102 * ace_hpsram_power_down_entire(); 103 * } 104 */ 105 beqz b_disable_hpsram, _PD_SEND_IPC 106 m_ace_hpsram_power_down_entire temp_reg0, temp_reg1, temp_reg2, temp_reg3 107 108_PD_SEND_IPC: 109 /** 110 * Send IPC to host informing of PD completion - Clear BUSY 111 * bit by writing IPC_DIPCTDR_BUSY to IPC_DIPCTDR 112 * and writing IPC_DIPCTDA_DONE to IPC_DIPCTDA 113 */ 114 115 /** 116 * effecfively executes: 117 * if (b_ipc_response) 118 * { 119 * temp_reg0 = *p_ipc_regs; 120 * temp_reg0 = temp_reg0 | 0x80000000; 121 * temp_reg0 = temp_reg0 | u32_ipc_response_mask; 122 * *(p_ipc_regs + 0x180) = 0x0; 123 * *(p_ipc_regs + 0x10) = temp_reg0; 124 * } 125 */ 126 beqz b_ipc_response, _PD_SLEEP 127 /* copy value from IPCxTDR */ 128 l32i temp_reg0, p_ipc_regs, 0 129 /* set IPC Busy bit to 1 */ 130 movi temp_reg1, 1 131 slli temp_reg1, temp_reg1, 31 132 or temp_reg0, temp_reg0, temp_reg1 133 /* mark the message as a reply */ 134 or temp_reg0, temp_reg0, u32_ipc_response_mask 135 /* clear IPCxIDD i.e. message extension */ 136 movi temp_reg1, 0 137 s32i temp_reg1, p_ipc_regs, 0x180 138 /* write response to IPCxIDR */ 139 s32i temp_reg0, p_ipc_regs, 0x10 140 141_PD_SLEEP: 142/* effecfively executes: 143 * xmp_spin() 144 * waiti 5 145 */ 146 movi temp_reg0, 128 147loop: 148 addi temp_reg0, temp_reg0, -1 149 bnez temp_reg0, loop 150 151 extw 152 extw 153 waiti 5 154 1: 155 j 1b 156 157.size power_down , . - power_down 158