Linux 6.7-rc7
[linux-modified.git] / sound / soc / intel / catpt / messages.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 //
3 // Copyright(c) 2020 Intel Corporation. All rights reserved.
4 //
5 // Author: Cezary Rojewski <cezary.rojewski@intel.com>
6 //
7
8 #include <linux/slab.h>
9 #include "core.h"
10 #include "messages.h"
11 #include "registers.h"
12
13 int catpt_ipc_get_fw_version(struct catpt_dev *cdev,
14                              struct catpt_fw_version *version)
15 {
16         union catpt_global_msg msg = CATPT_GLOBAL_MSG(GET_FW_VERSION);
17         struct catpt_ipc_msg request = {{0}}, reply;
18         int ret;
19
20         request.header = msg.val;
21         reply.size = sizeof(*version);
22         reply.data = version;
23
24         ret = catpt_dsp_send_msg(cdev, request, &reply);
25         if (ret)
26                 dev_err(cdev->dev, "get fw version failed: %d\n", ret);
27
28         return ret;
29 }
30
31 struct catpt_alloc_stream_input {
32         enum catpt_path_id path_id:8;
33         enum catpt_stream_type stream_type:8;
34         enum catpt_format_id format_id:8;
35         u8 reserved;
36         struct catpt_audio_format input_format;
37         struct catpt_ring_info ring_info;
38         u8 num_entries;
39         /* flex array with entries here */
40         struct catpt_memory_info persistent_mem;
41         struct catpt_memory_info scratch_mem;
42         u32 num_notifications; /* obsolete */
43 } __packed;
44
45 int catpt_ipc_alloc_stream(struct catpt_dev *cdev,
46                            enum catpt_path_id path_id,
47                            enum catpt_stream_type type,
48                            struct catpt_audio_format *afmt,
49                            struct catpt_ring_info *rinfo,
50                            u8 num_modules,
51                            struct catpt_module_entry *modules,
52                            struct resource *persistent,
53                            struct resource *scratch,
54                            struct catpt_stream_info *sinfo)
55 {
56         union catpt_global_msg msg = CATPT_GLOBAL_MSG(ALLOCATE_STREAM);
57         struct catpt_alloc_stream_input input;
58         struct catpt_ipc_msg request, reply;
59         size_t size, arrsz;
60         u8 *payload;
61         off_t off;
62         int ret;
63
64         off = offsetof(struct catpt_alloc_stream_input, persistent_mem);
65         arrsz = sizeof(*modules) * num_modules;
66         size = sizeof(input) + arrsz;
67
68         payload = kzalloc(size, GFP_KERNEL);
69         if (!payload)
70                 return -ENOMEM;
71
72         memset(&input, 0, sizeof(input));
73         input.path_id = path_id;
74         input.stream_type = type;
75         input.format_id = CATPT_FORMAT_PCM;
76         input.input_format = *afmt;
77         input.ring_info = *rinfo;
78         input.num_entries = num_modules;
79         input.persistent_mem.offset = catpt_to_dsp_offset(persistent->start);
80         input.persistent_mem.size = resource_size(persistent);
81         if (scratch) {
82                 input.scratch_mem.offset = catpt_to_dsp_offset(scratch->start);
83                 input.scratch_mem.size = resource_size(scratch);
84         }
85
86         /* re-arrange the input: account for flex array 'entries' */
87         memcpy(payload, &input, sizeof(input));
88         memmove(payload + off + arrsz, payload + off, sizeof(input) - off);
89         memcpy(payload + off, modules, arrsz);
90
91         request.header = msg.val;
92         request.size = size;
93         request.data = payload;
94         reply.size = sizeof(*sinfo);
95         reply.data = sinfo;
96
97         ret = catpt_dsp_send_msg(cdev, request, &reply);
98         if (ret)
99                 dev_err(cdev->dev, "alloc stream type %d failed: %d\n",
100                         type, ret);
101
102         kfree(payload);
103         return ret;
104 }
105
106 int catpt_ipc_free_stream(struct catpt_dev *cdev, u8 stream_hw_id)
107 {
108         union catpt_global_msg msg = CATPT_GLOBAL_MSG(FREE_STREAM);
109         struct catpt_ipc_msg request;
110         int ret;
111
112         request.header = msg.val;
113         request.size = sizeof(stream_hw_id);
114         request.data = &stream_hw_id;
115
116         ret = catpt_dsp_send_msg(cdev, request, NULL);
117         if (ret)
118                 dev_err(cdev->dev, "free stream %d failed: %d\n",
119                         stream_hw_id, ret);
120
121         return ret;
122 }
123
124 int catpt_ipc_set_device_format(struct catpt_dev *cdev,
125                                 struct catpt_ssp_device_format *devfmt)
126 {
127         union catpt_global_msg msg = CATPT_GLOBAL_MSG(SET_DEVICE_FORMATS);
128         struct catpt_ipc_msg request;
129         int ret;
130
131         request.header = msg.val;
132         request.size = sizeof(*devfmt);
133         request.data = devfmt;
134
135         ret = catpt_dsp_send_msg(cdev, request, NULL);
136         if (ret)
137                 dev_err(cdev->dev, "set device format failed: %d\n", ret);
138
139         return ret;
140 }
141
142 int catpt_ipc_enter_dxstate(struct catpt_dev *cdev, enum catpt_dx_state state,
143                             struct catpt_dx_context *context)
144 {
145         union catpt_global_msg msg = CATPT_GLOBAL_MSG(ENTER_DX_STATE);
146         struct catpt_ipc_msg request, reply;
147         int ret;
148
149         request.header = msg.val;
150         request.size = sizeof(state);
151         request.data = &state;
152         reply.size = sizeof(*context);
153         reply.data = context;
154
155         ret = catpt_dsp_send_msg(cdev, request, &reply);
156         if (ret)
157                 dev_err(cdev->dev, "enter dx state failed: %d\n", ret);
158
159         return ret;
160 }
161
162 int catpt_ipc_get_mixer_stream_info(struct catpt_dev *cdev,
163                                     struct catpt_mixer_stream_info *info)
164 {
165         union catpt_global_msg msg = CATPT_GLOBAL_MSG(GET_MIXER_STREAM_INFO);
166         struct catpt_ipc_msg request = {{0}}, reply;
167         int ret;
168
169         request.header = msg.val;
170         reply.size = sizeof(*info);
171         reply.data = info;
172
173         ret = catpt_dsp_send_msg(cdev, request, &reply);
174         if (ret)
175                 dev_err(cdev->dev, "get mixer info failed: %d\n", ret);
176
177         return ret;
178 }
179
180 int catpt_ipc_reset_stream(struct catpt_dev *cdev, u8 stream_hw_id)
181 {
182         union catpt_stream_msg msg = CATPT_STREAM_MSG(RESET_STREAM);
183         struct catpt_ipc_msg request = {{0}};
184         int ret;
185
186         msg.stream_hw_id = stream_hw_id;
187         request.header = msg.val;
188
189         ret = catpt_dsp_send_msg(cdev, request, NULL);
190         if (ret)
191                 dev_err(cdev->dev, "reset stream %d failed: %d\n",
192                         stream_hw_id, ret);
193
194         return ret;
195 }
196
197 int catpt_ipc_pause_stream(struct catpt_dev *cdev, u8 stream_hw_id)
198 {
199         union catpt_stream_msg msg = CATPT_STREAM_MSG(PAUSE_STREAM);
200         struct catpt_ipc_msg request = {{0}};
201         int ret;
202
203         msg.stream_hw_id = stream_hw_id;
204         request.header = msg.val;
205
206         ret = catpt_dsp_send_msg(cdev, request, NULL);
207         if (ret)
208                 dev_err(cdev->dev, "pause stream %d failed: %d\n",
209                         stream_hw_id, ret);
210
211         return ret;
212 }
213
214 int catpt_ipc_resume_stream(struct catpt_dev *cdev, u8 stream_hw_id)
215 {
216         union catpt_stream_msg msg = CATPT_STREAM_MSG(RESUME_STREAM);
217         struct catpt_ipc_msg request = {{0}};
218         int ret;
219
220         msg.stream_hw_id = stream_hw_id;
221         request.header = msg.val;
222
223         ret = catpt_dsp_send_msg(cdev, request, NULL);
224         if (ret)
225                 dev_err(cdev->dev, "resume stream %d failed: %d\n",
226                         stream_hw_id, ret);
227
228         return ret;
229 }
230
231 struct catpt_set_volume_input {
232         u32 channel;
233         u32 target_volume;
234         u64 curve_duration;
235         u32 curve_type;
236 } __packed;
237
238 int catpt_ipc_set_volume(struct catpt_dev *cdev, u8 stream_hw_id,
239                          u32 channel, u32 volume,
240                          u32 curve_duration,
241                          enum catpt_audio_curve_type curve_type)
242 {
243         union catpt_stream_msg msg = CATPT_STAGE_MSG(SET_VOLUME);
244         struct catpt_ipc_msg request;
245         struct catpt_set_volume_input input;
246         int ret;
247
248         msg.stream_hw_id = stream_hw_id;
249         input.channel = channel;
250         input.target_volume = volume;
251         input.curve_duration = curve_duration;
252         input.curve_type = curve_type;
253
254         request.header = msg.val;
255         request.size = sizeof(input);
256         request.data = &input;
257
258         ret = catpt_dsp_send_msg(cdev, request, NULL);
259         if (ret)
260                 dev_err(cdev->dev, "set stream %d volume failed: %d\n",
261                         stream_hw_id, ret);
262
263         return ret;
264 }
265
266 struct catpt_set_write_pos_input {
267         u32 new_write_pos;
268         bool end_of_buffer;
269         bool low_latency;
270 } __packed;
271
272 int catpt_ipc_set_write_pos(struct catpt_dev *cdev, u8 stream_hw_id,
273                             u32 pos, bool eob, bool ll)
274 {
275         union catpt_stream_msg msg = CATPT_STAGE_MSG(SET_WRITE_POSITION);
276         struct catpt_ipc_msg request;
277         struct catpt_set_write_pos_input input;
278         int ret;
279
280         msg.stream_hw_id = stream_hw_id;
281         input.new_write_pos = pos;
282         input.end_of_buffer = eob;
283         input.low_latency = ll;
284
285         request.header = msg.val;
286         request.size = sizeof(input);
287         request.data = &input;
288
289         ret = catpt_dsp_send_msg(cdev, request, NULL);
290         if (ret)
291                 dev_err(cdev->dev, "set stream %d write pos failed: %d\n",
292                         stream_hw_id, ret);
293
294         return ret;
295 }
296
297 int catpt_ipc_mute_loopback(struct catpt_dev *cdev, u8 stream_hw_id, bool mute)
298 {
299         union catpt_stream_msg msg = CATPT_STAGE_MSG(MUTE_LOOPBACK);
300         struct catpt_ipc_msg request;
301         int ret;
302
303         msg.stream_hw_id = stream_hw_id;
304         request.header = msg.val;
305         request.size = sizeof(mute);
306         request.data = &mute;
307
308         ret = catpt_dsp_send_msg(cdev, request, NULL);
309         if (ret)
310                 dev_err(cdev->dev, "mute loopback failed: %d\n", ret);
311
312         return ret;
313 }