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