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 - pointer to array containing power gating mask.
26 * Size of array is determined by MAX_MEMORY_SEGMENTS define.
27 * @param A4 - send response to ipc
28 */
29
30#define IPC_HOST_BASE				0x00073000
31#define b_enable_lpsram				a2
32#define pu32_hpsram_mask			a3
33#define b_ipc_response				a4
34#define temp_reg0					a6
35#define temp_reg1					a7
36#define temp_reg2					a8
37#define temp_reg3					a9
38#define temp_reg4					a10
39#define temp_reg5					a11
40#define temp_reg6					a12
41#define p_ipc_regs					a13
42#define u32_ipc_response_mask		a14
43#define pfl_reg						a15
44
45power_down:
46	entry sp, 32
47	/**
48	 * effectively executes:
49	 * xthal_dcache_region_lock(&literals, 128);
50	 * xthal_icache_region_lock(&powerdown, 256);
51	 * xthal_dcache_region_lock(&pu32_hpsram_mask, 64);
52	 */
53	movi pfl_reg, power_down_literals
54	dpfl pfl_reg, 0
55	dpfl pfl_reg, 64
56
57	movi pfl_reg, power_down
58	ipfl pfl_reg, 0
59	ipfl pfl_reg, 64
60	ipfl pfl_reg, 128
61	ipfl pfl_reg, 192
62
63	/* move some values to registries before switching off whole memory */
64	/* load address of DIPCTDR register */
65	movi p_ipc_regs, IPC_HOST_BASE
66	movi u32_ipc_response_mask, 0x20000000
67
68	beqz pu32_hpsram_mask, _PD_DISABLE_LPSRAM
69	/*
70	 * This assumes a single HPSRAM segment although the code below is
71	 * generic and uses MAX_MEMORY_SEGMENTS for their number
72	 */
73	mov  pfl_reg, pu32_hpsram_mask
74	dpfl pfl_reg, 0
75
76_PD_DISABLE_LPSRAM:
77/**
78 * effectively executes:
79 * if (b_enable_lpsram) {
80 *     ace_lpsram_power_down_entire();
81 * }
82 */
83	beqz b_enable_lpsram, _PD_DISABLE_HPSRAM
84	m_ace_lpsram_power_down_entire temp_reg0, temp_reg1, temp_reg2, temp_reg3
85
86_PD_DISABLE_HPSRAM:
87	/* if value pu32_hpsram_mask = 0 - do not disable hpsram. */
88	beqz pu32_hpsram_mask, _PD_SEND_IPC
89	/**
90	 * effectively executes:
91	 * for (size_t seg_index = (MAX_MEMORY_SEGMENTS - 1); seg_index >= 0;
92	 * --seg_index) {
93	 * ace_hpsram_power_change(seg_index, mask[seg_index]);
94	 * }
95	 * where mask is given in pu32_hpsram_mask register
96	 */
97
98	.set seg_index, MAX_MEMORY_SEGMENTS - 1
99	.rept MAX_MEMORY_SEGMENTS
100		l32i temp_reg0, pu32_hpsram_mask, 4 * seg_index
101		m_ace_hpsram_power_change\
102			/*segment_index=*/	seg_index,\
103			/*mask=*/	temp_reg0,\
104			temp_reg1,\
105			temp_reg2,\
106			temp_reg3,\
107			temp_reg4,\
108			temp_reg5
109		.set seg_index, seg_index - 1
110	.endr
111
112_PD_SEND_IPC:
113	/**
114	 * Send IPC to host informing of PD completion - Clear BUSY
115	 * bit by writing IPC_DIPCTDR_BUSY to IPC_DIPCTDR
116	 * and writing IPC_DIPCTDA_DONE to IPC_DIPCTDA
117	 */
118
119	/**
120	 * effecfively executes:
121	 * if (b_ipc_response)
122	 * {
123	 *     temp_reg0 = *p_ipc_regs;
124	 *     temp_reg0 = temp_reg0 | 0x80000000;
125	 *     temp_reg0 = temp_reg0 | u32_ipc_response_mask;
126	 *     *(p_ipc_regs + 0x180) = 0x0;
127	 *     *(p_ipc_regs + 0x10) = temp_reg0;
128	 * }
129	 */
130	beqz b_ipc_response, _PD_SLEEP
131	/* copy value from IPCxTDR */
132	l32i temp_reg0, p_ipc_regs, 0
133	/* set IPC Busy bit to 1 */
134	movi temp_reg1, 1
135	slli temp_reg1, temp_reg1, 31
136	or temp_reg0, temp_reg0, temp_reg1
137	/* mark the message as a reply */
138	or temp_reg0, temp_reg0, u32_ipc_response_mask
139	/* clear IPCxIDD i.e. message extension */
140	movi temp_reg1, 0
141	s32i temp_reg1, p_ipc_regs, 0x180
142	/* write response to IPCxIDR */
143	s32i temp_reg0, p_ipc_regs, 0x10
144
145_PD_SLEEP:
146/* effecfively executes:
147 * xmp_spin()
148 * waiti 5
149 */
150	movi temp_reg0, 128
151loop:
152	addi temp_reg0, temp_reg0, -1
153	bnez temp_reg0, loop
154
155	extw
156	extw
157	waiti 5
158	1:
159	j 1b
160
161.size power_down , . - power_down
162