1 /*
2  * Copyright (c) 2023 Intel Corporation
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include "sedi_driver_core.h"
8 #include <sedi_driver_common.h>
9 #include <sedi_ipc_regs.h>
10 #include <sedi_driver_ipc.h>
11 
12 #define SEDI_IPC_API_VERSION 0
13 /* driver version */
14 #define SEDI_IPC_DRIVER_VERSION SEDI_DRIVER_VERSION_MAJOR_MINOR(0, 1)
15 
16 #define IPC_REG_SB_LOCAL2PMC_DRBL 0x1804
17 #define IPC_REG_SB_LOCAL2PMC_MSG 0x1808
18 #define IPC_REG_SB_PMC2LOCAL_DRBL_MIRROR 0x1888
19 #define IPC_REG_SB_PMC2LOCAL_DRBL_MIRROR 0x1888
20 
21 #define IPC_REG_SB_LOCAL2CSE_CSR 0x3c
22 #define IPC_REG_SB_LOCAL2CSE_DRBL 0x0
23 #define IPC_REG_SB_LOCAL2CSE_MSG 0x40
24 #define IPC_REG_SB_CSE2LOCAL_DRBL_MIRROR 0x4
25 
26 #define IPC_REG_SB_LOCAL2CNVI_CSR 0x698
27 #define IPC_REG_SB_LOCAL2CNVI_DRBL 0x690
28 #define IPC_REG_SB_LOCAL2CNVI_MSG 0x7600
29 #define IPC_REG_SB_CNVI2LOCAL_DRBL_MIRROR 0x694
30 
31 #define IPC_REG_SB_LOCAL2BT_CSR 0x698
32 #define IPC_REG_SB_LOCAL2BT_DRBL 0x690
33 #define IPC_REG_SB_LOCAL2BT_MSG 0x7600
34 #define IPC_REG_SB_BT2LOCAL_DRBL_MIRROR 0x694
35 
36 #ifdef SEDI_SB_SUPPORT
37 #define SEDI_SIDEBAND_PMC SEDI_SIDEBAND_0
38 #define SEDI_SIDEBAND_CSE SEDI_SIDEBAND_0
39 #endif
40 
41 /*driver version*/
42 static const sedi_driver_version_t driver_version = { SEDI_IPC_API_VERSION,
43 						      SEDI_IPC_DRIVER_VERSION };
44 /* sideband params for non-host interfaces */
45 #ifdef SEDI_SB_SUPPORT
46 typedef struct {
47 	sedi_sideband_t dev;
48 	sb_port_t port;
49 	uint32_t csr_peer_addr;
50 	uint32_t drbl_peer_addr;
51 	uint32_t msg_peer_addr;
52 	uint32_t drbl_mirror_peer_addr;
53 } sideband_param_t;
54 #else
55 typedef struct {
56 } sideband_param_t;
57 #endif
58 
59 /* ipc resource information */
60 typedef struct {
61 	sedi_ipc_regs_t *reg_base_addr;
62 	vnn_id_t read_vnn;
63 	vnn_id_t write_vnn;
64 	sideband_param_t *sb;
65 } ipc_resource_t;
66 
67 /*ipc runtime context information */
68 typedef struct {
69 	bool initialized;
70 	uint32_t csr_saved;
71 	sedi_ipc_event_cb_t cb_event; /*event callback*/
72 	uint32_t in_msg_count; /* for debug usage*/
73 	uint32_t out_msg_count; /* for debug usage*/
74 	/* user parameters for event callback other private runtime data*/
75 	void *usr_params;
76 } ipc_context_t;
77 
78 static sedi_ipc_capabilities_t driver_capabilities[SEDI_IPC_NUM] = { 0 };
79 
80 #ifdef SEDI_SB_SUPPORT
81 static sideband_param_t pmc_sb = { .dev = SEDI_SIDEBAND_PMC,
82 				   .port = SB_PMC,
83 				   .csr_peer_addr = IPC_REG_SB_LOCAL2PMC_CSR,
84 				   .drbl_peer_addr = IPC_REG_SB_LOCAL2PMC_DRBL,
85 				   .msg_peer_addr = IPC_REG_SB_LOCAL2PMC_MSG,
86 				   .drbl_mirror_peer_addr = IPC_REG_SB_PMC2LOCAL_DRBL_MIRROR };
87 static sideband_param_t cse_sb = { .dev = SEDI_SIDEBAND_CSE,
88 				   .port = SB_CSME,
89 				   .csr_peer_addr = IPC_REG_SB_LOCAL2CSE_CSR,
90 				   .drbl_peer_addr = IPC_REG_SB_LOCAL2CSE_DRBL,
91 				   .msg_peer_addr = IPC_REG_SB_LOCAL2CSE_MSG,
92 				   .drbl_mirror_peer_addr = IPC_REG_SB_CSE2LOCAL_DRBL_MIRROR };
93 #endif
94 
95 static const ipc_resource_t ipc_resource[SEDI_IPC_NUM] = {
96 #ifdef SEDI_SB_SUPPORT
97 	{ .reg_base_addr = (sedi_ipc_regs_t *)SEDI_REG_BASE(IPC_HOST),
98 	  .read_vnn = VNN_ID_IPC_HOST_R,
99 	  .write_vnn = VNN_ID_IPC_HOST_W,
100 	  .sb = NULL },
101 	{ .reg_base_addr = (sedi_ipc_regs_t *)SEDI_REG_BASE(IPC_CSME),
102 	  .read_vnn = VNN_ID_IPC_CSE_R,
103 	  .write_vnn = VNN_ID_IPC_CSE_W,
104 	  .sb = &cse_sb },
105 	{ .reg_base_addr = (sedi_ipc_regs_t *)SEDI_REG_BASE(IPC_PMC),
106 	  .read_vnn = VNN_ID_IPC_PMC_R,
107 	  .write_vnn = VNN_ID_IPC_PMC_W,
108 	  .sb = &pmc_sb },
109 #else
110 	{ .reg_base_addr = (sedi_ipc_regs_t *)SEDI_REG_BASE(IPC_HOST),
111 	  .read_vnn = VNN_ID_IPC_HOST_R,
112 	  .write_vnn = VNN_ID_IPC_HOST_W },
113 	{ .reg_base_addr = (sedi_ipc_regs_t *)SEDI_REG_BASE(IPC_CSME),
114 	  .read_vnn = VNN_ID_IPC_CSE_R,
115 	  .write_vnn = VNN_ID_IPC_CSE_W },
116 	{ .reg_base_addr = (sedi_ipc_regs_t *)SEDI_REG_BASE(IPC_PMC),
117 	  .read_vnn = VNN_ID_IPC_PMC_R,
118 	  .write_vnn = VNN_ID_IPC_PMC_W },
119 #endif
120 };
121 
122 /*driver contexts */
123 static ipc_context_t ipc_contexts[SEDI_IPC_NUM] = { 0 };
124 
check_ipc_available(IN sedi_ipc_t ipc_device)125 static int32_t check_ipc_available(IN sedi_ipc_t ipc_device)
126 {
127 	DBG_CHECK(ipc_device < SEDI_IPC_NUM, SEDI_DRIVER_ERROR_PARAMETER);
128 	if (!ipc_contexts[ipc_device].initialized) {
129 		return SEDI_DRIVER_ERROR;
130 	}
131 	return SEDI_DRIVER_OK;
132 }
133 
134 /********** IPC driver API implementation ***********/
135 
sedi_ipc_get_version(void)136 sedi_driver_version_t sedi_ipc_get_version(void)
137 {
138 	return driver_version;
139 }
140 
sedi_ipc_get_capabilities(IN sedi_ipc_t ipc_device,INOUT sedi_ipc_capabilities_t * cap)141 int32_t sedi_ipc_get_capabilities(IN sedi_ipc_t ipc_device, INOUT sedi_ipc_capabilities_t *cap)
142 {
143 	DBG_CHECK(ipc_device < SEDI_IPC_NUM, SEDI_DRIVER_ERROR_PARAMETER);
144 
145 	/* IPC is always available */
146 	driver_capabilities[ipc_device].is_available = 1;
147 	*cap = driver_capabilities[ipc_device];
148 	return SEDI_DRIVER_OK;
149 }
150 
sedi_ipc_init(IN sedi_ipc_t ipc_device,IN sedi_ipc_event_cb_t cb,INOUT void * param)151 int32_t sedi_ipc_init(IN sedi_ipc_t ipc_device, IN sedi_ipc_event_cb_t cb, INOUT void *param)
152 {
153 	DBG_CHECK(ipc_device < SEDI_IPC_NUM, SEDI_DRIVER_ERROR_PARAMETER);
154 	volatile sedi_ipc_regs_t *regs = ipc_resource[ipc_device].reg_base_addr;
155 	vnn_id_t write_vnn = ipc_resource[ipc_device].write_vnn;
156 
157 	ipc_contexts[ipc_device].initialized = false;
158 	ipc_contexts[ipc_device].csr_saved = 0;
159 	ipc_contexts[ipc_device].cb_event = cb;
160 	ipc_contexts[ipc_device].usr_params = param;
161 	ipc_contexts[ipc_device].in_msg_count = 0;
162 	ipc_contexts[ipc_device].out_msg_count = 0;
163 
164 #ifdef SEDI_SB_SUPPORT
165 	sideband_param_t *sb = ipc_resource[ipc_device].sb;
166 
167 	if (sb) {
168 		sedi_sideband_init(sb->dev);
169 	}
170 #endif
171 	if (SEDI_PREG_RBFV_IS_SET(IPC, ISH2AGENT_DOORBELL_AGENT, BUSY, 1,
172 				&regs->ish2agent_doorbell_agent)) {
173 		PM_VNN_DRIVER_REQ(write_vnn);
174 		SEDI_PREG_RBFV_SET(IPC, ISH2AGENT_DOORBELL_AGENT, BUSY, 0,
175 				&regs->ish2agent_doorbell_agent);
176 		PM_VNN_DRIVER_DEREQ(write_vnn);
177 	}
178 	ipc_contexts[ipc_device].initialized = true;
179 
180 	if (SEDI_PREG_RBFV_IS_SET(IPC, ISH_IPC_BUSY_CLEAR_AGENT,
181 				ISH2AGENT_BUSY_CLEAR, 1,
182 				&regs->ish_ipc_busy_clear_agent)) {
183 		/*set 1 to clear this interrupt*/
184 		SEDI_PREG_RBFV_SET(IPC, ISH_IPC_BUSY_CLEAR_AGENT,
185 				ISH2AGENT_BUSY_CLEAR, 1, &regs->ish_ipc_busy_clear_agent);
186 	}
187 	/* Enable Msg in, busyClean and out Interrupt */
188 	SEDI_PREG_RBFV_SET(IPC, PIMR_AGENT2ISH, AGENT2ISH_DB, 1, &regs->pimr_agent2ish);
189 	SEDI_PREG_RBFV_SET(IPC, PIMR_AGENT2ISH, ISH2AGENT_BC, 1, &regs->pimr_agent2ish);
190 	SEDI_PREG_RBFV_SET(IPC, PIMR_ISH2AGENT, ISH2AGENT_DB, 1, &regs->pimr_ish2agent);
191 	SEDI_PREG_RBFV_SET(IPC, CIM_AGENT, CH_INTR_MASK, 0, &regs->cim_agent);
192 
193 	return SEDI_DRIVER_OK;
194 }
195 
sedi_ipc_uninit(IN sedi_ipc_t ipc_device)196 int32_t sedi_ipc_uninit(IN sedi_ipc_t ipc_device)
197 {
198 	DBG_CHECK(ipc_device < SEDI_IPC_NUM, SEDI_DRIVER_ERROR_PARAMETER);
199 	volatile sedi_ipc_regs_t *regs = ipc_resource[ipc_device].reg_base_addr;
200 
201 	/* disable Msg in, busyClean and out Interrupt  */
202 	SEDI_PREG_RBFV_SET(IPC, PIMR_AGENT2ISH, AGENT2ISH_DB, 0, &regs->pimr_agent2ish);
203 	SEDI_PREG_RBFV_SET(IPC, PIMR_AGENT2ISH, ISH2AGENT_BC, 0, &regs->pimr_agent2ish);
204 
205 	ipc_contexts[ipc_device].cb_event = NULL;
206 	ipc_contexts[ipc_device].initialized = false;
207 #ifdef SEDI_SB_SUPPORT
208 	sideband_param_t *sb = ipc_resource[ipc_device].sb;
209 
210 	if (sb) {
211 		sedi_sideband_uninit(sb->dev);
212 	}
213 #endif
214 	return SEDI_DRIVER_OK;
215 }
216 
217 /*
218  * IPC is an always-on IP, no power operation available for IPC,
219  * keep API for future
220  */
sedi_ipc_set_power(IN sedi_ipc_t ipc_device,IN sedi_power_state_t state)221 int32_t sedi_ipc_set_power(IN sedi_ipc_t ipc_device, IN sedi_power_state_t state)
222 {
223 	int ret;
224 
225 	ret = check_ipc_available(ipc_device);
226 	if (ret != SEDI_DRIVER_OK) {
227 		return ret;
228 	}
229 
230 	PARAM_UNUSED(state);
231 
232 	return SEDI_DRIVER_OK;
233 }
234 
sedi_ipc_write_msg(IN sedi_ipc_t ipc_device,IN uint8_t * msg,IN int32_t size)235 int32_t sedi_ipc_write_msg(IN sedi_ipc_t ipc_device, IN uint8_t *msg, IN int32_t size)
236 {
237 	int ret, i;
238 	uint32_t tail = 0;
239 
240 	ret = check_ipc_available(ipc_device);
241 	if (ret != SEDI_DRIVER_OK) {
242 		return ret;
243 	}
244 
245 	volatile sedi_ipc_regs_t *regs = ipc_resource[ipc_device].reg_base_addr;
246 	sideband_param_t *sb = ipc_resource[ipc_device].sb;
247 
248 	DBG_CHECK((size <= IPC_DATA_LEN_MAX) && (size >= 0), SEDI_DRIVER_ERROR_PARAMETER);
249 	DBG_CHECK(msg != NULL, SEDI_DRIVER_ERROR_PARAMETER);
250 
251 	if (sb) {
252 #ifdef SEDI_SB_SUPPORT
253 		/* for CSE and PMC, use sideband */
254 		for (i = 0; i < size; i = i + 4) {
255 			sedi_sideband_send(sb->dev, sb->port, SEDI_SIDEBAND_ACTION_WRITE,
256 					   sb->msg_peer_addr + i, *((uint32_t *)(msg + i)));
257 		}
258 #endif
259 	} else {
260 		/* write data in 32-bit*/
261 		for (i = 0; i < (size >> 2); i++) {
262 			regs->ish2agent_msg_agent[i] = *((uint32_t *)msg + i);
263 		}
264 		/* write data in 8-bit for the rest*/
265 		if (size % sizeof(uint32_t)) {
266 			for (i = ((size >> 2) << 2); i < size; i++) {
267 				tail += msg[i] << ((i % 4) << 3);
268 			}
269 			regs->ish2agent_msg_agent[size >> 2] = tail;
270 		}
271 	}
272 	return SEDI_DRIVER_OK;
273 }
274 
sedi_ipc_write_dbl(IN sedi_ipc_t ipc_device,IN uint32_t doorbell)275 int32_t sedi_ipc_write_dbl(IN sedi_ipc_t ipc_device, IN uint32_t doorbell)
276 {
277 	int ret;
278 
279 	ret = check_ipc_available(ipc_device);
280 	if (ret != SEDI_DRIVER_OK) {
281 		return ret;
282 	}
283 
284 	vnn_id_t write_vnn = ipc_resource[ipc_device].write_vnn;
285 	sideband_param_t *sb = ipc_resource[ipc_device].sb;
286 	volatile sedi_ipc_regs_t *regs = ipc_resource[ipc_device].reg_base_addr;
287 
288 	if (sb) {
289 		regs->ish2agent_doorbell_agent = doorbell;
290 #ifdef SEDI_SB_SUPPORT
291 		sedi_sideband_send(sb->dev, sb->port, SEDI_SIDEBAND_ACTION_WRITE,
292 				   sb->drbl_peer_addr, doorbell);
293 #endif
294 	} else {
295 		/* IPC to HOST */
296 		PM_VNN_DRIVER_REQ(write_vnn);
297 		regs->ish2agent_doorbell_agent = doorbell;
298 		if (SEDI_PREG_RBFV_IS_SET(IPC, ISH2AGENT_DOORBELL_AGENT, BUSY, 0,
299 					(uint32_t *)&doorbell)) {
300 			PM_VNN_DRIVER_DEREQ(write_vnn);
301 		}
302 	}
303 
304 	return SEDI_DRIVER_OK;
305 }
306 
sedi_ipc_write_csr(IN sedi_ipc_t ipc_device,IN uint32_t csr)307 int32_t sedi_ipc_write_csr(IN sedi_ipc_t ipc_device, IN uint32_t csr)
308 {
309 	int ret;
310 
311 	ret = check_ipc_available(ipc_device);
312 	if (ret != SEDI_DRIVER_OK) {
313 		return ret;
314 	}
315 
316 	sideband_param_t *sb = ipc_resource[ipc_device].sb;
317 
318 	if (sb) {
319 #ifdef SEDI_SB_SUPPORT
320 		sedi_sideband_send(sb->dev, sb->port, SEDI_SIDEBAND_ACTION_WRITE, sb->csr_peer_addr,
321 				   csr);
322 #endif
323 	}
324 
325 	return SEDI_DRIVER_OK;
326 }
327 
sedi_ipc_read_csr(IN sedi_ipc_t ipc_device,OUT uint32_t * csr)328 int32_t sedi_ipc_read_csr(IN sedi_ipc_t ipc_device, OUT uint32_t *csr)
329 {
330 	int ret;
331 
332 	ret = check_ipc_available(ipc_device);
333 	if (ret != SEDI_DRIVER_OK) {
334 		return ret;
335 	}
336 
337 	if (csr) {
338 		*csr = ipc_contexts[ipc_device].csr_saved;
339 	} else {
340 		return SEDI_DRIVER_ERROR_PARAMETER;
341 	}
342 
343 	return SEDI_DRIVER_OK;
344 }
345 
sedi_ipc_read_msg(IN sedi_ipc_t ipc_device,OUT uint8_t * msg,IN int32_t size)346 int32_t sedi_ipc_read_msg(IN sedi_ipc_t ipc_device, OUT uint8_t *msg, IN int32_t size)
347 {
348 	int ret, i;
349 	uint32_t tail = 0;
350 
351 	ret = check_ipc_available(ipc_device);
352 	if (ret != SEDI_DRIVER_OK) {
353 		return ret;
354 	}
355 
356 	volatile sedi_ipc_regs_t *regs = ipc_resource[ipc_device].reg_base_addr;
357 
358 	DBG_CHECK((size <= IPC_DATA_LEN_MAX) && (size >= 0), SEDI_DRIVER_ERROR_PARAMETER);
359 	DBG_CHECK(msg != NULL, SEDI_DRIVER_ERROR_PARAMETER);
360 
361 	/* read data in 32-bit*/
362 	for (i = 0; i < (size >> 2); i++) {
363 		*((uint32_t *)msg + i) = regs->agent2ish_msg_agent[i];
364 	}
365 
366 	/* read data in 8-bit for the rest*/
367 	if (size % sizeof(uint32_t)) {
368 		tail = regs->agent2ish_msg_agent[size >> 2];
369 	}
370 	for (i = ((size >> 2) << 2); i < size; i++) {
371 		msg[i] = *((uint8_t *)&tail + i % sizeof(uint32_t));
372 	}
373 	return SEDI_DRIVER_OK;
374 }
375 
sedi_ipc_read_dbl(IN sedi_ipc_t ipc_device,OUT uint32_t * doorbell)376 int32_t sedi_ipc_read_dbl(IN sedi_ipc_t ipc_device, OUT uint32_t *doorbell)
377 {
378 	int ret;
379 
380 	ret = check_ipc_available(ipc_device);
381 	if (ret != SEDI_DRIVER_OK) {
382 		return ret;
383 	}
384 
385 	volatile sedi_ipc_regs_t *regs = ipc_resource[ipc_device].reg_base_addr;
386 	*doorbell = regs->agent2ish_doorbell_agent;
387 	return SEDI_DRIVER_OK;
388 }
389 
sedi_ipc_send_ack_drbl(IN sedi_ipc_t ipc_device,IN uint32_t ack)390 int32_t sedi_ipc_send_ack_drbl(IN sedi_ipc_t ipc_device, IN uint32_t ack)
391 {
392 	int ret;
393 
394 	ret = check_ipc_available(ipc_device);
395 	if (ret != SEDI_DRIVER_OK) {
396 		return ret;
397 	}
398 
399 	sideband_param_t *sb = ipc_resource[ipc_device].sb;
400 
401 	if (SEDI_PREG_RBFV_IS_SET(IPC, ISH2AGENT_DOORBELL_AGENT, BUSY, 1, (uint32_t *)&ack)) {
402 		return SEDI_DRIVER_ERROR_PARAMETER;
403 	}
404 
405 	volatile sedi_ipc_regs_t *regs = ipc_resource[ipc_device].reg_base_addr;
406 	vnn_id_t read_vnn = ipc_resource[ipc_device].read_vnn;
407 
408 	regs->agent2ish_doorbell_agent = ack;
409 	if (sb) {
410 #ifdef SEDI_SB_SUPPORT
411 		/* the peer is PMC or CSE */
412 		sedi_sideband_send(sb->dev, sb->port, SEDI_SIDEBAND_ACTION_WRITE,
413 				   sb->drbl_mirror_peer_addr, ack);
414 #endif
415 	} else {
416 		/* the peer is host */
417 		PM_VNN_DRIVER_DEREQ(read_vnn);
418 	}
419 	SEDI_PREG_RBFV_SET(IPC, PIMR_AGENT2ISH, AGENT2ISH_DB, 1, &regs->pimr_agent2ish);
420 	return SEDI_DRIVER_OK;
421 }
422 
sedi_ipc_read_ack_drbl(IN sedi_ipc_t ipc_device,OUT uint32_t * ack)423 int32_t sedi_ipc_read_ack_drbl(IN sedi_ipc_t ipc_device, OUT uint32_t *ack)
424 {
425 	int ret;
426 
427 	ret = check_ipc_available(ipc_device);
428 	if (ret != SEDI_DRIVER_OK) {
429 		return ret;
430 	}
431 
432 	DBG_CHECK(ack != NULL, ret);
433 	volatile sedi_ipc_regs_t *regs = ipc_resource[ipc_device].reg_base_addr;
434 
435 	*ack = regs->ish2agent_doorbell_agent;
436 
437 	return SEDI_DRIVER_OK;
438 }
439 
sedi_ipc_send_ack_msg(IN sedi_ipc_t ipc_device,IN uint8_t * msg,IN int32_t size)440 int32_t sedi_ipc_send_ack_msg(IN sedi_ipc_t ipc_device, IN uint8_t *msg, IN int32_t size)
441 {
442 	int ret, i;
443 	uint32_t tail = 0;
444 
445 	ret = check_ipc_available(ipc_device);
446 	if (ret != SEDI_DRIVER_OK) {
447 		return ret;
448 	}
449 
450 	volatile sedi_ipc_regs_t *regs = ipc_resource[ipc_device].reg_base_addr;
451 
452 	DBG_CHECK((size <= IPC_DATA_LEN_MAX) && (size >= 0), SEDI_DRIVER_ERROR_PARAMETER);
453 	DBG_CHECK(msg != NULL, SEDI_DRIVER_ERROR_PARAMETER);
454 
455 	/* write data in 32-bit*/
456 	for (i = 0; i < (size >> 2); i++) {
457 		regs->agent2ish_msg_agent[i] = *((uint32_t *)msg + i);
458 	}
459 	/* write data in 8-bit for the rest*/
460 	if (size % sizeof(uint32_t)) {
461 		for (i = ((size >> 2) << 2); i < size; i++) {
462 			tail += msg[i] << ((i % 4) << 3);
463 		}
464 		regs->agent2ish_msg_agent[size >> 2] = tail;
465 	}
466 	return SEDI_DRIVER_OK;
467 }
468 
sedi_ipc_read_ack_msg(IN sedi_ipc_t ipc_device,OUT uint8_t * msg,IN int32_t size)469 int32_t sedi_ipc_read_ack_msg(IN sedi_ipc_t ipc_device, OUT uint8_t *msg, IN int32_t size)
470 {
471 	int ret, i;
472 	uint32_t tail;
473 
474 	ret = check_ipc_available(ipc_device);
475 	if (ret != SEDI_DRIVER_OK) {
476 		return ret;
477 	}
478 
479 	volatile sedi_ipc_regs_t *regs = ipc_resource[ipc_device].reg_base_addr;
480 
481 	DBG_CHECK((size <= IPC_DATA_LEN_MAX) && (size >= 0), SEDI_DRIVER_ERROR_PARAMETER);
482 	DBG_CHECK(msg != NULL, SEDI_DRIVER_ERROR_PARAMETER);
483 
484 	if (ipc_device == SEDI_IPC_HOST) {
485 		/* read data in 32-bit*/
486 		for (i = 0; i < (size >> 2); i++) {
487 			*((uint32_t *)msg + i) = regs->ish2agent_msg_agent[i];
488 		}
489 		/* read data in 8-bit for the rest*/
490 		if (size % sizeof(uint32_t)) {
491 			tail = regs->ish2agent_msg_agent[size >> 2];
492 		}
493 		for (i = ((size >> 2) << 2); i < size; i++) {
494 			msg[i] = *((uint8_t *)&tail + i % sizeof(uint32_t));
495 		}
496 	} else {
497 #ifdef SEDI_SB_SUPPORT
498 		sideband_param_t *sb = ipc_resource[ipc_device].sb;
499 
500 		for (i = 0; i < size; i = i + 4) {
501 			sedi_sideband_send(sb->dev, sb->port, SEDI_SIDEBAND_ACTION_READ,
502 					   sb->msg_peer_addr + i, 0);
503 			sedi_sideband_wait_ack(sb->dev, sb->port, SEDI_SIDEBAND_ACTION_READ,
504 					       (uint32_t *)(msg + i));
505 		}
506 #endif
507 	}
508 
509 	return SEDI_DRIVER_OK;
510 }
511 /* IPC ISR process function */
512 
sedi_ipc_isr(IN sedi_ipc_t ipc_device)513 void sedi_ipc_isr(IN sedi_ipc_t ipc_device)
514 {
515 	int ret;
516 	volatile sedi_ipc_regs_t *regs = ipc_resource[ipc_device].reg_base_addr;
517 
518 	ret = check_ipc_available(ipc_device);
519 	if (ret != SEDI_DRIVER_OK) {
520 		return;
521 	}
522 
523 	/* check whether it is an inbound interrupt*/
524 	if (SEDI_PREG_RBFV_IS_SET(IPC, PISR_AGENT2ISH, AGENT2ISH_DB, 1, &regs->pisr_agent2ish) &&
525 			SEDI_PREG_RBFV_IS_SET(IPC, PIMR_AGENT2ISH, AGENT2ISH_DB, 1,
526 				&regs->pimr_agent2ish)) {
527 		/* mask interrupts before ack */
528 		SEDI_PREG_RBFV_SET(IPC, PIMR_AGENT2ISH, AGENT2ISH_DB, 0, &regs->pimr_agent2ish);
529 		if (ipc_device == SEDI_IPC_HOST) {
530 			PM_VNN_DRIVER_REQ(ipc_resource[ipc_device].read_vnn);
531 		}
532 		if (ipc_contexts[ipc_device].cb_event) {
533 			ipc_contexts[ipc_device].in_msg_count++;
534 			ipc_contexts[ipc_device].cb_event(ipc_device, SEDI_IPC_EVENT_MSG_IN,
535 							  ipc_contexts[ipc_device].usr_params);
536 		}
537 	}
538 
539 	/* check whether it is an outbound interrupt*/
540 	if (SEDI_PREG_RBFV_IS_SET(IPC, ISH_IPC_BUSY_CLEAR_AGENT, ISH2AGENT_BUSY_CLEAR, 1,
541 				&regs->ish_ipc_busy_clear_agent)) {
542 		/*set 1 to clear this interrupt*/
543 		SEDI_PREG_RBFV_SET(IPC, ISH_IPC_BUSY_CLEAR_AGENT, ISH2AGENT_BUSY_CLEAR, 1,
544 				&regs->ish_ipc_busy_clear_agent);
545 		if ((ipc_contexts[ipc_device].initialized == true) &&
546 		    (ipc_contexts[ipc_device].cb_event)) {
547 			ipc_contexts[ipc_device].out_msg_count++;
548 			ipc_contexts[ipc_device].cb_event(ipc_device, SEDI_IPC_EVENT_MSG_PEER_ACKED,
549 							  ipc_contexts[ipc_device].usr_params);
550 		}
551 		if (ipc_device == SEDI_IPC_HOST) {
552 			PM_VNN_DRIVER_DEREQ(ipc_resource[ipc_device].write_vnn);
553 		}
554 	}
555 
556 	/* check whether it is a csr interrupt */
557 	if ((ipc_device != SEDI_IPC_HOST) && (regs->agent2ish_csr_agent != 0)) {
558 		ipc_contexts[ipc_device].csr_saved = regs->agent2ish_csr_agent;
559 		/* write back to clear the interrupt */
560 		regs->agent2ish_csr_agent = ipc_contexts[ipc_device].csr_saved;
561 		if ((ipc_contexts[ipc_device].initialized == true) &&
562 		    (ipc_contexts[ipc_device].cb_event)) {
563 			ipc_contexts[ipc_device].cb_event(ipc_device, SEDI_IPC_EVENT_CSR_ACK,
564 							  ipc_contexts[ipc_device].usr_params);
565 		}
566 	}
567 }
568