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(struct snd_pcm_substream *substream, int spdif) 86 { 87 struct bcm2835_chip *chip = snd_pcm_substream_chip(substream); 88 struct snd_pcm_runtime *runtime = substream->runtime; 89 struct bcm2835_alsa_stream *alsa_stream; 90 int idx; 91 int err; 92 93 mutex_lock(&chip->audio_mutex); 94 idx = substream->number; 95 96 if (spdif && chip->opened) { 97 err = -EBUSY; 98 goto out; 99 } else if (!spdif && (chip->opened & (1 << idx))) { 100 err = -EBUSY; 101 goto out; 102 } 103 if (idx >= MAX_SUBSTREAMS) { 104 dev_err(chip->dev, 105 "substream(%d) device doesn't exist max(%d) substreams allowed\n", 106 idx, MAX_SUBSTREAMS); 107 err = -ENODEV; 108 goto out; 109 } 110 111 alsa_stream = kzalloc(sizeof(*alsa_stream), GFP_KERNEL); 112 if (!alsa_stream) { 113 err = -ENOMEM; 114 goto out; 115 } 116 117 /* Initialise alsa_stream */ 118 alsa_stream->chip = chip; 119 alsa_stream->substream = substream; 120 alsa_stream->idx = idx; 121 122 err = bcm2835_audio_open(alsa_stream); 123 if (err) { 124 kfree(alsa_stream); 125 goto out; 126 } 127 runtime->private_data = alsa_stream; 128 runtime->private_free = snd_bcm2835_playback_free; 129 if (spdif) { 130 runtime->hw = snd_bcm2835_playback_spdif_hw; 131 } else { 132 /* clear spdif status, as we are not in spdif mode */ 133 chip->spdif_status = 0; 134 runtime->hw = snd_bcm2835_playback_hw; 135 } 136 /* minimum 16 bytes alignment (for vchiq bulk transfers) */ 137 snd_pcm_hw_constraint_step(runtime, 138 0, 139 SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 140 16); 141 142 /* position update is in 10ms order */ 143 snd_pcm_hw_constraint_minmax(runtime, 144 SNDRV_PCM_HW_PARAM_PERIOD_TIME, 145 10 * 1000, UINT_MAX); 146 147 chip->alsa_stream[idx] = alsa_stream; 148 149 chip->opened |= (1 << idx); 150 151 out: 152 mutex_unlock(&chip->audio_mutex); 153 154 return err; 155 } 156 157 static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream) 158 { 159 return snd_bcm2835_playback_open_generic(substream, 0); 160 } 161 162 static int snd_bcm2835_playback_spdif_open(struct snd_pcm_substream *substream) 163 { 164 return snd_bcm2835_playback_open_generic(substream, 1); 165 } 166 167 static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream) 168 { 169 struct bcm2835_alsa_stream *alsa_stream; 170 struct snd_pcm_runtime *runtime; 171 struct bcm2835_chip *chip; 172 173 chip = snd_pcm_substream_chip(substream); 174 mutex_lock(&chip->audio_mutex); 175 runtime = substream->runtime; 176 alsa_stream = runtime->private_data; 177 178 alsa_stream->period_size = 0; 179 alsa_stream->buffer_size = 0; 180 181 bcm2835_audio_close(alsa_stream); 182 alsa_stream->chip->alsa_stream[alsa_stream->idx] = NULL; 183 /* 184 * Do not free up alsa_stream here, it will be freed up by 185 * runtime->private_free callback we registered in *_open above 186 */ 187 188 chip->opened &= ~(1 << substream->number); 189 190 mutex_unlock(&chip->audio_mutex); 191 192 return 0; 193 } 194 195 static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream) 196 { 197 struct bcm2835_chip *chip = snd_pcm_substream_chip(substream); 198 struct snd_pcm_runtime *runtime = substream->runtime; 199 struct bcm2835_alsa_stream *alsa_stream = runtime->private_data; 200 int channels; 201 int err; 202 203 /* notify the vchiq that it should enter spdif passthrough mode by 204 * setting channels=0 (see 205 * https://github.com/raspberrypi/linux/issues/528) 206 */ 207 if (chip->spdif_status & IEC958_AES0_NONAUDIO) 208 channels = 0; 209 else 210 channels = runtime->channels; 211 212 err = bcm2835_audio_set_params(alsa_stream, channels, 213 runtime->rate, 214 snd_pcm_format_width(runtime->format)); 215 if (err < 0) 216 return err; 217 218 memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect)); 219 220 alsa_stream->pcm_indirect.hw_buffer_size = 221 alsa_stream->pcm_indirect.sw_buffer_size = 222 snd_pcm_lib_buffer_bytes(substream); 223 224 alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream); 225 alsa_stream->period_size = snd_pcm_lib_period_bytes(substream); 226 atomic_set(&alsa_stream->pos, 0); 227 alsa_stream->period_offset = 0; 228 alsa_stream->draining = false; 229 alsa_stream->interpolate_start = ktime_get(); 230 231 return 0; 232 } 233 234 static void snd_bcm2835_pcm_transfer(struct snd_pcm_substream *substream, 235 struct snd_pcm_indirect *rec, size_t bytes) 236 { 237 struct snd_pcm_runtime *runtime = substream->runtime; 238 struct bcm2835_alsa_stream *alsa_stream = runtime->private_data; 239 void *src = (void *)(substream->runtime->dma_area + rec->sw_data); 240 241 bcm2835_audio_write(alsa_stream, bytes, src); 242 } 243 244 static int snd_bcm2835_pcm_ack(struct snd_pcm_substream *substream) 245 { 246 struct snd_pcm_runtime *runtime = substream->runtime; 247 struct bcm2835_alsa_stream *alsa_stream = runtime->private_data; 248 struct snd_pcm_indirect *pcm_indirect = &alsa_stream->pcm_indirect; 249 250 return snd_pcm_indirect_playback_transfer(substream, pcm_indirect, 251 snd_bcm2835_pcm_transfer); 252 } 253 254 /* trigger callback */ 255 static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd) 256 { 257 struct snd_pcm_runtime *runtime = substream->runtime; 258 struct bcm2835_alsa_stream *alsa_stream = runtime->private_data; 259 260 switch (cmd) { 261 case SNDRV_PCM_TRIGGER_START: 262 return bcm2835_audio_start(alsa_stream); 263 case SNDRV_PCM_TRIGGER_DRAIN: 264 alsa_stream->draining = true; 265 return bcm2835_audio_drain(alsa_stream); 266 case SNDRV_PCM_TRIGGER_STOP: 267 return bcm2835_audio_stop(alsa_stream); 268 default: 269 return -EINVAL; 270 } 271 } 272 273 /* pointer callback */ 274 static snd_pcm_uframes_t 275 snd_bcm2835_pcm_pointer(struct snd_pcm_substream *substream) 276 { 277 struct snd_pcm_runtime *runtime = substream->runtime; 278 struct bcm2835_alsa_stream *alsa_stream = runtime->private_data; 279 ktime_t now = ktime_get(); 280 281 /* Give userspace better delay reporting by interpolating between GPU 282 * notifications, assuming audio speed is close enough to the clock 283 * used for ktime 284 */ 285 286 if ((ktime_to_ns(alsa_stream->interpolate_start)) && 287 (ktime_compare(alsa_stream->interpolate_start, now) < 0)) { 288 u64 interval = 289 (ktime_to_ns(ktime_sub(now, 290 alsa_stream->interpolate_start))); 291 u64 frames_output_in_interval = 292 div_u64((interval * runtime->rate), 1000000000); 293 snd_pcm_sframes_t frames_output_in_interval_sized = 294 -frames_output_in_interval; 295 runtime->delay = frames_output_in_interval_sized; 296 } 297 298 return snd_pcm_indirect_playback_pointer(substream, 299 &alsa_stream->pcm_indirect, 300 atomic_read(&alsa_stream->pos)); 301 } 302 303 /* operators */ 304 static const struct snd_pcm_ops snd_bcm2835_playback_ops = { 305 .open = snd_bcm2835_playback_open, 306 .close = snd_bcm2835_playback_close, 307 .prepare = snd_bcm2835_pcm_prepare, 308 .trigger = snd_bcm2835_pcm_trigger, 309 .pointer = snd_bcm2835_pcm_pointer, 310 .ack = snd_bcm2835_pcm_ack, 311 }; 312 313 static const struct snd_pcm_ops snd_bcm2835_playback_spdif_ops = { 314 .open = snd_bcm2835_playback_spdif_open, 315 .close = snd_bcm2835_playback_close, 316 .prepare = snd_bcm2835_pcm_prepare, 317 .trigger = snd_bcm2835_pcm_trigger, 318 .pointer = snd_bcm2835_pcm_pointer, 319 .ack = snd_bcm2835_pcm_ack, 320 }; 321 322 /* create a pcm device */ 323 int snd_bcm2835_new_pcm(struct bcm2835_chip *chip, const char *name, 324 int idx, enum snd_bcm2835_route route, 325 u32 numchannels, bool spdif) 326 { 327 struct snd_pcm *pcm; 328 int err; 329 330 err = snd_pcm_new(chip->card, name, idx, numchannels, 0, &pcm); 331 if (err) 332 return err; 333 334 pcm->private_data = chip; 335 pcm->nonatomic = true; 336 strscpy(pcm->name, name, sizeof(pcm->name)); 337 if (!spdif) { 338 chip->dest = route; 339 chip->volume = 0; 340 chip->mute = CTRL_VOL_UNMUTE; 341 } 342 343 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, 344 spdif ? &snd_bcm2835_playback_spdif_ops : 345 &snd_bcm2835_playback_ops); 346 347 snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, 348 chip->card->dev, 128 * 1024, 128 * 1024); 349 350 if (spdif) 351 chip->pcm_spdif = pcm; 352 else 353 chip->pcm = pcm; 354 return 0; 355 } 356