Commit 7ed6c665 authored by Russell King's avatar Russell King

drm: bridge/dw_hdmi-ahb-audio: add audio driver

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.
Reviewed-by: default avatarTakashi Iwai <tiwai@suse.de>
Tested-by: default avatarFabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent aeac23bd
...@@ -11,6 +11,17 @@ config DRM_DW_HDMI ...@@ -11,6 +11,17 @@ config DRM_DW_HDMI
tristate tristate
select DRM_KMS_HELPER 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_NXP_PTN3460 config DRM_NXP_PTN3460
tristate "NXP PTN3460 DP/LVDS bridge" tristate "NXP PTN3460 DP/LVDS bridge"
depends on OF depends on OF
......
ccflags-y := -Iinclude/drm ccflags-y := -Iinclude/drm
obj-$(CONFIG_DRM_DW_HDMI) += dw_hdmi.o obj-$(CONFIG_DRM_DW_HDMI) += dw_hdmi.o
obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw_hdmi-ahb-audio.o
obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o
This diff is collapsed.
#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
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <drm/bridge/dw_hdmi.h> #include <drm/bridge/dw_hdmi.h>
#include "dw_hdmi.h" #include "dw_hdmi.h"
#include "dw_hdmi-audio.h"
#define HDMI_EDID_LEN 512 #define HDMI_EDID_LEN 512
...@@ -104,6 +105,7 @@ struct dw_hdmi { ...@@ -104,6 +105,7 @@ struct dw_hdmi {
struct drm_encoder *encoder; struct drm_encoder *encoder;
struct drm_bridge *bridge; struct drm_bridge *bridge;
struct platform_device *audio;
enum dw_hdmi_devtype dev_type; enum dw_hdmi_devtype dev_type;
struct device *dev; struct device *dev;
struct clk *isfr_clk; struct clk *isfr_clk;
...@@ -1732,7 +1734,9 @@ int dw_hdmi_bind(struct device *dev, struct device *master, ...@@ -1732,7 +1734,9 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
{ {
struct drm_device *drm = data; struct drm_device *drm = data;
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
struct platform_device_info pdevinfo;
struct device_node *ddc_node; struct device_node *ddc_node;
struct dw_hdmi_audio_data audio;
struct dw_hdmi *hdmi; struct dw_hdmi *hdmi;
int ret; int ret;
u32 val = 1; u32 val = 1;
...@@ -1860,6 +1864,23 @@ int dw_hdmi_bind(struct device *dev, struct device *master, ...@@ -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_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE),
HDMI_IH_MUTE_PHY_STAT0); 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); dev_set_drvdata(dev, hdmi);
return 0; return 0;
...@@ -1877,6 +1898,9 @@ void dw_hdmi_unbind(struct device *dev, struct device *master, void *data) ...@@ -1877,6 +1898,9 @@ void dw_hdmi_unbind(struct device *dev, struct device *master, void *data)
{ {
struct dw_hdmi *hdmi = dev_get_drvdata(dev); struct dw_hdmi *hdmi = dev_get_drvdata(dev);
if (hdmi->audio && !IS_ERR(hdmi->audio))
platform_device_unregister(hdmi->audio);
/* Disable all interrupts */ /* Disable all interrupts */
hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0); hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
......
...@@ -545,6 +545,9 @@ ...@@ -545,6 +545,9 @@
#define HDMI_I2CM_FS_SCL_LCNT_0_ADDR 0x7E12 #define HDMI_I2CM_FS_SCL_LCNT_0_ADDR 0x7E12
enum { enum {
/* CONFIG1_ID field values */
HDMI_CONFIG1_AHB = 0x01,
/* IH_FC_INT2 field values */ /* IH_FC_INT2 field values */
HDMI_IH_FC_INT2_OVERFLOW_MASK = 0x03, HDMI_IH_FC_INT2_OVERFLOW_MASK = 0x03,
HDMI_IH_FC_INT2_LOW_PRIORITY_OVERFLOW = 0x02, HDMI_IH_FC_INT2_LOW_PRIORITY_OVERFLOW = 0x02,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment