1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright 2011 Broadcom Corporation. All rights reserved. */ 3 4 #include <linux/interrupt.h> 5 #include <linux/slab.h> 6 7 #include <sound/asoundef.h> 8 9 #include "bcm2835.h" 10 11 /* hardware definition */ 12 static const struct snd_pcm_hardware snd_bcm2835_playback_hw = { 13 .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | 14 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | 15 SNDRV_PCM_INFO_SYNC_APPLPTR | SNDRV_PCM_INFO_BATCH), 16 .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, 17 .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000, 18 .rate_min = 8000, 19 .rate_max = 192000, 20 .channels_min = 1, 21 .channels_max = 8, 22 .buffer_bytes_max = 512 * 1024, 23 .period_bytes_min = 1 * 1024, 24 .period_bytes_max = 512 * 1024, 25 .periods_min = 1, 26 .periods_max = 128, 27 }; 28 29 static const struct snd_pcm_hardware snd_bcm2835_playback_spdif_hw = { 30 .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | 31 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | 32 SNDRV_PCM_INFO_SYNC_APPLPTR | SNDRV_PCM_INFO_BATCH), 33 .formats = SNDRV_PCM_FMTBIT_S16_LE, 34 .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_44100 | 35 SNDRV_PCM_RATE_48000, 36 .rate_min = 44100, 37 .rate_max = 48000, 38 .channels_min = 2, 39 .channels_max = 2, 40 .buffer_bytes_max = 128 * 1024, 41 .period_bytes_min = 1 * 1024, 42 .period_bytes_max = 128 * 1024, 43 .periods_min = 1, 44 .periods_max = 128, 45 }; 46 47 static void snd_bcm2835_playback_free(struct snd_pcm_runtime *runtime) 48 { 49 kfree(runtime->private_data); 50 } 51 52 void bcm2835_playback_fifo(struct bcm2835_alsa_stream *alsa_stream, 53 unsigned int bytes) 54 { 55 struct snd_pcm_substream *substream = alsa_stream->substream; 56 unsigned int pos; 57 58 if (!alsa_stream->period_size) 59 return; 60 61 if (bytes >= alsa_stream->buffer_size) { 62 snd_pcm_stream_lock(substream); 63 snd_pcm_stop(substream, 64 alsa_stream->draining ? 65 SNDRV_PCM_STATE_SETUP : 66 SNDRV_PCM_STATE_XRUN); 67 snd_pcm_stream_unlock(substream); 68 return; 69 } 70 71 pos = atomic_read(&alsa_stream->pos); 72 pos += bytes; 73 pos %= alsa_stream->buffer_size; 74 atomic_set(&alsa_stream->pos, pos); 75 76 alsa_stream->period_offset += bytes; 77 alsa_stream->interpolate_start = ktime_get(); 78 if (alsa_stream->period_offset >= alsa_stream->period_size) { 79 alsa_stream->period_offset %= alsa_stream->period_size; 80 snd_pcm_period_elapsed(substream); 81 } 82 } 83 84 /* open callback */ 85 static int snd_bcm2835_playback_open_generic( 86 struct snd_pcm_substream *substream, int spdif) 87 { 88 struct bcm2835_chip *chip = snd_pcm_substream_chip(substream); 89 struct snd_pcm_runtime *runtime = substream->runtime; 90 struct bcm2835_alsa_stream *alsa_stream; 91 int idx; 92 int err; 93 94 mutex_lock(&chip->audio_mutex); 95 idx = substream->number; 96 97 if (spdif && chip->opened) { 98 err = -EBUSY; 99 goto out; 100 } else if (!spdif && (chip->opened & (1 << idx))) { 101 err = -EBUSY; 102 goto out; 103 } 104 if (idx >= MAX_SUBSTREAMS) { 105 dev_err(chip->dev, 106 "substream(%d) device doesn't exist max(%d) substreams allowed\n", 107 idx, MAX_SUBSTREAMS); 108 err = -ENODEV; 109 goto out; 110 } 111 112 alsa_stream = kzalloc(sizeof(*alsa_stream), GFP_KERNEL); 113 if (!alsa_stream) { 114 err = -ENOMEM; 115 goto out; 116 } 117 118 /* Initialise alsa_stream */ 119 alsa_stream->chip = chip; 120 alsa_stream->substream = substream; 121 alsa_stream->idx = idx; 122 123 err = bcm2835_audio_open(alsa_stream); 124 if (err) { 125 kfree(alsa_stream); 126 goto out; 127 } 128 runtime->private_data = alsa_stream; 129 runtime->private_free = snd_bcm2835_playback_free; 130 if (spdif) { 131 runtime->hw = snd_bcm2835_playback_spdif_hw; 132 } else { 133 /* clear spdif status, as we are not in spdif mode */ 134 chip->spdif_status = 0; 135 runtime->hw = snd_bcm2835_playback_hw; 136 } 137 /* minimum 16 bytes alignment (for vchiq bulk transfers) */ 138 snd_pcm_hw_constraint_step(runtime, 139 0, 140 SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 141 16); 142 143 /* position update is in 10ms order */ 144 snd_pcm_hw_constraint_minmax(runtime, 145 SNDRV_PCM_HW_PARAM_PERIOD_TIME, 146 10 * 1000, UINT_MAX); 147 148 chip->alsa_stream[idx] = alsa_stream; 149 150 chip->opened |= (1 << idx); 151 152 out: 153 mutex_unlock(&chip->audio_mutex); 154 155 return err; 156 } 157 158 static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream) 159 { 160 return snd_bcm2835_playback_open_generic(substream, 0); 161 } 162 163 static int snd_bcm2835_playback_spdif_open(struct snd_pcm_substream *substream) 164 { 165 return snd_bcm2835_playback_open_generic(substream, 1); 166 } 167 168 static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream) 169 { 170 struct bcm2835_alsa_stream *alsa_stream; 171 struct snd_pcm_runtime *runtime; 172 struct bcm2835_chip *chip; 173 174 chip = snd_pcm_substream_chip(substream); 175 mutex_lock(&chip->audio_mutex); 176 runtime = substream->runtime; 177 alsa_stream = runtime->private_data; 178 179 alsa_stream->period_size = 0; 180 alsa_stream->buffer_size = 0; 181 182 bcm2835_audio_close(alsa_stream); 183 alsa_stream->chip->alsa_stream[alsa_stream->idx] = NULL; 184 /* 185 * Do not free up alsa_stream here, it will be freed up by 186 * runtime->private_free callback we registered in *_open above 187 */ 188 189 chip->opened &= ~(1 << substream->number); 190 191 mutex_unlock(&chip->audio_mutex); 192 193 return 0; 194 } 195 196 static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream) 197 { 198 struct bcm2835_chip *chip = snd_pcm_substream_chip(substream); 199 struct snd_pcm_runtime *runtime = substream->runtime; 200 struct bcm2835_alsa_stream *alsa_stream = runtime->private_data; 201 int channels; 202 int err; 203 204 /* notify the vchiq that it should enter spdif passthrough mode by 205 * setting channels=0 (see 206 * https://github.com/raspberrypi/linux/issues/528) 207 */ 208 if (chip->spdif_status & IEC958_AES0_NONAUDIO) 209 channels = 0; 210 else 211 channels = runtime->channels; 212 213 err = bcm2835_audio_set_params(alsa_stream, channels, 214 runtime->rate, 215 snd_pcm_format_width(runtime->format)); 216 if (err < 0) 217 return err; 218 219 memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect)); 220 221 alsa_stream->pcm_indirect.hw_buffer_size = 222 alsa_stream->pcm_indirect.sw_buffer_size = 223 snd_pcm_lib_buffer_bytes(substream); 224 225 alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream); 226 alsa_stream->period_size = snd_pcm_lib_period_bytes(substream); 227 atomic_set(&alsa_stream->pos, 0); 228 alsa_stream->period_offset = 0; 229 alsa_stream->draining = false; 230 alsa_stream->interpolate_start = ktime_get(); 231 232 return 0; 233 } 234 235 static void snd_bcm2835_pcm_transfer(struct snd_pcm_substream *substream, 236 struct snd_pcm_indirect *rec, size_t bytes) 237 { 238 struct snd_pcm_runtime *runtime = substream->runtime; 239 struct bcm2835_alsa_stream *alsa_stream = runtime->private_data; 240 void *src = (void *) (substream->runtime->dma_area + rec->sw_data); 241 242 bcm2835_audio_write(alsa_stream, bytes, src); 243 } 244 245 static int snd_bcm2835_pcm_ack(struct snd_pcm_substream *substream) 246 { 247 struct snd_pcm_runtime *runtime = substream->runtime; 248 struct bcm2835_alsa_stream *alsa_stream = runtime->private_data; 249 struct snd_pcm_indirect *pcm_indirect = &alsa_stream->pcm_indirect; 250 251 return snd_pcm_indirect_playback_transfer(substream, pcm_indirect, 252 snd_bcm2835_pcm_transfer); 253 } 254 255 /* trigger callback */ 256 static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd) 257 { 258 struct snd_pcm_runtime *runtime = substream->runtime; 259 struct bcm2835_alsa_stream *alsa_stream = runtime->private_data; 260 261 switch (cmd) { 262 case SNDRV_PCM_TRIGGER_START: 263 return bcm2835_audio_start(alsa_stream); 264 case SNDRV_PCM_TRIGGER_DRAIN: 265 alsa_stream->draining = true; 266 return bcm2835_audio_drain(alsa_stream); 267 case SNDRV_PCM_TRIGGER_STOP: 268 return bcm2835_audio_stop(alsa_stream); 269 default: 270 return -EINVAL; 271 } 272 } 273 274 /* pointer callback */ 275 static snd_pcm_uframes_t 276 snd_bcm2835_pcm_pointer(struct snd_pcm_substream *substream) 277 { 278 struct snd_pcm_runtime *runtime = substream->runtime; 279 struct bcm2835_alsa_stream *alsa_stream = runtime->private_data; 280 ktime_t now = ktime_get(); 281 282 /* Give userspace better delay reporting by interpolating between GPU 283 * notifications, assuming audio speed is close enough to the clock 284 * used for ktime 285 */ 286 287 if ((ktime_to_ns(alsa_stream->interpolate_start)) && 288 (ktime_compare(alsa_stream->interpolate_start, now) < 0)) { 289 u64 interval = 290 (ktime_to_ns(ktime_sub(now, 291 alsa_stream->interpolate_start))); 292 u64 frames_output_in_interval = 293 div_u64((interval * runtime->rate), 1000000000); 294 snd_pcm_sframes_t frames_output_in_interval_sized = 295 -frames_output_in_interval; 296 runtime->delay = frames_output_in_interval_sized; 297 } 298 299 return snd_pcm_indirect_playback_pointer(substream, 300 &alsa_stream->pcm_indirect, 301 atomic_read(&alsa_stream->pos)); 302 } 303 304 /* operators */ 305 static const struct snd_pcm_ops snd_bcm2835_playback_ops = { 306 .open = snd_bcm2835_playback_open, 307 .close = snd_bcm2835_playback_close, 308 .prepare = snd_bcm2835_pcm_prepare, 309 .trigger = snd_bcm2835_pcm_trigger, 310 .pointer = snd_bcm2835_pcm_pointer, 311 .ack = snd_bcm2835_pcm_ack, 312 }; 313 314 static const struct snd_pcm_ops snd_bcm2835_playback_spdif_ops = { 315 .open = snd_bcm2835_playback_spdif_open, 316 .close = snd_bcm2835_playback_close, 317 .prepare = snd_bcm2835_pcm_prepare, 318 .trigger = snd_bcm2835_pcm_trigger, 319 .pointer = snd_bcm2835_pcm_pointer, 320 .ack = snd_bcm2835_pcm_ack, 321 }; 322 323 /* create a pcm device */ 324 int snd_bcm2835_new_pcm(struct bcm2835_chip *chip, const char *name, 325 int idx, enum snd_bcm2835_route route, 326 u32 numchannels, bool spdif) 327 { 328 struct snd_pcm *pcm; 329 int err; 330 331 err = snd_pcm_new(chip->card, name, idx, numchannels, 0, &pcm); 332 if (err) 333 return err; 334 335 pcm->private_data = chip; 336 pcm->nonatomic = true; 337 strscpy(pcm->name, name, sizeof(pcm->name)); 338 if (!spdif) { 339 chip->dest = route; 340 chip->volume = 0; 341 chip->mute = CTRL_VOL_UNMUTE; 342 } 343 344 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, 345 spdif ? &snd_bcm2835_playback_spdif_ops : 346 &snd_bcm2835_playback_ops); 347 348 snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, 349 chip->card->dev, 128 * 1024, 128 * 1024); 350 351 if (spdif) 352 chip->pcm_spdif = pcm; 353 else 354 chip->pcm = pcm; 355 return 0; 356 } 357