GNU Linux-libre 5.10.219-gnu1
[releases.git] / drivers / staging / vc04_services / bcm2835-audio / bcm2835-vchiq.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright 2011 Broadcom Corporation.  All rights reserved. */
3
4 #include <linux/slab.h>
5 #include <linux/module.h>
6 #include <linux/completion.h>
7 #include "bcm2835.h"
8 #include "vc_vchi_audioserv_defs.h"
9
10 struct bcm2835_audio_instance {
11         struct device *dev;
12         unsigned int service_handle;
13         struct completion msg_avail_comp;
14         struct mutex vchi_mutex;
15         struct bcm2835_alsa_stream *alsa_stream;
16         int result;
17         unsigned int max_packet;
18         short peer_version;
19 };
20
21 static bool force_bulk;
22 module_param(force_bulk, bool, 0444);
23 MODULE_PARM_DESC(force_bulk, "Force use of vchiq bulk for audio");
24
25 static void bcm2835_audio_lock(struct bcm2835_audio_instance *instance)
26 {
27         mutex_lock(&instance->vchi_mutex);
28         vchiq_use_service(instance->service_handle);
29 }
30
31 static void bcm2835_audio_unlock(struct bcm2835_audio_instance *instance)
32 {
33         vchiq_release_service(instance->service_handle);
34         mutex_unlock(&instance->vchi_mutex);
35 }
36
37 static int bcm2835_audio_send_msg_locked(struct bcm2835_audio_instance *instance,
38                                          struct vc_audio_msg *m, bool wait)
39 {
40         int status;
41
42         if (wait) {
43                 instance->result = -1;
44                 init_completion(&instance->msg_avail_comp);
45         }
46
47         status = vchiq_queue_kernel_message(instance->service_handle,
48                                             m, sizeof(*m));
49         if (status) {
50                 dev_err(instance->dev,
51                         "vchi message queue failed: %d, msg=%d\n",
52                         status, m->type);
53                 return -EIO;
54         }
55
56         if (wait) {
57                 if (!wait_for_completion_timeout(&instance->msg_avail_comp,
58                                                  msecs_to_jiffies(10 * 1000))) {
59                         dev_err(instance->dev,
60                                 "vchi message timeout, msg=%d\n", m->type);
61                         return -ETIMEDOUT;
62                 } else if (instance->result) {
63                         dev_err(instance->dev,
64                                 "vchi message response error:%d, msg=%d\n",
65                                 instance->result, m->type);
66                         return -EIO;
67                 }
68         }
69
70         return 0;
71 }
72
73 static int bcm2835_audio_send_msg(struct bcm2835_audio_instance *instance,
74                                   struct vc_audio_msg *m, bool wait)
75 {
76         int err;
77
78         bcm2835_audio_lock(instance);
79         err = bcm2835_audio_send_msg_locked(instance, m, wait);
80         bcm2835_audio_unlock(instance);
81         return err;
82 }
83
84 static int bcm2835_audio_send_simple(struct bcm2835_audio_instance *instance,
85                                      int type, bool wait)
86 {
87         struct vc_audio_msg m = { .type = type };
88
89         return bcm2835_audio_send_msg(instance, &m, wait);
90 }
91
92 static enum vchiq_status audio_vchi_callback(enum vchiq_reason reason,
93                                              struct vchiq_header *header,
94                                              unsigned int handle, void *userdata)
95 {
96         struct bcm2835_audio_instance *instance = vchiq_get_service_userdata(handle);
97         struct vc_audio_msg *m;
98
99         if (reason != VCHIQ_MESSAGE_AVAILABLE)
100                 return VCHIQ_SUCCESS;
101
102         m = (void *)header->data;
103         if (m->type == VC_AUDIO_MSG_TYPE_RESULT) {
104                 instance->result = m->result.success;
105                 complete(&instance->msg_avail_comp);
106         } else if (m->type == VC_AUDIO_MSG_TYPE_COMPLETE) {
107                 if (m->complete.cookie1 != VC_AUDIO_WRITE_COOKIE1 ||
108                     m->complete.cookie2 != VC_AUDIO_WRITE_COOKIE2)
109                         dev_err(instance->dev, "invalid cookie\n");
110                 else
111                         bcm2835_playback_fifo(instance->alsa_stream,
112                                               m->complete.count);
113         } else {
114                 dev_err(instance->dev, "unexpected callback type=%d\n", m->type);
115         }
116
117         vchiq_release_message(handle, header);
118         return VCHIQ_SUCCESS;
119 }
120
121 static int
122 vc_vchi_audio_init(struct vchiq_instance *vchiq_instance,
123                    struct bcm2835_audio_instance *instance)
124 {
125         struct vchiq_service_params_kernel params = {
126                 .version                = VC_AUDIOSERV_VER,
127                 .version_min            = VC_AUDIOSERV_MIN_VER,
128                 .fourcc                 = VCHIQ_MAKE_FOURCC('A', 'U', 'D', 'S'),
129                 .callback               = audio_vchi_callback,
130                 .userdata               = instance,
131         };
132         int status;
133
134         /* Open the VCHI service connections */
135         status = vchiq_open_service(vchiq_instance, &params,
136                                     &instance->service_handle);
137
138         if (status) {
139                 dev_err(instance->dev,
140                         "failed to open VCHI service connection (status=%d)\n",
141                         status);
142                 return -EPERM;
143         }
144
145         /* Finished with the service for now */
146         vchiq_release_service(instance->service_handle);
147
148         return 0;
149 }
150
151 static void vc_vchi_audio_deinit(struct bcm2835_audio_instance *instance)
152 {
153         int status;
154
155         mutex_lock(&instance->vchi_mutex);
156         vchiq_use_service(instance->service_handle);
157
158         /* Close all VCHI service connections */
159         status = vchiq_close_service(instance->service_handle);
160         if (status) {
161                 dev_err(instance->dev,
162                         "failed to close VCHI service connection (status=%d)\n",
163                         status);
164         }
165
166         mutex_unlock(&instance->vchi_mutex);
167 }
168
169 int bcm2835_new_vchi_ctx(struct device *dev, struct bcm2835_vchi_ctx *vchi_ctx)
170 {
171         int ret;
172
173         /* Initialize and create a VCHI connection */
174         ret = vchiq_initialise(&vchi_ctx->instance);
175         if (ret) {
176                 dev_err(dev, "failed to initialise VCHI instance (ret=%d)\n",
177                         ret);
178                 return -EIO;
179         }
180
181         ret = vchiq_connect(vchi_ctx->instance);
182         if (ret) {
183                 dev_dbg(dev, "failed to connect VCHI instance (ret=%d)\n",
184                         ret);
185
186                 kfree(vchi_ctx->instance);
187                 vchi_ctx->instance = NULL;
188
189                 return -EIO;
190         }
191
192         return 0;
193 }
194
195 void bcm2835_free_vchi_ctx(struct bcm2835_vchi_ctx *vchi_ctx)
196 {
197         /* Close the VCHI connection - it will also free vchi_ctx->instance */
198         WARN_ON(vchiq_shutdown(vchi_ctx->instance));
199
200         vchi_ctx->instance = NULL;
201 }
202
203 int bcm2835_audio_open(struct bcm2835_alsa_stream *alsa_stream)
204 {
205         struct bcm2835_vchi_ctx *vchi_ctx = alsa_stream->chip->vchi_ctx;
206         struct bcm2835_audio_instance *instance;
207         int err;
208
209         /* Allocate memory for this instance */
210         instance = kzalloc(sizeof(*instance), GFP_KERNEL);
211         if (!instance)
212                 return -ENOMEM;
213         mutex_init(&instance->vchi_mutex);
214         instance->dev = alsa_stream->chip->dev;
215         instance->alsa_stream = alsa_stream;
216         alsa_stream->instance = instance;
217
218         err = vc_vchi_audio_init(vchi_ctx->instance,
219                                  instance);
220         if (err < 0)
221                 goto free_instance;
222
223         err = bcm2835_audio_send_simple(instance, VC_AUDIO_MSG_TYPE_OPEN,
224                                         false);
225         if (err < 0)
226                 goto deinit;
227
228         bcm2835_audio_lock(instance);
229         vchiq_get_peer_version(instance->service_handle,
230                                &instance->peer_version);
231         bcm2835_audio_unlock(instance);
232         if (instance->peer_version < 2 || force_bulk)
233                 instance->max_packet = 0; /* bulk transfer */
234         else
235                 instance->max_packet = 4000;
236
237         return 0;
238
239  deinit:
240         vc_vchi_audio_deinit(instance);
241  free_instance:
242         alsa_stream->instance = NULL;
243         kfree(instance);
244         return err;
245 }
246
247 int bcm2835_audio_set_ctls(struct bcm2835_alsa_stream *alsa_stream)
248 {
249         struct bcm2835_chip *chip = alsa_stream->chip;
250         struct vc_audio_msg m = {};
251
252         m.type = VC_AUDIO_MSG_TYPE_CONTROL;
253         m.control.dest = chip->dest;
254         if (!chip->mute)
255                 m.control.volume = CHIP_MIN_VOLUME;
256         else
257                 m.control.volume = alsa2chip(chip->volume);
258
259         return bcm2835_audio_send_msg(alsa_stream->instance, &m, true);
260 }
261
262 int bcm2835_audio_set_params(struct bcm2835_alsa_stream *alsa_stream,
263                              unsigned int channels, unsigned int samplerate,
264                              unsigned int bps)
265 {
266         struct vc_audio_msg m = {
267                  .type = VC_AUDIO_MSG_TYPE_CONFIG,
268                  .config.channels = channels,
269                  .config.samplerate = samplerate,
270                  .config.bps = bps,
271         };
272         int err;
273
274         /* resend ctls - alsa_stream may not have been open when first send */
275         err = bcm2835_audio_set_ctls(alsa_stream);
276         if (err)
277                 return err;
278
279         return bcm2835_audio_send_msg(alsa_stream->instance, &m, true);
280 }
281
282 int bcm2835_audio_start(struct bcm2835_alsa_stream *alsa_stream)
283 {
284         return bcm2835_audio_send_simple(alsa_stream->instance,
285                                          VC_AUDIO_MSG_TYPE_START, false);
286 }
287
288 int bcm2835_audio_stop(struct bcm2835_alsa_stream *alsa_stream)
289 {
290         return bcm2835_audio_send_simple(alsa_stream->instance,
291                                          VC_AUDIO_MSG_TYPE_STOP, false);
292 }
293
294 /* FIXME: this doesn't seem working as expected for "draining" */
295 int bcm2835_audio_drain(struct bcm2835_alsa_stream *alsa_stream)
296 {
297         struct vc_audio_msg m = {
298                 .type = VC_AUDIO_MSG_TYPE_STOP,
299                 .stop.draining = 1,
300         };
301
302         return bcm2835_audio_send_msg(alsa_stream->instance, &m, false);
303 }
304
305 int bcm2835_audio_close(struct bcm2835_alsa_stream *alsa_stream)
306 {
307         struct bcm2835_audio_instance *instance = alsa_stream->instance;
308         int err;
309
310         err = bcm2835_audio_send_simple(alsa_stream->instance,
311                                         VC_AUDIO_MSG_TYPE_CLOSE, true);
312
313         /* Stop the audio service */
314         vc_vchi_audio_deinit(instance);
315         alsa_stream->instance = NULL;
316         kfree(instance);
317
318         return err;
319 }
320
321 int bcm2835_audio_write(struct bcm2835_alsa_stream *alsa_stream,
322                         unsigned int size, void *src)
323 {
324         struct bcm2835_audio_instance *instance = alsa_stream->instance;
325         struct vc_audio_msg m = {
326                 .type = VC_AUDIO_MSG_TYPE_WRITE,
327                 .write.count = size,
328                 .write.max_packet = instance->max_packet,
329                 .write.cookie1 = VC_AUDIO_WRITE_COOKIE1,
330                 .write.cookie2 = VC_AUDIO_WRITE_COOKIE2,
331         };
332         unsigned int count;
333         int err, status;
334
335         if (!size)
336                 return 0;
337
338         bcm2835_audio_lock(instance);
339         err = bcm2835_audio_send_msg_locked(instance, &m, false);
340         if (err < 0)
341                 goto unlock;
342
343         count = size;
344         if (!instance->max_packet) {
345                 /* Send the message to the videocore */
346                 status = vchiq_bulk_transmit(instance->service_handle, src,
347                                              count, NULL,
348                                              VCHIQ_BULK_MODE_BLOCKING);
349         } else {
350                 while (count > 0) {
351                         int bytes = min(instance->max_packet, count);
352
353                         status = vchiq_queue_kernel_message(instance->service_handle,
354                                                             src, bytes);
355                         src += bytes;
356                         count -= bytes;
357                 }
358         }
359
360         if (status) {
361                 dev_err(instance->dev,
362                         "failed on %d bytes transfer (status=%d)\n",
363                         size, status);
364                 err = -EIO;
365         }
366
367  unlock:
368         bcm2835_audio_unlock(instance);
369         return err;
370 }