Re: [PATCH 2/3] drm/vc4: Add HDMI audio support

2017-02-24 Thread Boris Brezillon
Hi Eric,

On Tue,  7 Feb 2017 13:07:02 -0800
Eric Anholt  wrote:

> +static int vc4_hdmi_audio_init(struct vc4_hdmi *hdmi)
> +{
> + struct snd_soc_dai_link *dai_link = &hdmi->audio.link;
> + struct snd_soc_card *card = &hdmi->audio.card;
> + struct device *dev = &hdmi->pdev->dev;
> + const __be32 *addr;
> + int ret;
> +
> + if (!of_find_property(dev->of_node, "dmas", NULL)) {
> + dev_warn(dev,
> +  "'dmas' DT property is missing, no HDMI audio\n");
> + return 0;
> + }
> +
> + /*
> +  * Get the physical address of VC4_HD_MAI_DATA. We need to retrieve
> +  * the bus address specified in the DT, because the physical address
> +  * (the one returned by platform_get_resource()) is not appropriate
> +  * for DMA transfers.
> +  * This VC/MMU should probably be exposed to avoid this kind of hacks.
> +  */
> + addr = of_get_address(dev->of_node, 1, NULL, NULL);
> + hdmi->audio.dma_data.addr = be32_to_cpup(addr) + VC4_HD_MAI_DATA;
> + hdmi->audio.dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
> + hdmi->audio.dma_data.maxburst = 2;
> +
> + ret = devm_snd_dmaengine_pcm_register(dev, &pcm_conf, 0);
> + if (ret) {
> + dev_err(dev, "Could not register PCM component: %d\n", ret);
> + return ret;
> + }
> +
> + ret = devm_snd_soc_register_component(dev, &vc4_hdmi_audio_cpu_dai_comp,
> +   &vc4_hdmi_audio_cpu_dai_drv, 1);
> + if (ret) {
> + dev_err(dev, "Could not register CPU DAI: %d\n", ret);
> + return ret;
> + }
> +
> + /* register codec and codec dai */
> + ret = snd_soc_register_codec(dev, &vc4_hdmi_audio_codec_drv,
> +  &vc4_hdmi_audio_codec_dai_drv, 1);
> + if (ret) {
> + dev_err(dev, "Could not register codec: %d\n", ret);
> + return ret;
> + }
> +
> + dai_link->name = "MAI";
> + dai_link->stream_name = "MAI PCM";
> + dai_link->codec_dai_name = vc4_hdmi_audio_codec_dai_drv.name;
> + dai_link->cpu_dai_name = dev_name(dev);
> + dai_link->codec_name = dev_name(dev);
> + dai_link->platform_name = dev_name(dev);
> +
> + card->dai_link = dai_link;
> + card->num_links = 1;
> + card->name = "vc4-hdmi-audio";

I know I'm the one who chose this name, but maybe we should just change
it for "vc4-hdmi", since audio is kind of implied here ;-).
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 2/3] drm/vc4: Add HDMI audio support

2017-02-07 Thread Eric Anholt
The HDMI encoder IP embeds all needed blocks to output audio, with a
custom DAI called MAI moving audio between the two parts of the HDMI
core.  This driver now exposes a sound card to let users stream audio
to their display.

Using the hdmi-codec driver has been considered here, but MAI meant
having to significantly rework hdmi-codec, and it would have left
little shared code with the I2S mode anyway.

The encoder requires that the audio be SPDIF-formatted frames only,
which alsalib will format-convert for us.

This patch is the combined work of Eric Anholt (initial register setup
with a separate dmaengine driver and using simple-audio-card) and
Boris Brezillon (moving it all into HDMI, massive debug to get it
actually working), and which Eric has the permission to release.

Signed-off-by: Eric Anholt 
---
 drivers/gpu/drm/vc4/Kconfig|   4 +
 drivers/gpu/drm/vc4/vc4_hdmi.c | 494 -
 drivers/gpu/drm/vc4/vc4_regs.h | 107 -
 3 files changed, 603 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/vc4/Kconfig b/drivers/gpu/drm/vc4/Kconfig
index e1517d07cb7d..973b4203c0b2 100644
--- a/drivers/gpu/drm/vc4/Kconfig
+++ b/drivers/gpu/drm/vc4/Kconfig
@@ -2,11 +2,15 @@ config DRM_VC4
tristate "Broadcom VC4 Graphics"
depends on ARCH_BCM2835 || COMPILE_TEST
depends on DRM
+   depends on SND && SND_SOC
depends on COMMON_CLK
select DRM_KMS_HELPER
select DRM_KMS_CMA_HELPER
select DRM_GEM_CMA_HELPER
select DRM_PANEL
+   select SND_PCM
+   select SND_PCM_ELD
+   select SND_SOC_GENERIC_DMAENGINE_PCM
select DRM_MIPI_DSI
help
  Choose this option if you have a system that has a Broadcom
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 93d5994f3a04..56c285253ee5 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -31,11 +31,27 @@
 #include "linux/clk.h"
 #include "linux/component.h"
 #include "linux/i2c.h"
+#include "linux/of_address.h"
 #include "linux/of_gpio.h"
 #include "linux/of_platform.h"
+#include "linux/rational.h"
+#include "sound/dmaengine_pcm.h"
+#include "sound/pcm_drm_eld.h"
+#include "sound/pcm_params.h"
+#include "sound/soc.h"
 #include "vc4_drv.h"
 #include "vc4_regs.h"
 
+/* HDMI audio information */
+struct vc4_hdmi_audio {
+   struct snd_soc_card card;
+   struct snd_soc_dai_link link;
+   int samplerate;
+   int channels;
+   struct snd_dmaengine_dai_dma_data dma_data;
+   struct snd_pcm_substream *substream;
+};
+
 /* General HDMI hardware state. */
 struct vc4_hdmi {
struct platform_device *pdev;
@@ -43,6 +59,8 @@ struct vc4_hdmi {
struct drm_encoder *encoder;
struct drm_connector *connector;
 
+   struct vc4_hdmi_audio audio;
+
struct i2c_adapter *ddc;
void __iomem *hdmicore_regs;
void __iomem *hd_regs;
@@ -98,6 +116,10 @@ static const struct {
HDMI_REG(VC4_HDMI_SW_RESET_CONTROL),
HDMI_REG(VC4_HDMI_HOTPLUG_INT),
HDMI_REG(VC4_HDMI_HOTPLUG),
+   HDMI_REG(VC4_HDMI_MAI_CHANNEL_MAP),
+   HDMI_REG(VC4_HDMI_MAI_CONFIG),
+   HDMI_REG(VC4_HDMI_MAI_FORMAT),
+   HDMI_REG(VC4_HDMI_AUDIO_PACKET_CONFIG),
HDMI_REG(VC4_HDMI_RAM_PACKET_CONFIG),
HDMI_REG(VC4_HDMI_HORZA),
HDMI_REG(VC4_HDMI_HORZB),
@@ -108,6 +130,7 @@ static const struct {
HDMI_REG(VC4_HDMI_VERTB0),
HDMI_REG(VC4_HDMI_VERTB1),
HDMI_REG(VC4_HDMI_TX_PHY_RESET_CTL),
+   HDMI_REG(VC4_HDMI_TX_PHY_CTL0),
 };
 
 static const struct {
@@ -116,6 +139,9 @@ static const struct {
 } hd_regs[] = {
HDMI_REG(VC4_HD_M_CTL),
HDMI_REG(VC4_HD_MAI_CTL),
+   HDMI_REG(VC4_HD_MAI_THR),
+   HDMI_REG(VC4_HD_MAI_FMT),
+   HDMI_REG(VC4_HD_MAI_SMP),
HDMI_REG(VC4_HD_VID_CTL),
HDMI_REG(VC4_HD_CSC_CTL),
HDMI_REG(VC4_HD_FRAME_COUNT),
@@ -215,6 +241,7 @@ static int vc4_hdmi_connector_get_modes(struct 
drm_connector *connector)
 
drm_mode_connector_update_edid_property(connector, edid);
ret = drm_add_edid_modes(connector, edid);
+   drm_edid_to_eld(connector, edid);
 
return ret;
 }
@@ -300,7 +327,7 @@ static void vc4_hdmi_write_infoframe(struct drm_encoder 
*encoder,
struct drm_device *dev = encoder->dev;
struct vc4_dev *vc4 = to_vc4_dev(dev);
u32 packet_id = frame->any.type - 0x80;
-   u32 packet_reg = VC4_HDMI_GCP_0 + VC4_HDMI_PACKET_STRIDE * packet_id;
+   u32 packet_reg = VC4_HDMI_RAM_PACKET(packet_id);
uint8_t buffer[VC4_HDMI_PACKET_STRIDE];
ssize_t len, i;
int ret;
@@ -381,6 +408,24 @@ static void vc4_hdmi_set_spd_infoframe(struct drm_encoder 
*encoder)
vc4_hdmi_write_infoframe(encoder, &frame);
 }
 
+static void vc4_hdmi_set_audio_infoframe(struct drm_encoder *encoder)
+{
+   struct drm_device *drm = encoder->dev;
+   struct vc4_dev *vc4 = drm-