1/* SPDX-License-Identifier: BSD-3-Clause
2 *
3 * Copyright(c) 2016 Intel Corporation. All rights reserved.
4 *
5 * Author: Lech Betlej <lech.betlej@linux.intel.com>
6 */
7
8/**
9 * \file platform/intel/cavs/lib/power_down.S
10 * \brief Power gating memory banks - implementation specific for platforms
11 *  with cAVS 2.5 (i.e. Tiger Lake)
12 * \author Lech Betlej <lech.betlej@linux.intel.com>
13 */
14
15
16#include <cavs/version.h>
17#include <cavs/drivers/sideband-ipc.h>
18#include <cavs/lib/asm_ldo_management.h>
19#include <cavs/lib/asm_memory_management.h>
20#include <sof/lib/memory.h>
21#include <sof/lib/shim.h>
22
23	.section .text, "ax"
24	.align 64
25power_down_literals:
26	.literal_position
27#if CONFIG_IPC_MAJOR_3
28ipc_flag:
29	.word IPC_DIPCTDR_BUSY
30#elif CONFIG_IPC_MAJOR_4
31set_dx_reply:
32	/* BUSY (bit31), MODULE_MSG (bit30), reply (bit29), SET_DX (bit 24-28: 7) */
33	.word 0xE7000000
34
35#endif
36sram_dis_loop_cnt:
37	.word 4096
38
39	.global power_down
40	.type power_down, @function
41
42/**
43 * Perform power down.
44 *
45 * Depending on arguments, memories are switched off.
46 * A2 - argument for LPSRAM
47 * A3 - pointer to array containing power gating mask.
48 *Size of array is determined by MEMORY_SEGMENTS define.
49 * A4 - platform type
50 * A5 - response_to_ipc
51 */
52
53#define b_enable_lpsram              a2
54#define pu32_hpsram_mask             a3
55#define temp_reg0                    a6
56#define temp_reg1                    a7
57#define temp_reg2                    a8
58#define temp_reg3                    a9
59#define host_base		     a10
60#define pfl_reg                      a15
61
62power_down:
63	entry sp, 32
64	// effectively executes:
65	// xthal_dcache_region_lock(&literals, 128);
66	// xthal_dcache_region_lock(&powerdown, 256);
67	// xthal_dcache_region_lock(&pu32_hpsram_mask, 64);
68	movi pfl_reg, power_down_literals
69	dpfl pfl_reg, 0
70	dpfl pfl_reg, 64
71
72	movi pfl_reg, power_down
73	ipfl pfl_reg, 0
74	ipfl pfl_reg, 64
75	ipfl pfl_reg, 128
76	ipfl pfl_reg, 192
77
78	mov  pfl_reg, pu32_hpsram_mask
79	dpfl pfl_reg, 0
80
81_PD_DISABLE_LPSRAM:
82/* effectively executes:
83 * if (b_enable_lpsram){
84 *  cavs_lpsram_power_down_entire();
85 * }
86 */
87	movi host_base, IPC_HOST_BASE
88
89	beqz b_enable_lpsram, _PD_DISABLE_HPSRAM
90	m_cavs_lpsram_power_down_entire temp_reg0, temp_reg1, temp_reg2,\
91					sram_dis_loop_cnt
92	j _PD_DISABLE_HPSRAM
93
94_PD_DISABLE_HPSRAM:
95 /* if value in memory pointed by pu32_hpsram_mask = 0
96	 (hpsram_pwrgating_mask) - do not disable hpsram. */
97	beqz pu32_hpsram_mask, _PD_SEND_IPC
98
99/* mandatory sequence for LDO ON - effectively executes:
100 * m_cavs_s_set_ldo_hpsram_on_state();
101 * WAIT_300NS();
102 */
103	movi temp_reg0, SHIM_LDOCTL_HPSRAM_LDO_ON
104	m_cavs_set_hpldo_state temp_reg0, temp_reg1, temp_reg2
105	movi temp_reg0, 128
1061 :
107	addi temp_reg0, temp_reg0, -1
108	bnez temp_reg0, 1b
109
110
111/* effectively executes:
112 * for (size_t seg_index = (MAX_MEMORY_SEGMENTS - 1); seg_index >= 0;
113 * --seg_index) {
114 * cavs_hpsram_power_change(seg_index, mask[seg_index]);
115 * }
116 * where mask is given in pu32_hpsram_mask register
117 */
118
119	.set seg_index, MAX_MEMORY_SEGMENTS - 1
120	.rept MAX_MEMORY_SEGMENTS
121	l32i temp_reg0, pu32_hpsram_mask, 4 * seg_index
122	m_cavs_hpsram_power_change\
123	/*segment_index=*/	seg_index,\
124	/*mask=*/	temp_reg0,\
125	temp_reg1,\
126	temp_reg2,\
127	temp_reg3
128	.set seg_index, seg_index - 1
129	.endr
130
131
132/* mandatory sequence for LDO OFF - effectively executes:
133 * WAIT_300NS();
134 * m_cavs_set_ldo_hpsram_on_state()
135 */
136	movi temp_reg0, 128
1371 :
138	addi temp_reg0, temp_reg0, -1
139	bnez temp_reg0, 1b
140
141	movi temp_reg0, SHIM_LDOCTL_HPSRAM_LDO_OFF
142	m_cavs_set_hpldo_state temp_reg0, temp_reg1, temp_reg2
143
144_PD_SEND_IPC:
145#if CONFIG_IPC_MAJOR_3
146/* Send IPC to host informing of PD completion - Clear BUSY
147 * bit by writing IPC_DIPCTDR_BUSY to IPC_DIPCTDR
148 * and writing IPC_DIPCTDA_DONE to IPC_DIPCTDA
149 */
150	l32i temp_reg1, host_base, IPC_DIPCTDR
151	movi temp_reg2, ipc_flag
152	l32i temp_reg2, temp_reg2, 0
153	or temp_reg1, temp_reg1, temp_reg2
154	s32i temp_reg1, host_base, IPC_DIPCTDR
155
156	l32i temp_reg1, host_base, IPC_DIPCTDA
157	or temp_reg1, temp_reg1, temp_reg2
158	s32i temp_reg1, host_base, IPC_DIPCTDA
159#elif CONFIG_IPC_MAJOR_4
160/* Send IPC reply for SET_DX message */
161	movi temp_reg1, 0
162	s32i temp_reg1, host_base, IPC_DIPCIDD
163
164	movi temp_reg1, set_dx_reply
165	l32i temp_reg1, temp_reg1, 0
166	s32i temp_reg1, host_base, IPC_DIPCIDR
167#else
168#error "Support for this IPC version is not implemented"
169#endif
170
171_PD_SLEEP:
172/* effecfively executes:
173 * xmp_spin()
174 * waiti 5
175 */
176	movi temp_reg0, 128
177loop:
178	addi temp_reg0, temp_reg0, -1
179	bnez temp_reg0, loop
180
181    extw
182    extw
183    waiti 5
184    1:
185    j 1b
186
187.size power_down , . - power_down
188