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