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