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