1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright(c) 2016 Intel Corporation. All rights reserved.
4  *
5  * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
6  *         Keyon Jie <yang.jie@linux.intel.com>
7  */
8 
9 #ifndef __SOF_IPC_COMMON_H__
10 #define __SOF_IPC_COMMON_H__
11 
12 #include <sof/lib/alloc.h>
13 #include <sof/list.h>
14 #include <sof/schedule/task.h>
15 #include <sof/sof.h>
16 #include <user/trace.h>
17 #include <stdbool.h>
18 #include <stdint.h>
19 
20 struct dma_sg_elem_array;
21 struct ipc_msg;
22 
23 /* generic IPC header regardless of ABI MAJOR type that is always 4 byte aligned */
24 typedef uint32_t ipc_cmd_hdr;
25 
26 /*
27  * Common IPC logic uses standard types for abstract IPC features. This means all ABI MAJOR
28  * abstraction is done in the IPC layer only and not in the surrounding infrastructure.
29  */
30 #if CONFIG_IPC_MAJOR_3
31 #include <ipc/header.h>
32 #define ipc_from_hdr(x) ((struct sof_ipc_cmd_hdr *)x)
33 #elif CONFIG_IPC_MAJOR_4
34 #include <ipc4/header.h>
35 #define ipc_from_hdr(x) ((union ipc4_message_header *)x)
36 #else
37 #error "No or invalid IPC MAJOR version selected."
38 #endif
39 
40 #define ipc_to_hdr(x) ((ipc_cmd_hdr *)x)
41 
42 /* validates internal non tail structures within IPC command structure */
43 #define IPC_IS_SIZE_INVALID(object)					\
44 	(object).hdr.size == sizeof(object) ? 0 : 1
45 
46 /* ipc trace context, used by multiple units */
47 extern struct tr_ctx ipc_tr;
48 
49 /* convenience error trace for mismatched internal structures */
50 #define IPC_SIZE_ERROR_TRACE(ctx, object)		\
51 	tr_err(ctx, "ipc: size %d expected %d",		\
52 	       (object).hdr.size, sizeof(object))
53 
54 /* Returns pipeline source component */
55 #define ipc_get_ppl_src_comp(ipc, ppl_id) \
56 	ipc_get_ppl_comp(ipc, ppl_id, PPL_DIR_UPSTREAM)
57 
58 /* Returns pipeline sink component */
59 #define ipc_get_ppl_sink_comp(ipc, ppl_id) \
60 	ipc_get_ppl_comp(ipc, ppl_id, PPL_DIR_DOWNSTREAM)
61 
62 struct ipc {
63 	spinlock_t lock;	/* locking mechanism */
64 	void *comp_data;
65 
66 	/* PM */
67 	int pm_prepare_D3;	/* do we need to prepare for D3 */
68 
69 	struct list_item msg_list;	/* queue of messages to be sent */
70 	bool is_notification_pending;	/* notification is being sent to host */
71 	unsigned int core;		/* core, processing the IPC */
72 
73 	struct list_item comp_list;	/* list of component devices */
74 
75 	/* processing task */
76 	struct task ipc_task;
77 
78 	void *private;
79 };
80 
81 #define ipc_set_drvdata(ipc, data) \
82 	((ipc)->private = data)
83 #define ipc_get_drvdata(ipc) \
84 	((ipc)->private)
85 
86 extern struct task_ops ipc_task_ops;
87 
88 /**
89  * \brief Get the IPC global context.
90  * @return The global IPC context.
91  */
ipc_get(void)92 static inline struct ipc *ipc_get(void)
93 {
94 	return sof_get()->ipc;
95 }
96 
97 /**
98  * \brief Initialise global IPC context.
99  * @param[in,out] sof Global SOF context.
100  * @return 0 on success.
101  */
102 int ipc_init(struct sof *sof);
103 
104 /**
105  * \brief Free global IPC context.
106  * @param[in] ipc Global IPC context.
107  */
108 void ipc_free(struct ipc *ipc);
109 
110 /**
111  * \brief Data provided by the platform which use ipc...page_descriptors().
112  *
113  * Note: this should be made private for ipc-host-ptable.c and ipc
114  * drivers for platforms that use ptables.
115  */
116 struct ipc_data_host_buffer {
117 	/* DMA */
118 	struct dma *dmac;
119 	uint8_t *page_table;
120 };
121 
122 /**
123  * \brief Processes page tables for the host buffer.
124  * @param[in] ipc Ipc
125  * @param[in] ring Ring description sent via Ipc
126  * @param[in] direction Direction (playback/capture)
127  * @param[out] elem_array Array of SG elements
128  * @param[out] ring_size Size of the ring
129  * @return Status, 0 if successful, error code otherwise.
130  */
131 int ipc_process_host_buffer(struct ipc *ipc,
132 			    struct sof_ipc_host_buffer *ring,
133 			    uint32_t direction,
134 			    struct dma_sg_elem_array *elem_array,
135 			    uint32_t *ring_size);
136 
137 /**
138  * \brief Send DMA trace host buffer position to host.
139  * @return 0 on success.
140  */
141 int ipc_dma_trace_send_position(void);
142 
143 /**
144  * \brief Configure DAI.
145  * @return 0 on success.
146  */
147 int ipc_dai_data_config(struct comp_dev *dev);
148 
149 /**
150  * \brief create a IPC boot complete message.
151  * @param[in] header header.
152  * @param[in] data data.
153  */
154 void ipc_boot_complete_msg(ipc_cmd_hdr *header, uint32_t *data);
155 
156 /**
157  * \brief Read a compact IPC message or return NULL for normal message.
158  * @return Pointer to the compact message data.
159  */
160 ipc_cmd_hdr *ipc_compact_read_msg(void);
161 
162 /**
163  * \brief Write a compact IPC message.
164  * @param[in] hdr Compact message header data.
165  * @return Number of words written.
166  */
167 int ipc_compact_write_msg(ipc_cmd_hdr *hdr);
168 
169 /**
170  * \brief Prepare an IPC message for sending.
171  * @param[in] msg The ipc msg.
172  * @return pointer to raw header or NULL.
173  */
174 ipc_cmd_hdr *ipc_prepare_to_send(struct ipc_msg *msg);
175 
176 /**
177  * \brief Validate mailbox contents for valid IPC header.
178  * @return pointer to header if valid or NULL.
179  */
180 ipc_cmd_hdr *mailbox_validate(void);
181 
182 /**
183  * Generic IPC command handler. Expects that IPC command (the header plus
184  * any optional payload) is deserialized from the IPC HW by the platform
185  * specific method.
186  *
187  * @param hdr Points to the IPC command header.
188  */
189 void ipc_cmd(ipc_cmd_hdr *hdr);
190 
191 /**
192  * \brief IPC message to be processed on other core.
193  * @param[in] core Core id for IPC to be processed on.
194  * @param[in] blocking Process in blocking mode: wait for completion.
195  * @return 1 if successful (reply sent by other core), error code otherwise.
196  */
197 int ipc_process_on_core(uint32_t core, bool blocking);
198 
199 #endif /* __SOF_DRIVERS_IPC_H__ */
200