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; 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 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 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 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 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 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 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 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, ¶ms, 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 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 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 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 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 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 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 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 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" */ 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 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 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