1b81fd263SSubhransu S. Prusty /*
2b81fd263SSubhransu S. Prusty  * skl-sst-ipc.c - Intel skl IPC Support
3b81fd263SSubhransu S. Prusty  *
4b81fd263SSubhransu S. Prusty  * Copyright (C) 2014-15, Intel Corporation.
5b81fd263SSubhransu S. Prusty  *
6b81fd263SSubhransu S. Prusty  * This program is free software; you can redistribute it and/or modify
7b81fd263SSubhransu S. Prusty  * it under the terms of the GNU General Public License as version 2, as
8b81fd263SSubhransu S. Prusty  * published by the Free Software Foundation.
9b81fd263SSubhransu S. Prusty  *
10b81fd263SSubhransu S. Prusty  * This program is distributed in the hope that it will be useful, but
11b81fd263SSubhransu S. Prusty  * WITHOUT ANY WARRANTY; without even the implied warranty of
12b81fd263SSubhransu S. Prusty  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13b81fd263SSubhransu S. Prusty  * General Public License for more details.
14b81fd263SSubhransu S. Prusty  */
15b81fd263SSubhransu S. Prusty #include <linux/device.h>
16b81fd263SSubhransu S. Prusty 
17b81fd263SSubhransu S. Prusty #include "../common/sst-dsp.h"
18b81fd263SSubhransu S. Prusty #include "../common/sst-dsp-priv.h"
19b81fd263SSubhransu S. Prusty #include "skl-sst-dsp.h"
20b81fd263SSubhransu S. Prusty #include "skl-sst-ipc.h"
21b81fd263SSubhransu S. Prusty 
22b81fd263SSubhransu S. Prusty 
23b81fd263SSubhransu S. Prusty #define IPC_IXC_STATUS_BITS		24
24b81fd263SSubhransu S. Prusty 
25b81fd263SSubhransu S. Prusty /* Global Message - Generic */
26b81fd263SSubhransu S. Prusty #define IPC_GLB_TYPE_SHIFT		24
27b81fd263SSubhransu S. Prusty #define IPC_GLB_TYPE_MASK		(0xf << IPC_GLB_TYPE_SHIFT)
28b81fd263SSubhransu S. Prusty #define IPC_GLB_TYPE(x)			((x) << IPC_GLB_TYPE_SHIFT)
29b81fd263SSubhransu S. Prusty 
30b81fd263SSubhransu S. Prusty /* Global Message - Reply */
31b81fd263SSubhransu S. Prusty #define IPC_GLB_REPLY_STATUS_SHIFT	24
32b81fd263SSubhransu S. Prusty #define IPC_GLB_REPLY_STATUS_MASK	((0x1 << IPC_GLB_REPLY_STATUS_SHIFT) - 1)
33b81fd263SSubhransu S. Prusty #define IPC_GLB_REPLY_STATUS(x)		((x) << IPC_GLB_REPLY_STATUS_SHIFT)
34b81fd263SSubhransu S. Prusty 
35b81fd263SSubhransu S. Prusty #define IPC_TIMEOUT_MSECS		3000
36b81fd263SSubhransu S. Prusty 
37b81fd263SSubhransu S. Prusty #define IPC_EMPTY_LIST_SIZE		8
38b81fd263SSubhransu S. Prusty 
39b81fd263SSubhransu S. Prusty #define IPC_MSG_TARGET_SHIFT		30
40b81fd263SSubhransu S. Prusty #define IPC_MSG_TARGET_MASK		0x1
41b81fd263SSubhransu S. Prusty #define IPC_MSG_TARGET(x)		(((x) & IPC_MSG_TARGET_MASK) \
42b81fd263SSubhransu S. Prusty 					<< IPC_MSG_TARGET_SHIFT)
43b81fd263SSubhransu S. Prusty 
44b81fd263SSubhransu S. Prusty #define IPC_MSG_DIR_SHIFT		29
45b81fd263SSubhransu S. Prusty #define IPC_MSG_DIR_MASK		0x1
46b81fd263SSubhransu S. Prusty #define IPC_MSG_DIR(x)			(((x) & IPC_MSG_DIR_MASK) \
47b81fd263SSubhransu S. Prusty 					<< IPC_MSG_DIR_SHIFT)
48b81fd263SSubhransu S. Prusty /* Global Notification Message */
49b81fd263SSubhransu S. Prusty #define IPC_GLB_NOTIFY_TYPE_SHIFT	16
50b81fd263SSubhransu S. Prusty #define IPC_GLB_NOTIFY_TYPE_MASK	0xFF
51b81fd263SSubhransu S. Prusty #define IPC_GLB_NOTIFY_TYPE(x)		(((x) >> IPC_GLB_NOTIFY_TYPE_SHIFT) \
52b81fd263SSubhransu S. Prusty 					& IPC_GLB_NOTIFY_TYPE_MASK)
53b81fd263SSubhransu S. Prusty 
54b81fd263SSubhransu S. Prusty #define IPC_GLB_NOTIFY_MSG_TYPE_SHIFT	24
55b81fd263SSubhransu S. Prusty #define IPC_GLB_NOTIFY_MSG_TYPE_MASK	0x1F
56b81fd263SSubhransu S. Prusty #define IPC_GLB_NOTIFY_MSG_TYPE(x)	(((x) >> IPC_GLB_NOTIFY_MSG_TYPE_SHIFT)	\
57b81fd263SSubhransu S. Prusty 						& IPC_GLB_NOTIFY_MSG_TYPE_MASK)
58b81fd263SSubhransu S. Prusty 
59b81fd263SSubhransu S. Prusty #define IPC_GLB_NOTIFY_RSP_SHIFT	29
60b81fd263SSubhransu S. Prusty #define IPC_GLB_NOTIFY_RSP_MASK		0x1
61b81fd263SSubhransu S. Prusty #define IPC_GLB_NOTIFY_RSP_TYPE(x)	(((x) >> IPC_GLB_NOTIFY_RSP_SHIFT) \
62b81fd263SSubhransu S. Prusty 					& IPC_GLB_NOTIFY_RSP_MASK)
63b81fd263SSubhransu S. Prusty 
64b81fd263SSubhransu S. Prusty /* Pipeline operations */
65b81fd263SSubhransu S. Prusty 
66b81fd263SSubhransu S. Prusty /* Create pipeline message */
67b81fd263SSubhransu S. Prusty #define IPC_PPL_MEM_SIZE_SHIFT		0
68b81fd263SSubhransu S. Prusty #define IPC_PPL_MEM_SIZE_MASK		0x7FF
69b81fd263SSubhransu S. Prusty #define IPC_PPL_MEM_SIZE(x)		(((x) & IPC_PPL_MEM_SIZE_MASK) \
70b81fd263SSubhransu S. Prusty 					<< IPC_PPL_MEM_SIZE_SHIFT)
71b81fd263SSubhransu S. Prusty 
72b81fd263SSubhransu S. Prusty #define IPC_PPL_TYPE_SHIFT		11
73b81fd263SSubhransu S. Prusty #define IPC_PPL_TYPE_MASK		0x1F
74b81fd263SSubhransu S. Prusty #define IPC_PPL_TYPE(x)			(((x) & IPC_PPL_TYPE_MASK) \
75b81fd263SSubhransu S. Prusty 					<< IPC_PPL_TYPE_SHIFT)
76b81fd263SSubhransu S. Prusty 
77b81fd263SSubhransu S. Prusty #define IPC_INSTANCE_ID_SHIFT		16
78b81fd263SSubhransu S. Prusty #define IPC_INSTANCE_ID_MASK		0xFF
79b81fd263SSubhransu S. Prusty #define IPC_INSTANCE_ID(x)		(((x) & IPC_INSTANCE_ID_MASK) \
80b81fd263SSubhransu S. Prusty 					<< IPC_INSTANCE_ID_SHIFT)
81b81fd263SSubhransu S. Prusty 
82b81fd263SSubhransu S. Prusty /* Set pipeline state message */
83b81fd263SSubhransu S. Prusty #define IPC_PPL_STATE_SHIFT		0
84b81fd263SSubhransu S. Prusty #define IPC_PPL_STATE_MASK		0x1F
85b81fd263SSubhransu S. Prusty #define IPC_PPL_STATE(x)		(((x) & IPC_PPL_STATE_MASK) \
86b81fd263SSubhransu S. Prusty 					<< IPC_PPL_STATE_SHIFT)
87b81fd263SSubhransu S. Prusty 
88b81fd263SSubhransu S. Prusty /* Module operations primary register */
89b81fd263SSubhransu S. Prusty #define IPC_MOD_ID_SHIFT		0
90b81fd263SSubhransu S. Prusty #define IPC_MOD_ID_MASK		0xFFFF
91b81fd263SSubhransu S. Prusty #define IPC_MOD_ID(x)		(((x) & IPC_MOD_ID_MASK) \
92b81fd263SSubhransu S. Prusty 					<< IPC_MOD_ID_SHIFT)
93b81fd263SSubhransu S. Prusty 
94b81fd263SSubhransu S. Prusty #define IPC_MOD_INSTANCE_ID_SHIFT	16
95b81fd263SSubhransu S. Prusty #define IPC_MOD_INSTANCE_ID_MASK	0xFF
96b81fd263SSubhransu S. Prusty #define IPC_MOD_INSTANCE_ID(x)	(((x) & IPC_MOD_INSTANCE_ID_MASK) \
97b81fd263SSubhransu S. Prusty 					<< IPC_MOD_INSTANCE_ID_SHIFT)
98b81fd263SSubhransu S. Prusty 
99b81fd263SSubhransu S. Prusty /* Init instance message extension register */
100b81fd263SSubhransu S. Prusty #define IPC_PARAM_BLOCK_SIZE_SHIFT	0
101b81fd263SSubhransu S. Prusty #define IPC_PARAM_BLOCK_SIZE_MASK	0xFFFF
102b81fd263SSubhransu S. Prusty #define IPC_PARAM_BLOCK_SIZE(x)		(((x) & IPC_PARAM_BLOCK_SIZE_MASK) \
103b81fd263SSubhransu S. Prusty 					<< IPC_PARAM_BLOCK_SIZE_SHIFT)
104b81fd263SSubhransu S. Prusty 
105b81fd263SSubhransu S. Prusty #define IPC_PPL_INSTANCE_ID_SHIFT	16
106b81fd263SSubhransu S. Prusty #define IPC_PPL_INSTANCE_ID_MASK	0xFF
107b81fd263SSubhransu S. Prusty #define IPC_PPL_INSTANCE_ID(x)		(((x) & IPC_PPL_INSTANCE_ID_MASK) \
108b81fd263SSubhransu S. Prusty 					<< IPC_PPL_INSTANCE_ID_SHIFT)
109b81fd263SSubhransu S. Prusty 
110b81fd263SSubhransu S. Prusty #define IPC_CORE_ID_SHIFT		24
111b81fd263SSubhransu S. Prusty #define IPC_CORE_ID_MASK		0x1F
112b81fd263SSubhransu S. Prusty #define IPC_CORE_ID(x)			(((x) & IPC_CORE_ID_MASK) \
113b81fd263SSubhransu S. Prusty 					<< IPC_CORE_ID_SHIFT)
114b81fd263SSubhransu S. Prusty 
115b81fd263SSubhransu S. Prusty /* Bind/Unbind message extension register */
116b81fd263SSubhransu S. Prusty #define IPC_DST_MOD_ID_SHIFT		0
117b81fd263SSubhransu S. Prusty #define IPC_DST_MOD_ID(x)		(((x) & IPC_MOD_ID_MASK) \
118b81fd263SSubhransu S. Prusty 					<< IPC_DST_MOD_ID_SHIFT)
119b81fd263SSubhransu S. Prusty 
120b81fd263SSubhransu S. Prusty #define IPC_DST_MOD_INSTANCE_ID_SHIFT 16
121b81fd263SSubhransu S. Prusty #define IPC_DST_MOD_INSTANCE_ID(x)	(((x) & IPC_MOD_INSTANCE_ID_MASK) \
122b81fd263SSubhransu S. Prusty 					<< IPC_DST_MOD_INSTANCE_ID_SHIFT)
123b81fd263SSubhransu S. Prusty 
124b81fd263SSubhransu S. Prusty #define IPC_DST_QUEUE_SHIFT		24
125b81fd263SSubhransu S. Prusty #define IPC_DST_QUEUE_MASK		0x7
126b81fd263SSubhransu S. Prusty #define IPC_DST_QUEUE(x)		(((x) & IPC_DST_QUEUE_MASK) \
127b81fd263SSubhransu S. Prusty 					<< IPC_DST_QUEUE_SHIFT)
128b81fd263SSubhransu S. Prusty 
129b81fd263SSubhransu S. Prusty #define IPC_SRC_QUEUE_SHIFT		27
130b81fd263SSubhransu S. Prusty #define IPC_SRC_QUEUE_MASK		0x7
131b81fd263SSubhransu S. Prusty #define IPC_SRC_QUEUE(x)		(((x) & IPC_SRC_QUEUE_MASK) \
132b81fd263SSubhransu S. Prusty 					<< IPC_SRC_QUEUE_SHIFT)
133b81fd263SSubhransu S. Prusty 
134b81fd263SSubhransu S. Prusty /* Save pipeline messgae extension register */
135b81fd263SSubhransu S. Prusty #define IPC_DMA_ID_SHIFT		0
136b81fd263SSubhransu S. Prusty #define IPC_DMA_ID_MASK			0x1F
137b81fd263SSubhransu S. Prusty #define IPC_DMA_ID(x)			(((x) & IPC_DMA_ID_MASK) \
138b81fd263SSubhransu S. Prusty 					<< IPC_DMA_ID_SHIFT)
139b81fd263SSubhransu S. Prusty /* Large Config message extension register */
140b81fd263SSubhransu S. Prusty #define IPC_DATA_OFFSET_SZ_SHIFT	0
141b81fd263SSubhransu S. Prusty #define IPC_DATA_OFFSET_SZ_MASK		0xFFFFF
142b81fd263SSubhransu S. Prusty #define IPC_DATA_OFFSET_SZ(x)		(((x) & IPC_DATA_OFFSET_SZ_MASK) \
143b81fd263SSubhransu S. Prusty 					<< IPC_DATA_OFFSET_SZ_SHIFT)
144b81fd263SSubhransu S. Prusty #define IPC_DATA_OFFSET_SZ_CLEAR	~(IPC_DATA_OFFSET_SZ_MASK \
145b81fd263SSubhransu S. Prusty 					  << IPC_DATA_OFFSET_SZ_SHIFT)
146b81fd263SSubhransu S. Prusty 
147b81fd263SSubhransu S. Prusty #define IPC_LARGE_PARAM_ID_SHIFT	20
148b81fd263SSubhransu S. Prusty #define IPC_LARGE_PARAM_ID_MASK		0xFF
149b81fd263SSubhransu S. Prusty #define IPC_LARGE_PARAM_ID(x)		(((x) & IPC_LARGE_PARAM_ID_MASK) \
150b81fd263SSubhransu S. Prusty 					<< IPC_LARGE_PARAM_ID_SHIFT)
151b81fd263SSubhransu S. Prusty 
152b81fd263SSubhransu S. Prusty #define IPC_FINAL_BLOCK_SHIFT		28
153b81fd263SSubhransu S. Prusty #define IPC_FINAL_BLOCK_MASK		0x1
154b81fd263SSubhransu S. Prusty #define IPC_FINAL_BLOCK(x)		(((x) & IPC_FINAL_BLOCK_MASK) \
155b81fd263SSubhransu S. Prusty 					<< IPC_FINAL_BLOCK_SHIFT)
156b81fd263SSubhransu S. Prusty 
157b81fd263SSubhransu S. Prusty #define IPC_INITIAL_BLOCK_SHIFT		29
158b81fd263SSubhransu S. Prusty #define IPC_INITIAL_BLOCK_MASK		0x1
159b81fd263SSubhransu S. Prusty #define IPC_INITIAL_BLOCK(x)		(((x) & IPC_INITIAL_BLOCK_MASK) \
160b81fd263SSubhransu S. Prusty 					<< IPC_INITIAL_BLOCK_SHIFT)
161b81fd263SSubhransu S. Prusty #define IPC_INITIAL_BLOCK_CLEAR		~(IPC_INITIAL_BLOCK_MASK \
162b81fd263SSubhransu S. Prusty 					  << IPC_INITIAL_BLOCK_SHIFT)
163b81fd263SSubhransu S. Prusty 
164b81fd263SSubhransu S. Prusty enum skl_ipc_msg_target {
165b81fd263SSubhransu S. Prusty 	IPC_FW_GEN_MSG = 0,
166b81fd263SSubhransu S. Prusty 	IPC_MOD_MSG = 1
167b81fd263SSubhransu S. Prusty };
168b81fd263SSubhransu S. Prusty 
169b81fd263SSubhransu S. Prusty enum skl_ipc_msg_direction {
170b81fd263SSubhransu S. Prusty 	IPC_MSG_REQUEST = 0,
171b81fd263SSubhransu S. Prusty 	IPC_MSG_REPLY = 1
172b81fd263SSubhransu S. Prusty };
173b81fd263SSubhransu S. Prusty 
174b81fd263SSubhransu S. Prusty /* Global Message Types */
175b81fd263SSubhransu S. Prusty enum skl_ipc_glb_type {
176b81fd263SSubhransu S. Prusty 	IPC_GLB_GET_FW_VERSION = 0, /* Retrieves firmware version */
177b81fd263SSubhransu S. Prusty 	IPC_GLB_LOAD_MULTIPLE_MODS = 15,
178b81fd263SSubhransu S. Prusty 	IPC_GLB_UNLOAD_MULTIPLE_MODS = 16,
179b81fd263SSubhransu S. Prusty 	IPC_GLB_CREATE_PPL = 17,
180b81fd263SSubhransu S. Prusty 	IPC_GLB_DELETE_PPL = 18,
181b81fd263SSubhransu S. Prusty 	IPC_GLB_SET_PPL_STATE = 19,
182b81fd263SSubhransu S. Prusty 	IPC_GLB_GET_PPL_STATE = 20,
183b81fd263SSubhransu S. Prusty 	IPC_GLB_GET_PPL_CONTEXT_SIZE = 21,
184b81fd263SSubhransu S. Prusty 	IPC_GLB_SAVE_PPL = 22,
185b81fd263SSubhransu S. Prusty 	IPC_GLB_RESTORE_PPL = 23,
186b81fd263SSubhransu S. Prusty 	IPC_GLB_NOTIFY = 26,
187b81fd263SSubhransu S. Prusty 	IPC_GLB_MAX_IPC_MSG_NUMBER = 31 /* Maximum message number */
188b81fd263SSubhransu S. Prusty };
189b81fd263SSubhransu S. Prusty 
190b81fd263SSubhransu S. Prusty enum skl_ipc_glb_reply {
191b81fd263SSubhransu S. Prusty 	IPC_GLB_REPLY_SUCCESS = 0,
192b81fd263SSubhransu S. Prusty 
193b81fd263SSubhransu S. Prusty 	IPC_GLB_REPLY_UNKNOWN_MSG_TYPE = 1,
194b81fd263SSubhransu S. Prusty 	IPC_GLB_REPLY_ERROR_INVALID_PARAM = 2,
195b81fd263SSubhransu S. Prusty 
196b81fd263SSubhransu S. Prusty 	IPC_GLB_REPLY_BUSY = 3,
197b81fd263SSubhransu S. Prusty 	IPC_GLB_REPLY_PENDING = 4,
198b81fd263SSubhransu S. Prusty 	IPC_GLB_REPLY_FAILURE = 5,
199b81fd263SSubhransu S. Prusty 	IPC_GLB_REPLY_INVALID_REQUEST = 6,
200b81fd263SSubhransu S. Prusty 
201b81fd263SSubhransu S. Prusty 	IPC_GLB_REPLY_OUT_OF_MEMORY = 7,
202b81fd263SSubhransu S. Prusty 	IPC_GLB_REPLY_OUT_OF_MIPS = 8,
203b81fd263SSubhransu S. Prusty 
204b81fd263SSubhransu S. Prusty 	IPC_GLB_REPLY_INVALID_RESOURCE_ID = 9,
205b81fd263SSubhransu S. Prusty 	IPC_GLB_REPLY_INVALID_RESOURCE_STATE = 10,
206b81fd263SSubhransu S. Prusty 
207b81fd263SSubhransu S. Prusty 	IPC_GLB_REPLY_MOD_MGMT_ERROR = 100,
208b81fd263SSubhransu S. Prusty 	IPC_GLB_REPLY_MOD_LOAD_CL_FAILED = 101,
209b81fd263SSubhransu S. Prusty 	IPC_GLB_REPLY_MOD_LOAD_INVALID_HASH = 102,
210b81fd263SSubhransu S. Prusty 
211b81fd263SSubhransu S. Prusty 	IPC_GLB_REPLY_MOD_UNLOAD_INST_EXIST = 103,
212b81fd263SSubhransu S. Prusty 	IPC_GLB_REPLY_MOD_NOT_INITIALIZED = 104,
213b81fd263SSubhransu S. Prusty 
214b81fd263SSubhransu S. Prusty 	IPC_GLB_REPLY_INVALID_CONFIG_PARAM_ID = 120,
215b81fd263SSubhransu S. Prusty 	IPC_GLB_REPLY_INVALID_CONFIG_DATA_LEN = 121,
216b81fd263SSubhransu S. Prusty 	IPC_GLB_REPLY_GATEWAY_NOT_INITIALIZED = 140,
217b81fd263SSubhransu S. Prusty 	IPC_GLB_REPLY_GATEWAY_NOT_EXIST = 141,
218b81fd263SSubhransu S. Prusty 
219b81fd263SSubhransu S. Prusty 	IPC_GLB_REPLY_PPL_NOT_INITIALIZED = 160,
220b81fd263SSubhransu S. Prusty 	IPC_GLB_REPLY_PPL_NOT_EXIST = 161,
221b81fd263SSubhransu S. Prusty 	IPC_GLB_REPLY_PPL_SAVE_FAILED = 162,
222b81fd263SSubhransu S. Prusty 	IPC_GLB_REPLY_PPL_RESTORE_FAILED = 163,
223b81fd263SSubhransu S. Prusty 
224b81fd263SSubhransu S. Prusty 	IPC_MAX_STATUS = ((1<<IPC_IXC_STATUS_BITS)-1)
225b81fd263SSubhransu S. Prusty };
226b81fd263SSubhransu S. Prusty 
227b81fd263SSubhransu S. Prusty enum skl_ipc_notification_type {
228b81fd263SSubhransu S. Prusty 	IPC_GLB_NOTIFY_GLITCH = 0,
229b81fd263SSubhransu S. Prusty 	IPC_GLB_NOTIFY_OVERRUN = 1,
230b81fd263SSubhransu S. Prusty 	IPC_GLB_NOTIFY_UNDERRUN = 2,
231b81fd263SSubhransu S. Prusty 	IPC_GLB_NOTIFY_END_STREAM = 3,
232b81fd263SSubhransu S. Prusty 	IPC_GLB_NOTIFY_PHRASE_DETECTED = 4,
233b81fd263SSubhransu S. Prusty 	IPC_GLB_NOTIFY_RESOURCE_EVENT = 5,
234b81fd263SSubhransu S. Prusty 	IPC_GLB_NOTIFY_LOG_BUFFER_STATUS = 6,
235b81fd263SSubhransu S. Prusty 	IPC_GLB_NOTIFY_TIMESTAMP_CAPTURED = 7,
236b81fd263SSubhransu S. Prusty 	IPC_GLB_NOTIFY_FW_READY = 8
237b81fd263SSubhransu S. Prusty };
238b81fd263SSubhransu S. Prusty 
239b81fd263SSubhransu S. Prusty /* Module Message Types */
240b81fd263SSubhransu S. Prusty enum skl_ipc_module_msg {
241b81fd263SSubhransu S. Prusty 	IPC_MOD_INIT_INSTANCE = 0,
242b81fd263SSubhransu S. Prusty 	IPC_MOD_CONFIG_GET = 1,
243b81fd263SSubhransu S. Prusty 	IPC_MOD_CONFIG_SET = 2,
244b81fd263SSubhransu S. Prusty 	IPC_MOD_LARGE_CONFIG_GET = 3,
245b81fd263SSubhransu S. Prusty 	IPC_MOD_LARGE_CONFIG_SET = 4,
246b81fd263SSubhransu S. Prusty 	IPC_MOD_BIND = 5,
247b81fd263SSubhransu S. Prusty 	IPC_MOD_UNBIND = 6,
248b81fd263SSubhransu S. Prusty 	IPC_MOD_SET_DX = 7
249b81fd263SSubhransu S. Prusty };
250b81fd263SSubhransu S. Prusty 
251b81fd263SSubhransu S. Prusty static void skl_ipc_tx_data_copy(struct ipc_message *msg, char *tx_data,
252b81fd263SSubhransu S. Prusty 		size_t tx_size)
253b81fd263SSubhransu S. Prusty {
254b81fd263SSubhransu S. Prusty 	if (tx_size)
255b81fd263SSubhransu S. Prusty 		memcpy(msg->tx_data, tx_data, tx_size);
256b81fd263SSubhransu S. Prusty }
257b81fd263SSubhransu S. Prusty 
258b81fd263SSubhransu S. Prusty static bool skl_ipc_is_dsp_busy(struct sst_dsp *dsp)
259b81fd263SSubhransu S. Prusty {
260b81fd263SSubhransu S. Prusty 	u32 hipci;
261b81fd263SSubhransu S. Prusty 
262b81fd263SSubhransu S. Prusty 	hipci = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCI);
263b81fd263SSubhransu S. Prusty 	return (hipci & SKL_ADSP_REG_HIPCI_BUSY);
264b81fd263SSubhransu S. Prusty }
265b81fd263SSubhransu S. Prusty 
266b81fd263SSubhransu S. Prusty /* Lock to be held by caller */
267b81fd263SSubhransu S. Prusty static void skl_ipc_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg)
268b81fd263SSubhransu S. Prusty {
269b81fd263SSubhransu S. Prusty 	struct skl_ipc_header *header = (struct skl_ipc_header *)(&msg->header);
270b81fd263SSubhransu S. Prusty 
271b81fd263SSubhransu S. Prusty 	if (msg->tx_size)
272b81fd263SSubhransu S. Prusty 		sst_dsp_outbox_write(ipc->dsp, msg->tx_data, msg->tx_size);
273b81fd263SSubhransu S. Prusty 	sst_dsp_shim_write_unlocked(ipc->dsp, SKL_ADSP_REG_HIPCIE,
274b81fd263SSubhransu S. Prusty 						header->extension);
275b81fd263SSubhransu S. Prusty 	sst_dsp_shim_write_unlocked(ipc->dsp, SKL_ADSP_REG_HIPCI,
276b81fd263SSubhransu S. Prusty 		header->primary | SKL_ADSP_REG_HIPCI_BUSY);
277b81fd263SSubhransu S. Prusty }
278b81fd263SSubhransu S. Prusty 
279b81fd263SSubhransu S. Prusty static struct ipc_message *skl_ipc_reply_get_msg(struct sst_generic_ipc *ipc,
280b81fd263SSubhransu S. Prusty 				u64 ipc_header)
281b81fd263SSubhransu S. Prusty {
282b81fd263SSubhransu S. Prusty 	struct ipc_message *msg =  NULL;
283b81fd263SSubhransu S. Prusty 	struct skl_ipc_header *header = (struct skl_ipc_header *)(&ipc_header);
284b81fd263SSubhransu S. Prusty 
285b81fd263SSubhransu S. Prusty 	if (list_empty(&ipc->rx_list)) {
286b81fd263SSubhransu S. Prusty 		dev_err(ipc->dev, "ipc: rx list is empty but received 0x%x\n",
287b81fd263SSubhransu S. Prusty 			header->primary);
288b81fd263SSubhransu S. Prusty 		goto out;
289b81fd263SSubhransu S. Prusty 	}
290b81fd263SSubhransu S. Prusty 
291b81fd263SSubhransu S. Prusty 	msg = list_first_entry(&ipc->rx_list, struct ipc_message, list);
292b81fd263SSubhransu S. Prusty 
293b81fd263SSubhransu S. Prusty out:
294b81fd263SSubhransu S. Prusty 	return msg;
295b81fd263SSubhransu S. Prusty 
296b81fd263SSubhransu S. Prusty }
297b81fd263SSubhransu S. Prusty 
298b81fd263SSubhransu S. Prusty static int skl_ipc_process_notification(struct sst_generic_ipc *ipc,
299b81fd263SSubhransu S. Prusty 		struct skl_ipc_header header)
300b81fd263SSubhransu S. Prusty {
301b81fd263SSubhransu S. Prusty 	struct skl_sst *skl = container_of(ipc, struct skl_sst, ipc);
302b81fd263SSubhransu S. Prusty 
303b81fd263SSubhransu S. Prusty 	if (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) {
304b81fd263SSubhransu S. Prusty 		switch (IPC_GLB_NOTIFY_TYPE(header.primary)) {
305b81fd263SSubhransu S. Prusty 
306b81fd263SSubhransu S. Prusty 		case IPC_GLB_NOTIFY_UNDERRUN:
307b81fd263SSubhransu S. Prusty 			dev_err(ipc->dev, "FW Underrun %x\n", header.primary);
308b81fd263SSubhransu S. Prusty 			break;
309b81fd263SSubhransu S. Prusty 
310b81fd263SSubhransu S. Prusty 		case IPC_GLB_NOTIFY_RESOURCE_EVENT:
311b81fd263SSubhransu S. Prusty 			dev_err(ipc->dev, "MCPS Budget Violation: %x\n",
312b81fd263SSubhransu S. Prusty 						header.primary);
313b81fd263SSubhransu S. Prusty 			break;
314b81fd263SSubhransu S. Prusty 
315b81fd263SSubhransu S. Prusty 		case IPC_GLB_NOTIFY_FW_READY:
316b81fd263SSubhransu S. Prusty 			skl->boot_complete = true;
317b81fd263SSubhransu S. Prusty 			wake_up(&skl->boot_wait);
318b81fd263SSubhransu S. Prusty 			break;
319b81fd263SSubhransu S. Prusty 
320b81fd263SSubhransu S. Prusty 		default:
321b81fd263SSubhransu S. Prusty 			dev_err(ipc->dev, "ipc: Unhandled error msg=%x",
322b81fd263SSubhransu S. Prusty 						header.primary);
323b81fd263SSubhransu S. Prusty 			break;
324b81fd263SSubhransu S. Prusty 		}
325b81fd263SSubhransu S. Prusty 	}
326b81fd263SSubhransu S. Prusty 
327b81fd263SSubhransu S. Prusty 	return 0;
328b81fd263SSubhransu S. Prusty }
329b81fd263SSubhransu S. Prusty 
330b81fd263SSubhransu S. Prusty static void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
331b81fd263SSubhransu S. Prusty 		struct skl_ipc_header header)
332b81fd263SSubhransu S. Prusty {
333b81fd263SSubhransu S. Prusty 	struct ipc_message *msg;
334b81fd263SSubhransu S. Prusty 	u32 reply = header.primary & IPC_GLB_REPLY_STATUS_MASK;
335b81fd263SSubhransu S. Prusty 	u64 *ipc_header = (u64 *)(&header);
336b81fd263SSubhransu S. Prusty 
337b81fd263SSubhransu S. Prusty 	msg = skl_ipc_reply_get_msg(ipc, *ipc_header);
338b81fd263SSubhransu S. Prusty 	if (msg == NULL) {
339b81fd263SSubhransu S. Prusty 		dev_dbg(ipc->dev, "ipc: rx list is empty\n");
340b81fd263SSubhransu S. Prusty 		return;
341b81fd263SSubhransu S. Prusty 	}
342b81fd263SSubhransu S. Prusty 
343b81fd263SSubhransu S. Prusty 	/* first process the header */
344b81fd263SSubhransu S. Prusty 	switch (reply) {
345b81fd263SSubhransu S. Prusty 	case IPC_GLB_REPLY_SUCCESS:
346b81fd263SSubhransu S. Prusty 		dev_info(ipc->dev, "ipc FW reply %x: success\n", header.primary);
347b81fd263SSubhransu S. Prusty 		break;
348b81fd263SSubhransu S. Prusty 
349b81fd263SSubhransu S. Prusty 	case IPC_GLB_REPLY_OUT_OF_MEMORY:
350b81fd263SSubhransu S. Prusty 		dev_err(ipc->dev, "ipc fw reply: %x: no memory\n", header.primary);
351b81fd263SSubhransu S. Prusty 		msg->errno = -ENOMEM;
352b81fd263SSubhransu S. Prusty 		break;
353b81fd263SSubhransu S. Prusty 
354b81fd263SSubhransu S. Prusty 	case IPC_GLB_REPLY_BUSY:
355b81fd263SSubhransu S. Prusty 		dev_err(ipc->dev, "ipc fw reply: %x: Busy\n", header.primary);
356b81fd263SSubhransu S. Prusty 		msg->errno = -EBUSY;
357b81fd263SSubhransu S. Prusty 		break;
358b81fd263SSubhransu S. Prusty 
359b81fd263SSubhransu S. Prusty 	default:
360b81fd263SSubhransu S. Prusty 		dev_err(ipc->dev, "Unknown ipc reply: 0x%x", reply);
361b81fd263SSubhransu S. Prusty 		msg->errno = -EINVAL;
362b81fd263SSubhransu S. Prusty 		break;
363b81fd263SSubhransu S. Prusty 	}
364b81fd263SSubhransu S. Prusty 
36528f3b6f1SOmair M Abdullah 	if (reply != IPC_GLB_REPLY_SUCCESS) {
36628f3b6f1SOmair M Abdullah 		dev_err(ipc->dev, "ipc FW reply: reply=%d", reply);
36728f3b6f1SOmair M Abdullah 		dev_err(ipc->dev, "FW Error Code: %u\n",
36828f3b6f1SOmair M Abdullah 			ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp));
36928f3b6f1SOmair M Abdullah 	}
37028f3b6f1SOmair M Abdullah 
371b81fd263SSubhransu S. Prusty 	list_del(&msg->list);
372b81fd263SSubhransu S. Prusty 	sst_ipc_tx_msg_reply_complete(ipc, msg);
373b81fd263SSubhransu S. Prusty }
374b81fd263SSubhransu S. Prusty 
375b81fd263SSubhransu S. Prusty irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context)
376b81fd263SSubhransu S. Prusty {
377b81fd263SSubhransu S. Prusty 	struct sst_dsp *dsp = context;
378b81fd263SSubhransu S. Prusty 	struct skl_sst *skl = sst_dsp_get_thread_context(dsp);
379b81fd263SSubhransu S. Prusty 	struct sst_generic_ipc *ipc = &skl->ipc;
380b81fd263SSubhransu S. Prusty 	struct skl_ipc_header header = {0};
381b81fd263SSubhransu S. Prusty 	u32 hipcie, hipct, hipcte;
382b81fd263SSubhransu S. Prusty 	int ipc_irq = 0;
383b81fd263SSubhransu S. Prusty 
3846cb00333SSubhransu S. Prusty 	if (dsp->intr_status & SKL_ADSPIS_CL_DMA)
3856cb00333SSubhransu S. Prusty 		skl_cldma_process_intr(dsp);
3866cb00333SSubhransu S. Prusty 
387b81fd263SSubhransu S. Prusty 	/* Here we handle IPC interrupts only */
388b81fd263SSubhransu S. Prusty 	if (!(dsp->intr_status & SKL_ADSPIS_IPC))
389b81fd263SSubhransu S. Prusty 		return IRQ_NONE;
390b81fd263SSubhransu S. Prusty 
391b81fd263SSubhransu S. Prusty 	hipcie = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCIE);
392b81fd263SSubhransu S. Prusty 	hipct = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCT);
393b81fd263SSubhransu S. Prusty 
394b81fd263SSubhransu S. Prusty 	/* reply message from DSP */
395b81fd263SSubhransu S. Prusty 	if (hipcie & SKL_ADSP_REG_HIPCIE_DONE) {
396b81fd263SSubhransu S. Prusty 		sst_dsp_shim_update_bits(dsp, SKL_ADSP_REG_HIPCCTL,
397b81fd263SSubhransu S. Prusty 			SKL_ADSP_REG_HIPCCTL_DONE, 0);
398b81fd263SSubhransu S. Prusty 
399b81fd263SSubhransu S. Prusty 		/* clear DONE bit - tell DSP we have completed the operation */
400b81fd263SSubhransu S. Prusty 		sst_dsp_shim_update_bits_forced(dsp, SKL_ADSP_REG_HIPCIE,
401b81fd263SSubhransu S. Prusty 			SKL_ADSP_REG_HIPCIE_DONE, SKL_ADSP_REG_HIPCIE_DONE);
402b81fd263SSubhransu S. Prusty 
403b81fd263SSubhransu S. Prusty 		ipc_irq = 1;
404b81fd263SSubhransu S. Prusty 
405b81fd263SSubhransu S. Prusty 		/* unmask Done interrupt */
406b81fd263SSubhransu S. Prusty 		sst_dsp_shim_update_bits(dsp, SKL_ADSP_REG_HIPCCTL,
407b81fd263SSubhransu S. Prusty 			SKL_ADSP_REG_HIPCCTL_DONE, SKL_ADSP_REG_HIPCCTL_DONE);
408b81fd263SSubhransu S. Prusty 	}
409b81fd263SSubhransu S. Prusty 
410b81fd263SSubhransu S. Prusty 	/* New message from DSP */
411b81fd263SSubhransu S. Prusty 	if (hipct & SKL_ADSP_REG_HIPCT_BUSY) {
412b81fd263SSubhransu S. Prusty 		hipcte = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCTE);
413b81fd263SSubhransu S. Prusty 		header.primary = hipct;
414b81fd263SSubhransu S. Prusty 		header.extension = hipcte;
415b81fd263SSubhransu S. Prusty 		dev_dbg(dsp->dev, "IPC irq: Firmware respond primary:%x",
416b81fd263SSubhransu S. Prusty 						header.primary);
417b81fd263SSubhransu S. Prusty 		dev_dbg(dsp->dev, "IPC irq: Firmware respond extension:%x",
418b81fd263SSubhransu S. Prusty 						header.extension);
419b81fd263SSubhransu S. Prusty 
420b81fd263SSubhransu S. Prusty 		if (IPC_GLB_NOTIFY_RSP_TYPE(header.primary)) {
421b81fd263SSubhransu S. Prusty 			/* Handle Immediate reply from DSP Core */
422b81fd263SSubhransu S. Prusty 			skl_ipc_process_reply(ipc, header);
423b81fd263SSubhransu S. Prusty 		} else {
424b81fd263SSubhransu S. Prusty 			dev_dbg(dsp->dev, "IPC irq: Notification from firmware\n");
425b81fd263SSubhransu S. Prusty 			skl_ipc_process_notification(ipc, header);
426b81fd263SSubhransu S. Prusty 		}
427b81fd263SSubhransu S. Prusty 		/* clear  busy interrupt */
428b81fd263SSubhransu S. Prusty 		sst_dsp_shim_update_bits_forced(dsp, SKL_ADSP_REG_HIPCT,
429b81fd263SSubhransu S. Prusty 			SKL_ADSP_REG_HIPCT_BUSY, SKL_ADSP_REG_HIPCT_BUSY);
430b81fd263SSubhransu S. Prusty 		ipc_irq = 1;
431b81fd263SSubhransu S. Prusty 	}
432b81fd263SSubhransu S. Prusty 
433b81fd263SSubhransu S. Prusty 	if (ipc_irq == 0)
434b81fd263SSubhransu S. Prusty 		return IRQ_NONE;
435b81fd263SSubhransu S. Prusty 
436b81fd263SSubhransu S. Prusty 	skl_ipc_int_enable(dsp);
437b81fd263SSubhransu S. Prusty 
438b81fd263SSubhransu S. Prusty 	/* continue to send any remaining messages... */
439b81fd263SSubhransu S. Prusty 	queue_kthread_work(&ipc->kworker, &ipc->kwork);
440b81fd263SSubhransu S. Prusty 
441b81fd263SSubhransu S. Prusty 	return IRQ_HANDLED;
442b81fd263SSubhransu S. Prusty }
443b81fd263SSubhransu S. Prusty 
444b81fd263SSubhransu S. Prusty void skl_ipc_int_enable(struct sst_dsp *ctx)
445b81fd263SSubhransu S. Prusty {
446b81fd263SSubhransu S. Prusty 	sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_ADSPIC,
447b81fd263SSubhransu S. Prusty 			SKL_ADSPIC_IPC, SKL_ADSPIC_IPC);
448b81fd263SSubhransu S. Prusty }
449b81fd263SSubhransu S. Prusty 
450b81fd263SSubhransu S. Prusty void skl_ipc_int_disable(struct sst_dsp *ctx)
451b81fd263SSubhransu S. Prusty {
452b81fd263SSubhransu S. Prusty 	sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPIC,
453b81fd263SSubhransu S. Prusty 			SKL_ADSPIC_IPC, 0);
454b81fd263SSubhransu S. Prusty }
455b81fd263SSubhransu S. Prusty 
456b81fd263SSubhransu S. Prusty void skl_ipc_op_int_enable(struct sst_dsp *ctx)
457b81fd263SSubhransu S. Prusty {
458b81fd263SSubhransu S. Prusty 	/* enable IPC DONE interrupt */
459b81fd263SSubhransu S. Prusty 	sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_HIPCCTL,
460b81fd263SSubhransu S. Prusty 		SKL_ADSP_REG_HIPCCTL_DONE, SKL_ADSP_REG_HIPCCTL_DONE);
461b81fd263SSubhransu S. Prusty 
462b81fd263SSubhransu S. Prusty 	/* Enable IPC BUSY interrupt */
463b81fd263SSubhransu S. Prusty 	sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_HIPCCTL,
464b81fd263SSubhransu S. Prusty 		SKL_ADSP_REG_HIPCCTL_BUSY, SKL_ADSP_REG_HIPCCTL_BUSY);
465b81fd263SSubhransu S. Prusty }
466b81fd263SSubhransu S. Prusty 
46784c9e283SJeeja KP void skl_ipc_op_int_disable(struct sst_dsp *ctx)
46884c9e283SJeeja KP {
46984c9e283SJeeja KP 	/* disable IPC DONE interrupt */
47084c9e283SJeeja KP 	sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_HIPCCTL,
47184c9e283SJeeja KP 					SKL_ADSP_REG_HIPCCTL_DONE, 0);
47284c9e283SJeeja KP 
47384c9e283SJeeja KP 	/* Disable IPC BUSY interrupt */
47484c9e283SJeeja KP 	sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_HIPCCTL,
47584c9e283SJeeja KP 					SKL_ADSP_REG_HIPCCTL_BUSY, 0);
47684c9e283SJeeja KP 
47784c9e283SJeeja KP }
47884c9e283SJeeja KP 
479b81fd263SSubhransu S. Prusty bool skl_ipc_int_status(struct sst_dsp *ctx)
480b81fd263SSubhransu S. Prusty {
481b81fd263SSubhransu S. Prusty 	return sst_dsp_shim_read_unlocked(ctx,
482b81fd263SSubhransu S. Prusty 			SKL_ADSP_REG_ADSPIS) & SKL_ADSPIS_IPC;
483b81fd263SSubhransu S. Prusty }
484b81fd263SSubhransu S. Prusty 
485b81fd263SSubhransu S. Prusty int skl_ipc_init(struct device *dev, struct skl_sst *skl)
486b81fd263SSubhransu S. Prusty {
487b81fd263SSubhransu S. Prusty 	struct sst_generic_ipc *ipc;
488b81fd263SSubhransu S. Prusty 	int err;
489b81fd263SSubhransu S. Prusty 
490b81fd263SSubhransu S. Prusty 	ipc = &skl->ipc;
491b81fd263SSubhransu S. Prusty 	ipc->dsp = skl->dsp;
492b81fd263SSubhransu S. Prusty 	ipc->dev = dev;
493b81fd263SSubhransu S. Prusty 
494b81fd263SSubhransu S. Prusty 	ipc->tx_data_max_size = SKL_ADSP_W1_SZ;
495b81fd263SSubhransu S. Prusty 	ipc->rx_data_max_size = SKL_ADSP_W0_UP_SZ;
496b81fd263SSubhransu S. Prusty 
497b81fd263SSubhransu S. Prusty 	err = sst_ipc_init(ipc);
498b81fd263SSubhransu S. Prusty 	if (err)
499b81fd263SSubhransu S. Prusty 		return err;
500b81fd263SSubhransu S. Prusty 
501b81fd263SSubhransu S. Prusty 	ipc->ops.tx_msg = skl_ipc_tx_msg;
502b81fd263SSubhransu S. Prusty 	ipc->ops.tx_data_copy = skl_ipc_tx_data_copy;
503b81fd263SSubhransu S. Prusty 	ipc->ops.is_dsp_busy = skl_ipc_is_dsp_busy;
504b81fd263SSubhransu S. Prusty 
505b81fd263SSubhransu S. Prusty 	return 0;
506b81fd263SSubhransu S. Prusty }
507b81fd263SSubhransu S. Prusty 
508b81fd263SSubhransu S. Prusty void skl_ipc_free(struct sst_generic_ipc *ipc)
509b81fd263SSubhransu S. Prusty {
510b81fd263SSubhransu S. Prusty 	/* Disable IPC DONE interrupt */
511b81fd263SSubhransu S. Prusty 	sst_dsp_shim_update_bits(ipc->dsp, SKL_ADSP_REG_HIPCCTL,
512b81fd263SSubhransu S. Prusty 		SKL_ADSP_REG_HIPCCTL_DONE, 0);
513b81fd263SSubhransu S. Prusty 
514b81fd263SSubhransu S. Prusty 	/* Disable IPC BUSY interrupt */
515b81fd263SSubhransu S. Prusty 	sst_dsp_shim_update_bits(ipc->dsp, SKL_ADSP_REG_HIPCCTL,
516b81fd263SSubhransu S. Prusty 		SKL_ADSP_REG_HIPCCTL_BUSY, 0);
517a750ba5fSSubhransu S. Prusty 
518a750ba5fSSubhransu S. Prusty 	sst_ipc_fini(ipc);
519b81fd263SSubhransu S. Prusty }
520b81fd263SSubhransu S. Prusty 
521b81fd263SSubhransu S. Prusty int skl_ipc_create_pipeline(struct sst_generic_ipc *ipc,
522b81fd263SSubhransu S. Prusty 		u16 ppl_mem_size, u8 ppl_type, u8 instance_id)
523b81fd263SSubhransu S. Prusty {
524b81fd263SSubhransu S. Prusty 	struct skl_ipc_header header = {0};
525b81fd263SSubhransu S. Prusty 	u64 *ipc_header = (u64 *)(&header);
526b81fd263SSubhransu S. Prusty 	int ret;
527b81fd263SSubhransu S. Prusty 
528b81fd263SSubhransu S. Prusty 	header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG);
529b81fd263SSubhransu S. Prusty 	header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
530b81fd263SSubhransu S. Prusty 	header.primary |= IPC_GLB_TYPE(IPC_GLB_CREATE_PPL);
531b81fd263SSubhransu S. Prusty 	header.primary |= IPC_INSTANCE_ID(instance_id);
532b81fd263SSubhransu S. Prusty 	header.primary |= IPC_PPL_TYPE(ppl_type);
533b81fd263SSubhransu S. Prusty 	header.primary |= IPC_PPL_MEM_SIZE(ppl_mem_size);
534b81fd263SSubhransu S. Prusty 
535b81fd263SSubhransu S. Prusty 	dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary);
536b81fd263SSubhransu S. Prusty 	ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0);
537b81fd263SSubhransu S. Prusty 	if (ret < 0) {
538b81fd263SSubhransu S. Prusty 		dev_err(ipc->dev, "ipc: create pipeline fail, err: %d\n", ret);
539b81fd263SSubhransu S. Prusty 		return ret;
540b81fd263SSubhransu S. Prusty 	}
541b81fd263SSubhransu S. Prusty 
542b81fd263SSubhransu S. Prusty 	return ret;
543b81fd263SSubhransu S. Prusty }
544b81fd263SSubhransu S. Prusty EXPORT_SYMBOL_GPL(skl_ipc_create_pipeline);
545b81fd263SSubhransu S. Prusty 
546b81fd263SSubhransu S. Prusty int skl_ipc_delete_pipeline(struct sst_generic_ipc *ipc, u8 instance_id)
547b81fd263SSubhransu S. Prusty {
548b81fd263SSubhransu S. Prusty 	struct skl_ipc_header header = {0};
549b81fd263SSubhransu S. Prusty 	u64 *ipc_header = (u64 *)(&header);
550b81fd263SSubhransu S. Prusty 	int ret;
551b81fd263SSubhransu S. Prusty 
552b81fd263SSubhransu S. Prusty 	header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG);
553b81fd263SSubhransu S. Prusty 	header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
554b81fd263SSubhransu S. Prusty 	header.primary |= IPC_GLB_TYPE(IPC_GLB_DELETE_PPL);
555b81fd263SSubhransu S. Prusty 	header.primary |= IPC_INSTANCE_ID(instance_id);
556b81fd263SSubhransu S. Prusty 
557b81fd263SSubhransu S. Prusty 	dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary);
558b81fd263SSubhransu S. Prusty 	ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0);
559b81fd263SSubhransu S. Prusty 	if (ret < 0) {
560b81fd263SSubhransu S. Prusty 		dev_err(ipc->dev, "ipc: delete pipeline failed, err %d\n", ret);
561b81fd263SSubhransu S. Prusty 		return ret;
562b81fd263SSubhransu S. Prusty 	}
563b81fd263SSubhransu S. Prusty 
564b81fd263SSubhransu S. Prusty 	return 0;
565b81fd263SSubhransu S. Prusty }
566b81fd263SSubhransu S. Prusty EXPORT_SYMBOL_GPL(skl_ipc_delete_pipeline);
567b81fd263SSubhransu S. Prusty 
568b81fd263SSubhransu S. Prusty int skl_ipc_set_pipeline_state(struct sst_generic_ipc *ipc,
569b81fd263SSubhransu S. Prusty 		u8 instance_id, enum skl_ipc_pipeline_state state)
570b81fd263SSubhransu S. Prusty {
571b81fd263SSubhransu S. Prusty 	struct skl_ipc_header header = {0};
572b81fd263SSubhransu S. Prusty 	u64 *ipc_header = (u64 *)(&header);
573b81fd263SSubhransu S. Prusty 	int ret;
574b81fd263SSubhransu S. Prusty 
575b81fd263SSubhransu S. Prusty 	header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG);
576b81fd263SSubhransu S. Prusty 	header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
577b81fd263SSubhransu S. Prusty 	header.primary |= IPC_GLB_TYPE(IPC_GLB_SET_PPL_STATE);
578b81fd263SSubhransu S. Prusty 	header.primary |= IPC_INSTANCE_ID(instance_id);
579b81fd263SSubhransu S. Prusty 	header.primary |= IPC_PPL_STATE(state);
580b81fd263SSubhransu S. Prusty 
581b81fd263SSubhransu S. Prusty 	dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary);
582b81fd263SSubhransu S. Prusty 	ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0);
583b81fd263SSubhransu S. Prusty 	if (ret < 0) {
584b81fd263SSubhransu S. Prusty 		dev_err(ipc->dev, "ipc: set pipeline state failed, err: %d\n", ret);
585b81fd263SSubhransu S. Prusty 		return ret;
586b81fd263SSubhransu S. Prusty 	}
587b81fd263SSubhransu S. Prusty 	return ret;
588b81fd263SSubhransu S. Prusty }
589b81fd263SSubhransu S. Prusty EXPORT_SYMBOL_GPL(skl_ipc_set_pipeline_state);
590b81fd263SSubhransu S. Prusty 
591b81fd263SSubhransu S. Prusty int
592b81fd263SSubhransu S. Prusty skl_ipc_save_pipeline(struct sst_generic_ipc *ipc, u8 instance_id, int dma_id)
593b81fd263SSubhransu S. Prusty {
594b81fd263SSubhransu S. Prusty 	struct skl_ipc_header header = {0};
595b81fd263SSubhransu S. Prusty 	u64 *ipc_header = (u64 *)(&header);
596b81fd263SSubhransu S. Prusty 	int ret;
597b81fd263SSubhransu S. Prusty 
598b81fd263SSubhransu S. Prusty 	header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG);
599b81fd263SSubhransu S. Prusty 	header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
600b81fd263SSubhransu S. Prusty 	header.primary |= IPC_GLB_TYPE(IPC_GLB_SAVE_PPL);
601b81fd263SSubhransu S. Prusty 	header.primary |= IPC_INSTANCE_ID(instance_id);
602b81fd263SSubhransu S. Prusty 
603b81fd263SSubhransu S. Prusty 	header.extension = IPC_DMA_ID(dma_id);
604b81fd263SSubhransu S. Prusty 	dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary);
605b81fd263SSubhransu S. Prusty 	ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0);
606b81fd263SSubhransu S. Prusty 	if (ret < 0) {
607b81fd263SSubhransu S. Prusty 		dev_err(ipc->dev, "ipc: save pipeline failed, err: %d\n", ret);
608b81fd263SSubhransu S. Prusty 		return ret;
609b81fd263SSubhransu S. Prusty 	}
610b81fd263SSubhransu S. Prusty 
611b81fd263SSubhransu S. Prusty 	return ret;
612b81fd263SSubhransu S. Prusty }
613b81fd263SSubhransu S. Prusty EXPORT_SYMBOL_GPL(skl_ipc_save_pipeline);
614b81fd263SSubhransu S. Prusty 
615b81fd263SSubhransu S. Prusty int skl_ipc_restore_pipeline(struct sst_generic_ipc *ipc, u8 instance_id)
616b81fd263SSubhransu S. Prusty {
617b81fd263SSubhransu S. Prusty 	struct skl_ipc_header header = {0};
618b81fd263SSubhransu S. Prusty 	u64 *ipc_header = (u64 *)(&header);
619b81fd263SSubhransu S. Prusty 	int ret;
620b81fd263SSubhransu S. Prusty 
621b81fd263SSubhransu S. Prusty 	header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG);
622b81fd263SSubhransu S. Prusty 	header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
623b81fd263SSubhransu S. Prusty 	header.primary |= IPC_GLB_TYPE(IPC_GLB_RESTORE_PPL);
624b81fd263SSubhransu S. Prusty 	header.primary |= IPC_INSTANCE_ID(instance_id);
625b81fd263SSubhransu S. Prusty 
626b81fd263SSubhransu S. Prusty 	dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary);
627b81fd263SSubhransu S. Prusty 	ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0);
628b81fd263SSubhransu S. Prusty 	if (ret < 0) {
629b81fd263SSubhransu S. Prusty 		dev_err(ipc->dev, "ipc: restore  pipeline failed, err: %d\n", ret);
630b81fd263SSubhransu S. Prusty 		return ret;
631b81fd263SSubhransu S. Prusty 	}
632b81fd263SSubhransu S. Prusty 
633b81fd263SSubhransu S. Prusty 	return ret;
634b81fd263SSubhransu S. Prusty }
635b81fd263SSubhransu S. Prusty EXPORT_SYMBOL_GPL(skl_ipc_restore_pipeline);
636b81fd263SSubhransu S. Prusty 
637b81fd263SSubhransu S. Prusty int skl_ipc_set_dx(struct sst_generic_ipc *ipc, u8 instance_id,
638b81fd263SSubhransu S. Prusty 		u16 module_id, struct skl_ipc_dxstate_info *dx)
639b81fd263SSubhransu S. Prusty {
640b81fd263SSubhransu S. Prusty 	struct skl_ipc_header header = {0};
641b81fd263SSubhransu S. Prusty 	u64 *ipc_header = (u64 *)(&header);
642b81fd263SSubhransu S. Prusty 	int ret;
643b81fd263SSubhransu S. Prusty 
644b81fd263SSubhransu S. Prusty 	header.primary = IPC_MSG_TARGET(IPC_MOD_MSG);
645b81fd263SSubhransu S. Prusty 	header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
646b81fd263SSubhransu S. Prusty 	header.primary |= IPC_GLB_TYPE(IPC_MOD_SET_DX);
647b81fd263SSubhransu S. Prusty 	header.primary |= IPC_MOD_INSTANCE_ID(instance_id);
648b81fd263SSubhransu S. Prusty 	header.primary |= IPC_MOD_ID(module_id);
649b81fd263SSubhransu S. Prusty 
650b81fd263SSubhransu S. Prusty 	dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__,
651b81fd263SSubhransu S. Prusty 			 header.primary, header.extension);
652b81fd263SSubhransu S. Prusty 	ret = sst_ipc_tx_message_wait(ipc, *ipc_header,
653b81fd263SSubhransu S. Prusty 				dx, sizeof(dx), NULL, 0);
654b81fd263SSubhransu S. Prusty 	if (ret < 0) {
655b81fd263SSubhransu S. Prusty 		dev_err(ipc->dev, "ipc: set dx failed, err %d\n", ret);
656b81fd263SSubhransu S. Prusty 		return ret;
657b81fd263SSubhransu S. Prusty 	}
658b81fd263SSubhransu S. Prusty 
659b81fd263SSubhransu S. Prusty 	return ret;
660b81fd263SSubhransu S. Prusty }
661b81fd263SSubhransu S. Prusty EXPORT_SYMBOL_GPL(skl_ipc_set_dx);
662b81fd263SSubhransu S. Prusty 
663b81fd263SSubhransu S. Prusty int skl_ipc_init_instance(struct sst_generic_ipc *ipc,
664b81fd263SSubhransu S. Prusty 		struct skl_ipc_init_instance_msg *msg, void *param_data)
665b81fd263SSubhransu S. Prusty {
666b81fd263SSubhransu S. Prusty 	struct skl_ipc_header header = {0};
667b81fd263SSubhransu S. Prusty 	u64 *ipc_header = (u64 *)(&header);
668b81fd263SSubhransu S. Prusty 	int ret;
669b81fd263SSubhransu S. Prusty 	u32 *buffer = (u32 *)param_data;
670b81fd263SSubhransu S. Prusty 	 /* param_block_size must be in dwords */
671b81fd263SSubhransu S. Prusty 	u16 param_block_size = msg->param_data_size / sizeof(u32);
672b81fd263SSubhransu S. Prusty 
673b81fd263SSubhransu S. Prusty 	print_hex_dump(KERN_DEBUG, NULL, DUMP_PREFIX_NONE,
674b81fd263SSubhransu S. Prusty 		16, 4, buffer, param_block_size, false);
675b81fd263SSubhransu S. Prusty 
676b81fd263SSubhransu S. Prusty 	header.primary = IPC_MSG_TARGET(IPC_MOD_MSG);
677b81fd263SSubhransu S. Prusty 	header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
678b81fd263SSubhransu S. Prusty 	header.primary |= IPC_GLB_TYPE(IPC_MOD_INIT_INSTANCE);
679b81fd263SSubhransu S. Prusty 	header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id);
680b81fd263SSubhransu S. Prusty 	header.primary |= IPC_MOD_ID(msg->module_id);
681b81fd263SSubhransu S. Prusty 
682b81fd263SSubhransu S. Prusty 	header.extension = IPC_CORE_ID(msg->core_id);
683b81fd263SSubhransu S. Prusty 	header.extension |= IPC_PPL_INSTANCE_ID(msg->ppl_instance_id);
684b81fd263SSubhransu S. Prusty 	header.extension |= IPC_PARAM_BLOCK_SIZE(param_block_size);
685b81fd263SSubhransu S. Prusty 
686b81fd263SSubhransu S. Prusty 	dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__,
687b81fd263SSubhransu S. Prusty 			 header.primary, header.extension);
688b81fd263SSubhransu S. Prusty 	ret = sst_ipc_tx_message_wait(ipc, *ipc_header, param_data,
689b81fd263SSubhransu S. Prusty 			msg->param_data_size, NULL, 0);
690b81fd263SSubhransu S. Prusty 
691b81fd263SSubhransu S. Prusty 	if (ret < 0) {
692b81fd263SSubhransu S. Prusty 		dev_err(ipc->dev, "ipc: init instance failed\n");
693b81fd263SSubhransu S. Prusty 		return ret;
694b81fd263SSubhransu S. Prusty 	}
695b81fd263SSubhransu S. Prusty 
696b81fd263SSubhransu S. Prusty 	return ret;
697b81fd263SSubhransu S. Prusty }
698b81fd263SSubhransu S. Prusty EXPORT_SYMBOL_GPL(skl_ipc_init_instance);
699b81fd263SSubhransu S. Prusty 
700b81fd263SSubhransu S. Prusty int skl_ipc_bind_unbind(struct sst_generic_ipc *ipc,
701b81fd263SSubhransu S. Prusty 		struct skl_ipc_bind_unbind_msg *msg)
702b81fd263SSubhransu S. Prusty {
703b81fd263SSubhransu S. Prusty 	struct skl_ipc_header header = {0};
704b81fd263SSubhransu S. Prusty 	u64 *ipc_header = (u64 *)(&header);
705b81fd263SSubhransu S. Prusty 	u8 bind_unbind = msg->bind ? IPC_MOD_BIND : IPC_MOD_UNBIND;
706b81fd263SSubhransu S. Prusty 	int ret;
707b81fd263SSubhransu S. Prusty 
708b81fd263SSubhransu S. Prusty 	header.primary = IPC_MSG_TARGET(IPC_MOD_MSG);
709b81fd263SSubhransu S. Prusty 	header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
710b81fd263SSubhransu S. Prusty 	header.primary |= IPC_GLB_TYPE(bind_unbind);
711b81fd263SSubhransu S. Prusty 	header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id);
712b81fd263SSubhransu S. Prusty 	header.primary |= IPC_MOD_ID(msg->module_id);
713b81fd263SSubhransu S. Prusty 
714b81fd263SSubhransu S. Prusty 	header.extension = IPC_DST_MOD_ID(msg->dst_module_id);
715b81fd263SSubhransu S. Prusty 	header.extension |= IPC_DST_MOD_INSTANCE_ID(msg->dst_instance_id);
716b81fd263SSubhransu S. Prusty 	header.extension |= IPC_DST_QUEUE(msg->dst_queue);
717b81fd263SSubhransu S. Prusty 	header.extension |= IPC_SRC_QUEUE(msg->src_queue);
718b81fd263SSubhransu S. Prusty 
719b81fd263SSubhransu S. Prusty 	dev_dbg(ipc->dev, "In %s hdr=%x ext=%x\n", __func__, header.primary,
720b81fd263SSubhransu S. Prusty 			 header.extension);
721b81fd263SSubhransu S. Prusty 	ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0);
722b81fd263SSubhransu S. Prusty 	if (ret < 0) {
723b81fd263SSubhransu S. Prusty 		dev_err(ipc->dev, "ipc: bind/unbind faileden");
724b81fd263SSubhransu S. Prusty 		return ret;
725b81fd263SSubhransu S. Prusty 	}
726b81fd263SSubhransu S. Prusty 
727b81fd263SSubhransu S. Prusty 	return ret;
728b81fd263SSubhransu S. Prusty }
729b81fd263SSubhransu S. Prusty EXPORT_SYMBOL_GPL(skl_ipc_bind_unbind);
730b81fd263SSubhransu S. Prusty 
731b81fd263SSubhransu S. Prusty int skl_ipc_set_large_config(struct sst_generic_ipc *ipc,
732b81fd263SSubhransu S. Prusty 		struct skl_ipc_large_config_msg *msg, u32 *param)
733b81fd263SSubhransu S. Prusty {
734b81fd263SSubhransu S. Prusty 	struct skl_ipc_header header = {0};
735b81fd263SSubhransu S. Prusty 	u64 *ipc_header = (u64 *)(&header);
736b81fd263SSubhransu S. Prusty 	int ret = 0;
737b81fd263SSubhransu S. Prusty 	size_t sz_remaining, tx_size, data_offset;
738b81fd263SSubhransu S. Prusty 
739b81fd263SSubhransu S. Prusty 	header.primary = IPC_MSG_TARGET(IPC_MOD_MSG);
740b81fd263SSubhransu S. Prusty 	header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
741b81fd263SSubhransu S. Prusty 	header.primary |= IPC_GLB_TYPE(IPC_MOD_LARGE_CONFIG_SET);
742b81fd263SSubhransu S. Prusty 	header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id);
743b81fd263SSubhransu S. Prusty 	header.primary |= IPC_MOD_ID(msg->module_id);
744b81fd263SSubhransu S. Prusty 
745b81fd263SSubhransu S. Prusty 	header.extension = IPC_DATA_OFFSET_SZ(msg->param_data_size);
746b81fd263SSubhransu S. Prusty 	header.extension |= IPC_LARGE_PARAM_ID(msg->large_param_id);
747b81fd263SSubhransu S. Prusty 	header.extension |= IPC_FINAL_BLOCK(0);
748b81fd263SSubhransu S. Prusty 	header.extension |= IPC_INITIAL_BLOCK(1);
749b81fd263SSubhransu S. Prusty 
750b81fd263SSubhransu S. Prusty 	sz_remaining = msg->param_data_size;
751b81fd263SSubhransu S. Prusty 	data_offset = 0;
752b81fd263SSubhransu S. Prusty 	while (sz_remaining != 0) {
753b81fd263SSubhransu S. Prusty 		tx_size = sz_remaining > SKL_ADSP_W1_SZ
754b81fd263SSubhransu S. Prusty 				? SKL_ADSP_W1_SZ : sz_remaining;
755b81fd263SSubhransu S. Prusty 		if (tx_size == sz_remaining)
756b81fd263SSubhransu S. Prusty 			header.extension |= IPC_FINAL_BLOCK(1);
757b81fd263SSubhransu S. Prusty 
758b81fd263SSubhransu S. Prusty 		dev_dbg(ipc->dev, "In %s primary=%#x ext=%#x\n", __func__,
759b81fd263SSubhransu S. Prusty 			header.primary, header.extension);
760b81fd263SSubhransu S. Prusty 		dev_dbg(ipc->dev, "transmitting offset: %#x, size: %#x\n",
761b81fd263SSubhransu S. Prusty 			(unsigned)data_offset, (unsigned)tx_size);
762b81fd263SSubhransu S. Prusty 		ret = sst_ipc_tx_message_wait(ipc, *ipc_header,
763b81fd263SSubhransu S. Prusty 					  ((char *)param) + data_offset,
764b81fd263SSubhransu S. Prusty 					  tx_size, NULL, 0);
765b81fd263SSubhransu S. Prusty 		if (ret < 0) {
766b81fd263SSubhransu S. Prusty 			dev_err(ipc->dev,
767b81fd263SSubhransu S. Prusty 				"ipc: set large config fail, err: %d\n", ret);
768b81fd263SSubhransu S. Prusty 			return ret;
769b81fd263SSubhransu S. Prusty 		}
770b81fd263SSubhransu S. Prusty 		sz_remaining -= tx_size;
771b81fd263SSubhransu S. Prusty 		data_offset = msg->param_data_size - sz_remaining;
772b81fd263SSubhransu S. Prusty 
773b81fd263SSubhransu S. Prusty 		/* clear the fields */
774b81fd263SSubhransu S. Prusty 		header.extension &= IPC_INITIAL_BLOCK_CLEAR;
775b81fd263SSubhransu S. Prusty 		header.extension &= IPC_DATA_OFFSET_SZ_CLEAR;
776b81fd263SSubhransu S. Prusty 		/* fill the fields */
777b81fd263SSubhransu S. Prusty 		header.extension |= IPC_INITIAL_BLOCK(0);
778b81fd263SSubhransu S. Prusty 		header.extension |= IPC_DATA_OFFSET_SZ(data_offset);
779b81fd263SSubhransu S. Prusty 	}
780b81fd263SSubhransu S. Prusty 
781b81fd263SSubhransu S. Prusty 	return ret;
782b81fd263SSubhransu S. Prusty }
783b81fd263SSubhransu S. Prusty EXPORT_SYMBOL_GPL(skl_ipc_set_large_config);
784