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