Merge tag 'trace-v5.5-3' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt...
[linux-2.6-microblaze.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         struct vchi_service_handle *vchi_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         vchi_service_use(instance->vchi_handle);
29 }
30
31 static void bcm2835_audio_unlock(struct bcm2835_audio_instance *instance)
32 {
33         vchi_service_release(instance->vchi_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 = vchi_queue_kernel_message(instance->vchi_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 void audio_vchi_callback(void *param,
93                                 const enum vchi_callback_reason reason,
94                                 void *msg_handle)
95 {
96         struct bcm2835_audio_instance *instance = param;
97         struct vc_audio_msg m;
98         int msg_len;
99         int status;
100
101         if (reason != VCHI_CALLBACK_MSG_AVAILABLE)
102                 return;
103
104         status = vchi_msg_dequeue(instance->vchi_handle,
105                                   &m, sizeof(m), &msg_len, VCHI_FLAGS_NONE);
106         if (status)
107                 return;
108
109         if (m.type == VC_AUDIO_MSG_TYPE_RESULT) {
110                 instance->result = m.result.success;
111                 complete(&instance->msg_avail_comp);
112         } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
113                 if (m.complete.cookie1 != VC_AUDIO_WRITE_COOKIE1 ||
114                     m.complete.cookie2 != VC_AUDIO_WRITE_COOKIE2)
115                         dev_err(instance->dev, "invalid cookie\n");
116                 else
117                         bcm2835_playback_fifo(instance->alsa_stream,
118                                               m.complete.count);
119         } else {
120                 dev_err(instance->dev, "unexpected callback type=%d\n", m.type);
121         }
122 }
123
124 static int
125 vc_vchi_audio_init(struct vchi_instance_handle *vchi_instance,
126                    struct bcm2835_audio_instance *instance)
127 {
128         struct service_creation params = {
129                 .version                = VCHI_VERSION_EX(VC_AUDIOSERV_VER, VC_AUDIOSERV_MIN_VER),
130                 .service_id             = VC_AUDIO_SERVER_NAME,
131                 .callback               = audio_vchi_callback,
132                 .callback_param         = instance,
133         };
134         int status;
135
136         /* Open the VCHI service connections */
137         status = vchi_service_open(vchi_instance, &params,
138                                    &instance->vchi_handle);
139
140         if (status) {
141                 dev_err(instance->dev,
142                         "failed to open VCHI service connection (status=%d)\n",
143                         status);
144                 return -EPERM;
145         }
146
147         /* Finished with the service for now */
148         vchi_service_release(instance->vchi_handle);
149
150         return 0;
151 }
152
153 static void vc_vchi_audio_deinit(struct bcm2835_audio_instance *instance)
154 {
155         int status;
156
157         mutex_lock(&instance->vchi_mutex);
158         vchi_service_use(instance->vchi_handle);
159
160         /* Close all VCHI service connections */
161         status = vchi_service_close(instance->vchi_handle);
162         if (status) {
163                 dev_err(instance->dev,
164                         "failed to close VCHI service connection (status=%d)\n",
165                         status);
166         }
167
168         mutex_unlock(&instance->vchi_mutex);
169 }
170
171 int bcm2835_new_vchi_ctx(struct device *dev, struct bcm2835_vchi_ctx *vchi_ctx)
172 {
173         int ret;
174
175         /* Initialize and create a VCHI connection */
176         ret = vchi_initialise(&vchi_ctx->vchi_instance);
177         if (ret) {
178                 dev_err(dev, "failed to initialise VCHI instance (ret=%d)\n",
179                         ret);
180                 return -EIO;
181         }
182
183         ret = vchi_connect(vchi_ctx->vchi_instance);
184         if (ret) {
185                 dev_dbg(dev, "failed to connect VCHI instance (ret=%d)\n",
186                         ret);
187
188                 kfree(vchi_ctx->vchi_instance);
189                 vchi_ctx->vchi_instance = NULL;
190
191                 return -EIO;
192         }
193
194         return 0;
195 }
196
197 void bcm2835_free_vchi_ctx(struct bcm2835_vchi_ctx *vchi_ctx)
198 {
199         /* Close the VCHI connection - it will also free vchi_instance */
200         WARN_ON(vchi_disconnect(vchi_ctx->vchi_instance));
201
202         vchi_ctx->vchi_instance = NULL;
203 }
204
205 int bcm2835_audio_open(struct bcm2835_alsa_stream *alsa_stream)
206 {
207         struct bcm2835_vchi_ctx *vchi_ctx = alsa_stream->chip->vchi_ctx;
208         struct bcm2835_audio_instance *instance;
209         int err;
210
211         /* Allocate memory for this instance */
212         instance = kzalloc(sizeof(*instance), GFP_KERNEL);
213         if (!instance)
214                 return -ENOMEM;
215         mutex_init(&instance->vchi_mutex);
216         instance->dev = alsa_stream->chip->dev;
217         instance->alsa_stream = alsa_stream;
218         alsa_stream->instance = instance;
219
220         err = vc_vchi_audio_init(vchi_ctx->vchi_instance,
221                                  instance);
222         if (err < 0)
223                 goto free_instance;
224
225         err = bcm2835_audio_send_simple(instance, VC_AUDIO_MSG_TYPE_OPEN,
226                                         false);
227         if (err < 0)
228                 goto deinit;
229
230         bcm2835_audio_lock(instance);
231         vchi_get_peer_version(instance->vchi_handle, &instance->peer_version);
232         bcm2835_audio_unlock(instance);
233         if (instance->peer_version < 2 || force_bulk)
234                 instance->max_packet = 0; /* bulk transfer */
235         else
236                 instance->max_packet = 4000;
237
238         return 0;
239
240  deinit:
241         vc_vchi_audio_deinit(instance);
242  free_instance:
243         alsa_stream->instance = NULL;
244         kfree(instance);
245         return err;
246 }
247
248 int bcm2835_audio_set_ctls(struct bcm2835_alsa_stream *alsa_stream)
249 {
250         struct bcm2835_chip *chip = alsa_stream->chip;
251         struct vc_audio_msg m = {};
252
253         m.type = VC_AUDIO_MSG_TYPE_CONTROL;
254         m.control.dest = chip->dest;
255         if (!chip->mute)
256                 m.control.volume = CHIP_MIN_VOLUME;
257         else
258                 m.control.volume = alsa2chip(chip->volume);
259
260         return bcm2835_audio_send_msg(alsa_stream->instance, &m, true);
261 }
262
263 int bcm2835_audio_set_params(struct bcm2835_alsa_stream *alsa_stream,
264                              unsigned int channels, unsigned int samplerate,
265                              unsigned int bps)
266 {
267         struct vc_audio_msg m = {
268                  .type = VC_AUDIO_MSG_TYPE_CONFIG,
269                  .config.channels = channels,
270                  .config.samplerate = samplerate,
271                  .config.bps = bps,
272         };
273         int err;
274
275         /* resend ctls - alsa_stream may not have been open when first send */
276         err = bcm2835_audio_set_ctls(alsa_stream);
277         if (err)
278                 return err;
279
280         return bcm2835_audio_send_msg(alsa_stream->instance, &m, true);
281 }
282
283 int bcm2835_audio_start(struct bcm2835_alsa_stream *alsa_stream)
284 {
285         return bcm2835_audio_send_simple(alsa_stream->instance,
286                                          VC_AUDIO_MSG_TYPE_START, false);
287 }
288
289 int bcm2835_audio_stop(struct bcm2835_alsa_stream *alsa_stream)
290 {
291         return bcm2835_audio_send_simple(alsa_stream->instance,
292                                          VC_AUDIO_MSG_TYPE_STOP, false);
293 }
294
295 /* FIXME: this doesn't seem working as expected for "draining" */
296 int bcm2835_audio_drain(struct bcm2835_alsa_stream *alsa_stream)
297 {
298         struct vc_audio_msg m = {
299                 .type = VC_AUDIO_MSG_TYPE_STOP,
300                 .stop.draining = 1,
301         };
302
303         return bcm2835_audio_send_msg(alsa_stream->instance, &m, false);
304 }
305
306 int bcm2835_audio_close(struct bcm2835_alsa_stream *alsa_stream)
307 {
308         struct bcm2835_audio_instance *instance = alsa_stream->instance;
309         int err;
310
311         err = bcm2835_audio_send_simple(alsa_stream->instance,
312                                         VC_AUDIO_MSG_TYPE_CLOSE, true);
313
314         /* Stop the audio service */
315         vc_vchi_audio_deinit(instance);
316         alsa_stream->instance = NULL;
317         kfree(instance);
318
319         return err;
320 }
321
322 int bcm2835_audio_write(struct bcm2835_alsa_stream *alsa_stream,
323                         unsigned int size, void *src)
324 {
325         struct bcm2835_audio_instance *instance = alsa_stream->instance;
326         struct vc_audio_msg m = {
327                 .type = VC_AUDIO_MSG_TYPE_WRITE,
328                 .write.count = size,
329                 .write.max_packet = instance->max_packet,
330                 .write.cookie1 = VC_AUDIO_WRITE_COOKIE1,
331                 .write.cookie2 = VC_AUDIO_WRITE_COOKIE2,
332         };
333         unsigned int count;
334         int err, status;
335
336         if (!size)
337                 return 0;
338
339         bcm2835_audio_lock(instance);
340         err = bcm2835_audio_send_msg_locked(instance, &m, false);
341         if (err < 0)
342                 goto unlock;
343
344         count = size;
345         if (!instance->max_packet) {
346                 /* Send the message to the videocore */
347                 status = vchi_bulk_queue_transmit(instance->vchi_handle,
348                                                   src, count,
349                                                   VCHI_FLAGS_BLOCK_UNTIL_DATA_READ,
350                                                   NULL);
351         } else {
352                 while (count > 0) {
353                         int bytes = min(instance->max_packet, count);
354
355                         status = vchi_queue_kernel_message(instance->vchi_handle,
356                                                            src, bytes);
357                         src += bytes;
358                         count -= bytes;
359                 }
360         }
361
362         if (status) {
363                 dev_err(instance->dev,
364                         "failed on %d bytes transfer (status=%d)\n",
365                         size, status);
366                 err = -EIO;
367         }
368
369  unlock:
370         bcm2835_audio_unlock(instance);
371         return err;
372 }