Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1203293 > unrolled thread
| Started by | Russell King - ARM Linux <linux@arm.linux.org.uk> |
|---|---|
| First post | 2015-08-08 18:10 +0200 |
| Last post | 2015-08-18 12:40 +0200 |
| Articles | 14 on this page of 34 — 6 participants |
Back to article view | Back to linux.kernel
[PATCH 00/12] dw-hdmi development Russell King - ARM Linux <linux@arm.linux.org.uk> - 2015-08-08 18:10 +0200
[PATCH 05/12] drm: bridge/dw_hdmi: add support for interlaced video modes Russell King <rmk+kernel@arm.linux.org.uk> - 2015-08-08 18:10 +0200
[PATCH 12/12] drm: bridge/dw_hdmi: improve HDMI enable/disable handling Russell King <rmk+kernel@arm.linux.org.uk> - 2015-08-08 18:10 +0200
Re: [PATCH 0/9] dw-hdmi audio support Russell King - ARM Linux <linux@arm.linux.org.uk> - 2015-08-08 18:10 +0200
[PATCH 2/9] drm: bridge/dw_hdmi-ahb-audio: parse ELD from HDMI driver Russell King <rmk+kernel@arm.linux.org.uk> - 2015-08-08 18:20 +0200
[PATCH 6/9] drm: bridge/dw_hdmi: adjust pixel clock values in N calculation Russell King <rmk+kernel@arm.linux.org.uk> - 2015-08-08 18:20 +0200
[PATCH 5/9] drm: bridge/dw_hdmi: avoid being recursive in N calculation Russell King <rmk+kernel@arm.linux.org.uk> - 2015-08-08 18:20 +0200
[PATCH 4/9] drm: bridge/dw_hdmi-ahb-audio: allow larger buffer sizes Russell King <rmk+kernel@arm.linux.org.uk> - 2015-08-08 18:20 +0200
[PATCH 8/9] drm: bridge/dw_hdmi: replace CTS calculation for the ACR Russell King <rmk+kernel@arm.linux.org.uk> - 2015-08-08 18:20 +0200
[PATCH 7/9] drm: bridge/dw_hdmi: remove ratio support from ACR code Russell King <rmk+kernel@arm.linux.org.uk> - 2015-08-08 18:20 +0200
[PATCH 9/9] drm: bridge/dw_hdmi-i2s-audio: add audio driver Russell King <rmk+kernel@arm.linux.org.uk> - 2015-08-08 18:20 +0200
Re: [PATCH 9/9] drm: bridge/dw_hdmi-i2s-audio: add audio driver Russell King - ARM Linux <linux@arm.linux.org.uk> - 2015-08-10 17:50 +0200
Re: [PATCH 9/9] drm: bridge/dw_hdmi-i2s-audio: add audio driver Yakir Yang <ykk@rock-chips.com> - 2015-08-10 18:30 +0200
[PATCH 1/9] drm: bridge/dw_hdmi-ahb-audio: add audio driver Russell King <rmk+kernel@arm.linux.org.uk> - 2015-08-08 18:20 +0200
Re: [PATCH 1/9] drm: bridge/dw_hdmi-ahb-audio: add audio driver Takashi Iwai <tiwai@suse.de> - 2015-08-10 12:10 +0200
Re: [PATCH 1/9] drm: bridge/dw_hdmi-ahb-audio: add audio driver Russell King - ARM Linux <linux@arm.linux.org.uk> - 2015-08-10 12:40 +0200
Re: [PATCH 1/9] drm: bridge/dw_hdmi-ahb-audio: add audio driver Takashi Iwai <tiwai@suse.de> - 2015-08-10 14:30 +0200
Re: [PATCH 1/9] drm: bridge/dw_hdmi-ahb-audio: add audio driver Russell King - ARM Linux <linux@arm.linux.org.uk> - 2015-08-10 19:00 +0200
Re: [PATCH 1/9] drm: bridge/dw_hdmi-ahb-audio: add audio driver Mark Brown <broonie@kernel.org> - 2015-08-10 20:20 +0200
Re: [PATCH v2 1/9] drm: bridge/dw_hdmi-ahb-audio: add audio driver David Airlie <airlied@linux.ie>, Sascha Hauer <s.hauer@pengutronix.de>, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, Jaroslav Kysela <perex@perex.cz>, linux-rockchip@lists.infradead.org, Mark Brown <broonie@kernel.org>, Philipp Zabel <p.zabel@pengutronix.de>, Yakir Yang <ykk@rock-chips.com>, Andy Yan <andy.yan@rock-chips.com>, Jon Nettleton <jon.nettleton@gmail.com>, linux-arm-kernel@lists.infradead.org Russell King <rmk+kernel@arm.linux.org.uk> - 2015-08-14 16:00 +0200
Re: [PATCH v2 1/9] drm: bridge/dw_hdmi-ahb-audio: add audio driver Russell King <rmk+kernel@arm.linux.org.uk> - 2015-08-14 16:10 +0200
Re: [alsa-devel] [PATCH v2 1/9] drm: bridge/dw_hdmi-ahb-audio: add audio driver Takashi Iwai <tiwai@suse.de> - 2015-08-14 16:40 +0200
[PATCH 3/9] drm: bridge/dw_hdmi-ahb-audio: basic support for multi-channel PCM audio Russell King <rmk+kernel@arm.linux.org.uk> - 2015-08-08 18:20 +0200
[PATCH 08/12] drm: bridge/dw_hdmi: avoid enabling interface in mode_set Russell King <rmk+kernel@arm.linux.org.uk> - 2015-08-08 18:10 +0200
[PATCH 04/12] gpu: imx: fix support for interlaced modes Russell King <rmk+kernel@arm.linux.org.uk> - 2015-08-08 18:10 +0200
[PATCH 09/12] drm: bridge/dw_hdmi: rename dw_hdmi_phy_enable_power() Russell King <rmk+kernel@arm.linux.org.uk> - 2015-08-08 18:10 +0200
[PATCH 03/12] gpu: imx: simplify sync polarity setting Russell King <rmk+kernel@arm.linux.org.uk> - 2015-08-08 18:10 +0200
[PATCH 01/12] drm: bridge/dw_hdmi: remove pixel repetition setting for all VICs Russell King <rmk+kernel@arm.linux.org.uk> - 2015-08-08 18:10 +0200
[PATCH 02/12] drm: bridge/dw_hdmi: don't support any pixel doubled modes Russell King <rmk+kernel@arm.linux.org.uk> - 2015-08-08 18:10 +0200
[PATCH 06/12] drm: bridge/dw_hdmi: clean up HDMI vs DVI mode handling Russell King <rmk+kernel@arm.linux.org.uk> - 2015-08-08 18:10 +0200
[PATCH 11/12] drm: bridge/dw_hdmi: add connector mode forcing Russell King <rmk+kernel@arm.linux.org.uk> - 2015-08-08 18:10 +0200
[PATCH 10/12] drm: bridge/dw_hdmi: fix phy enable/disable handling Russell King <rmk+kernel@arm.linux.org.uk> - 2015-08-08 18:20 +0200
Re: [PATCH 00/12] dw-hdmi development Thierry Reding <thierry.reding@gmail.com> - 2015-08-10 14:30 +0200
Re: [PATCH 00/12] dw-hdmi development Russell King - ARM Linux <linux@arm.linux.org.uk> - 2015-08-18 12:40 +0200
Page 2 of 2 — ← Prev page 1 [2]
| From | Russell King <rmk+kernel@arm.linux.org.uk> |
|---|---|
| Date | 2015-08-14 16:10 +0200 |
| Subject | Re: [PATCH v2 1/9] drm: bridge/dw_hdmi-ahb-audio: add audio driver |
| Message-ID | <pXnQd-4h6-3@gated-at.bofh.it> |
| In reply to | #1203991 |
Add ALSA based HDMI AHB audio driver for dw_hdmi. The only buffer
format supported by the hardware is its own special IEC958 based format,
which is not compatible with any ALSA format. To avoid doing too much
data manipulation within the driver, we support only ALSAs IEC958 LE and
24-bit PCM formats for 2 to 6 channels, which we convert to its hardware
format.
A more desirable solution would be to have this conversion in userspace,
but ALSA does not appear to allow such transformations outside of
libasound itself.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
v2: updated with Takashi Iwai's comments... and with a fixed Cc: line.
drivers/gpu/drm/bridge/Kconfig | 10 +
drivers/gpu/drm/bridge/Makefile | 1 +
drivers/gpu/drm/bridge/dw_hdmi-ahb-audio.c | 579 +++++++++++++++++++++++++++++
drivers/gpu/drm/bridge/dw_hdmi-audio.h | 13 +
drivers/gpu/drm/bridge/dw_hdmi.c | 24 ++
drivers/gpu/drm/bridge/dw_hdmi.h | 3 +
6 files changed, 630 insertions(+)
create mode 100644 drivers/gpu/drm/bridge/dw_hdmi-ahb-audio.c
create mode 100644 drivers/gpu/drm/bridge/dw_hdmi-audio.h
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index acef3223772c..56ed35fe0734 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -3,6 +3,16 @@ config DRM_DW_HDMI
depends on DRM
select DRM_KMS_HELPER
+config DRM_DW_HDMI_AHB_AUDIO
+ tristate "Synopsis Designware AHB Audio interface"
+ depends on DRM_DW_HDMI && SND
+ select SND_PCM
+ select SND_PCM_IEC958
+ help
+ Support the AHB Audio interface which is part of the Synopsis
+ Designware HDMI block. This is used in conjunction with
+ the i.MX6 HDMI driver.
+
config DRM_PTN3460
tristate "PTN3460 DP/LVDS bridge"
depends on DRM
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index 8dfebd984370..eb80dbbb8365 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -3,3 +3,4 @@ ccflags-y := -Iinclude/drm
obj-$(CONFIG_DRM_PS8622) += ps8622.o
obj-$(CONFIG_DRM_PTN3460) += ptn3460.o
obj-$(CONFIG_DRM_DW_HDMI) += dw_hdmi.o
+obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw_hdmi-ahb-audio.o
diff --git a/drivers/gpu/drm/bridge/dw_hdmi-ahb-audio.c b/drivers/gpu/drm/bridge/dw_hdmi-ahb-audio.c
new file mode 100644
index 000000000000..bf379310008a
--- /dev/null
+++ b/drivers/gpu/drm/bridge/dw_hdmi-ahb-audio.c
@@ -0,0 +1,579 @@
+/*
+ * DesignWare HDMI audio driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Written and tested against the Designware HDMI Tx found in iMX6.
+ */
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <drm/bridge/dw_hdmi.h>
+
+#include <sound/asoundef.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_iec958.h>
+
+#include "dw_hdmi-audio.h"
+
+#define DRIVER_NAME "dw-hdmi-ahb-audio"
+
+/* Provide some bits rather than bit offsets */
+enum {
+ HDMI_AHB_DMA_CONF0_SW_FIFO_RST = BIT(7),
+ HDMI_AHB_DMA_CONF0_EN_HLOCK = BIT(3),
+ HDMI_AHB_DMA_START_START = BIT(0),
+ HDMI_AHB_DMA_STOP_STOP = BIT(0),
+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_ERROR = BIT(5),
+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_LOST = BIT(4),
+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_RETRY = BIT(3),
+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE = BIT(2),
+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFFULL = BIT(1),
+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFEMPTY = BIT(0),
+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL =
+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_ERROR |
+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_LOST |
+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_RETRY |
+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE |
+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFFULL |
+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFEMPTY,
+ HDMI_IH_AHBDMAAUD_STAT0_ERROR = BIT(5),
+ HDMI_IH_AHBDMAAUD_STAT0_LOST = BIT(4),
+ HDMI_IH_AHBDMAAUD_STAT0_RETRY = BIT(3),
+ HDMI_IH_AHBDMAAUD_STAT0_DONE = BIT(2),
+ HDMI_IH_AHBDMAAUD_STAT0_BUFFFULL = BIT(1),
+ HDMI_IH_AHBDMAAUD_STAT0_BUFFEMPTY = BIT(0),
+ HDMI_IH_AHBDMAAUD_STAT0_ALL =
+ HDMI_IH_AHBDMAAUD_STAT0_ERROR |
+ HDMI_IH_AHBDMAAUD_STAT0_LOST |
+ HDMI_IH_AHBDMAAUD_STAT0_RETRY |
+ HDMI_IH_AHBDMAAUD_STAT0_DONE |
+ HDMI_IH_AHBDMAAUD_STAT0_BUFFFULL |
+ HDMI_IH_AHBDMAAUD_STAT0_BUFFEMPTY,
+ HDMI_AHB_DMA_CONF0_INCR16 = 2 << 1,
+ HDMI_AHB_DMA_CONF0_INCR8 = 1 << 1,
+ HDMI_AHB_DMA_CONF0_INCR4 = 0,
+ HDMI_AHB_DMA_CONF0_BURST_MODE = BIT(0),
+ HDMI_AHB_DMA_MASK_DONE = BIT(7),
+ HDMI_REVISION_ID = 0x0001,
+ HDMI_IH_AHBDMAAUD_STAT0 = 0x0109,
+ HDMI_IH_MUTE_AHBDMAAUD_STAT0 = 0x0189,
+ HDMI_AHB_DMA_CONF0 = 0x3600,
+ HDMI_AHB_DMA_START = 0x3601,
+ HDMI_AHB_DMA_STOP = 0x3602,
+ HDMI_AHB_DMA_THRSLD = 0x3603,
+ HDMI_AHB_DMA_STRADDR0 = 0x3604,
+ HDMI_AHB_DMA_STPADDR0 = 0x3608,
+ HDMI_AHB_DMA_MASK = 0x3614,
+ HDMI_AHB_DMA_POL = 0x3615,
+ HDMI_AHB_DMA_CONF1 = 0x3616,
+ HDMI_AHB_DMA_BUFFPOL = 0x361a,
+};
+
+struct snd_dw_hdmi {
+ struct snd_card *card;
+ struct snd_pcm *pcm;
+ spinlock_t lock;
+ struct dw_hdmi_audio_data data;
+ struct snd_pcm_substream *substream;
+ void (*reformat)(struct snd_dw_hdmi *, size_t, size_t);
+ void *buf_src;
+ void *buf_dst;
+ dma_addr_t buf_addr;
+ unsigned buf_offset;
+ unsigned buf_period;
+ unsigned buf_size;
+ unsigned channels;
+ u8 revision;
+ u8 iec_offset;
+ u8 cs[192][8];
+};
+
+static void dw_hdmi_writel(u32 val, void __iomem *ptr)
+{
+ writeb_relaxed(val, ptr);
+ writeb_relaxed(val >> 8, ptr + 1);
+ writeb_relaxed(val >> 16, ptr + 2);
+ writeb_relaxed(val >> 24, ptr + 3);
+}
+
+/*
+ * Convert to hardware format: The userspace buffer contains IEC958 samples,
+ * with the PCUV bits in bits 31..28 and audio samples in bits 27..4. We
+ * need these to be in bits 27..24, with the IEC B bit in bit 28, and audio
+ * samples in 23..0.
+ *
+ * Default preamble in bits 3..0: 8 = block start, 4 = even 2 = odd
+ *
+ * Ideally, we could do with having the data properly formatted in userspace.
+ */
+static void dw_hdmi_reformat_iec958(struct snd_dw_hdmi *dw,
+ size_t offset, size_t bytes)
+{
+ u32 *src = dw->buf_src + offset;
+ u32 *dst = dw->buf_dst + offset;
+ u32 *end = dw->buf_src + offset + bytes;
+
+ do {
+ u32 b, sample = *src++;
+
+ b = (sample & 8) << (28 - 3);
+
+ sample >>= 4;
+
+ *dst++ = sample | b;
+ } while (src < end);
+}
+
+static u32 parity(u32 sample)
+{
+ sample ^= sample >> 16;
+ sample ^= sample >> 8;
+ sample ^= sample >> 4;
+ sample ^= sample >> 2;
+ sample ^= sample >> 1;
+ return (sample & 1) << 27;
+}
+
+static void dw_hdmi_reformat_s24(struct snd_dw_hdmi *dw,
+ size_t offset, size_t bytes)
+{
+ u32 *src = dw->buf_src + offset;
+ u32 *dst = dw->buf_dst + offset;
+ u32 *end = dw->buf_src + offset + bytes;
+
+ do {
+ unsigned i;
+ u8 *cs;
+
+ cs = dw->cs[dw->iec_offset++];
+ if (dw->iec_offset >= 192)
+ dw->iec_offset = 0;
+
+ i = dw->channels;
+ do {
+ u32 sample = *src++;
+
+ sample &= ~0xff000000;
+ sample |= *cs++ << 24;
+ sample |= parity(sample & ~0xf8000000);
+
+ *dst++ = sample;
+ } while (--i);
+ } while (src < end);
+}
+
+static void dw_hdmi_create_cs(struct snd_dw_hdmi *dw,
+ struct snd_pcm_runtime *runtime)
+{
+ u8 cs[4];
+ unsigned ch, i, j;
+
+ snd_pcm_create_iec958_consumer(runtime, cs, sizeof(cs));
+
+ memset(dw->cs, 0, sizeof(dw->cs));
+
+ for (ch = 0; ch < 8; ch++) {
+ cs[2] &= ~IEC958_AES2_CON_CHANNEL;
+ cs[2] |= (ch + 1) << 4;
+
+ for (i = 0; i < ARRAY_SIZE(cs); i++) {
+ unsigned c = cs[i];
+
+ for (j = 0; j < 8; j++, c >>= 1)
+ dw->cs[i * 8 + j][ch] = (c & 1) << 2;
+ }
+ }
+ dw->cs[0][0] |= BIT(4);
+}
+
+static void dw_hdmi_start_dma(struct snd_dw_hdmi *dw)
+{
+ void __iomem *base = dw->data.base;
+ unsigned offset = dw->buf_offset;
+ unsigned period = dw->buf_period;
+ u32 start, stop;
+
+ dw->reformat(dw, offset, period);
+
+ /* Clear all irqs before enabling irqs and starting DMA */
+ writeb_relaxed(HDMI_IH_AHBDMAAUD_STAT0_ALL,
+ base + HDMI_IH_AHBDMAAUD_STAT0);
+
+ start = dw->buf_addr + offset;
+ stop = start + period - 1;
+
+ /* Setup the hardware start/stop addresses */
+ dw_hdmi_writel(start, base + HDMI_AHB_DMA_STRADDR0);
+ dw_hdmi_writel(stop, base + HDMI_AHB_DMA_STPADDR0);
+
+ writeb_relaxed((u8)~HDMI_AHB_DMA_MASK_DONE, base + HDMI_AHB_DMA_MASK);
+ writeb(HDMI_AHB_DMA_START_START, base + HDMI_AHB_DMA_START);
+
+ offset += period;
+ if (offset >= dw->buf_size)
+ offset = 0;
+ dw->buf_offset = offset;
+}
+
+static void dw_hdmi_stop_dma(struct snd_dw_hdmi *dw)
+{
+ /* Disable interrupts before disabling DMA */
+ writeb_relaxed(~0, dw->data.base + HDMI_AHB_DMA_MASK);
+ writeb_relaxed(HDMI_AHB_DMA_STOP_STOP, dw->data.base + HDMI_AHB_DMA_STOP);
+}
+
+static irqreturn_t snd_dw_hdmi_irq(int irq, void *data)
+{
+ struct snd_dw_hdmi *dw = data;
+ struct snd_pcm_substream *substream;
+ unsigned stat;
+
+ stat = readb_relaxed(dw->data.base + HDMI_IH_AHBDMAAUD_STAT0);
+ if (!stat)
+ return IRQ_NONE;
+
+ writeb_relaxed(stat, dw->data.base + HDMI_IH_AHBDMAAUD_STAT0);
+
+ substream = dw->substream;
+ if (stat & HDMI_IH_AHBDMAAUD_STAT0_DONE && substream) {
+ snd_pcm_period_elapsed(substream);
+
+ spin_lock(&dw->lock);
+ if (dw->substream)
+ dw_hdmi_start_dma(dw);
+ spin_unlock(&dw->lock);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static struct snd_pcm_hardware dw_hdmi_hw = {
+ .info = SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID,
+ .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .rates = SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_176400 |
+ SNDRV_PCM_RATE_192000,
+ .channels_min = 2,
+ .channels_max = 8,
+ .buffer_bytes_max = 64 * 1024,
+ .period_bytes_min = 256,
+ .period_bytes_max = 8192, /* ERR004323: must limit to 8k */
+ .periods_min = 2,
+ .periods_max = 16,
+ .fifo_size = 0,
+};
+
+static int dw_hdmi_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_dw_hdmi *dw = substream->private_data;
+ void __iomem *base = dw->data.base;
+ int ret;
+
+ runtime->hw = dw_hdmi_hw;
+
+ ret = snd_pcm_limit_hw_rates(runtime);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+ if (ret < 0)
+ return ret;
+
+ /* Clear FIFO */
+ writeb_relaxed(HDMI_AHB_DMA_CONF0_SW_FIFO_RST,
+ base + HDMI_AHB_DMA_CONF0);
+
+ /* Configure interrupt polarities */
+ writeb_relaxed(~0, base + HDMI_AHB_DMA_POL);
+ writeb_relaxed(~0, base + HDMI_AHB_DMA_BUFFPOL);
+
+ /* Keep interrupts masked, and clear any pending */
+ writeb_relaxed(~0, base + HDMI_AHB_DMA_MASK);
+ writeb_relaxed(~0, base + HDMI_IH_AHBDMAAUD_STAT0);
+
+ ret = request_irq(dw->data.irq, snd_dw_hdmi_irq, IRQF_SHARED,
+ "dw-hdmi-audio", dw);
+ if (ret)
+ return ret;
+
+ /* Un-mute done interrupt */
+ writeb_relaxed(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL &
+ ~HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE,
+ base + HDMI_IH_MUTE_AHBDMAAUD_STAT0);
+
+ return 0;
+}
+
+static int dw_hdmi_close(struct snd_pcm_substream *substream)
+{
+ struct snd_dw_hdmi *dw = substream->private_data;
+
+ /* Mute all interrupts */
+ writeb_relaxed(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL,
+ dw->data.base + HDMI_IH_MUTE_AHBDMAAUD_STAT0);
+
+ free_irq(dw->data.irq, dw);
+
+ return 0;
+}
+
+static int dw_hdmi_hw_free(struct snd_pcm_substream *substream)
+{
+ return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+
+static int dw_hdmi_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ return snd_pcm_lib_alloc_vmalloc_buffer(substream,
+ params_buffer_bytes(params));
+}
+
+static int dw_hdmi_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_dw_hdmi *dw = substream->private_data;
+ u8 threshold, conf0, conf1;
+
+ /* Setup as per 3.0.5 FSL 4.1.0 BSP */
+ switch (dw->revision) {
+ case 0x0a:
+ conf0 = HDMI_AHB_DMA_CONF0_BURST_MODE |
+ HDMI_AHB_DMA_CONF0_INCR4;
+ if (runtime->channels == 2)
+ threshold = 126;
+ else
+ threshold = 124;
+ break;
+ case 0x1a:
+ conf0 = HDMI_AHB_DMA_CONF0_BURST_MODE |
+ HDMI_AHB_DMA_CONF0_INCR8;
+ threshold = 128;
+ break;
+ default:
+ /* NOTREACHED */
+ return -EINVAL;
+ }
+
+ dw_hdmi_set_sample_rate(dw->data.hdmi, runtime->rate);
+
+ /* Minimum number of bytes in the fifo. */
+ runtime->hw.fifo_size = threshold * 32;
+
+ conf0 |= HDMI_AHB_DMA_CONF0_EN_HLOCK;
+ conf1 = (1 << runtime->channels) - 1;
+
+ writeb_relaxed(threshold, dw->data.base + HDMI_AHB_DMA_THRSLD);
+ writeb_relaxed(conf0, dw->data.base + HDMI_AHB_DMA_CONF0);
+ writeb_relaxed(conf1, dw->data.base + HDMI_AHB_DMA_CONF1);
+
+ switch (runtime->format) {
+ case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
+ dw->reformat = dw_hdmi_reformat_iec958;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ dw_hdmi_create_cs(dw, runtime);
+ dw->reformat = dw_hdmi_reformat_s24;
+ break;
+ }
+ dw->iec_offset = 0;
+ dw->channels = runtime->channels;
+ dw->buf_src = runtime->dma_area;
+ dw->buf_dst = substream->dma_buffer.area;
+ dw->buf_addr = substream->dma_buffer.addr;
+ dw->buf_period = snd_pcm_lib_period_bytes(substream);
+ dw->buf_size = snd_pcm_lib_buffer_bytes(substream);
+
+ return 0;
+}
+
+static int dw_hdmi_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_dw_hdmi *dw = substream->private_data;
+ unsigned long flags;
+ int ret = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ spin_lock_irqsave(&dw->lock, flags);
+ dw->buf_offset = 0;
+ dw->substream = substream;
+ dw_hdmi_start_dma(dw);
+ dw_hdmi_audio_enable(dw->data.hdmi);
+ spin_unlock_irqrestore(&dw->lock, flags);
+ substream->runtime->delay = substream->runtime->period_size;
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ spin_lock_irqsave(&dw->lock, flags);
+ dw->substream = NULL;
+ dw_hdmi_stop_dma(dw);
+ dw_hdmi_audio_disable(dw->data.hdmi);
+ spin_unlock_irqrestore(&dw->lock, flags);
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static snd_pcm_uframes_t dw_hdmi_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_dw_hdmi *dw = substream->private_data;
+
+ /*
+ * We are unable to report the exact hardware position as
+ * reading the 32-bit DMA position using 8-bit reads is racy.
+ */
+ return bytes_to_frames(runtime, dw->buf_offset);
+}
+
+static struct snd_pcm_ops snd_dw_hdmi_ops = {
+ .open = dw_hdmi_open,
+ .close = dw_hdmi_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = dw_hdmi_hw_params,
+ .hw_free = dw_hdmi_hw_free,
+ .prepare = dw_hdmi_prepare,
+ .trigger = dw_hdmi_trigger,
+ .pointer = dw_hdmi_pointer,
+ .page = snd_pcm_lib_get_vmalloc_page,
+};
+
+static int snd_dw_hdmi_probe(struct platform_device *pdev)
+{
+ const struct dw_hdmi_audio_data *data = pdev->dev.platform_data;
+ struct device *dev = pdev->dev.parent;
+ struct snd_dw_hdmi *dw;
+ struct snd_card *card;
+ struct snd_pcm *pcm;
+ unsigned revision;
+ int ret;
+
+ writeb_relaxed(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL,
+ data->base + HDMI_IH_MUTE_AHBDMAAUD_STAT0);
+ revision = readb_relaxed(data->base + HDMI_REVISION_ID);
+ if (revision != 0x0a && revision != 0x1a) {
+ dev_err(dev, "dw-hdmi-audio: unknown revision 0x%02x\n",
+ revision);
+ return -ENXIO;
+ }
+
+ ret = snd_card_new(dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+ THIS_MODULE, sizeof(struct snd_dw_hdmi), &card);
+ if (ret < 0)
+ return ret;
+
+ strlcpy(card->driver, DRIVER_NAME, sizeof(card->driver));
+ strlcpy(card->shortname, "DW-HDMI", sizeof(card->shortname));
+ snprintf(card->longname, sizeof(card->longname),
+ "%s rev 0x%02x, irq %d", card->shortname, revision,
+ data->irq);
+
+ dw = card->private_data;
+ dw->card = card;
+ dw->data = *data;
+ dw->revision = revision;
+
+ spin_lock_init(&dw->lock);
+
+ ret = snd_pcm_new(card, "DW HDMI", 0, 1, 0, &pcm);
+ if (ret < 0)
+ goto err;
+
+ dw->pcm = pcm;
+ pcm->private_data = dw;
+ strlcpy(pcm->name, DRIVER_NAME, sizeof(pcm->name));
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_dw_hdmi_ops);
+
+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+ dev, 64 * 1024, 64 * 1024);
+
+ ret = snd_card_register(card);
+ if (ret < 0)
+ goto err;
+
+ platform_set_drvdata(pdev, dw);
+
+ return 0;
+
+err:
+ snd_card_free(card);
+ return ret;
+}
+
+static int snd_dw_hdmi_remove(struct platform_device *pdev)
+{
+ struct snd_dw_hdmi *dw = platform_get_drvdata(pdev);
+
+ snd_card_free(dw->card);
+
+ return 0;
+}
+
+#if defined(CONFIG_PM_SLEEP) && defined(IS_NOT_BROKEN)
+/*
+ * This code is fine, but requires implementation in the dw_hdmi_trigger()
+ * method which is currently missing as I have no way to test this.
+ */
+static int snd_dw_hdmi_suspend(struct device *dev)
+{
+ struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
+
+ snd_power_change_state(dw->card, SNDRV_CTL_POWER_D3cold);
+ snd_pcm_suspend_all(dw->pcm);
+
+ return 0;
+}
+
+static int snd_dw_hdmi_resume(struct device *dev)
+{
+ struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
+
+ snd_power_change_state(dw->card, SNDRV_CTL_POWER_D0);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(snd_dw_hdmi_pm, snd_dw_hdmi_suspend,
+ snd_dw_hdmi_resume);
+#define PM_OPS &snd_dw_hdmi_pm
+#else
+#define PM_OPS NULL
+#endif
+
+static struct platform_driver snd_dw_hdmi_driver = {
+ .probe = snd_dw_hdmi_probe,
+ .remove = snd_dw_hdmi_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .pm = PM_OPS,
+ },
+};
+
+module_platform_driver(snd_dw_hdmi_driver);
+
+MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>");
+MODULE_DESCRIPTION("Synopsis Designware HDMI AHB ALSA interface");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/gpu/drm/bridge/dw_hdmi-audio.h b/drivers/gpu/drm/bridge/dw_hdmi-audio.h
new file mode 100644
index 000000000000..1e840118d90a
--- /dev/null
+++ b/drivers/gpu/drm/bridge/dw_hdmi-audio.h
@@ -0,0 +1,13 @@
+#ifndef DW_HDMI_AUDIO_H
+#define DW_HDMI_AUDIO_H
+
+struct dw_hdmi;
+
+struct dw_hdmi_audio_data {
+ phys_addr_t phys;
+ void __iomem *base;
+ int irq;
+ struct dw_hdmi *hdmi;
+};
+
+#endif
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
index fba25607ef88..b65464789fbd 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -28,6 +28,7 @@
#include <drm/bridge/dw_hdmi.h>
#include "dw_hdmi.h"
+#include "dw_hdmi-audio.h"
#define HDMI_EDID_LEN 512
@@ -104,6 +105,7 @@ struct dw_hdmi {
struct drm_encoder *encoder;
struct drm_bridge *bridge;
+ struct platform_device *audio;
enum dw_hdmi_devtype dev_type;
struct device *dev;
struct clk *isfr_clk;
@@ -1732,7 +1734,9 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
{
struct drm_device *drm = data;
struct device_node *np = dev->of_node;
+ struct platform_device_info pdevinfo;
struct device_node *ddc_node;
+ struct dw_hdmi_audio_data audio;
struct dw_hdmi *hdmi;
int ret;
u32 val = 1;
@@ -1860,6 +1864,23 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE),
HDMI_IH_MUTE_PHY_STAT0);
+ memset(&pdevinfo, 0, sizeof(pdevinfo));
+ pdevinfo.parent = dev;
+ pdevinfo.id = PLATFORM_DEVID_AUTO;
+
+ if (hdmi_readb(hdmi, HDMI_CONFIG1_ID) & HDMI_CONFIG1_AHB) {
+ audio.phys = iores->start;
+ audio.base = hdmi->regs;
+ audio.irq = irq;
+ audio.hdmi = hdmi;
+
+ pdevinfo.name = "dw-hdmi-ahb-audio";
+ pdevinfo.data = &audio;
+ pdevinfo.size_data = sizeof(audio);
+ pdevinfo.dma_mask = DMA_BIT_MASK(32);
+ hdmi->audio = platform_device_register_full(&pdevinfo);
+ }
+
dev_set_drvdata(dev, hdmi);
return 0;
@@ -1877,6 +1898,9 @@ void dw_hdmi_unbind(struct device *dev, struct device *master, void *data)
{
struct dw_hdmi *hdmi = dev_get_drvdata(dev);
+ if (hdmi->audio && !IS_ERR(hdmi->audio))
+ platform_device_unregister(hdmi->audio);
+
/* Disable all interrupts */
hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.h b/drivers/gpu/drm/bridge/dw_hdmi.h
index 175dbc89a824..78e54e813212 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.h
+++ b/drivers/gpu/drm/bridge/dw_hdmi.h
@@ -545,6 +545,9 @@
#define HDMI_I2CM_FS_SCL_LCNT_0_ADDR 0x7E12
enum {
+/* CONFIG1_ID field values */
+ HDMI_CONFIG1_AHB = 0x01,
+
/* IH_FC_INT2 field values */
HDMI_IH_FC_INT2_OVERFLOW_MASK = 0x03,
HDMI_IH_FC_INT2_LOW_PRIORITY_OVERFLOW = 0x02,
--
2.1.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Takashi Iwai <tiwai@suse.de> |
|---|---|
| Date | 2015-08-14 16:40 +0200 |
| Subject | Re: [alsa-devel] [PATCH v2 1/9] drm: bridge/dw_hdmi-ahb-audio: add audio driver |
| Message-ID | <pXojg-4OP-7@gated-at.bofh.it> |
| In reply to | #1207552 |
On Fri, 14 Aug 2015 16:04:25 +0200,
Russell King wrote:
>
> Add ALSA based HDMI AHB audio driver for dw_hdmi. The only buffer
> format supported by the hardware is its own special IEC958 based format,
> which is not compatible with any ALSA format. To avoid doing too much
> data manipulation within the driver, we support only ALSAs IEC958 LE and
> 24-bit PCM formats for 2 to 6 channels, which we convert to its hardware
> format.
>
> A more desirable solution would be to have this conversion in userspace,
> but ALSA does not appear to allow such transformations outside of
> libasound itself.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
> ---
> v2: updated with Takashi Iwai's comments... and with a fixed Cc: line.
Reviewed-by: Takashi Iwai <tiwai@suse.de>
thanks,
Takashi
> drivers/gpu/drm/bridge/Kconfig | 10 +
> drivers/gpu/drm/bridge/Makefile | 1 +
> drivers/gpu/drm/bridge/dw_hdmi-ahb-audio.c | 579 +++++++++++++++++++++++++++++
> drivers/gpu/drm/bridge/dw_hdmi-audio.h | 13 +
> drivers/gpu/drm/bridge/dw_hdmi.c | 24 ++
> drivers/gpu/drm/bridge/dw_hdmi.h | 3 +
> 6 files changed, 630 insertions(+)
> create mode 100644 drivers/gpu/drm/bridge/dw_hdmi-ahb-audio.c
> create mode 100644 drivers/gpu/drm/bridge/dw_hdmi-audio.h
>
> diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
> index acef3223772c..56ed35fe0734 100644
> --- a/drivers/gpu/drm/bridge/Kconfig
> +++ b/drivers/gpu/drm/bridge/Kconfig
> @@ -3,6 +3,16 @@ config DRM_DW_HDMI
> depends on DRM
> select DRM_KMS_HELPER
>
> +config DRM_DW_HDMI_AHB_AUDIO
> + tristate "Synopsis Designware AHB Audio interface"
> + depends on DRM_DW_HDMI && SND
> + select SND_PCM
> + select SND_PCM_IEC958
> + help
> + Support the AHB Audio interface which is part of the Synopsis
> + Designware HDMI block. This is used in conjunction with
> + the i.MX6 HDMI driver.
> +
> config DRM_PTN3460
> tristate "PTN3460 DP/LVDS bridge"
> depends on DRM
> diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
> index 8dfebd984370..eb80dbbb8365 100644
> --- a/drivers/gpu/drm/bridge/Makefile
> +++ b/drivers/gpu/drm/bridge/Makefile
> @@ -3,3 +3,4 @@ ccflags-y := -Iinclude/drm
> obj-$(CONFIG_DRM_PS8622) += ps8622.o
> obj-$(CONFIG_DRM_PTN3460) += ptn3460.o
> obj-$(CONFIG_DRM_DW_HDMI) += dw_hdmi.o
> +obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw_hdmi-ahb-audio.o
> diff --git a/drivers/gpu/drm/bridge/dw_hdmi-ahb-audio.c b/drivers/gpu/drm/bridge/dw_hdmi-ahb-audio.c
> new file mode 100644
> index 000000000000..bf379310008a
> --- /dev/null
> +++ b/drivers/gpu/drm/bridge/dw_hdmi-ahb-audio.c
> @@ -0,0 +1,579 @@
> +/*
> + * DesignWare HDMI audio driver
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * Written and tested against the Designware HDMI Tx found in iMX6.
> + */
> +#include <linux/io.h>
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <drm/bridge/dw_hdmi.h>
> +
> +#include <sound/asoundef.h>
> +#include <sound/core.h>
> +#include <sound/initval.h>
> +#include <sound/pcm.h>
> +#include <sound/pcm_iec958.h>
> +
> +#include "dw_hdmi-audio.h"
> +
> +#define DRIVER_NAME "dw-hdmi-ahb-audio"
> +
> +/* Provide some bits rather than bit offsets */
> +enum {
> + HDMI_AHB_DMA_CONF0_SW_FIFO_RST = BIT(7),
> + HDMI_AHB_DMA_CONF0_EN_HLOCK = BIT(3),
> + HDMI_AHB_DMA_START_START = BIT(0),
> + HDMI_AHB_DMA_STOP_STOP = BIT(0),
> + HDMI_IH_MUTE_AHBDMAAUD_STAT0_ERROR = BIT(5),
> + HDMI_IH_MUTE_AHBDMAAUD_STAT0_LOST = BIT(4),
> + HDMI_IH_MUTE_AHBDMAAUD_STAT0_RETRY = BIT(3),
> + HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE = BIT(2),
> + HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFFULL = BIT(1),
> + HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFEMPTY = BIT(0),
> + HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL =
> + HDMI_IH_MUTE_AHBDMAAUD_STAT0_ERROR |
> + HDMI_IH_MUTE_AHBDMAAUD_STAT0_LOST |
> + HDMI_IH_MUTE_AHBDMAAUD_STAT0_RETRY |
> + HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE |
> + HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFFULL |
> + HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFEMPTY,
> + HDMI_IH_AHBDMAAUD_STAT0_ERROR = BIT(5),
> + HDMI_IH_AHBDMAAUD_STAT0_LOST = BIT(4),
> + HDMI_IH_AHBDMAAUD_STAT0_RETRY = BIT(3),
> + HDMI_IH_AHBDMAAUD_STAT0_DONE = BIT(2),
> + HDMI_IH_AHBDMAAUD_STAT0_BUFFFULL = BIT(1),
> + HDMI_IH_AHBDMAAUD_STAT0_BUFFEMPTY = BIT(0),
> + HDMI_IH_AHBDMAAUD_STAT0_ALL =
> + HDMI_IH_AHBDMAAUD_STAT0_ERROR |
> + HDMI_IH_AHBDMAAUD_STAT0_LOST |
> + HDMI_IH_AHBDMAAUD_STAT0_RETRY |
> + HDMI_IH_AHBDMAAUD_STAT0_DONE |
> + HDMI_IH_AHBDMAAUD_STAT0_BUFFFULL |
> + HDMI_IH_AHBDMAAUD_STAT0_BUFFEMPTY,
> + HDMI_AHB_DMA_CONF0_INCR16 = 2 << 1,
> + HDMI_AHB_DMA_CONF0_INCR8 = 1 << 1,
> + HDMI_AHB_DMA_CONF0_INCR4 = 0,
> + HDMI_AHB_DMA_CONF0_BURST_MODE = BIT(0),
> + HDMI_AHB_DMA_MASK_DONE = BIT(7),
> + HDMI_REVISION_ID = 0x0001,
> + HDMI_IH_AHBDMAAUD_STAT0 = 0x0109,
> + HDMI_IH_MUTE_AHBDMAAUD_STAT0 = 0x0189,
> + HDMI_AHB_DMA_CONF0 = 0x3600,
> + HDMI_AHB_DMA_START = 0x3601,
> + HDMI_AHB_DMA_STOP = 0x3602,
> + HDMI_AHB_DMA_THRSLD = 0x3603,
> + HDMI_AHB_DMA_STRADDR0 = 0x3604,
> + HDMI_AHB_DMA_STPADDR0 = 0x3608,
> + HDMI_AHB_DMA_MASK = 0x3614,
> + HDMI_AHB_DMA_POL = 0x3615,
> + HDMI_AHB_DMA_CONF1 = 0x3616,
> + HDMI_AHB_DMA_BUFFPOL = 0x361a,
> +};
> +
> +struct snd_dw_hdmi {
> + struct snd_card *card;
> + struct snd_pcm *pcm;
> + spinlock_t lock;
> + struct dw_hdmi_audio_data data;
> + struct snd_pcm_substream *substream;
> + void (*reformat)(struct snd_dw_hdmi *, size_t, size_t);
> + void *buf_src;
> + void *buf_dst;
> + dma_addr_t buf_addr;
> + unsigned buf_offset;
> + unsigned buf_period;
> + unsigned buf_size;
> + unsigned channels;
> + u8 revision;
> + u8 iec_offset;
> + u8 cs[192][8];
> +};
> +
> +static void dw_hdmi_writel(u32 val, void __iomem *ptr)
> +{
> + writeb_relaxed(val, ptr);
> + writeb_relaxed(val >> 8, ptr + 1);
> + writeb_relaxed(val >> 16, ptr + 2);
> + writeb_relaxed(val >> 24, ptr + 3);
> +}
> +
> +/*
> + * Convert to hardware format: The userspace buffer contains IEC958 samples,
> + * with the PCUV bits in bits 31..28 and audio samples in bits 27..4. We
> + * need these to be in bits 27..24, with the IEC B bit in bit 28, and audio
> + * samples in 23..0.
> + *
> + * Default preamble in bits 3..0: 8 = block start, 4 = even 2 = odd
> + *
> + * Ideally, we could do with having the data properly formatted in userspace.
> + */
> +static void dw_hdmi_reformat_iec958(struct snd_dw_hdmi *dw,
> + size_t offset, size_t bytes)
> +{
> + u32 *src = dw->buf_src + offset;
> + u32 *dst = dw->buf_dst + offset;
> + u32 *end = dw->buf_src + offset + bytes;
> +
> + do {
> + u32 b, sample = *src++;
> +
> + b = (sample & 8) << (28 - 3);
> +
> + sample >>= 4;
> +
> + *dst++ = sample | b;
> + } while (src < end);
> +}
> +
> +static u32 parity(u32 sample)
> +{
> + sample ^= sample >> 16;
> + sample ^= sample >> 8;
> + sample ^= sample >> 4;
> + sample ^= sample >> 2;
> + sample ^= sample >> 1;
> + return (sample & 1) << 27;
> +}
> +
> +static void dw_hdmi_reformat_s24(struct snd_dw_hdmi *dw,
> + size_t offset, size_t bytes)
> +{
> + u32 *src = dw->buf_src + offset;
> + u32 *dst = dw->buf_dst + offset;
> + u32 *end = dw->buf_src + offset + bytes;
> +
> + do {
> + unsigned i;
> + u8 *cs;
> +
> + cs = dw->cs[dw->iec_offset++];
> + if (dw->iec_offset >= 192)
> + dw->iec_offset = 0;
> +
> + i = dw->channels;
> + do {
> + u32 sample = *src++;
> +
> + sample &= ~0xff000000;
> + sample |= *cs++ << 24;
> + sample |= parity(sample & ~0xf8000000);
> +
> + *dst++ = sample;
> + } while (--i);
> + } while (src < end);
> +}
> +
> +static void dw_hdmi_create_cs(struct snd_dw_hdmi *dw,
> + struct snd_pcm_runtime *runtime)
> +{
> + u8 cs[4];
> + unsigned ch, i, j;
> +
> + snd_pcm_create_iec958_consumer(runtime, cs, sizeof(cs));
> +
> + memset(dw->cs, 0, sizeof(dw->cs));
> +
> + for (ch = 0; ch < 8; ch++) {
> + cs[2] &= ~IEC958_AES2_CON_CHANNEL;
> + cs[2] |= (ch + 1) << 4;
> +
> + for (i = 0; i < ARRAY_SIZE(cs); i++) {
> + unsigned c = cs[i];
> +
> + for (j = 0; j < 8; j++, c >>= 1)
> + dw->cs[i * 8 + j][ch] = (c & 1) << 2;
> + }
> + }
> + dw->cs[0][0] |= BIT(4);
> +}
> +
> +static void dw_hdmi_start_dma(struct snd_dw_hdmi *dw)
> +{
> + void __iomem *base = dw->data.base;
> + unsigned offset = dw->buf_offset;
> + unsigned period = dw->buf_period;
> + u32 start, stop;
> +
> + dw->reformat(dw, offset, period);
> +
> + /* Clear all irqs before enabling irqs and starting DMA */
> + writeb_relaxed(HDMI_IH_AHBDMAAUD_STAT0_ALL,
> + base + HDMI_IH_AHBDMAAUD_STAT0);
> +
> + start = dw->buf_addr + offset;
> + stop = start + period - 1;
> +
> + /* Setup the hardware start/stop addresses */
> + dw_hdmi_writel(start, base + HDMI_AHB_DMA_STRADDR0);
> + dw_hdmi_writel(stop, base + HDMI_AHB_DMA_STPADDR0);
> +
> + writeb_relaxed((u8)~HDMI_AHB_DMA_MASK_DONE, base + HDMI_AHB_DMA_MASK);
> + writeb(HDMI_AHB_DMA_START_START, base + HDMI_AHB_DMA_START);
> +
> + offset += period;
> + if (offset >= dw->buf_size)
> + offset = 0;
> + dw->buf_offset = offset;
> +}
> +
> +static void dw_hdmi_stop_dma(struct snd_dw_hdmi *dw)
> +{
> + /* Disable interrupts before disabling DMA */
> + writeb_relaxed(~0, dw->data.base + HDMI_AHB_DMA_MASK);
> + writeb_relaxed(HDMI_AHB_DMA_STOP_STOP, dw->data.base + HDMI_AHB_DMA_STOP);
> +}
> +
> +static irqreturn_t snd_dw_hdmi_irq(int irq, void *data)
> +{
> + struct snd_dw_hdmi *dw = data;
> + struct snd_pcm_substream *substream;
> + unsigned stat;
> +
> + stat = readb_relaxed(dw->data.base + HDMI_IH_AHBDMAAUD_STAT0);
> + if (!stat)
> + return IRQ_NONE;
> +
> + writeb_relaxed(stat, dw->data.base + HDMI_IH_AHBDMAAUD_STAT0);
> +
> + substream = dw->substream;
> + if (stat & HDMI_IH_AHBDMAAUD_STAT0_DONE && substream) {
> + snd_pcm_period_elapsed(substream);
> +
> + spin_lock(&dw->lock);
> + if (dw->substream)
> + dw_hdmi_start_dma(dw);
> + spin_unlock(&dw->lock);
> + }
> +
> + return IRQ_HANDLED;
> +}
> +
> +static struct snd_pcm_hardware dw_hdmi_hw = {
> + .info = SNDRV_PCM_INFO_INTERLEAVED |
> + SNDRV_PCM_INFO_BLOCK_TRANSFER |
> + SNDRV_PCM_INFO_MMAP |
> + SNDRV_PCM_INFO_MMAP_VALID,
> + .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE |
> + SNDRV_PCM_FMTBIT_S24_LE,
> + .rates = SNDRV_PCM_RATE_32000 |
> + SNDRV_PCM_RATE_44100 |
> + SNDRV_PCM_RATE_48000 |
> + SNDRV_PCM_RATE_88200 |
> + SNDRV_PCM_RATE_96000 |
> + SNDRV_PCM_RATE_176400 |
> + SNDRV_PCM_RATE_192000,
> + .channels_min = 2,
> + .channels_max = 8,
> + .buffer_bytes_max = 64 * 1024,
> + .period_bytes_min = 256,
> + .period_bytes_max = 8192, /* ERR004323: must limit to 8k */
> + .periods_min = 2,
> + .periods_max = 16,
> + .fifo_size = 0,
> +};
> +
> +static int dw_hdmi_open(struct snd_pcm_substream *substream)
> +{
> + struct snd_pcm_runtime *runtime = substream->runtime;
> + struct snd_dw_hdmi *dw = substream->private_data;
> + void __iomem *base = dw->data.base;
> + int ret;
> +
> + runtime->hw = dw_hdmi_hw;
> +
> + ret = snd_pcm_limit_hw_rates(runtime);
> + if (ret < 0)
> + return ret;
> +
> + ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
> + if (ret < 0)
> + return ret;
> +
> + /* Clear FIFO */
> + writeb_relaxed(HDMI_AHB_DMA_CONF0_SW_FIFO_RST,
> + base + HDMI_AHB_DMA_CONF0);
> +
> + /* Configure interrupt polarities */
> + writeb_relaxed(~0, base + HDMI_AHB_DMA_POL);
> + writeb_relaxed(~0, base + HDMI_AHB_DMA_BUFFPOL);
> +
> + /* Keep interrupts masked, and clear any pending */
> + writeb_relaxed(~0, base + HDMI_AHB_DMA_MASK);
> + writeb_relaxed(~0, base + HDMI_IH_AHBDMAAUD_STAT0);
> +
> + ret = request_irq(dw->data.irq, snd_dw_hdmi_irq, IRQF_SHARED,
> + "dw-hdmi-audio", dw);
> + if (ret)
> + return ret;
> +
> + /* Un-mute done interrupt */
> + writeb_relaxed(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL &
> + ~HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE,
> + base + HDMI_IH_MUTE_AHBDMAAUD_STAT0);
> +
> + return 0;
> +}
> +
> +static int dw_hdmi_close(struct snd_pcm_substream *substream)
> +{
> + struct snd_dw_hdmi *dw = substream->private_data;
> +
> + /* Mute all interrupts */
> + writeb_relaxed(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL,
> + dw->data.base + HDMI_IH_MUTE_AHBDMAAUD_STAT0);
> +
> + free_irq(dw->data.irq, dw);
> +
> + return 0;
> +}
> +
> +static int dw_hdmi_hw_free(struct snd_pcm_substream *substream)
> +{
> + return snd_pcm_lib_free_vmalloc_buffer(substream);
> +}
> +
> +static int dw_hdmi_hw_params(struct snd_pcm_substream *substream,
> + struct snd_pcm_hw_params *params)
> +{
> + return snd_pcm_lib_alloc_vmalloc_buffer(substream,
> + params_buffer_bytes(params));
> +}
> +
> +static int dw_hdmi_prepare(struct snd_pcm_substream *substream)
> +{
> + struct snd_pcm_runtime *runtime = substream->runtime;
> + struct snd_dw_hdmi *dw = substream->private_data;
> + u8 threshold, conf0, conf1;
> +
> + /* Setup as per 3.0.5 FSL 4.1.0 BSP */
> + switch (dw->revision) {
> + case 0x0a:
> + conf0 = HDMI_AHB_DMA_CONF0_BURST_MODE |
> + HDMI_AHB_DMA_CONF0_INCR4;
> + if (runtime->channels == 2)
> + threshold = 126;
> + else
> + threshold = 124;
> + break;
> + case 0x1a:
> + conf0 = HDMI_AHB_DMA_CONF0_BURST_MODE |
> + HDMI_AHB_DMA_CONF0_INCR8;
> + threshold = 128;
> + break;
> + default:
> + /* NOTREACHED */
> + return -EINVAL;
> + }
> +
> + dw_hdmi_set_sample_rate(dw->data.hdmi, runtime->rate);
> +
> + /* Minimum number of bytes in the fifo. */
> + runtime->hw.fifo_size = threshold * 32;
> +
> + conf0 |= HDMI_AHB_DMA_CONF0_EN_HLOCK;
> + conf1 = (1 << runtime->channels) - 1;
> +
> + writeb_relaxed(threshold, dw->data.base + HDMI_AHB_DMA_THRSLD);
> + writeb_relaxed(conf0, dw->data.base + HDMI_AHB_DMA_CONF0);
> + writeb_relaxed(conf1, dw->data.base + HDMI_AHB_DMA_CONF1);
> +
> + switch (runtime->format) {
> + case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
> + dw->reformat = dw_hdmi_reformat_iec958;
> + break;
> + case SNDRV_PCM_FORMAT_S24_LE:
> + dw_hdmi_create_cs(dw, runtime);
> + dw->reformat = dw_hdmi_reformat_s24;
> + break;
> + }
> + dw->iec_offset = 0;
> + dw->channels = runtime->channels;
> + dw->buf_src = runtime->dma_area;
> + dw->buf_dst = substream->dma_buffer.area;
> + dw->buf_addr = substream->dma_buffer.addr;
> + dw->buf_period = snd_pcm_lib_period_bytes(substream);
> + dw->buf_size = snd_pcm_lib_buffer_bytes(substream);
> +
> + return 0;
> +}
> +
> +static int dw_hdmi_trigger(struct snd_pcm_substream *substream, int cmd)
> +{
> + struct snd_dw_hdmi *dw = substream->private_data;
> + unsigned long flags;
> + int ret = 0;
> +
> + switch (cmd) {
> + case SNDRV_PCM_TRIGGER_START:
> + spin_lock_irqsave(&dw->lock, flags);
> + dw->buf_offset = 0;
> + dw->substream = substream;
> + dw_hdmi_start_dma(dw);
> + dw_hdmi_audio_enable(dw->data.hdmi);
> + spin_unlock_irqrestore(&dw->lock, flags);
> + substream->runtime->delay = substream->runtime->period_size;
> + break;
> +
> + case SNDRV_PCM_TRIGGER_STOP:
> + spin_lock_irqsave(&dw->lock, flags);
> + dw->substream = NULL;
> + dw_hdmi_stop_dma(dw);
> + dw_hdmi_audio_disable(dw->data.hdmi);
> + spin_unlock_irqrestore(&dw->lock, flags);
> + break;
> +
> + default:
> + ret = -EINVAL;
> + break;
> + }
> +
> + return ret;
> +}
> +
> +static snd_pcm_uframes_t dw_hdmi_pointer(struct snd_pcm_substream *substream)
> +{
> + struct snd_pcm_runtime *runtime = substream->runtime;
> + struct snd_dw_hdmi *dw = substream->private_data;
> +
> + /*
> + * We are unable to report the exact hardware position as
> + * reading the 32-bit DMA position using 8-bit reads is racy.
> + */
> + return bytes_to_frames(runtime, dw->buf_offset);
> +}
> +
> +static struct snd_pcm_ops snd_dw_hdmi_ops = {
> + .open = dw_hdmi_open,
> + .close = dw_hdmi_close,
> + .ioctl = snd_pcm_lib_ioctl,
> + .hw_params = dw_hdmi_hw_params,
> + .hw_free = dw_hdmi_hw_free,
> + .prepare = dw_hdmi_prepare,
> + .trigger = dw_hdmi_trigger,
> + .pointer = dw_hdmi_pointer,
> + .page = snd_pcm_lib_get_vmalloc_page,
> +};
> +
> +static int snd_dw_hdmi_probe(struct platform_device *pdev)
> +{
> + const struct dw_hdmi_audio_data *data = pdev->dev.platform_data;
> + struct device *dev = pdev->dev.parent;
> + struct snd_dw_hdmi *dw;
> + struct snd_card *card;
> + struct snd_pcm *pcm;
> + unsigned revision;
> + int ret;
> +
> + writeb_relaxed(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL,
> + data->base + HDMI_IH_MUTE_AHBDMAAUD_STAT0);
> + revision = readb_relaxed(data->base + HDMI_REVISION_ID);
> + if (revision != 0x0a && revision != 0x1a) {
> + dev_err(dev, "dw-hdmi-audio: unknown revision 0x%02x\n",
> + revision);
> + return -ENXIO;
> + }
> +
> + ret = snd_card_new(dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
> + THIS_MODULE, sizeof(struct snd_dw_hdmi), &card);
> + if (ret < 0)
> + return ret;
> +
> + strlcpy(card->driver, DRIVER_NAME, sizeof(card->driver));
> + strlcpy(card->shortname, "DW-HDMI", sizeof(card->shortname));
> + snprintf(card->longname, sizeof(card->longname),
> + "%s rev 0x%02x, irq %d", card->shortname, revision,
> + data->irq);
> +
> + dw = card->private_data;
> + dw->card = card;
> + dw->data = *data;
> + dw->revision = revision;
> +
> + spin_lock_init(&dw->lock);
> +
> + ret = snd_pcm_new(card, "DW HDMI", 0, 1, 0, &pcm);
> + if (ret < 0)
> + goto err;
> +
> + dw->pcm = pcm;
> + pcm->private_data = dw;
> + strlcpy(pcm->name, DRIVER_NAME, sizeof(pcm->name));
> + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_dw_hdmi_ops);
> +
> + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
> + dev, 64 * 1024, 64 * 1024);
> +
> + ret = snd_card_register(card);
> + if (ret < 0)
> + goto err;
> +
> + platform_set_drvdata(pdev, dw);
> +
> + return 0;
> +
> +err:
> + snd_card_free(card);
> + return ret;
> +}
> +
> +static int snd_dw_hdmi_remove(struct platform_device *pdev)
> +{
> + struct snd_dw_hdmi *dw = platform_get_drvdata(pdev);
> +
> + snd_card_free(dw->card);
> +
> + return 0;
> +}
> +
> +#if defined(CONFIG_PM_SLEEP) && defined(IS_NOT_BROKEN)
> +/*
> + * This code is fine, but requires implementation in the dw_hdmi_trigger()
> + * method which is currently missing as I have no way to test this.
> + */
> +static int snd_dw_hdmi_suspend(struct device *dev)
> +{
> + struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
> +
> + snd_power_change_state(dw->card, SNDRV_CTL_POWER_D3cold);
> + snd_pcm_suspend_all(dw->pcm);
> +
> + return 0;
> +}
> +
> +static int snd_dw_hdmi_resume(struct device *dev)
> +{
> + struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
> +
> + snd_power_change_state(dw->card, SNDRV_CTL_POWER_D0);
> +
> + return 0;
> +}
> +
> +static SIMPLE_DEV_PM_OPS(snd_dw_hdmi_pm, snd_dw_hdmi_suspend,
> + snd_dw_hdmi_resume);
> +#define PM_OPS &snd_dw_hdmi_pm
> +#else
> +#define PM_OPS NULL
> +#endif
> +
> +static struct platform_driver snd_dw_hdmi_driver = {
> + .probe = snd_dw_hdmi_probe,
> + .remove = snd_dw_hdmi_remove,
> + .driver = {
> + .name = DRIVER_NAME,
> + .owner = THIS_MODULE,
> + .pm = PM_OPS,
> + },
> +};
> +
> +module_platform_driver(snd_dw_hdmi_driver);
> +
> +MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>");
> +MODULE_DESCRIPTION("Synopsis Designware HDMI AHB ALSA interface");
> +MODULE_LICENSE("GPL v2");
> +MODULE_ALIAS("platform:" DRIVER_NAME);
> diff --git a/drivers/gpu/drm/bridge/dw_hdmi-audio.h b/drivers/gpu/drm/bridge/dw_hdmi-audio.h
> new file mode 100644
> index 000000000000..1e840118d90a
> --- /dev/null
> +++ b/drivers/gpu/drm/bridge/dw_hdmi-audio.h
> @@ -0,0 +1,13 @@
> +#ifndef DW_HDMI_AUDIO_H
> +#define DW_HDMI_AUDIO_H
> +
> +struct dw_hdmi;
> +
> +struct dw_hdmi_audio_data {
> + phys_addr_t phys;
> + void __iomem *base;
> + int irq;
> + struct dw_hdmi *hdmi;
> +};
> +
> +#endif
> diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
> index fba25607ef88..b65464789fbd 100644
> --- a/drivers/gpu/drm/bridge/dw_hdmi.c
> +++ b/drivers/gpu/drm/bridge/dw_hdmi.c
> @@ -28,6 +28,7 @@
> #include <drm/bridge/dw_hdmi.h>
>
> #include "dw_hdmi.h"
> +#include "dw_hdmi-audio.h"
>
> #define HDMI_EDID_LEN 512
>
> @@ -104,6 +105,7 @@ struct dw_hdmi {
> struct drm_encoder *encoder;
> struct drm_bridge *bridge;
>
> + struct platform_device *audio;
> enum dw_hdmi_devtype dev_type;
> struct device *dev;
> struct clk *isfr_clk;
> @@ -1732,7 +1734,9 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
> {
> struct drm_device *drm = data;
> struct device_node *np = dev->of_node;
> + struct platform_device_info pdevinfo;
> struct device_node *ddc_node;
> + struct dw_hdmi_audio_data audio;
> struct dw_hdmi *hdmi;
> int ret;
> u32 val = 1;
> @@ -1860,6 +1864,23 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
> hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE),
> HDMI_IH_MUTE_PHY_STAT0);
>
> + memset(&pdevinfo, 0, sizeof(pdevinfo));
> + pdevinfo.parent = dev;
> + pdevinfo.id = PLATFORM_DEVID_AUTO;
> +
> + if (hdmi_readb(hdmi, HDMI_CONFIG1_ID) & HDMI_CONFIG1_AHB) {
> + audio.phys = iores->start;
> + audio.base = hdmi->regs;
> + audio.irq = irq;
> + audio.hdmi = hdmi;
> +
> + pdevinfo.name = "dw-hdmi-ahb-audio";
> + pdevinfo.data = &audio;
> + pdevinfo.size_data = sizeof(audio);
> + pdevinfo.dma_mask = DMA_BIT_MASK(32);
> + hdmi->audio = platform_device_register_full(&pdevinfo);
> + }
> +
> dev_set_drvdata(dev, hdmi);
>
> return 0;
> @@ -1877,6 +1898,9 @@ void dw_hdmi_unbind(struct device *dev, struct device *master, void *data)
> {
> struct dw_hdmi *hdmi = dev_get_drvdata(dev);
>
> + if (hdmi->audio && !IS_ERR(hdmi->audio))
> + platform_device_unregister(hdmi->audio);
> +
> /* Disable all interrupts */
> hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
>
> diff --git a/drivers/gpu/drm/bridge/dw_hdmi.h b/drivers/gpu/drm/bridge/dw_hdmi.h
> index 175dbc89a824..78e54e813212 100644
> --- a/drivers/gpu/drm/bridge/dw_hdmi.h
> +++ b/drivers/gpu/drm/bridge/dw_hdmi.h
> @@ -545,6 +545,9 @@
> #define HDMI_I2CM_FS_SCL_LCNT_0_ADDR 0x7E12
>
> enum {
> +/* CONFIG1_ID field values */
> + HDMI_CONFIG1_AHB = 0x01,
> +
> /* IH_FC_INT2 field values */
> HDMI_IH_FC_INT2_OVERFLOW_MASK = 0x03,
> HDMI_IH_FC_INT2_LOW_PRIORITY_OVERFLOW = 0x02,
> --
> 2.1.0
>
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel@alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Russell King <rmk+kernel@arm.linux.org.uk> |
|---|---|
| Date | 2015-08-08 18:20 +0200 |
| Subject | [PATCH 3/9] drm: bridge/dw_hdmi-ahb-audio: basic support for multi-channel PCM audio |
| Message-ID | <pVf0K-3Qj-27@gated-at.bofh.it> |
| In reply to | #1203296 |
Add basic support for multi-channel PCM audio, with fixed speaker
mappings. This has been tested with an AV receiver, and appears to
work for low sample rates up to 8 channels.
It should be noted that multi-channel mode using the IEC958 alsa-lib
conversion plugin requires correct AES channel status for the AV
receiver to recognise the stream, especially the sample rate bits.
"Not identified" does not work there.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/gpu/drm/bridge/dw_hdmi-ahb-audio.c | 59 +++++++++++++++++++++++++++++-
1 file changed, 57 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw_hdmi-ahb-audio.c b/drivers/gpu/drm/bridge/dw_hdmi-ahb-audio.c
index 125b81306254..3a8f32e04b63 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi-ahb-audio.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi-ahb-audio.c
@@ -62,9 +62,14 @@ enum {
HDMI_AHB_DMA_CONF0_INCR4 = 0,
HDMI_AHB_DMA_CONF0_BURST_MODE = BIT(0),
HDMI_AHB_DMA_MASK_DONE = BIT(7),
+
HDMI_REVISION_ID = 0x0001,
HDMI_IH_AHBDMAAUD_STAT0 = 0x0109,
HDMI_IH_MUTE_AHBDMAAUD_STAT0 = 0x0189,
+ HDMI_FC_AUDICONF2 = 0x1027,
+ HDMI_FC_AUDSCONF = 0x1063,
+ HDMI_FC_AUDSCONF_LAYOUT1 = 1 << 0,
+ HDMI_FC_AUDSCONF_LAYOUT0 = 0 << 0,
HDMI_AHB_DMA_CONF0 = 0x3600,
HDMI_AHB_DMA_START = 0x3601,
HDMI_AHB_DMA_STOP = 0x3602,
@@ -77,6 +82,44 @@ enum {
HDMI_AHB_DMA_BUFFPOL = 0x361a,
};
+struct dw_hdmi_channel_conf {
+ u8 conf1;
+ u8 ca;
+};
+
+/*
+ * The default mapping of ALSA channels to HDMI channels and speaker
+ * allocation bits. Note that we can't do channel remapping here -
+ * channels must be in the same order.
+ *
+ * Mappings for alsa-lib pcm/surround*.conf files:
+ *
+ * Front Sur4.0 Sur4.1 Sur5.0 Sur5.1 Sur7.1
+ * Channels 2 4 6 6 6 8
+ *
+ * Our mapping from ALSA channel to CEA686D speaker name and HDMI channel:
+ *
+ * Number of ALSA channels
+ * ALSA Channel 2 3 4 5 6 7 8
+ * 0 FL:0 = = = = = =
+ * 1 FR:1 = = = = = =
+ * 2 FC:3 RL:4 LFE:2 = = =
+ * 3 RR:5 RL:4 FC:3 = =
+ * 4 RR:5 RL:4 = =
+ * 5 RR:5 = =
+ * 6 RC:6 =
+ * 7 RLC/FRC RLC/FRC
+ */
+static struct dw_hdmi_channel_conf default_hdmi_channel_config[7] = {
+ { 0x03, 0x00 }, /* FL,FR */
+ { 0x0b, 0x02 }, /* FL,FR,FC */
+ { 0x33, 0x08 }, /* FL,FR,RL,RR */
+ { 0x37, 0x09 }, /* FL,FR,LFE,RL,RR */
+ { 0x3f, 0x0b }, /* FL,FR,LFE,FC,RL,RR */
+ { 0x7f, 0x0f }, /* FL,FR,LFE,FC,RL,RR,RC */
+ { 0xff, 0x13 }, /* FL,FR,LFE,FC,RL,RR,[FR]RC,[FR]LC */
+};
+
struct snd_dw_hdmi {
struct snd_card *card;
struct snd_pcm *pcm;
@@ -352,7 +395,7 @@ static int dw_hdmi_prepare(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_dw_hdmi *dw = substream->private_data;
- u8 threshold, conf0, conf1;
+ u8 threshold, conf0, conf1, layout, ca;
/* Setup as per 3.0.5 FSL 4.1.0 BSP */
switch (dw->revision) {
@@ -380,11 +423,23 @@ static int dw_hdmi_prepare(struct snd_pcm_substream *substream)
runtime->hw.fifo_size = threshold * 32;
conf0 |= HDMI_AHB_DMA_CONF0_EN_HLOCK;
- conf1 = (1 << runtime->channels) - 1;
+ conf1 = default_hdmi_channel_config[runtime->channels - 2].conf1;
+ ca = default_hdmi_channel_config[runtime->channels - 2].ca;
+
+ /*
+ * For >2 channel PCM audio, we need to select layout 1
+ * and set an appropriate channel map.
+ */
+ if (runtime->channels > 2)
+ layout = HDMI_FC_AUDSCONF_LAYOUT1;
+ else
+ layout = HDMI_FC_AUDSCONF_LAYOUT0;
writeb_relaxed(threshold, dw->data.base + HDMI_AHB_DMA_THRSLD);
writeb_relaxed(conf0, dw->data.base + HDMI_AHB_DMA_CONF0);
writeb_relaxed(conf1, dw->data.base + HDMI_AHB_DMA_CONF1);
+ writeb_relaxed(layout, dw->data.base + HDMI_FC_AUDSCONF);
+ writeb_relaxed(ca, dw->data.base + HDMI_FC_AUDICONF2);
switch (runtime->format) {
case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
--
2.1.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Russell King <rmk+kernel@arm.linux.org.uk> |
|---|---|
| Date | 2015-08-08 18:10 +0200 |
| Subject | [PATCH 08/12] drm: bridge/dw_hdmi: avoid enabling interface in mode_set |
| Message-ID | <pVeR4-3EB-13@gated-at.bofh.it> |
| In reply to | #1203293 |
On a mode set, DRM makes the following sequence of calls:
* for_each_encoder
* bridge mode_fixup
* encoder mode_fixup
* crtc mode_fixup
* for_each_encoder
* bridge disable
* encoder prepare
* bridge post_disable
* disable unused encoders
* crtc prepare
* crtc mode_set
* for_each_encoder
* encoder mode_set
* bridge mode_set
* crtc commit
* for_each_encoder
* bridge pre_enable
* encoder commit
* bridge enable
dw_hdmi enables the HDMI output in both the bridge mode_set() and also
the bridge enable() step. This is duplicated work - we can avoid the
setup in mode_set() and just do it in the enable() stage. This
simplifies the code a little.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/gpu/drm/bridge/dw_hdmi.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
index 578d7362cd65..fbac8386552b 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -1389,8 +1389,6 @@ static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge,
{
struct dw_hdmi *hdmi = bridge->driver_private;
- dw_hdmi_setup(hdmi, mode);
-
/* Store the display mode for plugin/DKMS poweron events */
memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
}
--
2.1.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Russell King <rmk+kernel@arm.linux.org.uk> |
|---|---|
| Date | 2015-08-08 18:10 +0200 |
| Subject | [PATCH 04/12] gpu: imx: fix support for interlaced modes |
| Message-ID | <pVeR4-3EB-15@gated-at.bofh.it> |
| In reply to | #1203293 |
The support for interlaced video modes seems to be broken; we don't use
anything other than the vtotal/htotal from the timing information to
define the various sync counters.
Freescale patches for interlaced video support contain an alternative
sync counter setup, which we include here. This setup produces the
hsync and vsync via the normal counter 2 and 3, but moves the display
enable signal from counter 5 to counter 6. Therefore, we need to
change the display controller setup as well.
The corresponding Freescale patches for this change are:
iMX6-HDMI-support-interlaced-display-mode.patch
IPU-fine-tuning-the-interlace-display-timing-for-CEA.patch
This produces a working interlace format output from the IPU.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/gpu/ipu-v3/ipu-dc.c | 18 ++++++++---
drivers/gpu/ipu-v3/ipu-di.c | 79 +++++++++++++++++++++------------------------
2 files changed, 51 insertions(+), 46 deletions(-)
diff --git a/drivers/gpu/ipu-v3/ipu-dc.c b/drivers/gpu/ipu-v3/ipu-dc.c
index 9ef2e1f54ca4..aa560855c1dc 100644
--- a/drivers/gpu/ipu-v3/ipu-dc.c
+++ b/drivers/gpu/ipu-v3/ipu-dc.c
@@ -183,12 +183,22 @@ int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced,
}
if (interlaced) {
- dc_link_event(dc, DC_EVT_NL, 0, 3);
- dc_link_event(dc, DC_EVT_EOL, 0, 2);
- dc_link_event(dc, DC_EVT_NEW_DATA, 0, 1);
+ int word, addr;
+
+ if (dc->di) {
+ addr = 1;
+ word = 1;
+ } else {
+ addr = 0;
+ word = 0;
+ }
+
+ dc_link_event(dc, DC_EVT_NL, addr, 3);
+ dc_link_event(dc, DC_EVT_EOL, addr, 2);
+ dc_link_event(dc, DC_EVT_NEW_DATA, addr, 1);
/* Init template microcode */
- dc_write_tmpl(dc, 0, WROD(0), 0, map, SYNC_WAVE, 0, 8, 1);
+ dc_write_tmpl(dc, word, WROD(0), 0, map, SYNC_WAVE, 0, 6, 1);
} else {
if (dc->di) {
dc_link_event(dc, DC_EVT_NL, 2, 3);
diff --git a/drivers/gpu/ipu-v3/ipu-di.c b/drivers/gpu/ipu-v3/ipu-di.c
index a96991c5c15f..359268e3a166 100644
--- a/drivers/gpu/ipu-v3/ipu-di.c
+++ b/drivers/gpu/ipu-v3/ipu-di.c
@@ -71,6 +71,10 @@ enum di_sync_wave {
DI_SYNC_HSYNC = 3,
DI_SYNC_VSYNC = 4,
DI_SYNC_DE = 6,
+
+ DI_SYNC_CNT1 = 2, /* counter >= 2 only */
+ DI_SYNC_CNT4 = 5, /* counter >= 5 only */
+ DI_SYNC_CNT5 = 6, /* counter >= 6 only */
};
#define SYNC_WAVE 0
@@ -211,66 +215,59 @@ static void ipu_di_sync_config_interlaced(struct ipu_di *di,
sig->mode.hback_porch + sig->mode.hfront_porch;
u32 v_total = sig->mode.vactive + sig->mode.vsync_len +
sig->mode.vback_porch + sig->mode.vfront_porch;
- u32 reg;
struct di_sync_config cfg[] = {
{
- .run_count = h_total / 2 - 1,
- .run_src = DI_SYNC_CLK,
+ /* 1: internal VSYNC for each frame */
+ .run_count = v_total * 2 - 1,
+ .run_src = 3, /* == counter 7 */
}, {
- .run_count = h_total - 11,
+ /* PIN2: HSYNC waveform */
+ .run_count = h_total - 1,
.run_src = DI_SYNC_CLK,
- .cnt_down = 4,
+ .cnt_polarity_gen_en = 1,
+ .cnt_polarity_trigger_src = DI_SYNC_CLK,
+ .cnt_down = sig->mode.hsync_len * 2,
}, {
- .run_count = v_total * 2 - 1,
- .run_src = DI_SYNC_INT_HSYNC,
- .offset_count = 1,
- .offset_src = DI_SYNC_INT_HSYNC,
- .cnt_down = 4,
+ /* PIN3: VSYNC waveform */
+ .run_count = v_total - 1,
+ .run_src = 4, /* == counter 7 */
+ .cnt_polarity_gen_en = 1,
+ .cnt_polarity_trigger_src = 4, /* == counter 7 */
+ .cnt_down = sig->mode.vsync_len * 2,
+ .cnt_clr_src = DI_SYNC_CNT1,
}, {
- .run_count = v_total / 2 - 1,
+ /* 4: Field */
+ .run_count = v_total / 2,
.run_src = DI_SYNC_HSYNC,
- .offset_count = sig->mode.vback_porch,
- .offset_src = DI_SYNC_HSYNC,
+ .offset_count = h_total / 2,
+ .offset_src = DI_SYNC_CLK,
.repeat_count = 2,
- .cnt_clr_src = DI_SYNC_VSYNC,
+ .cnt_clr_src = DI_SYNC_CNT1,
}, {
+ /* 5: Active lines */
.run_src = DI_SYNC_HSYNC,
- .repeat_count = sig->mode.vactive / 2,
- .cnt_clr_src = 4,
- }, {
- .run_count = v_total - 1,
- .run_src = DI_SYNC_HSYNC,
- }, {
- .run_count = v_total / 2 - 1,
- .run_src = DI_SYNC_HSYNC,
- .offset_count = 9,
+ .offset_count = (sig->mode.vsync_len +
+ sig->mode.vback_porch) / 2,
.offset_src = DI_SYNC_HSYNC,
- .repeat_count = 2,
- .cnt_clr_src = DI_SYNC_VSYNC,
+ .repeat_count = sig->mode.vactive / 2,
+ .cnt_clr_src = DI_SYNC_CNT4,
}, {
+ /* 6: Active pixel, referenced by DC */
.run_src = DI_SYNC_CLK,
- .offset_count = sig->mode.hback_porch,
+ .offset_count = sig->mode.hsync_len +
+ sig->mode.hback_porch,
.offset_src = DI_SYNC_CLK,
.repeat_count = sig->mode.hactive,
- .cnt_clr_src = 5,
+ .cnt_clr_src = DI_SYNC_CNT5,
}, {
- .run_count = v_total - 1,
- .run_src = DI_SYNC_INT_HSYNC,
- .offset_count = v_total / 2,
- .offset_src = DI_SYNC_INT_HSYNC,
- .cnt_clr_src = DI_SYNC_HSYNC,
- .cnt_down = 4,
+ /* 7: Half line HSYNC */
+ .run_count = h_total / 2 - 1,
+ .run_src = DI_SYNC_CLK,
}
};
ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg));
- /* set gentime select and tag sel */
- reg = ipu_di_read(di, DI_SW_GEN1(9));
- reg &= 0x1FFFFFFF;
- reg |= (3 - 1) << 29 | 0x00008000;
- ipu_di_write(di, reg, DI_SW_GEN1(9));
-
ipu_di_write(di, v_total / 2 - 1, DI_SCR_CONF);
}
@@ -605,10 +602,8 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
/* set y_sel = 1 */
di_gen |= 0x10000000;
- di_gen |= DI_GEN_POLARITY_5;
- di_gen |= DI_GEN_POLARITY_8;
- vsync_cnt = 7;
+ vsync_cnt = 3;
} else {
ipu_di_sync_config_noninterlaced(di, sig, div);
--
2.1.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Russell King <rmk+kernel@arm.linux.org.uk> |
|---|---|
| Date | 2015-08-08 18:10 +0200 |
| Subject | [PATCH 09/12] drm: bridge/dw_hdmi: rename dw_hdmi_phy_enable_power() |
| Message-ID | <pVeR4-3EB-17@gated-at.bofh.it> |
| In reply to | #1203293 |
dw_hdmi_phy_enable_power() is not about enabling and disabling power.
It is about allowing or preventing power-down mode being entered - the
register is documented as "Power-down enable (active low 0b)."
This can be seen as the bit has no effect when the HDMI phy is
operational on iMX6 hardware.
Rename the function to dw_hdmi_phy_enable_powerdown() to reflect the
documentation, make it take a bool for the 'enable' argument, and invert
the value to be written.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/gpu/drm/bridge/dw_hdmi.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
index fbac8386552b..7b8a4e942a71 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -737,9 +737,9 @@ static int hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
return 0;
}
-static void dw_hdmi_phy_enable_power(struct dw_hdmi *hdmi, u8 enable)
+static void dw_hdmi_phy_enable_powerdown(struct dw_hdmi *hdmi, bool enable)
{
- hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+ hdmi_mask_writeb(hdmi, !enable, HDMI_PHY_CONF0,
HDMI_PHY_CONF0_PDZ_OFFSET,
HDMI_PHY_CONF0_PDZ_MASK);
}
@@ -879,7 +879,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
/* REMOVE CLK TERM */
hdmi_phy_i2c_write(hdmi, 0x8000, 0x05); /* CKCALCTRL */
- dw_hdmi_phy_enable_power(hdmi, 1);
+ dw_hdmi_phy_enable_powerdown(hdmi, false);
/* toggle TMDS enable */
dw_hdmi_phy_enable_tmds(hdmi, 0);
@@ -924,7 +924,7 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi)
dw_hdmi_phy_sel_data_en_pol(hdmi, 1);
dw_hdmi_phy_sel_interface_control(hdmi, 0);
dw_hdmi_phy_enable_tmds(hdmi, 0);
- dw_hdmi_phy_enable_power(hdmi, 0);
+ dw_hdmi_phy_enable_powerdown(hdmi, true);
/* Enable CSC */
ret = hdmi_phy_configure(hdmi, 0, 8, cscon);
@@ -1155,7 +1155,7 @@ static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi)
return;
dw_hdmi_phy_enable_tmds(hdmi, 0);
- dw_hdmi_phy_enable_power(hdmi, 0);
+ dw_hdmi_phy_enable_powerdown(hdmi, true);
hdmi->phy_enabled = false;
}
--
2.1.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Russell King <rmk+kernel@arm.linux.org.uk> |
|---|---|
| Date | 2015-08-08 18:10 +0200 |
| Subject | [PATCH 03/12] gpu: imx: simplify sync polarity setting |
| Message-ID | <pVeR4-3EB-19@gated-at.bofh.it> |
| In reply to | #1203293 |
Use a function to convert the sync pin to a bit mask for the DI_GENERAL
register, and move this out of the interlace/non-interlace path to the
common path.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/gpu/ipu-v3/ipu-di.c | 50 +++++++++++++++++++++++++--------------------
1 file changed, 28 insertions(+), 22 deletions(-)
diff --git a/drivers/gpu/ipu-v3/ipu-di.c b/drivers/gpu/ipu-v3/ipu-di.c
index 2970c6bb668c..a96991c5c15f 100644
--- a/drivers/gpu/ipu-v3/ipu-di.c
+++ b/drivers/gpu/ipu-v3/ipu-di.c
@@ -543,6 +543,29 @@ int ipu_di_adjust_videomode(struct ipu_di *di, struct videomode *mode)
}
EXPORT_SYMBOL_GPL(ipu_di_adjust_videomode);
+static u32 ipu_di_gen_polarity(int pin)
+{
+ switch (pin) {
+ case 1:
+ return DI_GEN_POLARITY_1;
+ case 2:
+ return DI_GEN_POLARITY_2;
+ case 3:
+ return DI_GEN_POLARITY_3;
+ case 4:
+ return DI_GEN_POLARITY_4;
+ case 5:
+ return DI_GEN_POLARITY_5;
+ case 6:
+ return DI_GEN_POLARITY_6;
+ case 7:
+ return DI_GEN_POLARITY_7;
+ case 8:
+ return DI_GEN_POLARITY_8;
+ }
+ return 0;
+}
+
int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
{
u32 reg;
@@ -586,11 +609,6 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
di_gen |= DI_GEN_POLARITY_8;
vsync_cnt = 7;
-
- if (sig->mode.flags & DISPLAY_FLAGS_HSYNC_HIGH)
- di_gen |= DI_GEN_POLARITY_3;
- if (sig->mode.flags & DISPLAY_FLAGS_VSYNC_HIGH)
- di_gen |= DI_GEN_POLARITY_2;
} else {
ipu_di_sync_config_noninterlaced(di, sig, div);
@@ -602,25 +620,13 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
*/
if (!(sig->hsync_pin == 2 && sig->vsync_pin == 3))
vsync_cnt = 6;
-
- if (sig->mode.flags & DISPLAY_FLAGS_HSYNC_HIGH) {
- if (sig->hsync_pin == 2)
- di_gen |= DI_GEN_POLARITY_2;
- else if (sig->hsync_pin == 4)
- di_gen |= DI_GEN_POLARITY_4;
- else if (sig->hsync_pin == 7)
- di_gen |= DI_GEN_POLARITY_7;
- }
- if (sig->mode.flags & DISPLAY_FLAGS_VSYNC_HIGH) {
- if (sig->vsync_pin == 3)
- di_gen |= DI_GEN_POLARITY_3;
- else if (sig->vsync_pin == 6)
- di_gen |= DI_GEN_POLARITY_6;
- else if (sig->vsync_pin == 8)
- di_gen |= DI_GEN_POLARITY_8;
- }
}
+ if (sig->mode.flags & DISPLAY_FLAGS_HSYNC_HIGH)
+ di_gen |= ipu_di_gen_polarity(sig->hsync_pin);
+ if (sig->mode.flags & DISPLAY_FLAGS_VSYNC_HIGH)
+ di_gen |= ipu_di_gen_polarity(sig->vsync_pin);
+
if (sig->clk_pol)
di_gen |= DI_GEN_POLARITY_DISP_CLK;
--
2.1.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Russell King <rmk+kernel@arm.linux.org.uk> |
|---|---|
| Date | 2015-08-08 18:10 +0200 |
| Subject | [PATCH 01/12] drm: bridge/dw_hdmi: remove pixel repetition setting for all VICs |
| Message-ID | <pVeR5-3EB-29@gated-at.bofh.it> |
| In reply to | #1203293 |
dw_hdmi sets a pixel repetition factor of 1 for VICs 10-15, 25-30 and 35-38. However, DRM uses their native resolutions in its timing information. For example, VIC 14 can be 1440x480 with no repetition, or 720x480 with one pixel repetition. As DRM uses 1440 pixels per line for this video mode, we need no pixel repetition. In any case, pixel repetition appears broken in dw_hdmi. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> --- drivers/gpu/drm/bridge/dw_hdmi.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c index f070ee07b8c9..1c0ee3476138 100644 --- a/drivers/gpu/drm/bridge/dw_hdmi.c +++ b/drivers/gpu/drm/bridge/dw_hdmi.c @@ -1236,18 +1236,7 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) else hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_709; - if ((hdmi->vic == 10) || (hdmi->vic == 11) || - (hdmi->vic == 12) || (hdmi->vic == 13) || - (hdmi->vic == 14) || (hdmi->vic == 15) || - (hdmi->vic == 25) || (hdmi->vic == 26) || - (hdmi->vic == 27) || (hdmi->vic == 28) || - (hdmi->vic == 29) || (hdmi->vic == 30) || - (hdmi->vic == 35) || (hdmi->vic == 36) || - (hdmi->vic == 37) || (hdmi->vic == 38)) - hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 1; - else - hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0; - + hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0; hdmi->hdmi_data.video_mode.mpixelrepetitioninput = 0; /* TODO: Get input format from IPU (via FB driver interface) */ -- 2.1.0 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Russell King <rmk+kernel@arm.linux.org.uk> |
|---|---|
| Date | 2015-08-08 18:10 +0200 |
| Subject | [PATCH 02/12] drm: bridge/dw_hdmi: don't support any pixel doubled modes |
| Message-ID | <pVeR5-3EB-33@gated-at.bofh.it> |
| In reply to | #1203293 |
As mentioned in the previous commit, the dw-hdmi driver does not support pixel doubled modes at present; it does not configure the PLL correctly for these modes. Therefore, filter out the double-clocked modes as we presently are unable to support them. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> --- drivers/gpu/drm/bridge/dw_hdmi.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c index 1c0ee3476138..8edf4c31f55c 100644 --- a/drivers/gpu/drm/bridge/dw_hdmi.c +++ b/drivers/gpu/drm/bridge/dw_hdmi.c @@ -1448,6 +1448,10 @@ dw_hdmi_connector_mode_valid(struct drm_connector *connector, struct dw_hdmi, connector); enum drm_mode_status mode_status = MODE_OK; + /* We don't support double-clocked modes */ + if (mode->flags & DRM_MODE_FLAG_DBLCLK) + return MODE_BAD; + if (hdmi->plat_data->mode_valid) mode_status = hdmi->plat_data->mode_valid(connector, mode); -- 2.1.0 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Russell King <rmk+kernel@arm.linux.org.uk> |
|---|---|
| Date | 2015-08-08 18:10 +0200 |
| Subject | [PATCH 06/12] drm: bridge/dw_hdmi: clean up HDMI vs DVI mode handling |
| Message-ID | <pVeR5-3EB-31@gated-at.bofh.it> |
| In reply to | #1203293 |
The FSL kernel detects the HDMI vendor id, and uses this to set
hdmi->edid_cfg.hdmi_cap, which is then used to set mdvi appropriately,
rather than detecting whether we are outputting a CEA mode. Update
the dw_hdmi code to use this logic, but lets eliminate the mdvi
variable, prefering the more verbose "hdmi->sink_is_hdmi" instead.
Use the generic drm_detect_hdmi_monitor() to detect a HDMI sink.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/gpu/drm/bridge/dw_hdmi.c | 26 ++++++++++++--------------
1 file changed, 12 insertions(+), 14 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
index 2e211b8331ed..7f764716f3c4 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -82,7 +82,6 @@ static const u16 csc_coeff_rgb_in_eitu709[3][4] = {
};
struct hdmi_vmode {
- bool mdvi;
bool mdataenablepolarity;
unsigned int mpixelclock;
@@ -123,6 +122,7 @@ struct dw_hdmi {
struct i2c_adapter *ddc;
void __iomem *regs;
+ bool sink_is_hdmi;
spinlock_t audio_lock;
struct mutex audio_mutex;
@@ -913,11 +913,10 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
static int dw_hdmi_phy_init(struct dw_hdmi *hdmi)
{
int i, ret;
- bool cscon = false;
+ bool cscon;
/*check csc whether needed activated in HDMI mode */
- cscon = (is_color_space_conversion(hdmi) &&
- !hdmi->hdmi_data.video_mode.mdvi);
+ cscon = hdmi->sink_is_hdmi && is_color_space_conversion(hdmi);
/* HDMI Phy spec says to do the phy initialization sequence twice */
for (i = 0; i < 2; i++) {
@@ -1094,9 +1093,9 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
HDMI_FC_INVIDCONF_IN_I_P_INTERLACED :
HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE;
- inv_val |= (vmode->mdvi ?
- HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE :
- HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE);
+ inv_val |= hdmi->sink_is_hdmi ?
+ HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE :
+ HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE;
hdmi_writeb(hdmi, inv_val, HDMI_FC_INVIDCONF);
@@ -1236,10 +1235,8 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
if (!hdmi->vic) {
dev_dbg(hdmi->dev, "Non-CEA mode used in HDMI\n");
- hdmi->hdmi_data.video_mode.mdvi = true;
} else {
dev_dbg(hdmi->dev, "CEA mode used vic=%d\n", hdmi->vic);
- hdmi->hdmi_data.video_mode.mdvi = false;
}
if ((hdmi->vic == 6) || (hdmi->vic == 7) ||
@@ -1275,10 +1272,8 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
dw_hdmi_enable_video_path(hdmi);
/* not for DVI mode */
- if (hdmi->hdmi_data.video_mode.mdvi) {
- dev_dbg(hdmi->dev, "%s DVI mode\n", __func__);
- } else {
- dev_dbg(hdmi->dev, "%s CEA mode\n", __func__);
+ if (hdmi->sink_is_hdmi) {
+ dev_dbg(hdmi->dev, "%s HDMI mode\n", __func__);
/* HDMI Initialization Step E - Configure audio */
hdmi_clk_regenerator_update_pixel_clock(hdmi);
@@ -1286,6 +1281,8 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
/* HDMI Initialization Step F - Configure AVI InfoFrame */
hdmi_config_AVI(hdmi, mode);
+ } else {
+ dev_dbg(hdmi->dev, "%s DVI mode\n", __func__);
}
hdmi_video_packetize(hdmi);
@@ -1294,7 +1291,7 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
hdmi_tx_hdcp_config(hdmi);
dw_hdmi_clear_overflow(hdmi);
- if (hdmi->cable_plugin && !hdmi->hdmi_data.video_mode.mdvi)
+ if (hdmi->cable_plugin && hdmi->sink_is_hdmi)
hdmi_enable_overflow_interrupts(hdmi);
return 0;
@@ -1444,6 +1441,7 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
dev_dbg(hdmi->dev, "got edid: width[%d] x height[%d]\n",
edid->width_cm, edid->height_cm);
+ hdmi->sink_is_hdmi = drm_detect_hdmi_monitor(edid);
drm_mode_connector_update_edid_property(connector, edid);
ret = drm_add_edid_modes(connector, edid);
kfree(edid);
--
2.1.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Russell King <rmk+kernel@arm.linux.org.uk> |
|---|---|
| Date | 2015-08-08 18:10 +0200 |
| Subject | [PATCH 11/12] drm: bridge/dw_hdmi: add connector mode forcing |
| Message-ID | <pVeR5-3EB-35@gated-at.bofh.it> |
| In reply to | #1203293 |
When connected to HDMI sources, some DVI monitors de-assert their HPD
signal and TDMS loads for one seconds every four seconds when there is
no signal present on the connection.
Unfortunately, this behaviour is indistinguishable from a proper HDMI
setup with an AV receiver in the path to the display: the HDMI spec
requires us to detect HPD deassertions as short as 100ms, which indicate
that the EDID has changed.
Since it is possible to connect a DVI monitor to an AV receiver and then
to a HDMI source, merely working around this by detecting the lack of
HDMI vendor block in the EDID is insufficient - the AV receiver is at
liberty to modify the EDID as it sees fit, and it will place its own
parameters into the EDID including the HDMI vendor block.
DRM has support for forcing the state of a connector, which we should
implement to allow us to work around these broken DVI monitors - we can
tell DRM to force the connection state to indicate that there is always
a device connected to work around this problem. Although this requires
manual configuration, it is better than nothing at all.
When a forced connection state has been set, there is no point handling
our RXSENSE interrupts, so disable them in this circumstance.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/gpu/drm/bridge/dw_hdmi.c | 51 ++++++++++++++++++++++++++++++++++++----
1 file changed, 47 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
index 0ee188930d26..2d1c7e4ec086 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -126,7 +126,9 @@ struct dw_hdmi {
bool sink_has_audio;
struct mutex mutex; /* for state below and previous_mode */
+ enum drm_connector_force force; /* mutex-protected force state */
bool disabled; /* DRM has disabled our bridge */
+ bool bridge_is_on; /* indicates the bridge is on */
spinlock_t audio_lock;
struct mutex audio_mutex;
@@ -1378,12 +1380,36 @@ static void initialize_hdmi_ih_mutes(struct dw_hdmi *hdmi)
static void dw_hdmi_poweron(struct dw_hdmi *hdmi)
{
+ hdmi->bridge_is_on = true;
dw_hdmi_setup(hdmi, &hdmi->previous_mode);
}
static void dw_hdmi_poweroff(struct dw_hdmi *hdmi)
{
dw_hdmi_phy_disable(hdmi);
+ hdmi->bridge_is_on = false;
+}
+
+static void dw_hdmi_update_power(struct dw_hdmi *hdmi)
+{
+ int force = hdmi->force;
+
+ if (hdmi->disabled) {
+ force = DRM_FORCE_OFF;
+ } else if (force == DRM_FORCE_UNSPECIFIED) {
+ if (hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD)
+ force = DRM_FORCE_ON;
+ else
+ force = DRM_FORCE_OFF;
+ }
+
+ if (force == DRM_FORCE_OFF) {
+ if (hdmi->bridge_is_on)
+ dw_hdmi_poweroff(hdmi);
+ } else {
+ if (!hdmi->bridge_is_on)
+ dw_hdmi_poweron(hdmi);
+ }
}
static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge,
@@ -1413,7 +1439,7 @@ static void dw_hdmi_bridge_disable(struct drm_bridge *bridge)
mutex_lock(&hdmi->mutex);
hdmi->disabled = true;
- dw_hdmi_poweroff(hdmi);
+ dw_hdmi_update_power(hdmi);
mutex_unlock(&hdmi->mutex);
}
@@ -1422,8 +1448,8 @@ static void dw_hdmi_bridge_enable(struct drm_bridge *bridge)
struct dw_hdmi *hdmi = bridge->driver_private;
mutex_lock(&hdmi->mutex);
- dw_hdmi_poweron(hdmi);
hdmi->disabled = false;
+ dw_hdmi_update_power(hdmi);
mutex_unlock(&hdmi->mutex);
}
@@ -1438,6 +1464,11 @@ dw_hdmi_connector_detect(struct drm_connector *connector, bool force)
struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
connector);
+ mutex_lock(&hdmi->mutex);
+ hdmi->force = DRM_FORCE_UNSPECIFIED;
+ dw_hdmi_update_power(hdmi);
+ mutex_unlock(&hdmi->mutex);
+
return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ?
connector_status_connected : connector_status_disconnected;
}
@@ -1502,11 +1533,23 @@ static void dw_hdmi_connector_destroy(struct drm_connector *connector)
drm_connector_cleanup(connector);
}
+static void dw_hdmi_connector_force(struct drm_connector *connector)
+{
+ struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
+ connector);
+
+ mutex_lock(&hdmi->mutex);
+ hdmi->force = connector->force;
+ dw_hdmi_update_power(hdmi);
+ mutex_unlock(&hdmi->mutex);
+}
+
static struct drm_connector_funcs dw_hdmi_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = dw_hdmi_connector_detect,
.destroy = dw_hdmi_connector_destroy,
+ .force = dw_hdmi_connector_force,
};
static struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = {
@@ -1552,12 +1595,12 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
if (phy_int_pol & HDMI_PHY_HPD) {
dev_dbg(hdmi->dev, "EVENT=plugin\n");
- if (!hdmi->disabled)
+ if (!hdmi->disabled && !hdmi->force)
dw_hdmi_poweron(hdmi);
} else {
dev_dbg(hdmi->dev, "EVENT=plugout\n");
- if (!hdmi->disabled)
+ if (!hdmi->disabled && !hdmi->force)
dw_hdmi_poweroff(hdmi);
}
mutex_unlock(&hdmi->mutex);
--
2.1.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Russell King <rmk+kernel@arm.linux.org.uk> |
|---|---|
| Date | 2015-08-08 18:20 +0200 |
| Subject | [PATCH 10/12] drm: bridge/dw_hdmi: fix phy enable/disable handling |
| Message-ID | <pVf0K-3Qj-29@gated-at.bofh.it> |
| In reply to | #1203293 |
The dw_hdmi enable/disable handling is particularly weak in several
regards:
* The hotplug interrupt could call hdmi_poweron() or hdmi_poweroff()
while DRM is setting a mode, which could race with a mode being set.
* Hotplug will always re-enable the phy whenever it detects an active
hotplug signal, even if DRM has disabled the output.
Resolve all of these by introducing a mutex to prevent races, and a
state-tracking bool so we know whether DRM wishes the output to be
enabled. We choose to use our own mutex rather than ->struct_mutex
so that we can still process interrupts in a timely fashion.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/gpu/drm/bridge/dw_hdmi.c | 29 ++++++++++++++++++++++-------
1 file changed, 22 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
index 7b8a4e942a71..0ee188930d26 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -125,6 +125,9 @@ struct dw_hdmi {
bool sink_is_hdmi;
bool sink_has_audio;
+ struct mutex mutex; /* for state below and previous_mode */
+ bool disabled; /* DRM has disabled our bridge */
+
spinlock_t audio_lock;
struct mutex audio_mutex;
unsigned int sample_rate;
@@ -1389,8 +1392,12 @@ static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge,
{
struct dw_hdmi *hdmi = bridge->driver_private;
+ mutex_lock(&hdmi->mutex);
+
/* Store the display mode for plugin/DKMS poweron events */
memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
+
+ mutex_unlock(&hdmi->mutex);
}
static bool dw_hdmi_bridge_mode_fixup(struct drm_bridge *bridge,
@@ -1404,14 +1411,20 @@ static void dw_hdmi_bridge_disable(struct drm_bridge *bridge)
{
struct dw_hdmi *hdmi = bridge->driver_private;
+ mutex_lock(&hdmi->mutex);
+ hdmi->disabled = true;
dw_hdmi_poweroff(hdmi);
+ mutex_unlock(&hdmi->mutex);
}
static void dw_hdmi_bridge_enable(struct drm_bridge *bridge)
{
struct dw_hdmi *hdmi = bridge->driver_private;
+ mutex_lock(&hdmi->mutex);
dw_hdmi_poweron(hdmi);
+ hdmi->disabled = false;
+ mutex_unlock(&hdmi->mutex);
}
static void dw_hdmi_bridge_nop(struct drm_bridge *bridge)
@@ -1534,20 +1547,20 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
phy_int_pol = hdmi_readb(hdmi, HDMI_PHY_POL0);
if (intr_stat & HDMI_IH_PHY_STAT0_HPD) {
+ hdmi_modb(hdmi, ~phy_int_pol, HDMI_PHY_HPD, HDMI_PHY_POL0);
+ mutex_lock(&hdmi->mutex);
if (phy_int_pol & HDMI_PHY_HPD) {
dev_dbg(hdmi->dev, "EVENT=plugin\n");
- hdmi_modb(hdmi, 0, HDMI_PHY_HPD, HDMI_PHY_POL0);
-
- dw_hdmi_poweron(hdmi);
+ if (!hdmi->disabled)
+ dw_hdmi_poweron(hdmi);
} else {
dev_dbg(hdmi->dev, "EVENT=plugout\n");
- hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD,
- HDMI_PHY_POL0);
-
- dw_hdmi_poweroff(hdmi);
+ if (!hdmi->disabled)
+ dw_hdmi_poweroff(hdmi);
}
+ mutex_unlock(&hdmi->mutex);
drm_helper_hpd_irq_event(hdmi->bridge->dev);
}
@@ -1617,7 +1630,9 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
hdmi->sample_rate = 48000;
hdmi->ratio = 100;
hdmi->encoder = encoder;
+ hdmi->disabled = true;
+ mutex_init(&hdmi->mutex);
mutex_init(&hdmi->audio_mutex);
spin_lock_init(&hdmi->audio_lock);
--
2.1.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Thierry Reding <thierry.reding@gmail.com> |
|---|---|
| Date | 2015-08-10 14:30 +0200 |
| Message-ID | <pVUng-6dN-17@gated-at.bofh.it> |
| In reply to | #1203293 |
[Multipart message — attachments visible in raw view] — view raw
On Sat, Aug 08, 2015 at 05:02:51PM +0100, Russell King - ARM Linux wrote: > This sub-series is a mixture of development: > > * Removing the incorrect pixel repetition configuration code > * Preventing pixel-doubled modes from being used > * Adding interlaced video support > * Implementing the sink_is_hdmi/sink_has_audio flags I suggested a few > months ago > * Only enabling audio support if the sink indicates it has audio > * Avoiding double-enabling the HDMI interface > * Fixing the mis-leading name of "dw_hdmi_phy_enable_power" > * Adding connector mode forcing (important if your monitor bounces > RXSENSE and HPD signals while in low-power mode.) > * Improving the HDMI enable/disabling on sink status > > For review (and testing if people feel like it). Acks/tested-bys etc > welcome. It applies on top of my drm-dwhdmi-devel branch, which is > waiting for David Airlie to pull (see pull request on dri-devel, 15th > July.) Hi Russell, I have in the past merged patches for the bridge subdirectory via the drm/panel tree, though lately much of the dw-hdmi patches have gone in via Philipp or you directly. This seems to have worked fine so far, but this time around I carry a patch to clean up Kconfig and Makefile a little and bring more consistency to the subdirectory and I think it's going to conflict with your series here (and potentially any ongoing work you have). Would you be open to me picking up these patches into the drm/panel tree? It feeds into linux-next, so the code would get some exposure before Dave's return. Thierry
[toc] | [prev] | [next] | [standalone]
| From | Russell King - ARM Linux <linux@arm.linux.org.uk> |
|---|---|
| Date | 2015-08-18 12:40 +0200 |
| Message-ID | <pYMtc-3yQ-21@gated-at.bofh.it> |
| In reply to | #1204220 |
On Mon, Aug 10, 2015 at 02:21:36PM +0200, Thierry Reding wrote: > On Sat, Aug 08, 2015 at 05:02:51PM +0100, Russell King - ARM Linux wrote: > > This sub-series is a mixture of development: > > > > * Removing the incorrect pixel repetition configuration code > > * Preventing pixel-doubled modes from being used > > * Adding interlaced video support > > * Implementing the sink_is_hdmi/sink_has_audio flags I suggested a few > > months ago > > * Only enabling audio support if the sink indicates it has audio > > * Avoiding double-enabling the HDMI interface > > * Fixing the mis-leading name of "dw_hdmi_phy_enable_power" > > * Adding connector mode forcing (important if your monitor bounces > > RXSENSE and HPD signals while in low-power mode.) > > * Improving the HDMI enable/disabling on sink status > > > > For review (and testing if people feel like it). Acks/tested-bys etc > > welcome. It applies on top of my drm-dwhdmi-devel branch, which is > > waiting for David Airlie to pull (see pull request on dri-devel, 15th > > July.) > > Hi Russell, > > I have in the past merged patches for the bridge subdirectory via the > drm/panel tree, though lately much of the dw-hdmi patches have gone in > via Philipp or you directly. This seems to have worked fine so far, but > this time around I carry a patch to clean up Kconfig and Makefile a > little and bring more consistency to the subdirectory and I think it's > going to conflict with your series here (and potentially any ongoing > work you have). > > Would you be open to me picking up these patches into the drm/panel > tree? It feeds into linux-next, so the code would get some exposure > before Dave's return. I haven't seen any acks or comments on this set of 12 patches yet which is rather disappointing. David has now returned, and as David hasn't pulled stuff from the 15th, my intention is to re-send that pull request, but with certain patches from this set included in that - patches 1, 2, 6, 7, 8, 9 and 10. I'll also include Vladimir Zapolskiy's "fix register I2CM_ADDRESS register name" patch in the set too. None of that touches the Makefile or Kconfig, so there shouldn't be any conflicts with your work. -- FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up according to speedtest.net. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [standalone]
Page 2 of 2 — ← Prev page 1 [2]
Back to top | Article view | linux.kernel
csiph-web