diff options
Diffstat (limited to 'target/linux/brcm2708/patches-3.14/0032-snd-bcm2835-Add-support-for-spdif-hdmi-passthrough.patch')
-rw-r--r-- | target/linux/brcm2708/patches-3.14/0032-snd-bcm2835-Add-support-for-spdif-hdmi-passthrough.patch | 462 |
1 files changed, 0 insertions, 462 deletions
diff --git a/target/linux/brcm2708/patches-3.14/0032-snd-bcm2835-Add-support-for-spdif-hdmi-passthrough.patch b/target/linux/brcm2708/patches-3.14/0032-snd-bcm2835-Add-support-for-spdif-hdmi-passthrough.patch deleted file mode 100644 index e5420d3..0000000 --- a/target/linux/brcm2708/patches-3.14/0032-snd-bcm2835-Add-support-for-spdif-hdmi-passthrough.patch +++ /dev/null @@ -1,462 +0,0 @@ -From 2172c6578ef13acb8fcf5cac643cb1ee8e824117 Mon Sep 17 00:00:00 2001 -From: Julian Scheel <julian@jusst.de> -Date: Wed, 19 Feb 2014 16:06:59 +0100 -Subject: [PATCH 32/54] snd-bcm2835: Add support for spdif/hdmi passthrough - -This adds a dedicated subdevice which can be used for passthrough of non-audio -formats (ie encoded a52) through the hdmi audio link. In addition to this -driver extension an appropriate card config is required to make alsa-lib -support the AES parameters for this device. ---- - sound/arm/bcm2835-ctl.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++ - sound/arm/bcm2835-pcm.c | 128 +++++++++++++++++++++++++++++++++++++++++------- - sound/arm/bcm2835.c | 9 +++- - sound/arm/bcm2835.h | 9 ++++ - 4 files changed, 250 insertions(+), 19 deletions(-) - ---- a/sound/arm/bcm2835-ctl.c -+++ b/sound/arm/bcm2835-ctl.c -@@ -30,6 +30,7 @@ - #include <sound/rawmidi.h> - #include <sound/initval.h> - #include <sound/tlv.h> -+#include <sound/asoundef.h> - - #include "bcm2835.h" - -@@ -183,6 +184,122 @@ static struct snd_kcontrol_new snd_bcm28 - }, - }; - -+static int snd_bcm2835_spdif_default_info(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_info *uinfo) -+{ -+ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; -+ uinfo->count = 1; -+ return 0; -+} -+ -+static int snd_bcm2835_spdif_default_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol); -+ int i; -+ -+ for (i = 0; i < 4; i++) -+ ucontrol->value.iec958.status[i] = -+ (chip->spdif_status >> (i * 8)) && 0xff; -+ -+ return 0; -+} -+ -+static int snd_bcm2835_spdif_default_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol); -+ unsigned int val = 0; -+ int i, change; -+ -+ for (i = 0; i < 4; i++) -+ val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8); -+ -+ change = val != chip->spdif_status; -+ chip->spdif_status = val; -+ -+ return change; -+} -+ -+static int snd_bcm2835_spdif_mask_info(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_info *uinfo) -+{ -+ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; -+ uinfo->count = 1; -+ return 0; -+} -+ -+static int snd_bcm2835_spdif_mask_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ /* bcm2835 supports only consumer mode and sets all other format flags -+ * automatically. So the only thing left is signalling non-audio -+ * content */ -+ ucontrol->value.iec958.status[0] = IEC958_AES0_NONAUDIO; -+ return 0; -+} -+ -+static int snd_bcm2835_spdif_stream_info(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_info *uinfo) -+{ -+ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; -+ uinfo->count = 1; -+ return 0; -+} -+ -+static int snd_bcm2835_spdif_stream_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol); -+ int i; -+ -+ for (i = 0; i < 4; i++) -+ ucontrol->value.iec958.status[i] = -+ (chip->spdif_status >> (i * 8)) & 0xff; -+ return 0; -+} -+ -+static int snd_bcm2835_spdif_stream_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol); -+ unsigned int val = 0; -+ int i, change; -+ -+ for (i = 0; i < 4; i++) -+ val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8); -+ change = val != chip->spdif_status; -+ chip->spdif_status = val; -+ -+ return change; -+} -+ -+static struct snd_kcontrol_new snd_bcm2835_spdif[] = { -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_PCM, -+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), -+ .info = snd_bcm2835_spdif_default_info, -+ .get = snd_bcm2835_spdif_default_get, -+ .put = snd_bcm2835_spdif_default_put -+ }, -+ { -+ .access = SNDRV_CTL_ELEM_ACCESS_READ, -+ .iface = SNDRV_CTL_ELEM_IFACE_PCM, -+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK), -+ .info = snd_bcm2835_spdif_mask_info, -+ .get = snd_bcm2835_spdif_mask_get, -+ }, -+ { -+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | -+ SNDRV_CTL_ELEM_ACCESS_INACTIVE, -+ .iface = SNDRV_CTL_ELEM_IFACE_PCM, -+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM), -+ .info = snd_bcm2835_spdif_stream_info, -+ .get = snd_bcm2835_spdif_stream_get, -+ .put = snd_bcm2835_spdif_stream_put, -+ }, -+}; -+ - int snd_bcm2835_new_ctl(bcm2835_chip_t * chip) - { - int err; -@@ -196,5 +313,11 @@ int snd_bcm2835_new_ctl(bcm2835_chip_t * - if (err < 0) - return err; - } -+ for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_spdif); idx++) { -+ err = snd_ctl_add(chip->card, -+ snd_ctl_new1(&snd_bcm2835_spdif[idx], chip)); -+ if (err < 0) -+ return err; -+ } - return 0; - } ---- a/sound/arm/bcm2835-pcm.c -+++ b/sound/arm/bcm2835-pcm.c -@@ -15,6 +15,8 @@ - #include <linux/interrupt.h> - #include <linux/slab.h> - -+#include <sound/asoundef.h> -+ - #include "bcm2835.h" - - /* hardware definition */ -@@ -34,6 +36,23 @@ static struct snd_pcm_hardware snd_bcm28 - .periods_max = 128, - }; - -+static struct snd_pcm_hardware snd_bcm2835_playback_spdif_hw = { -+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | -+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID), -+ .formats = SNDRV_PCM_FMTBIT_S16_LE, -+ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_44100 | -+ SNDRV_PCM_RATE_48000, -+ .rate_min = 44100, -+ .rate_max = 48000, -+ .channels_min = 2, -+ .channels_max = 2, -+ .buffer_bytes_max = 128 * 1024, -+ .period_bytes_min = 1 * 1024, -+ .period_bytes_max = 128 * 1024, -+ .periods_min = 1, -+ .periods_max = 128, -+}; -+ - static void snd_bcm2835_playback_free(struct snd_pcm_runtime *runtime) - { - audio_info("Freeing up alsa stream here ..\n"); -@@ -89,7 +108,8 @@ static irqreturn_t bcm2835_playback_fifo - } - - /* open callback */ --static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream) -+static int snd_bcm2835_playback_open_generic( -+ struct snd_pcm_substream *substream, int spdif) - { - bcm2835_chip_t *chip = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; -@@ -102,6 +122,11 @@ static int snd_bcm2835_playback_open(str - audio_info("Alsa open (%d)\n", substream->number); - idx = substream->number; - -+ if (spdif && chip->opened != 0) -+ return -EBUSY; -+ else if (!spdif && (chip->opened & (1 << idx))) -+ return -EBUSY; -+ - if (idx > MAX_SUBSTREAMS) { - audio_error - ("substream(%d) device doesn't exist max(%d) substreams allowed\n", -@@ -143,13 +168,20 @@ static int snd_bcm2835_playback_open(str - } - runtime->private_data = alsa_stream; - runtime->private_free = snd_bcm2835_playback_free; -- runtime->hw = snd_bcm2835_playback_hw; -+ if (spdif) { -+ runtime->hw = snd_bcm2835_playback_spdif_hw; -+ } else { -+ /* clear spdif status, as we are not in spdif mode */ -+ chip->spdif_status = 0; -+ runtime->hw = snd_bcm2835_playback_hw; -+ } - /* minimum 16 bytes alignment (for vchiq bulk transfers) */ - snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, - 16); - - chip->alsa_stream[idx] = alsa_stream; - -+ chip->opened |= (1 << idx); - alsa_stream->open = 1; - alsa_stream->draining = 1; - -@@ -159,6 +191,16 @@ out: - return err; - } - -+static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream) -+{ -+ return snd_bcm2835_playback_open_generic(substream, 0); -+} -+ -+static int snd_bcm2835_playback_spdif_open(struct snd_pcm_substream *substream) -+{ -+ return snd_bcm2835_playback_open_generic(substream, 1); -+} -+ - /* close callback */ - static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream) - { -@@ -166,6 +208,7 @@ static int snd_bcm2835_playback_close(st - - struct snd_pcm_runtime *runtime = substream->runtime; - bcm2835_alsa_stream_t *alsa_stream = runtime->private_data; -+ bcm2835_chip_t *chip = snd_pcm_substream_chip(substream); - - audio_info(" .. IN\n"); - audio_info("Alsa close\n"); -@@ -196,6 +239,8 @@ static int snd_bcm2835_playback_close(st - * runtime->private_free callback we registered in *_open above - */ - -+ chip->opened &= ~(1 << substream->number); -+ - audio_info(" .. OUT\n"); - - return 0; -@@ -205,10 +250,9 @@ static int snd_bcm2835_playback_close(st - static int snd_bcm2835_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) - { -- int err; - struct snd_pcm_runtime *runtime = substream->runtime; -- bcm2835_alsa_stream_t *alsa_stream = -- (bcm2835_alsa_stream_t *) runtime->private_data; -+ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data; -+ int err; - - audio_info(" .. IN\n"); - -@@ -219,19 +263,9 @@ static int snd_bcm2835_pcm_hw_params(str - return err; - } - -- err = bcm2835_audio_set_params(alsa_stream, params_channels(params), -- params_rate(params), -- snd_pcm_format_width(params_format -- (params))); -- if (err < 0) { -- audio_error(" error setting hw params\n"); -- } -- -- bcm2835_audio_setup(alsa_stream); -- -- /* in preparation of the stream, set the controls (volume level) of the stream */ -- bcm2835_audio_set_ctls(alsa_stream->chip); -- -+ alsa_stream->channels = params_channels(params); -+ alsa_stream->params_rate = params_rate(params); -+ alsa_stream->pcm_format_width = snd_pcm_format_width(params_format (params)); - audio_info(" .. OUT\n"); - - return err; -@@ -247,11 +281,35 @@ static int snd_bcm2835_pcm_hw_free(struc - /* prepare callback */ - static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream) - { -+ bcm2835_chip_t *chip = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - bcm2835_alsa_stream_t *alsa_stream = runtime->private_data; -+ int channels; -+ int err; - - audio_info(" .. IN\n"); - -+ /* notify the vchiq that it should enter spdif passthrough mode by -+ * setting channels=0 (see -+ * https://github.com/raspberrypi/linux/issues/528) */ -+ if (chip->spdif_status & IEC958_AES0_NONAUDIO) -+ channels = 0; -+ else -+ channels = alsa_stream->channels; -+ -+ err = bcm2835_audio_set_params(alsa_stream, channels, -+ alsa_stream->params_rate, -+ alsa_stream->pcm_format_width); -+ if (err < 0) { -+ audio_error(" error setting hw params\n"); -+ } -+ -+ bcm2835_audio_setup(alsa_stream); -+ -+ /* in preparation of the stream, set the controls (volume level) of the stream */ -+ bcm2835_audio_set_ctls(alsa_stream->chip); -+ -+ - memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect)); - - alsa_stream->pcm_indirect.hw_buffer_size = -@@ -392,6 +450,18 @@ static struct snd_pcm_ops snd_bcm2835_pl - .ack = snd_bcm2835_pcm_ack, - }; - -+static struct snd_pcm_ops snd_bcm2835_playback_spdif_ops = { -+ .open = snd_bcm2835_playback_spdif_open, -+ .close = snd_bcm2835_playback_close, -+ .ioctl = snd_bcm2835_pcm_lib_ioctl, -+ .hw_params = snd_bcm2835_pcm_hw_params, -+ .hw_free = snd_bcm2835_pcm_hw_free, -+ .prepare = snd_bcm2835_pcm_prepare, -+ .trigger = snd_bcm2835_pcm_trigger, -+ .pointer = snd_bcm2835_pcm_pointer, -+ .ack = snd_bcm2835_pcm_ack, -+}; -+ - /* create a pcm device */ - int snd_bcm2835_new_pcm(bcm2835_chip_t * chip) - { -@@ -424,3 +494,25 @@ int snd_bcm2835_new_pcm(bcm2835_chip_t * - - return 0; - } -+ -+int snd_bcm2835_new_spdif_pcm(bcm2835_chip_t * chip) -+{ -+ struct snd_pcm *pcm; -+ int err; -+ -+ err = snd_pcm_new(chip->card, "bcm2835 ALSA", 1, 1, 0, &pcm); -+ if (err < 0) -+ return err; -+ -+ pcm->private_data = chip; -+ strcpy(pcm->name, "bcm2835 IEC958/HDMI"); -+ chip->pcm_spdif = pcm; -+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, -+ &snd_bcm2835_playback_spdif_ops); -+ -+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, -+ snd_dma_continuous_data (GFP_KERNEL), -+ 64 * 1024, 64 * 1024); -+ -+ return 0; -+} ---- a/sound/arm/bcm2835.c -+++ b/sound/arm/bcm2835.c -@@ -104,7 +104,7 @@ static int snd_bcm2835_alsa_probe(struct - goto out; - - snd_card_set_dev(g_card, &pdev->dev); -- strcpy(g_card->driver, "BRCM bcm2835 ALSA Driver"); -+ strcpy(g_card->driver, "bcm2835"); - strcpy(g_card->shortname, "bcm2835 ALSA"); - sprintf(g_card->longname, "%s", g_card->shortname); - -@@ -121,6 +121,12 @@ static int snd_bcm2835_alsa_probe(struct - goto out_bcm2835_new_pcm; - } - -+ err = snd_bcm2835_new_spdif_pcm(chip); -+ if (err < 0) { -+ dev_err(&pdev->dev, "Failed to create new BCM2835 spdif pcm device\n"); -+ goto out_bcm2835_new_spdif; -+ } -+ - err = snd_bcm2835_new_ctl(chip); - if (err < 0) { - dev_err(&pdev->dev, "Failed to create new BCM2835 ctl\n"); -@@ -156,6 +162,7 @@ add_register_map: - - out_card_register: - out_bcm2835_new_ctl: -+out_bcm2835_new_spdif: - out_bcm2835_new_pcm: - out_bcm2835_create: - BUG_ON(!g_card); ---- a/sound/arm/bcm2835.h -+++ b/sound/arm/bcm2835.h -@@ -97,6 +97,7 @@ typedef enum { - typedef struct bcm2835_chip { - struct snd_card *card; - struct snd_pcm *pcm; -+ struct snd_pcm *pcm_spdif; - /* Bitmat for valid reg_base and irq numbers */ - uint32_t avail_substreams; - struct platform_device *pdev[MAX_SUBSTREAMS]; -@@ -106,6 +107,9 @@ typedef struct bcm2835_chip { - int old_volume; /* stores the volume value whist muted */ - int dest; - int mute; -+ -+ unsigned int opened; -+ unsigned int spdif_status; - } bcm2835_chip_t; - - typedef struct bcm2835_alsa_stream { -@@ -123,6 +127,10 @@ typedef struct bcm2835_alsa_stream { - int running; - int draining; - -+ int channels; -+ int params_rate; -+ int pcm_format_width; -+ - unsigned int pos; - unsigned int buffer_size; - unsigned int period_size; -@@ -138,6 +146,7 @@ typedef struct bcm2835_alsa_stream { - - int snd_bcm2835_new_ctl(bcm2835_chip_t * chip); - int snd_bcm2835_new_pcm(bcm2835_chip_t * chip); -+int snd_bcm2835_new_spdif_pcm(bcm2835_chip_t * chip); - - int bcm2835_audio_open(bcm2835_alsa_stream_t * alsa_stream); - int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream); |