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 msecs_to_jiffies(10 * 1000))) {
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 * 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, void *userdata)
100 {
101 struct bcm2835_audio_instance *instance = vchiq_get_service_userdata(vchiq_instance,
102 handle);
103 struct vc_audio_msg *m;
104
105 if (reason != VCHIQ_MESSAGE_AVAILABLE)
106 return 0;
107
108 m = (void *)header->data;
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 vchiq_release_message(vchiq_instance, instance->service_handle, header);
124 return 0;
125 }
126
127 static int
vc_vchi_audio_init(struct vchiq_instance * vchiq_instance,struct bcm2835_audio_instance * instance)128 vc_vchi_audio_init(struct vchiq_instance *vchiq_instance,
129 struct bcm2835_audio_instance *instance)
130 {
131 struct vchiq_service_params_kernel params = {
132 .version = VC_AUDIOSERV_VER,
133 .version_min = VC_AUDIOSERV_MIN_VER,
134 .fourcc = VCHIQ_MAKE_FOURCC('A', 'U', 'D', 'S'),
135 .callback = audio_vchi_callback,
136 .userdata = instance,
137 };
138 int status;
139
140 /* Open the VCHI service connections */
141 status = vchiq_open_service(vchiq_instance, ¶ms,
142 &instance->service_handle);
143
144 if (status) {
145 dev_err(instance->dev,
146 "failed to open VCHI service connection (status=%d)\n",
147 status);
148 return -EPERM;
149 }
150
151 /* Finished with the service for now */
152 vchiq_release_service(instance->alsa_stream->chip->vchi_ctx->instance,
153 instance->service_handle);
154
155 return 0;
156 }
157
vc_vchi_audio_deinit(struct bcm2835_audio_instance * instance)158 static void vc_vchi_audio_deinit(struct bcm2835_audio_instance *instance)
159 {
160 int status;
161
162 mutex_lock(&instance->vchi_mutex);
163 vchiq_use_service(instance->alsa_stream->chip->vchi_ctx->instance,
164 instance->service_handle);
165
166 /* Close all VCHI service connections */
167 status = vchiq_close_service(instance->alsa_stream->chip->vchi_ctx->instance,
168 instance->service_handle);
169 if (status) {
170 dev_err(instance->dev,
171 "failed to close VCHI service connection (status=%d)\n",
172 status);
173 }
174
175 mutex_unlock(&instance->vchi_mutex);
176 }
177
bcm2835_new_vchi_ctx(struct device * dev,struct bcm2835_vchi_ctx * vchi_ctx)178 int bcm2835_new_vchi_ctx(struct device *dev, struct bcm2835_vchi_ctx *vchi_ctx)
179 {
180 struct vchiq_drv_mgmt *mgmt = dev_get_drvdata(dev->parent);
181 int ret;
182
183 /* Initialize and create a VCHI connection */
184 ret = vchiq_initialise(&mgmt->state, &vchi_ctx->instance);
185 if (ret) {
186 dev_err(dev, "failed to initialise VCHI instance (ret=%d)\n",
187 ret);
188 return -EIO;
189 }
190
191 ret = vchiq_connect(vchi_ctx->instance);
192 if (ret) {
193 dev_dbg(dev, "failed to connect VCHI instance (ret=%d)\n",
194 ret);
195
196 kfree(vchi_ctx->instance);
197 vchi_ctx->instance = NULL;
198
199 return -EIO;
200 }
201
202 return 0;
203 }
204
bcm2835_free_vchi_ctx(struct bcm2835_vchi_ctx * vchi_ctx)205 void bcm2835_free_vchi_ctx(struct bcm2835_vchi_ctx *vchi_ctx)
206 {
207 /* Close the VCHI connection - it will also free vchi_ctx->instance */
208 WARN_ON(vchiq_shutdown(vchi_ctx->instance));
209
210 vchi_ctx->instance = NULL;
211 }
212
bcm2835_audio_open(struct bcm2835_alsa_stream * alsa_stream)213 int bcm2835_audio_open(struct bcm2835_alsa_stream *alsa_stream)
214 {
215 struct bcm2835_vchi_ctx *vchi_ctx = alsa_stream->chip->vchi_ctx;
216 struct bcm2835_audio_instance *instance;
217 int err;
218
219 /* Allocate memory for this instance */
220 instance = kzalloc(sizeof(*instance), GFP_KERNEL);
221 if (!instance)
222 return -ENOMEM;
223 mutex_init(&instance->vchi_mutex);
224 instance->dev = alsa_stream->chip->dev;
225 instance->alsa_stream = alsa_stream;
226 alsa_stream->instance = instance;
227
228 err = vc_vchi_audio_init(vchi_ctx->instance,
229 instance);
230 if (err < 0)
231 goto free_instance;
232
233 err = bcm2835_audio_send_simple(instance, VC_AUDIO_MSG_TYPE_OPEN,
234 false);
235 if (err < 0)
236 goto deinit;
237
238 bcm2835_audio_lock(instance);
239 vchiq_get_peer_version(vchi_ctx->instance, instance->service_handle,
240 &instance->peer_version);
241 bcm2835_audio_unlock(instance);
242 if (instance->peer_version < 2 || force_bulk)
243 instance->max_packet = 0; /* bulk transfer */
244 else
245 instance->max_packet = 4000;
246
247 return 0;
248
249 deinit:
250 vc_vchi_audio_deinit(instance);
251 free_instance:
252 alsa_stream->instance = NULL;
253 kfree(instance);
254 return err;
255 }
256
bcm2835_audio_set_ctls(struct bcm2835_alsa_stream * alsa_stream)257 int bcm2835_audio_set_ctls(struct bcm2835_alsa_stream *alsa_stream)
258 {
259 struct bcm2835_chip *chip = alsa_stream->chip;
260 struct vc_audio_msg m = {};
261
262 m.type = VC_AUDIO_MSG_TYPE_CONTROL;
263 m.control.dest = chip->dest;
264 if (!chip->mute)
265 m.control.volume = CHIP_MIN_VOLUME;
266 else
267 m.control.volume = alsa2chip(chip->volume);
268
269 return bcm2835_audio_send_msg(alsa_stream->instance, &m, true);
270 }
271
bcm2835_audio_set_params(struct bcm2835_alsa_stream * alsa_stream,unsigned int channels,unsigned int samplerate,unsigned int bps)272 int bcm2835_audio_set_params(struct bcm2835_alsa_stream *alsa_stream,
273 unsigned int channels, unsigned int samplerate,
274 unsigned int bps)
275 {
276 struct vc_audio_msg m = {
277 .type = VC_AUDIO_MSG_TYPE_CONFIG,
278 .config.channels = channels,
279 .config.samplerate = samplerate,
280 .config.bps = bps,
281 };
282 int err;
283
284 /* resend ctls - alsa_stream may not have been open when first send */
285 err = bcm2835_audio_set_ctls(alsa_stream);
286 if (err)
287 return err;
288
289 return bcm2835_audio_send_msg(alsa_stream->instance, &m, true);
290 }
291
bcm2835_audio_start(struct bcm2835_alsa_stream * alsa_stream)292 int bcm2835_audio_start(struct bcm2835_alsa_stream *alsa_stream)
293 {
294 return bcm2835_audio_send_simple(alsa_stream->instance,
295 VC_AUDIO_MSG_TYPE_START, false);
296 }
297
bcm2835_audio_stop(struct bcm2835_alsa_stream * alsa_stream)298 int bcm2835_audio_stop(struct bcm2835_alsa_stream *alsa_stream)
299 {
300 return bcm2835_audio_send_simple(alsa_stream->instance,
301 VC_AUDIO_MSG_TYPE_STOP, false);
302 }
303
304 /* FIXME: this doesn't seem working as expected for "draining" */
bcm2835_audio_drain(struct bcm2835_alsa_stream * alsa_stream)305 int bcm2835_audio_drain(struct bcm2835_alsa_stream *alsa_stream)
306 {
307 struct vc_audio_msg m = {
308 .type = VC_AUDIO_MSG_TYPE_STOP,
309 .stop.draining = 1,
310 };
311
312 return bcm2835_audio_send_msg(alsa_stream->instance, &m, false);
313 }
314
bcm2835_audio_close(struct bcm2835_alsa_stream * alsa_stream)315 int bcm2835_audio_close(struct bcm2835_alsa_stream *alsa_stream)
316 {
317 struct bcm2835_audio_instance *instance = alsa_stream->instance;
318 int err;
319
320 err = bcm2835_audio_send_simple(alsa_stream->instance,
321 VC_AUDIO_MSG_TYPE_CLOSE, true);
322
323 /* Stop the audio service */
324 vc_vchi_audio_deinit(instance);
325 alsa_stream->instance = NULL;
326 kfree(instance);
327
328 return err;
329 }
330
bcm2835_audio_write(struct bcm2835_alsa_stream * alsa_stream,unsigned int size,void * src)331 int bcm2835_audio_write(struct bcm2835_alsa_stream *alsa_stream,
332 unsigned int size, void *src)
333 {
334 struct bcm2835_audio_instance *instance = alsa_stream->instance;
335 struct bcm2835_vchi_ctx *vchi_ctx = alsa_stream->chip->vchi_ctx;
336 struct vchiq_instance *vchiq_instance = vchi_ctx->instance;
337 struct vc_audio_msg m = {
338 .type = VC_AUDIO_MSG_TYPE_WRITE,
339 .write.count = size,
340 .write.max_packet = instance->max_packet,
341 .write.cookie1 = VC_AUDIO_WRITE_COOKIE1,
342 .write.cookie2 = VC_AUDIO_WRITE_COOKIE2,
343 };
344 unsigned int count;
345 int err, status;
346
347 if (!size)
348 return 0;
349
350 bcm2835_audio_lock(instance);
351 err = bcm2835_audio_send_msg_locked(instance, &m, false);
352 if (err < 0)
353 goto unlock;
354
355 count = size;
356 if (!instance->max_packet) {
357 /* Send the message to the videocore */
358 status = vchiq_bulk_transmit(vchiq_instance, instance->service_handle, src, count,
359 NULL, VCHIQ_BULK_MODE_BLOCKING);
360 } else {
361 while (count > 0) {
362 int bytes = min(instance->max_packet, count);
363
364 status = vchiq_queue_kernel_message(vchiq_instance,
365 instance->service_handle, src, bytes);
366 src += bytes;
367 count -= bytes;
368 }
369 }
370
371 if (status) {
372 dev_err(instance->dev,
373 "failed on %d bytes transfer (status=%d)\n",
374 size, status);
375 err = -EIO;
376 }
377
378 unlock:
379 bcm2835_audio_unlock(instance);
380 return err;
381 }
382