Merge branch 'omapdss-hdmi-audio'
Merge OMAP DSS HDMI audio patches from Ricardo Neri
This commit is contained in:
commit
037983e61b
@ -47,6 +47,51 @@ flexible way to enable non-common multi-display configuration. In addition to
|
||||
modelling the hardware overlays, omapdss supports virtual overlays and overlay
|
||||
managers. These can be used when updating a display with CPU or system DMA.
|
||||
|
||||
omapdss driver support for audio
|
||||
--------------------------------
|
||||
There exist several display technologies and standards that support audio as
|
||||
well. Hence, it is relevant to update the DSS device driver to provide an audio
|
||||
interface that may be used by an audio driver or any other driver interested in
|
||||
the functionality.
|
||||
|
||||
The audio_enable function is intended to prepare the relevant
|
||||
IP for playback (e.g., enabling an audio FIFO, taking in/out of reset
|
||||
some IP, enabling companion chips, etc). It is intended to be called before
|
||||
audio_start. The audio_disable function performs the reverse operation and is
|
||||
intended to be called after audio_stop.
|
||||
|
||||
While a given DSS device driver may support audio, it is possible that for
|
||||
certain configurations audio is not supported (e.g., an HDMI display using a
|
||||
VESA video timing). The audio_supported function is intended to query whether
|
||||
the current configuration of the display supports audio.
|
||||
|
||||
The audio_config function is intended to configure all the relevant audio
|
||||
parameters of the display. In order to make the function independent of any
|
||||
specific DSS device driver, a struct omap_dss_audio is defined. Its purpose
|
||||
is to contain all the required parameters for audio configuration. At the
|
||||
moment, such structure contains pointers to IEC-60958 channel status word
|
||||
and CEA-861 audio infoframe structures. This should be enough to support
|
||||
HDMI and DisplayPort, as both are based on CEA-861 and IEC-60958.
|
||||
|
||||
The audio_enable/disable, audio_config and audio_supported functions could be
|
||||
implemented as functions that may sleep. Hence, they should not be called
|
||||
while holding a spinlock or a readlock.
|
||||
|
||||
The audio_start/audio_stop function is intended to effectively start/stop audio
|
||||
playback after the configuration has taken place. These functions are designed
|
||||
to be used in an atomic context. Hence, audio_start should return quickly and be
|
||||
called only after all the needed resources for audio playback (audio FIFOs,
|
||||
DMA channels, companion chips, etc) have been enabled to begin data transfers.
|
||||
audio_stop is designed to only stop the audio transfers. The resources used
|
||||
for playback are released using audio_disable.
|
||||
|
||||
The enum omap_dss_audio_state may be used to help the implementations of
|
||||
the interface to keep track of the audio state. The initial state is _DISABLED;
|
||||
then, the state transitions to _CONFIGURED, and then, when it is ready to
|
||||
play audio, to _ENABLED. The state _PLAYING is used when the audio is being
|
||||
rendered.
|
||||
|
||||
|
||||
Panel and controller drivers
|
||||
----------------------------
|
||||
|
||||
|
@ -68,6 +68,10 @@ config OMAP4_DSS_HDMI
|
||||
HDMI Interface. This adds the High Definition Multimedia Interface.
|
||||
See http://www.hdmi.org/ for HDMI specification.
|
||||
|
||||
config OMAP4_DSS_HDMI_AUDIO
|
||||
bool
|
||||
depends on OMAP4_DSS_HDMI
|
||||
|
||||
config OMAP2_DSS_SDI
|
||||
bool "SDI support"
|
||||
depends on ARCH_OMAP3
|
||||
|
@ -464,6 +464,14 @@ int omapdss_hdmi_read_edid(u8 *buf, int len);
|
||||
bool omapdss_hdmi_detect(void);
|
||||
int hdmi_panel_init(void);
|
||||
void hdmi_panel_exit(void);
|
||||
#ifdef CONFIG_OMAP4_DSS_HDMI_AUDIO
|
||||
int hdmi_audio_enable(void);
|
||||
void hdmi_audio_disable(void);
|
||||
int hdmi_audio_start(void);
|
||||
void hdmi_audio_stop(void);
|
||||
bool hdmi_mode_has_audio(void);
|
||||
int hdmi_audio_config(struct omap_dss_audio *audio);
|
||||
#endif
|
||||
|
||||
/* RFBI */
|
||||
int rfbi_init_platform_driver(void) __init;
|
||||
|
@ -568,13 +568,17 @@ static const struct ti_hdmi_ip_ops omap4_hdmi_functions = {
|
||||
.pll_enable = ti_hdmi_4xxx_pll_enable,
|
||||
.pll_disable = ti_hdmi_4xxx_pll_disable,
|
||||
.video_enable = ti_hdmi_4xxx_wp_video_start,
|
||||
.video_disable = ti_hdmi_4xxx_wp_video_stop,
|
||||
.dump_wrapper = ti_hdmi_4xxx_wp_dump,
|
||||
.dump_core = ti_hdmi_4xxx_core_dump,
|
||||
.dump_pll = ti_hdmi_4xxx_pll_dump,
|
||||
.dump_phy = ti_hdmi_4xxx_phy_dump,
|
||||
#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
|
||||
defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
|
||||
#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
|
||||
.audio_enable = ti_hdmi_4xxx_wp_audio_enable,
|
||||
.audio_disable = ti_hdmi_4xxx_wp_audio_disable,
|
||||
.audio_start = ti_hdmi_4xxx_audio_start,
|
||||
.audio_stop = ti_hdmi_4xxx_audio_stop,
|
||||
.audio_config = ti_hdmi_4xxx_audio_config,
|
||||
#endif
|
||||
|
||||
};
|
||||
|
@ -33,12 +33,6 @@
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/clk.h>
|
||||
#include <video/omapdss.h>
|
||||
#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
|
||||
defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include "ti_hdmi_4xxx_ip.h"
|
||||
#endif
|
||||
|
||||
#include "ti_hdmi.h"
|
||||
#include "dss.h"
|
||||
@ -324,7 +318,7 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
|
||||
|
||||
hdmi_compute_pll(dssdev, phy, &hdmi.ip_data.pll_data);
|
||||
|
||||
hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 0);
|
||||
hdmi.ip_data.ops->video_disable(&hdmi.ip_data);
|
||||
|
||||
/* config the PLL and PHY hdmi_set_pll_pwrfirst */
|
||||
r = hdmi.ip_data.ops->pll_enable(&hdmi.ip_data);
|
||||
@ -358,7 +352,9 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
|
||||
/* tv size */
|
||||
dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings);
|
||||
|
||||
hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 1);
|
||||
r = hdmi.ip_data.ops->video_enable(&hdmi.ip_data);
|
||||
if (r)
|
||||
goto err_vid_enable;
|
||||
|
||||
r = dss_mgr_enable(dssdev->manager);
|
||||
if (r)
|
||||
@ -367,7 +363,8 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
|
||||
return 0;
|
||||
|
||||
err_mgr_enable:
|
||||
hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 0);
|
||||
hdmi.ip_data.ops->video_disable(&hdmi.ip_data);
|
||||
err_vid_enable:
|
||||
hdmi.ip_data.ops->phy_disable(&hdmi.ip_data);
|
||||
hdmi.ip_data.ops->pll_disable(&hdmi.ip_data);
|
||||
err:
|
||||
@ -379,7 +376,7 @@ static void hdmi_power_off(struct omap_dss_device *dssdev)
|
||||
{
|
||||
dss_mgr_disable(dssdev->manager);
|
||||
|
||||
hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 0);
|
||||
hdmi.ip_data.ops->video_disable(&hdmi.ip_data);
|
||||
hdmi.ip_data.ops->phy_disable(&hdmi.ip_data);
|
||||
hdmi.ip_data.ops->pll_disable(&hdmi.ip_data);
|
||||
hdmi_runtime_put();
|
||||
@ -536,220 +533,6 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev)
|
||||
mutex_unlock(&hdmi.lock);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
|
||||
defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
|
||||
|
||||
static int hdmi_audio_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct platform_device *pdev = to_platform_device(codec->dev);
|
||||
struct hdmi_ip_data *ip_data = snd_soc_codec_get_drvdata(codec);
|
||||
int err = 0;
|
||||
|
||||
if (!(ip_data->ops) && !(ip_data->ops->audio_enable)) {
|
||||
dev_err(&pdev->dev, "Cannot enable/disable audio\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
ip_data->ops->audio_enable(ip_data, true);
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
ip_data->ops->audio_enable(ip_data, false);
|
||||
break;
|
||||
default:
|
||||
err = -EINVAL;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int hdmi_audio_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct hdmi_ip_data *ip_data = snd_soc_codec_get_drvdata(codec);
|
||||
struct hdmi_audio_format audio_format;
|
||||
struct hdmi_audio_dma audio_dma;
|
||||
struct hdmi_core_audio_config core_cfg;
|
||||
struct hdmi_core_infoframe_audio aud_if_cfg;
|
||||
int err, n, cts;
|
||||
enum hdmi_core_audio_sample_freq sample_freq;
|
||||
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
core_cfg.i2s_cfg.word_max_length =
|
||||
HDMI_AUDIO_I2S_MAX_WORD_20BITS;
|
||||
core_cfg.i2s_cfg.word_length = HDMI_AUDIO_I2S_CHST_WORD_16_BITS;
|
||||
core_cfg.i2s_cfg.in_length_bits =
|
||||
HDMI_AUDIO_I2S_INPUT_LENGTH_16;
|
||||
core_cfg.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_LEFT;
|
||||
audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_TWOSAMPLES;
|
||||
audio_format.sample_size = HDMI_AUDIO_SAMPLE_16BITS;
|
||||
audio_format.justification = HDMI_AUDIO_JUSTIFY_LEFT;
|
||||
audio_dma.transfer_size = 0x10;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S24_LE:
|
||||
core_cfg.i2s_cfg.word_max_length =
|
||||
HDMI_AUDIO_I2S_MAX_WORD_24BITS;
|
||||
core_cfg.i2s_cfg.word_length = HDMI_AUDIO_I2S_CHST_WORD_24_BITS;
|
||||
core_cfg.i2s_cfg.in_length_bits =
|
||||
HDMI_AUDIO_I2S_INPUT_LENGTH_24;
|
||||
audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_ONESAMPLE;
|
||||
audio_format.sample_size = HDMI_AUDIO_SAMPLE_24BITS;
|
||||
audio_format.justification = HDMI_AUDIO_JUSTIFY_RIGHT;
|
||||
core_cfg.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_RIGHT;
|
||||
audio_dma.transfer_size = 0x20;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (params_rate(params)) {
|
||||
case 32000:
|
||||
sample_freq = HDMI_AUDIO_FS_32000;
|
||||
break;
|
||||
case 44100:
|
||||
sample_freq = HDMI_AUDIO_FS_44100;
|
||||
break;
|
||||
case 48000:
|
||||
sample_freq = HDMI_AUDIO_FS_48000;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = hdmi_config_audio_acr(ip_data, params_rate(params), &n, &cts);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* Audio wrapper config */
|
||||
audio_format.stereo_channels = HDMI_AUDIO_STEREO_ONECHANNEL;
|
||||
audio_format.active_chnnls_msk = 0x03;
|
||||
audio_format.type = HDMI_AUDIO_TYPE_LPCM;
|
||||
audio_format.sample_order = HDMI_AUDIO_SAMPLE_LEFT_FIRST;
|
||||
/* Disable start/stop signals of IEC 60958 blocks */
|
||||
audio_format.en_sig_blk_strt_end = HDMI_AUDIO_BLOCK_SIG_STARTEND_OFF;
|
||||
|
||||
audio_dma.block_size = 0xC0;
|
||||
audio_dma.mode = HDMI_AUDIO_TRANSF_DMA;
|
||||
audio_dma.fifo_threshold = 0x20; /* in number of samples */
|
||||
|
||||
hdmi_wp_audio_config_dma(ip_data, &audio_dma);
|
||||
hdmi_wp_audio_config_format(ip_data, &audio_format);
|
||||
|
||||
/*
|
||||
* I2S config
|
||||
*/
|
||||
core_cfg.i2s_cfg.en_high_bitrate_aud = false;
|
||||
/* Only used with high bitrate audio */
|
||||
core_cfg.i2s_cfg.cbit_order = false;
|
||||
/* Serial data and word select should change on sck rising edge */
|
||||
core_cfg.i2s_cfg.sck_edge_mode = HDMI_AUDIO_I2S_SCK_EDGE_RISING;
|
||||
core_cfg.i2s_cfg.vbit = HDMI_AUDIO_I2S_VBIT_FOR_PCM;
|
||||
/* Set I2S word select polarity */
|
||||
core_cfg.i2s_cfg.ws_polarity = HDMI_AUDIO_I2S_WS_POLARITY_LOW_IS_LEFT;
|
||||
core_cfg.i2s_cfg.direction = HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST;
|
||||
/* Set serial data to word select shift. See Phillips spec. */
|
||||
core_cfg.i2s_cfg.shift = HDMI_AUDIO_I2S_FIRST_BIT_SHIFT;
|
||||
/* Enable one of the four available serial data channels */
|
||||
core_cfg.i2s_cfg.active_sds = HDMI_AUDIO_I2S_SD0_EN;
|
||||
|
||||
/* Core audio config */
|
||||
core_cfg.freq_sample = sample_freq;
|
||||
core_cfg.n = n;
|
||||
core_cfg.cts = cts;
|
||||
if (dss_has_feature(FEAT_HDMI_CTS_SWMODE)) {
|
||||
core_cfg.aud_par_busclk = 0;
|
||||
core_cfg.cts_mode = HDMI_AUDIO_CTS_MODE_SW;
|
||||
core_cfg.use_mclk = dss_has_feature(FEAT_HDMI_AUDIO_USE_MCLK);
|
||||
} else {
|
||||
core_cfg.aud_par_busclk = (((128 * 31) - 1) << 8);
|
||||
core_cfg.cts_mode = HDMI_AUDIO_CTS_MODE_HW;
|
||||
core_cfg.use_mclk = true;
|
||||
}
|
||||
|
||||
if (core_cfg.use_mclk)
|
||||
core_cfg.mclk_mode = HDMI_AUDIO_MCLK_128FS;
|
||||
core_cfg.layout = HDMI_AUDIO_LAYOUT_2CH;
|
||||
core_cfg.en_spdif = false;
|
||||
/* Use sample frequency from channel status word */
|
||||
core_cfg.fs_override = true;
|
||||
/* Enable ACR packets */
|
||||
core_cfg.en_acr_pkt = true;
|
||||
/* Disable direct streaming digital audio */
|
||||
core_cfg.en_dsd_audio = false;
|
||||
/* Use parallel audio interface */
|
||||
core_cfg.en_parallel_aud_input = true;
|
||||
|
||||
hdmi_core_audio_config(ip_data, &core_cfg);
|
||||
|
||||
/*
|
||||
* Configure packet
|
||||
* info frame audio see doc CEA861-D page 74
|
||||
*/
|
||||
aud_if_cfg.db1_coding_type = HDMI_INFOFRAME_AUDIO_DB1CT_FROM_STREAM;
|
||||
aud_if_cfg.db1_channel_count = 2;
|
||||
aud_if_cfg.db2_sample_freq = HDMI_INFOFRAME_AUDIO_DB2SF_FROM_STREAM;
|
||||
aud_if_cfg.db2_sample_size = HDMI_INFOFRAME_AUDIO_DB2SS_FROM_STREAM;
|
||||
aud_if_cfg.db4_channel_alloc = 0x00;
|
||||
aud_if_cfg.db5_downmix_inh = false;
|
||||
aud_if_cfg.db5_lsv = 0;
|
||||
|
||||
hdmi_core_audio_infoframe_config(ip_data, &aud_if_cfg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hdmi_audio_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
if (!hdmi.ip_data.cfg.cm.mode) {
|
||||
pr_err("Current video settings do not support audio.\n");
|
||||
return -EIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hdmi_audio_codec_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct hdmi_ip_data *priv = &hdmi.ip_data;
|
||||
|
||||
snd_soc_codec_set_drvdata(codec, priv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver hdmi_audio_codec_drv = {
|
||||
.probe = hdmi_audio_codec_probe,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_ops hdmi_audio_codec_ops = {
|
||||
.hw_params = hdmi_audio_hw_params,
|
||||
.trigger = hdmi_audio_trigger,
|
||||
.startup = hdmi_audio_startup,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver hdmi_codec_dai_drv = {
|
||||
.name = "hdmi-audio-codec",
|
||||
.playback = {
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_32000 |
|
||||
SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_LE,
|
||||
},
|
||||
.ops = &hdmi_audio_codec_ops,
|
||||
};
|
||||
#endif
|
||||
|
||||
static int hdmi_get_clocks(struct platform_device *pdev)
|
||||
{
|
||||
struct clk *clk;
|
||||
@ -771,6 +554,150 @@ static void hdmi_put_clocks(void)
|
||||
clk_put(hdmi.sys_clk);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
|
||||
int hdmi_compute_acr(u32 sample_freq, u32 *n, u32 *cts)
|
||||
{
|
||||
u32 deep_color;
|
||||
bool deep_color_correct = false;
|
||||
u32 pclk = hdmi.ip_data.cfg.timings.pixel_clock;
|
||||
|
||||
if (n == NULL || cts == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
/* TODO: When implemented, query deep color mode here. */
|
||||
deep_color = 100;
|
||||
|
||||
/*
|
||||
* When using deep color, the default N value (as in the HDMI
|
||||
* specification) yields to an non-integer CTS. Hence, we
|
||||
* modify it while keeping the restrictions described in
|
||||
* section 7.2.1 of the HDMI 1.4a specification.
|
||||
*/
|
||||
switch (sample_freq) {
|
||||
case 32000:
|
||||
case 48000:
|
||||
case 96000:
|
||||
case 192000:
|
||||
if (deep_color == 125)
|
||||
if (pclk == 27027 || pclk == 74250)
|
||||
deep_color_correct = true;
|
||||
if (deep_color == 150)
|
||||
if (pclk == 27027)
|
||||
deep_color_correct = true;
|
||||
break;
|
||||
case 44100:
|
||||
case 88200:
|
||||
case 176400:
|
||||
if (deep_color == 125)
|
||||
if (pclk == 27027)
|
||||
deep_color_correct = true;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (deep_color_correct) {
|
||||
switch (sample_freq) {
|
||||
case 32000:
|
||||
*n = 8192;
|
||||
break;
|
||||
case 44100:
|
||||
*n = 12544;
|
||||
break;
|
||||
case 48000:
|
||||
*n = 8192;
|
||||
break;
|
||||
case 88200:
|
||||
*n = 25088;
|
||||
break;
|
||||
case 96000:
|
||||
*n = 16384;
|
||||
break;
|
||||
case 176400:
|
||||
*n = 50176;
|
||||
break;
|
||||
case 192000:
|
||||
*n = 32768;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
switch (sample_freq) {
|
||||
case 32000:
|
||||
*n = 4096;
|
||||
break;
|
||||
case 44100:
|
||||
*n = 6272;
|
||||
break;
|
||||
case 48000:
|
||||
*n = 6144;
|
||||
break;
|
||||
case 88200:
|
||||
*n = 12544;
|
||||
break;
|
||||
case 96000:
|
||||
*n = 12288;
|
||||
break;
|
||||
case 176400:
|
||||
*n = 25088;
|
||||
break;
|
||||
case 192000:
|
||||
*n = 24576;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
/* Calculate CTS. See HDMI 1.3a or 1.4a specifications */
|
||||
*cts = pclk * (*n / 128) * deep_color / (sample_freq / 10);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hdmi_audio_enable(void)
|
||||
{
|
||||
DSSDBG("audio_enable\n");
|
||||
|
||||
return hdmi.ip_data.ops->audio_enable(&hdmi.ip_data);
|
||||
}
|
||||
|
||||
void hdmi_audio_disable(void)
|
||||
{
|
||||
DSSDBG("audio_disable\n");
|
||||
|
||||
hdmi.ip_data.ops->audio_disable(&hdmi.ip_data);
|
||||
}
|
||||
|
||||
int hdmi_audio_start(void)
|
||||
{
|
||||
DSSDBG("audio_start\n");
|
||||
|
||||
return hdmi.ip_data.ops->audio_start(&hdmi.ip_data);
|
||||
}
|
||||
|
||||
void hdmi_audio_stop(void)
|
||||
{
|
||||
DSSDBG("audio_stop\n");
|
||||
|
||||
hdmi.ip_data.ops->audio_stop(&hdmi.ip_data);
|
||||
}
|
||||
|
||||
bool hdmi_mode_has_audio(void)
|
||||
{
|
||||
if (hdmi.ip_data.cfg.cm.mode == HDMI_HDMI)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
int hdmi_audio_config(struct omap_dss_audio *audio)
|
||||
{
|
||||
return hdmi.ip_data.ops->audio_config(&hdmi.ip_data, audio);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void __init hdmi_probe_pdata(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
|
||||
@ -838,17 +765,6 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev)
|
||||
|
||||
hdmi_probe_pdata(pdev);
|
||||
|
||||
#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
|
||||
defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
|
||||
|
||||
/* Register ASoC codec DAI */
|
||||
r = snd_soc_register_codec(&pdev->dev, &hdmi_audio_codec_drv,
|
||||
&hdmi_codec_dai_drv, 1);
|
||||
if (r) {
|
||||
DSSERR("can't register ASoC HDMI audio codec\n");
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -858,11 +774,6 @@ static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
|
||||
|
||||
hdmi_panel_exit();
|
||||
|
||||
#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
|
||||
defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
#endif
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
hdmi_put_clocks();
|
||||
|
@ -30,7 +30,12 @@
|
||||
#include "dss.h"
|
||||
|
||||
static struct {
|
||||
struct mutex hdmi_lock;
|
||||
/* This protects the panel ops, mainly when accessing the HDMI IP. */
|
||||
struct mutex lock;
|
||||
#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
|
||||
/* This protects the audio ops, specifically. */
|
||||
spinlock_t audio_lock;
|
||||
#endif
|
||||
} hdmi;
|
||||
|
||||
|
||||
@ -54,12 +59,168 @@ static void hdmi_panel_remove(struct omap_dss_device *dssdev)
|
||||
|
||||
}
|
||||
|
||||
#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
|
||||
static int hdmi_panel_audio_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
unsigned long flags;
|
||||
int r;
|
||||
|
||||
mutex_lock(&hdmi.lock);
|
||||
spin_lock_irqsave(&hdmi.audio_lock, flags);
|
||||
|
||||
/* enable audio only if the display is active and supports audio */
|
||||
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE ||
|
||||
!hdmi_mode_has_audio()) {
|
||||
DSSERR("audio not supported or display is off\n");
|
||||
r = -EPERM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
r = hdmi_audio_enable();
|
||||
|
||||
if (!r)
|
||||
dssdev->audio_state = OMAP_DSS_AUDIO_ENABLED;
|
||||
|
||||
err:
|
||||
spin_unlock_irqrestore(&hdmi.audio_lock, flags);
|
||||
mutex_unlock(&hdmi.lock);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void hdmi_panel_audio_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&hdmi.audio_lock, flags);
|
||||
|
||||
hdmi_audio_disable();
|
||||
|
||||
dssdev->audio_state = OMAP_DSS_AUDIO_DISABLED;
|
||||
|
||||
spin_unlock_irqrestore(&hdmi.audio_lock, flags);
|
||||
}
|
||||
|
||||
static int hdmi_panel_audio_start(struct omap_dss_device *dssdev)
|
||||
{
|
||||
unsigned long flags;
|
||||
int r;
|
||||
|
||||
spin_lock_irqsave(&hdmi.audio_lock, flags);
|
||||
/*
|
||||
* No need to check the panel state. It was checked when trasitioning
|
||||
* to AUDIO_ENABLED.
|
||||
*/
|
||||
if (dssdev->audio_state != OMAP_DSS_AUDIO_ENABLED) {
|
||||
DSSERR("audio start from invalid state\n");
|
||||
r = -EPERM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
r = hdmi_audio_start();
|
||||
|
||||
if (!r)
|
||||
dssdev->audio_state = OMAP_DSS_AUDIO_PLAYING;
|
||||
|
||||
err:
|
||||
spin_unlock_irqrestore(&hdmi.audio_lock, flags);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void hdmi_panel_audio_stop(struct omap_dss_device *dssdev)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&hdmi.audio_lock, flags);
|
||||
|
||||
hdmi_audio_stop();
|
||||
dssdev->audio_state = OMAP_DSS_AUDIO_ENABLED;
|
||||
|
||||
spin_unlock_irqrestore(&hdmi.audio_lock, flags);
|
||||
}
|
||||
|
||||
static bool hdmi_panel_audio_supported(struct omap_dss_device *dssdev)
|
||||
{
|
||||
bool r = false;
|
||||
|
||||
mutex_lock(&hdmi.lock);
|
||||
|
||||
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
|
||||
goto err;
|
||||
|
||||
if (!hdmi_mode_has_audio())
|
||||
goto err;
|
||||
|
||||
r = true;
|
||||
err:
|
||||
mutex_unlock(&hdmi.lock);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int hdmi_panel_audio_config(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_audio *audio)
|
||||
{
|
||||
unsigned long flags;
|
||||
int r;
|
||||
|
||||
mutex_lock(&hdmi.lock);
|
||||
spin_lock_irqsave(&hdmi.audio_lock, flags);
|
||||
|
||||
/* config audio only if the display is active and supports audio */
|
||||
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE ||
|
||||
!hdmi_mode_has_audio()) {
|
||||
DSSERR("audio not supported or display is off\n");
|
||||
r = -EPERM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
r = hdmi_audio_config(audio);
|
||||
|
||||
if (!r)
|
||||
dssdev->audio_state = OMAP_DSS_AUDIO_CONFIGURED;
|
||||
|
||||
err:
|
||||
spin_unlock_irqrestore(&hdmi.audio_lock, flags);
|
||||
mutex_unlock(&hdmi.lock);
|
||||
return r;
|
||||
}
|
||||
|
||||
#else
|
||||
static int hdmi_panel_audio_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
static void hdmi_panel_audio_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
}
|
||||
|
||||
static int hdmi_panel_audio_start(struct omap_dss_device *dssdev)
|
||||
{
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
static void hdmi_panel_audio_stop(struct omap_dss_device *dssdev)
|
||||
{
|
||||
}
|
||||
|
||||
static bool hdmi_panel_audio_supported(struct omap_dss_device *dssdev)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static int hdmi_panel_audio_config(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_audio *audio)
|
||||
{
|
||||
return -EPERM;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int hdmi_panel_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
int r = 0;
|
||||
DSSDBG("ENTER hdmi_panel_enable\n");
|
||||
|
||||
mutex_lock(&hdmi.hdmi_lock);
|
||||
mutex_lock(&hdmi.lock);
|
||||
|
||||
if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
|
||||
r = -EINVAL;
|
||||
@ -75,40 +236,52 @@ static int hdmi_panel_enable(struct omap_dss_device *dssdev)
|
||||
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||||
|
||||
err:
|
||||
mutex_unlock(&hdmi.hdmi_lock);
|
||||
mutex_unlock(&hdmi.lock);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void hdmi_panel_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
mutex_lock(&hdmi.hdmi_lock);
|
||||
mutex_lock(&hdmi.lock);
|
||||
|
||||
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
|
||||
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
|
||||
/*
|
||||
* TODO: notify audio users that the display was disabled. For
|
||||
* now, disable audio locally to not break our audio state
|
||||
* machine.
|
||||
*/
|
||||
hdmi_panel_audio_disable(dssdev);
|
||||
omapdss_hdmi_display_disable(dssdev);
|
||||
}
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
|
||||
mutex_unlock(&hdmi.hdmi_lock);
|
||||
mutex_unlock(&hdmi.lock);
|
||||
}
|
||||
|
||||
static int hdmi_panel_suspend(struct omap_dss_device *dssdev)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
mutex_lock(&hdmi.hdmi_lock);
|
||||
mutex_lock(&hdmi.lock);
|
||||
|
||||
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
|
||||
r = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
|
||||
/*
|
||||
* TODO: notify audio users that the display was suspended. For now,
|
||||
* disable audio locally to not break our audio state machine.
|
||||
*/
|
||||
hdmi_panel_audio_disable(dssdev);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
|
||||
omapdss_hdmi_display_disable(dssdev);
|
||||
|
||||
err:
|
||||
mutex_unlock(&hdmi.hdmi_lock);
|
||||
mutex_unlock(&hdmi.lock);
|
||||
|
||||
return r;
|
||||
}
|
||||
@ -117,7 +290,7 @@ static int hdmi_panel_resume(struct omap_dss_device *dssdev)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
mutex_lock(&hdmi.hdmi_lock);
|
||||
mutex_lock(&hdmi.lock);
|
||||
|
||||
if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) {
|
||||
r = -EINVAL;
|
||||
@ -129,11 +302,12 @@ static int hdmi_panel_resume(struct omap_dss_device *dssdev)
|
||||
DSSERR("failed to power on\n");
|
||||
goto err;
|
||||
}
|
||||
/* TODO: notify audio users that the panel resumed. */
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||||
|
||||
err:
|
||||
mutex_unlock(&hdmi.hdmi_lock);
|
||||
mutex_unlock(&hdmi.lock);
|
||||
|
||||
return r;
|
||||
}
|
||||
@ -141,11 +315,11 @@ err:
|
||||
static void hdmi_get_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
mutex_lock(&hdmi.hdmi_lock);
|
||||
mutex_lock(&hdmi.lock);
|
||||
|
||||
*timings = dssdev->panel.timings;
|
||||
|
||||
mutex_unlock(&hdmi.hdmi_lock);
|
||||
mutex_unlock(&hdmi.lock);
|
||||
}
|
||||
|
||||
static void hdmi_set_timings(struct omap_dss_device *dssdev,
|
||||
@ -153,12 +327,18 @@ static void hdmi_set_timings(struct omap_dss_device *dssdev,
|
||||
{
|
||||
DSSDBG("hdmi_set_timings\n");
|
||||
|
||||
mutex_lock(&hdmi.hdmi_lock);
|
||||
mutex_lock(&hdmi.lock);
|
||||
|
||||
/*
|
||||
* TODO: notify audio users that there was a timings change. For
|
||||
* now, disable audio locally to not break our audio state machine.
|
||||
*/
|
||||
hdmi_panel_audio_disable(dssdev);
|
||||
|
||||
dssdev->panel.timings = *timings;
|
||||
omapdss_hdmi_display_set_timing(dssdev);
|
||||
|
||||
mutex_unlock(&hdmi.hdmi_lock);
|
||||
mutex_unlock(&hdmi.lock);
|
||||
}
|
||||
|
||||
static int hdmi_check_timings(struct omap_dss_device *dssdev,
|
||||
@ -168,11 +348,11 @@ static int hdmi_check_timings(struct omap_dss_device *dssdev,
|
||||
|
||||
DSSDBG("hdmi_check_timings\n");
|
||||
|
||||
mutex_lock(&hdmi.hdmi_lock);
|
||||
mutex_lock(&hdmi.lock);
|
||||
|
||||
r = omapdss_hdmi_display_check_timing(dssdev, timings);
|
||||
|
||||
mutex_unlock(&hdmi.hdmi_lock);
|
||||
mutex_unlock(&hdmi.lock);
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -180,7 +360,7 @@ static int hdmi_read_edid(struct omap_dss_device *dssdev, u8 *buf, int len)
|
||||
{
|
||||
int r;
|
||||
|
||||
mutex_lock(&hdmi.hdmi_lock);
|
||||
mutex_lock(&hdmi.lock);
|
||||
|
||||
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
|
||||
r = omapdss_hdmi_display_enable(dssdev);
|
||||
@ -194,7 +374,7 @@ static int hdmi_read_edid(struct omap_dss_device *dssdev, u8 *buf, int len)
|
||||
dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
|
||||
omapdss_hdmi_display_disable(dssdev);
|
||||
err:
|
||||
mutex_unlock(&hdmi.hdmi_lock);
|
||||
mutex_unlock(&hdmi.lock);
|
||||
|
||||
return r;
|
||||
}
|
||||
@ -203,7 +383,7 @@ static bool hdmi_detect(struct omap_dss_device *dssdev)
|
||||
{
|
||||
int r;
|
||||
|
||||
mutex_lock(&hdmi.hdmi_lock);
|
||||
mutex_lock(&hdmi.lock);
|
||||
|
||||
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
|
||||
r = omapdss_hdmi_display_enable(dssdev);
|
||||
@ -217,7 +397,7 @@ static bool hdmi_detect(struct omap_dss_device *dssdev)
|
||||
dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
|
||||
omapdss_hdmi_display_disable(dssdev);
|
||||
err:
|
||||
mutex_unlock(&hdmi.hdmi_lock);
|
||||
mutex_unlock(&hdmi.lock);
|
||||
|
||||
return r;
|
||||
}
|
||||
@ -234,6 +414,12 @@ static struct omap_dss_driver hdmi_driver = {
|
||||
.check_timings = hdmi_check_timings,
|
||||
.read_edid = hdmi_read_edid,
|
||||
.detect = hdmi_detect,
|
||||
.audio_enable = hdmi_panel_audio_enable,
|
||||
.audio_disable = hdmi_panel_audio_disable,
|
||||
.audio_start = hdmi_panel_audio_start,
|
||||
.audio_stop = hdmi_panel_audio_stop,
|
||||
.audio_supported = hdmi_panel_audio_supported,
|
||||
.audio_config = hdmi_panel_audio_config,
|
||||
.driver = {
|
||||
.name = "hdmi_panel",
|
||||
.owner = THIS_MODULE,
|
||||
@ -242,7 +428,11 @@ static struct omap_dss_driver hdmi_driver = {
|
||||
|
||||
int hdmi_panel_init(void)
|
||||
{
|
||||
mutex_init(&hdmi.hdmi_lock);
|
||||
mutex_init(&hdmi.lock);
|
||||
|
||||
#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
|
||||
spin_lock_init(&hdmi.audio_lock);
|
||||
#endif
|
||||
|
||||
omap_dss_register_driver(&hdmi_driver);
|
||||
|
||||
|
@ -96,7 +96,9 @@ struct ti_hdmi_ip_ops {
|
||||
|
||||
void (*pll_disable)(struct hdmi_ip_data *ip_data);
|
||||
|
||||
void (*video_enable)(struct hdmi_ip_data *ip_data, bool start);
|
||||
int (*video_enable)(struct hdmi_ip_data *ip_data);
|
||||
|
||||
void (*video_disable)(struct hdmi_ip_data *ip_data);
|
||||
|
||||
void (*dump_wrapper)(struct hdmi_ip_data *ip_data, struct seq_file *s);
|
||||
|
||||
@ -106,9 +108,17 @@ struct ti_hdmi_ip_ops {
|
||||
|
||||
void (*dump_phy)(struct hdmi_ip_data *ip_data, struct seq_file *s);
|
||||
|
||||
#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
|
||||
defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
|
||||
void (*audio_enable)(struct hdmi_ip_data *ip_data, bool start);
|
||||
#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
|
||||
int (*audio_enable)(struct hdmi_ip_data *ip_data);
|
||||
|
||||
void (*audio_disable)(struct hdmi_ip_data *ip_data);
|
||||
|
||||
int (*audio_start)(struct hdmi_ip_data *ip_data);
|
||||
|
||||
void (*audio_stop)(struct hdmi_ip_data *ip_data);
|
||||
|
||||
int (*audio_config)(struct hdmi_ip_data *ip_data,
|
||||
struct omap_dss_audio *audio);
|
||||
#endif
|
||||
|
||||
};
|
||||
@ -173,7 +183,8 @@ int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data);
|
||||
void ti_hdmi_4xxx_phy_disable(struct hdmi_ip_data *ip_data);
|
||||
int ti_hdmi_4xxx_read_edid(struct hdmi_ip_data *ip_data, u8 *edid, int len);
|
||||
bool ti_hdmi_4xxx_detect(struct hdmi_ip_data *ip_data);
|
||||
void ti_hdmi_4xxx_wp_video_start(struct hdmi_ip_data *ip_data, bool start);
|
||||
int ti_hdmi_4xxx_wp_video_start(struct hdmi_ip_data *ip_data);
|
||||
void ti_hdmi_4xxx_wp_video_stop(struct hdmi_ip_data *ip_data);
|
||||
int ti_hdmi_4xxx_pll_enable(struct hdmi_ip_data *ip_data);
|
||||
void ti_hdmi_4xxx_pll_disable(struct hdmi_ip_data *ip_data);
|
||||
void ti_hdmi_4xxx_basic_configure(struct hdmi_ip_data *ip_data);
|
||||
@ -181,8 +192,13 @@ void ti_hdmi_4xxx_wp_dump(struct hdmi_ip_data *ip_data, struct seq_file *s);
|
||||
void ti_hdmi_4xxx_pll_dump(struct hdmi_ip_data *ip_data, struct seq_file *s);
|
||||
void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s);
|
||||
void ti_hdmi_4xxx_phy_dump(struct hdmi_ip_data *ip_data, struct seq_file *s);
|
||||
#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
|
||||
defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
|
||||
void ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data, bool enable);
|
||||
#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
|
||||
int hdmi_compute_acr(u32 sample_freq, u32 *n, u32 *cts);
|
||||
int ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data);
|
||||
void ti_hdmi_4xxx_wp_audio_disable(struct hdmi_ip_data *ip_data);
|
||||
int ti_hdmi_4xxx_audio_start(struct hdmi_ip_data *ip_data);
|
||||
void ti_hdmi_4xxx_audio_stop(struct hdmi_ip_data *ip_data);
|
||||
int ti_hdmi_4xxx_audio_config(struct hdmi_ip_data *ip_data,
|
||||
struct omap_dss_audio *audio);
|
||||
#endif
|
||||
#endif
|
||||
|
@ -29,9 +29,14 @@
|
||||
#include <linux/string.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/gpio.h>
|
||||
#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
|
||||
#include <sound/asound.h>
|
||||
#include <sound/asoundef.h>
|
||||
#endif
|
||||
|
||||
#include "ti_hdmi_4xxx_ip.h"
|
||||
#include "dss.h"
|
||||
#include "dss_features.h"
|
||||
|
||||
static inline void hdmi_write_reg(void __iomem *base_addr,
|
||||
const u16 idx, u32 val)
|
||||
@ -699,9 +704,15 @@ static void hdmi_wp_init(struct omap_video_timings *timings,
|
||||
|
||||
}
|
||||
|
||||
void ti_hdmi_4xxx_wp_video_start(struct hdmi_ip_data *ip_data, bool start)
|
||||
int ti_hdmi_4xxx_wp_video_start(struct hdmi_ip_data *ip_data)
|
||||
{
|
||||
REG_FLD_MOD(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG, start, 31, 31);
|
||||
REG_FLD_MOD(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG, true, 31, 31);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ti_hdmi_4xxx_wp_video_stop(struct hdmi_ip_data *ip_data)
|
||||
{
|
||||
REG_FLD_MOD(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG, false, 31, 31);
|
||||
}
|
||||
|
||||
static void hdmi_wp_video_init_format(struct hdmi_video_format *video_fmt,
|
||||
@ -1014,9 +1025,8 @@ void ti_hdmi_4xxx_phy_dump(struct hdmi_ip_data *ip_data, struct seq_file *s)
|
||||
DUMPPHY(HDMI_TXPHY_PAD_CFG_CTRL);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
|
||||
defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
|
||||
void hdmi_wp_audio_config_format(struct hdmi_ip_data *ip_data,
|
||||
#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
|
||||
static void ti_hdmi_4xxx_wp_audio_config_format(struct hdmi_ip_data *ip_data,
|
||||
struct hdmi_audio_format *aud_fmt)
|
||||
{
|
||||
u32 r;
|
||||
@ -1035,7 +1045,7 @@ void hdmi_wp_audio_config_format(struct hdmi_ip_data *ip_data,
|
||||
hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_AUDIO_CFG, r);
|
||||
}
|
||||
|
||||
void hdmi_wp_audio_config_dma(struct hdmi_ip_data *ip_data,
|
||||
static void ti_hdmi_4xxx_wp_audio_config_dma(struct hdmi_ip_data *ip_data,
|
||||
struct hdmi_audio_dma *aud_dma)
|
||||
{
|
||||
u32 r;
|
||||
@ -1053,7 +1063,7 @@ void hdmi_wp_audio_config_dma(struct hdmi_ip_data *ip_data,
|
||||
hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_AUDIO_CTRL, r);
|
||||
}
|
||||
|
||||
void hdmi_core_audio_config(struct hdmi_ip_data *ip_data,
|
||||
static void ti_hdmi_4xxx_core_audio_config(struct hdmi_ip_data *ip_data,
|
||||
struct hdmi_core_audio_config *cfg)
|
||||
{
|
||||
u32 r;
|
||||
@ -1104,27 +1114,33 @@ void hdmi_core_audio_config(struct hdmi_ip_data *ip_data,
|
||||
REG_FLD_MOD(av_base, HDMI_CORE_AV_SPDIF_CTRL,
|
||||
cfg->fs_override, 1, 1);
|
||||
|
||||
/* I2S parameters */
|
||||
REG_FLD_MOD(av_base, HDMI_CORE_AV_I2S_CHST4,
|
||||
cfg->freq_sample, 3, 0);
|
||||
/*
|
||||
* Set IEC-60958-3 channel status word. It is passed to the IP
|
||||
* just as it is received. The user of the driver is responsible
|
||||
* for its contents.
|
||||
*/
|
||||
hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST0,
|
||||
cfg->iec60958_cfg->status[0]);
|
||||
hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST1,
|
||||
cfg->iec60958_cfg->status[1]);
|
||||
hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST2,
|
||||
cfg->iec60958_cfg->status[2]);
|
||||
/* yes, this is correct: status[3] goes to CHST4 register */
|
||||
hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST4,
|
||||
cfg->iec60958_cfg->status[3]);
|
||||
/* yes, this is correct: status[4] goes to CHST5 register */
|
||||
hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST5,
|
||||
cfg->iec60958_cfg->status[4]);
|
||||
|
||||
/* set I2S parameters */
|
||||
r = hdmi_read_reg(av_base, HDMI_CORE_AV_I2S_IN_CTRL);
|
||||
r = FLD_MOD(r, cfg->i2s_cfg.en_high_bitrate_aud, 7, 7);
|
||||
r = FLD_MOD(r, cfg->i2s_cfg.sck_edge_mode, 6, 6);
|
||||
r = FLD_MOD(r, cfg->i2s_cfg.cbit_order, 5, 5);
|
||||
r = FLD_MOD(r, cfg->i2s_cfg.vbit, 4, 4);
|
||||
r = FLD_MOD(r, cfg->i2s_cfg.ws_polarity, 3, 3);
|
||||
r = FLD_MOD(r, cfg->i2s_cfg.justification, 2, 2);
|
||||
r = FLD_MOD(r, cfg->i2s_cfg.direction, 1, 1);
|
||||
r = FLD_MOD(r, cfg->i2s_cfg.shift, 0, 0);
|
||||
hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_IN_CTRL, r);
|
||||
|
||||
r = hdmi_read_reg(av_base, HDMI_CORE_AV_I2S_CHST5);
|
||||
r = FLD_MOD(r, cfg->freq_sample, 7, 4);
|
||||
r = FLD_MOD(r, cfg->i2s_cfg.word_length, 3, 1);
|
||||
r = FLD_MOD(r, cfg->i2s_cfg.word_max_length, 0, 0);
|
||||
hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST5, r);
|
||||
|
||||
REG_FLD_MOD(av_base, HDMI_CORE_AV_I2S_IN_LEN,
|
||||
cfg->i2s_cfg.in_length_bits, 3, 0);
|
||||
|
||||
@ -1136,12 +1152,19 @@ void hdmi_core_audio_config(struct hdmi_ip_data *ip_data,
|
||||
r = FLD_MOD(r, cfg->en_parallel_aud_input, 2, 2);
|
||||
r = FLD_MOD(r, cfg->en_spdif, 1, 1);
|
||||
hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_MODE, r);
|
||||
|
||||
/* Audio channel mappings */
|
||||
/* TODO: Make channel mapping dynamic. For now, map channels
|
||||
* in the ALSA order: FL/FR/RL/RR/C/LFE/SL/SR. Remapping is needed as
|
||||
* HDMI speaker order is different. See CEA-861 Section 6.6.2.
|
||||
*/
|
||||
hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_IN_MAP, 0x78);
|
||||
REG_FLD_MOD(av_base, HDMI_CORE_AV_SWAP_I2S, 1, 5, 5);
|
||||
}
|
||||
|
||||
void hdmi_core_audio_infoframe_config(struct hdmi_ip_data *ip_data,
|
||||
struct hdmi_core_infoframe_audio *info_aud)
|
||||
static void ti_hdmi_4xxx_core_audio_infoframe_cfg(struct hdmi_ip_data *ip_data,
|
||||
struct snd_cea_861_aud_if *info_aud)
|
||||
{
|
||||
u8 val;
|
||||
u8 sum = 0, checksum = 0;
|
||||
void __iomem *av_base = hdmi_av_base(ip_data);
|
||||
|
||||
@ -1155,24 +1178,23 @@ void hdmi_core_audio_infoframe_config(struct hdmi_ip_data *ip_data,
|
||||
hdmi_write_reg(av_base, HDMI_CORE_AV_AUDIO_LEN, 0x0a);
|
||||
sum += 0x84 + 0x001 + 0x00a;
|
||||
|
||||
val = (info_aud->db1_coding_type << 4)
|
||||
| (info_aud->db1_channel_count - 1);
|
||||
hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(0), val);
|
||||
sum += val;
|
||||
hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(0),
|
||||
info_aud->db1_ct_cc);
|
||||
sum += info_aud->db1_ct_cc;
|
||||
|
||||
val = (info_aud->db2_sample_freq << 2) | info_aud->db2_sample_size;
|
||||
hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(1), val);
|
||||
sum += val;
|
||||
hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(1),
|
||||
info_aud->db2_sf_ss);
|
||||
sum += info_aud->db2_sf_ss;
|
||||
|
||||
hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(2), 0x00);
|
||||
hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(2), info_aud->db3);
|
||||
sum += info_aud->db3;
|
||||
|
||||
val = info_aud->db4_channel_alloc;
|
||||
hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(3), val);
|
||||
sum += val;
|
||||
hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(3), info_aud->db4_ca);
|
||||
sum += info_aud->db4_ca;
|
||||
|
||||
val = (info_aud->db5_downmix_inh << 7) | (info_aud->db5_lsv << 3);
|
||||
hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(4), val);
|
||||
sum += val;
|
||||
hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(4),
|
||||
info_aud->db5_dminh_lsv);
|
||||
sum += info_aud->db5_dminh_lsv;
|
||||
|
||||
hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(5), 0x00);
|
||||
hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(6), 0x00);
|
||||
@ -1190,70 +1212,212 @@ void hdmi_core_audio_infoframe_config(struct hdmi_ip_data *ip_data,
|
||||
*/
|
||||
}
|
||||
|
||||
int hdmi_config_audio_acr(struct hdmi_ip_data *ip_data,
|
||||
u32 sample_freq, u32 *n, u32 *cts)
|
||||
int ti_hdmi_4xxx_audio_config(struct hdmi_ip_data *ip_data,
|
||||
struct omap_dss_audio *audio)
|
||||
{
|
||||
u32 r;
|
||||
u32 deep_color = 0;
|
||||
u32 pclk = ip_data->cfg.timings.pixel_clock;
|
||||
struct hdmi_audio_format audio_format;
|
||||
struct hdmi_audio_dma audio_dma;
|
||||
struct hdmi_core_audio_config core;
|
||||
int err, n, cts, channel_count;
|
||||
unsigned int fs_nr;
|
||||
bool word_length_16b = false;
|
||||
|
||||
if (n == NULL || cts == NULL)
|
||||
if (!audio || !audio->iec || !audio->cea || !ip_data)
|
||||
return -EINVAL;
|
||||
|
||||
core.iec60958_cfg = audio->iec;
|
||||
/*
|
||||
* Obtain current deep color configuration. This needed
|
||||
* to calculate the TMDS clock based on the pixel clock.
|
||||
* In the IEC-60958 status word, check if the audio sample word length
|
||||
* is 16-bit as several optimizations can be performed in such case.
|
||||
*/
|
||||
r = REG_GET(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG, 1, 0);
|
||||
switch (r) {
|
||||
case 1: /* No deep color selected */
|
||||
deep_color = 100;
|
||||
if (!(audio->iec->status[4] & IEC958_AES4_CON_MAX_WORDLEN_24))
|
||||
if (audio->iec->status[4] & IEC958_AES4_CON_WORDLEN_20_16)
|
||||
word_length_16b = true;
|
||||
|
||||
/* I2S configuration. See Phillips' specification */
|
||||
if (word_length_16b)
|
||||
core.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_LEFT;
|
||||
else
|
||||
core.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_RIGHT;
|
||||
/*
|
||||
* The I2S input word length is twice the lenght given in the IEC-60958
|
||||
* status word. If the word size is greater than
|
||||
* 20 bits, increment by one.
|
||||
*/
|
||||
core.i2s_cfg.in_length_bits = audio->iec->status[4]
|
||||
& IEC958_AES4_CON_WORDLEN;
|
||||
if (audio->iec->status[4] & IEC958_AES4_CON_MAX_WORDLEN_24)
|
||||
core.i2s_cfg.in_length_bits++;
|
||||
core.i2s_cfg.sck_edge_mode = HDMI_AUDIO_I2S_SCK_EDGE_RISING;
|
||||
core.i2s_cfg.vbit = HDMI_AUDIO_I2S_VBIT_FOR_PCM;
|
||||
core.i2s_cfg.direction = HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST;
|
||||
core.i2s_cfg.shift = HDMI_AUDIO_I2S_FIRST_BIT_SHIFT;
|
||||
|
||||
/* convert sample frequency to a number */
|
||||
switch (audio->iec->status[3] & IEC958_AES3_CON_FS) {
|
||||
case IEC958_AES3_CON_FS_32000:
|
||||
fs_nr = 32000;
|
||||
break;
|
||||
case 2: /* 10-bit deep color selected */
|
||||
deep_color = 125;
|
||||
case IEC958_AES3_CON_FS_44100:
|
||||
fs_nr = 44100;
|
||||
break;
|
||||
case 3: /* 12-bit deep color selected */
|
||||
deep_color = 150;
|
||||
case IEC958_AES3_CON_FS_48000:
|
||||
fs_nr = 48000;
|
||||
break;
|
||||
case IEC958_AES3_CON_FS_88200:
|
||||
fs_nr = 88200;
|
||||
break;
|
||||
case IEC958_AES3_CON_FS_96000:
|
||||
fs_nr = 96000;
|
||||
break;
|
||||
case IEC958_AES3_CON_FS_176400:
|
||||
fs_nr = 176400;
|
||||
break;
|
||||
case IEC958_AES3_CON_FS_192000:
|
||||
fs_nr = 192000;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (sample_freq) {
|
||||
case 32000:
|
||||
if ((deep_color == 125) && ((pclk == 54054)
|
||||
|| (pclk == 74250)))
|
||||
*n = 8192;
|
||||
else
|
||||
*n = 4096;
|
||||
err = hdmi_compute_acr(fs_nr, &n, &cts);
|
||||
|
||||
/* Audio clock regeneration settings */
|
||||
core.n = n;
|
||||
core.cts = cts;
|
||||
if (dss_has_feature(FEAT_HDMI_CTS_SWMODE)) {
|
||||
core.aud_par_busclk = 0;
|
||||
core.cts_mode = HDMI_AUDIO_CTS_MODE_SW;
|
||||
core.use_mclk = dss_has_feature(FEAT_HDMI_AUDIO_USE_MCLK);
|
||||
} else {
|
||||
core.aud_par_busclk = (((128 * 31) - 1) << 8);
|
||||
core.cts_mode = HDMI_AUDIO_CTS_MODE_HW;
|
||||
core.use_mclk = true;
|
||||
}
|
||||
|
||||
if (core.use_mclk)
|
||||
core.mclk_mode = HDMI_AUDIO_MCLK_128FS;
|
||||
|
||||
/* Audio channels settings */
|
||||
channel_count = (audio->cea->db1_ct_cc &
|
||||
CEA861_AUDIO_INFOFRAME_DB1CC) + 1;
|
||||
|
||||
switch (channel_count) {
|
||||
case 2:
|
||||
audio_format.active_chnnls_msk = 0x03;
|
||||
break;
|
||||
case 44100:
|
||||
*n = 6272;
|
||||
case 3:
|
||||
audio_format.active_chnnls_msk = 0x07;
|
||||
break;
|
||||
case 48000:
|
||||
if ((deep_color == 125) && ((pclk == 54054)
|
||||
|| (pclk == 74250)))
|
||||
*n = 8192;
|
||||
else
|
||||
*n = 6144;
|
||||
case 4:
|
||||
audio_format.active_chnnls_msk = 0x0f;
|
||||
break;
|
||||
case 5:
|
||||
audio_format.active_chnnls_msk = 0x1f;
|
||||
break;
|
||||
case 6:
|
||||
audio_format.active_chnnls_msk = 0x3f;
|
||||
break;
|
||||
case 7:
|
||||
audio_format.active_chnnls_msk = 0x7f;
|
||||
break;
|
||||
case 8:
|
||||
audio_format.active_chnnls_msk = 0xff;
|
||||
break;
|
||||
default:
|
||||
*n = 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Calculate CTS. See HDMI 1.3a or 1.4a specifications */
|
||||
*cts = pclk * (*n / 128) * deep_color / (sample_freq / 10);
|
||||
/*
|
||||
* the HDMI IP needs to enable four stereo channels when transmitting
|
||||
* more than 2 audio channels
|
||||
*/
|
||||
if (channel_count == 2) {
|
||||
audio_format.stereo_channels = HDMI_AUDIO_STEREO_ONECHANNEL;
|
||||
core.i2s_cfg.active_sds = HDMI_AUDIO_I2S_SD0_EN;
|
||||
core.layout = HDMI_AUDIO_LAYOUT_2CH;
|
||||
} else {
|
||||
audio_format.stereo_channels = HDMI_AUDIO_STEREO_FOURCHANNELS;
|
||||
core.i2s_cfg.active_sds = HDMI_AUDIO_I2S_SD0_EN |
|
||||
HDMI_AUDIO_I2S_SD1_EN | HDMI_AUDIO_I2S_SD2_EN |
|
||||
HDMI_AUDIO_I2S_SD3_EN;
|
||||
core.layout = HDMI_AUDIO_LAYOUT_8CH;
|
||||
}
|
||||
|
||||
core.en_spdif = false;
|
||||
/* use sample frequency from channel status word */
|
||||
core.fs_override = true;
|
||||
/* enable ACR packets */
|
||||
core.en_acr_pkt = true;
|
||||
/* disable direct streaming digital audio */
|
||||
core.en_dsd_audio = false;
|
||||
/* use parallel audio interface */
|
||||
core.en_parallel_aud_input = true;
|
||||
|
||||
/* DMA settings */
|
||||
if (word_length_16b)
|
||||
audio_dma.transfer_size = 0x10;
|
||||
else
|
||||
audio_dma.transfer_size = 0x20;
|
||||
audio_dma.block_size = 0xC0;
|
||||
audio_dma.mode = HDMI_AUDIO_TRANSF_DMA;
|
||||
audio_dma.fifo_threshold = 0x20; /* in number of samples */
|
||||
|
||||
/* audio FIFO format settings */
|
||||
if (word_length_16b) {
|
||||
audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_TWOSAMPLES;
|
||||
audio_format.sample_size = HDMI_AUDIO_SAMPLE_16BITS;
|
||||
audio_format.justification = HDMI_AUDIO_JUSTIFY_LEFT;
|
||||
} else {
|
||||
audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_ONESAMPLE;
|
||||
audio_format.sample_size = HDMI_AUDIO_SAMPLE_24BITS;
|
||||
audio_format.justification = HDMI_AUDIO_JUSTIFY_RIGHT;
|
||||
}
|
||||
audio_format.type = HDMI_AUDIO_TYPE_LPCM;
|
||||
audio_format.sample_order = HDMI_AUDIO_SAMPLE_LEFT_FIRST;
|
||||
/* disable start/stop signals of IEC 60958 blocks */
|
||||
audio_format.en_sig_blk_strt_end = HDMI_AUDIO_BLOCK_SIG_STARTEND_ON;
|
||||
|
||||
/* configure DMA and audio FIFO format*/
|
||||
ti_hdmi_4xxx_wp_audio_config_dma(ip_data, &audio_dma);
|
||||
ti_hdmi_4xxx_wp_audio_config_format(ip_data, &audio_format);
|
||||
|
||||
/* configure the core*/
|
||||
ti_hdmi_4xxx_core_audio_config(ip_data, &core);
|
||||
|
||||
/* configure CEA 861 audio infoframe*/
|
||||
ti_hdmi_4xxx_core_audio_infoframe_cfg(ip_data, audio->cea);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data, bool enable)
|
||||
int ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data)
|
||||
{
|
||||
REG_FLD_MOD(hdmi_wp_base(ip_data),
|
||||
HDMI_WP_AUDIO_CTRL, true, 31, 31);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ti_hdmi_4xxx_wp_audio_disable(struct hdmi_ip_data *ip_data)
|
||||
{
|
||||
REG_FLD_MOD(hdmi_wp_base(ip_data),
|
||||
HDMI_WP_AUDIO_CTRL, false, 31, 31);
|
||||
}
|
||||
|
||||
int ti_hdmi_4xxx_audio_start(struct hdmi_ip_data *ip_data)
|
||||
{
|
||||
REG_FLD_MOD(hdmi_av_base(ip_data),
|
||||
HDMI_CORE_AV_AUD_MODE, enable, 0, 0);
|
||||
HDMI_CORE_AV_AUD_MODE, true, 0, 0);
|
||||
REG_FLD_MOD(hdmi_wp_base(ip_data),
|
||||
HDMI_WP_AUDIO_CTRL, enable, 31, 31);
|
||||
HDMI_WP_AUDIO_CTRL, true, 30, 30);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ti_hdmi_4xxx_audio_stop(struct hdmi_ip_data *ip_data)
|
||||
{
|
||||
REG_FLD_MOD(hdmi_av_base(ip_data),
|
||||
HDMI_CORE_AV_AUD_MODE, false, 0, 0);
|
||||
REG_FLD_MOD(hdmi_wp_base(ip_data),
|
||||
HDMI_WP_AUDIO_CTRL, enable, 30, 30);
|
||||
HDMI_WP_AUDIO_CTRL, false, 30, 30);
|
||||
}
|
||||
#endif
|
||||
|
@ -24,11 +24,6 @@
|
||||
#include <linux/string.h>
|
||||
#include <video/omapdss.h>
|
||||
#include "ti_hdmi.h"
|
||||
#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
|
||||
defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#endif
|
||||
|
||||
/* HDMI Wrapper */
|
||||
|
||||
@ -279,35 +274,6 @@ enum hdmi_core_infoframe {
|
||||
HDMI_INFOFRAME_AVI_DB5PR_8 = 7,
|
||||
HDMI_INFOFRAME_AVI_DB5PR_9 = 8,
|
||||
HDMI_INFOFRAME_AVI_DB5PR_10 = 9,
|
||||
HDMI_INFOFRAME_AUDIO_DB1CT_FROM_STREAM = 0,
|
||||
HDMI_INFOFRAME_AUDIO_DB1CT_IEC60958 = 1,
|
||||
HDMI_INFOFRAME_AUDIO_DB1CT_AC3 = 2,
|
||||
HDMI_INFOFRAME_AUDIO_DB1CT_MPEG1 = 3,
|
||||
HDMI_INFOFRAME_AUDIO_DB1CT_MP3 = 4,
|
||||
HDMI_INFOFRAME_AUDIO_DB1CT_MPEG2_MULTICH = 5,
|
||||
HDMI_INFOFRAME_AUDIO_DB1CT_AAC = 6,
|
||||
HDMI_INFOFRAME_AUDIO_DB1CT_DTS = 7,
|
||||
HDMI_INFOFRAME_AUDIO_DB1CT_ATRAC = 8,
|
||||
HDMI_INFOFRAME_AUDIO_DB1CT_ONEBIT = 9,
|
||||
HDMI_INFOFRAME_AUDIO_DB1CT_DOLBY_DIGITAL_PLUS = 10,
|
||||
HDMI_INFOFRAME_AUDIO_DB1CT_DTS_HD = 11,
|
||||
HDMI_INFOFRAME_AUDIO_DB1CT_MAT = 12,
|
||||
HDMI_INFOFRAME_AUDIO_DB1CT_DST = 13,
|
||||
HDMI_INFOFRAME_AUDIO_DB1CT_WMA_PRO = 14,
|
||||
HDMI_INFOFRAME_AUDIO_DB2SF_FROM_STREAM = 0,
|
||||
HDMI_INFOFRAME_AUDIO_DB2SF_32000 = 1,
|
||||
HDMI_INFOFRAME_AUDIO_DB2SF_44100 = 2,
|
||||
HDMI_INFOFRAME_AUDIO_DB2SF_48000 = 3,
|
||||
HDMI_INFOFRAME_AUDIO_DB2SF_88200 = 4,
|
||||
HDMI_INFOFRAME_AUDIO_DB2SF_96000 = 5,
|
||||
HDMI_INFOFRAME_AUDIO_DB2SF_176400 = 6,
|
||||
HDMI_INFOFRAME_AUDIO_DB2SF_192000 = 7,
|
||||
HDMI_INFOFRAME_AUDIO_DB2SS_FROM_STREAM = 0,
|
||||
HDMI_INFOFRAME_AUDIO_DB2SS_16BIT = 1,
|
||||
HDMI_INFOFRAME_AUDIO_DB2SS_20BIT = 2,
|
||||
HDMI_INFOFRAME_AUDIO_DB2SS_24BIT = 3,
|
||||
HDMI_INFOFRAME_AUDIO_DB5_DM_INH_PERMITTED = 0,
|
||||
HDMI_INFOFRAME_AUDIO_DB5_DM_INH_PROHIBITED = 1
|
||||
};
|
||||
|
||||
enum hdmi_packing_mode {
|
||||
@ -317,17 +283,6 @@ enum hdmi_packing_mode {
|
||||
HDMI_PACK_ALREADYPACKED = 7
|
||||
};
|
||||
|
||||
enum hdmi_core_audio_sample_freq {
|
||||
HDMI_AUDIO_FS_32000 = 0x3,
|
||||
HDMI_AUDIO_FS_44100 = 0x0,
|
||||
HDMI_AUDIO_FS_48000 = 0x2,
|
||||
HDMI_AUDIO_FS_88200 = 0x8,
|
||||
HDMI_AUDIO_FS_96000 = 0xA,
|
||||
HDMI_AUDIO_FS_176400 = 0xC,
|
||||
HDMI_AUDIO_FS_192000 = 0xE,
|
||||
HDMI_AUDIO_FS_NOT_INDICATED = 0x1
|
||||
};
|
||||
|
||||
enum hdmi_core_audio_layout {
|
||||
HDMI_AUDIO_LAYOUT_2CH = 0,
|
||||
HDMI_AUDIO_LAYOUT_8CH = 1
|
||||
@ -382,37 +337,12 @@ enum hdmi_audio_blk_strt_end_sig {
|
||||
};
|
||||
|
||||
enum hdmi_audio_i2s_config {
|
||||
HDMI_AUDIO_I2S_WS_POLARITY_LOW_IS_LEFT = 0,
|
||||
HDMI_AUDIO_I2S_WS_POLARIT_YLOW_IS_RIGHT = 1,
|
||||
HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST = 0,
|
||||
HDMI_AUDIO_I2S_LSB_SHIFTED_FIRST = 1,
|
||||
HDMI_AUDIO_I2S_MAX_WORD_20BITS = 0,
|
||||
HDMI_AUDIO_I2S_MAX_WORD_24BITS = 1,
|
||||
HDMI_AUDIO_I2S_CHST_WORD_NOT_SPECIFIED = 0,
|
||||
HDMI_AUDIO_I2S_CHST_WORD_16_BITS = 1,
|
||||
HDMI_AUDIO_I2S_CHST_WORD_17_BITS = 6,
|
||||
HDMI_AUDIO_I2S_CHST_WORD_18_BITS = 2,
|
||||
HDMI_AUDIO_I2S_CHST_WORD_19_BITS = 4,
|
||||
HDMI_AUDIO_I2S_CHST_WORD_20_BITS_20MAX = 5,
|
||||
HDMI_AUDIO_I2S_CHST_WORD_20_BITS_24MAX = 1,
|
||||
HDMI_AUDIO_I2S_CHST_WORD_21_BITS = 6,
|
||||
HDMI_AUDIO_I2S_CHST_WORD_22_BITS = 2,
|
||||
HDMI_AUDIO_I2S_CHST_WORD_23_BITS = 4,
|
||||
HDMI_AUDIO_I2S_CHST_WORD_24_BITS = 5,
|
||||
HDMI_AUDIO_I2S_SCK_EDGE_FALLING = 0,
|
||||
HDMI_AUDIO_I2S_SCK_EDGE_RISING = 1,
|
||||
HDMI_AUDIO_I2S_VBIT_FOR_PCM = 0,
|
||||
HDMI_AUDIO_I2S_VBIT_FOR_COMPRESSED = 1,
|
||||
HDMI_AUDIO_I2S_INPUT_LENGTH_NA = 0,
|
||||
HDMI_AUDIO_I2S_INPUT_LENGTH_16 = 2,
|
||||
HDMI_AUDIO_I2S_INPUT_LENGTH_17 = 12,
|
||||
HDMI_AUDIO_I2S_INPUT_LENGTH_18 = 4,
|
||||
HDMI_AUDIO_I2S_INPUT_LENGTH_19 = 8,
|
||||
HDMI_AUDIO_I2S_INPUT_LENGTH_20 = 10,
|
||||
HDMI_AUDIO_I2S_INPUT_LENGTH_21 = 13,
|
||||
HDMI_AUDIO_I2S_INPUT_LENGTH_22 = 5,
|
||||
HDMI_AUDIO_I2S_INPUT_LENGTH_23 = 9,
|
||||
HDMI_AUDIO_I2S_INPUT_LENGTH_24 = 11,
|
||||
HDMI_AUDIO_I2S_FIRST_BIT_SHIFT = 0,
|
||||
HDMI_AUDIO_I2S_FIRST_BIT_NO_SHIFT = 1,
|
||||
HDMI_AUDIO_I2S_SD0_EN = 1,
|
||||
@ -441,20 +371,6 @@ struct hdmi_core_video_config {
|
||||
enum hdmi_core_tclkselclkmult tclk_sel_clkmult;
|
||||
};
|
||||
|
||||
/*
|
||||
* Refer to section 8.2 in HDMI 1.3 specification for
|
||||
* details about infoframe databytes
|
||||
*/
|
||||
struct hdmi_core_infoframe_audio {
|
||||
u8 db1_coding_type;
|
||||
u8 db1_channel_count;
|
||||
u8 db2_sample_freq;
|
||||
u8 db2_sample_size;
|
||||
u8 db4_channel_alloc;
|
||||
bool db5_downmix_inh;
|
||||
u8 db5_lsv; /* Level shift values for downmix */
|
||||
};
|
||||
|
||||
struct hdmi_core_packet_enable_repeat {
|
||||
u32 audio_pkt;
|
||||
u32 audio_pkt_repeat;
|
||||
@ -491,15 +407,10 @@ struct hdmi_audio_dma {
|
||||
};
|
||||
|
||||
struct hdmi_core_audio_i2s_config {
|
||||
u8 word_max_length;
|
||||
u8 word_length;
|
||||
u8 in_length_bits;
|
||||
u8 justification;
|
||||
u8 en_high_bitrate_aud;
|
||||
u8 sck_edge_mode;
|
||||
u8 cbit_order;
|
||||
u8 vbit;
|
||||
u8 ws_polarity;
|
||||
u8 direction;
|
||||
u8 shift;
|
||||
u8 active_sds;
|
||||
@ -507,7 +418,7 @@ struct hdmi_core_audio_i2s_config {
|
||||
|
||||
struct hdmi_core_audio_config {
|
||||
struct hdmi_core_audio_i2s_config i2s_cfg;
|
||||
enum hdmi_core_audio_sample_freq freq_sample;
|
||||
struct snd_aes_iec958 *iec60958_cfg;
|
||||
bool fs_override;
|
||||
u32 n;
|
||||
u32 cts;
|
||||
@ -522,17 +433,4 @@ struct hdmi_core_audio_config {
|
||||
bool en_spdif;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
|
||||
defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
|
||||
int hdmi_config_audio_acr(struct hdmi_ip_data *ip_data,
|
||||
u32 sample_freq, u32 *n, u32 *cts);
|
||||
void hdmi_core_audio_infoframe_config(struct hdmi_ip_data *ip_data,
|
||||
struct hdmi_core_infoframe_audio *info_aud);
|
||||
void hdmi_core_audio_config(struct hdmi_ip_data *ip_data,
|
||||
struct hdmi_core_audio_config *cfg);
|
||||
void hdmi_wp_audio_config_dma(struct hdmi_ip_data *ip_data,
|
||||
struct hdmi_audio_dma *aud_dma);
|
||||
void hdmi_wp_audio_config_format(struct hdmi_ip_data *ip_data,
|
||||
struct hdmi_audio_format *aud_fmt);
|
||||
#endif
|
||||
#endif
|
||||
|
@ -51,6 +51,8 @@
|
||||
|
||||
struct omap_dss_device;
|
||||
struct omap_overlay_manager;
|
||||
struct snd_aes_iec958;
|
||||
struct snd_cea_861_aud_if;
|
||||
|
||||
enum omap_display_type {
|
||||
OMAP_DISPLAY_TYPE_NONE = 0,
|
||||
@ -158,6 +160,13 @@ enum omap_dss_display_state {
|
||||
OMAP_DSS_DISPLAY_SUSPENDED,
|
||||
};
|
||||
|
||||
enum omap_dss_audio_state {
|
||||
OMAP_DSS_AUDIO_DISABLED = 0,
|
||||
OMAP_DSS_AUDIO_ENABLED,
|
||||
OMAP_DSS_AUDIO_CONFIGURED,
|
||||
OMAP_DSS_AUDIO_PLAYING,
|
||||
};
|
||||
|
||||
/* XXX perhaps this should be removed */
|
||||
enum omap_dss_overlay_managers {
|
||||
OMAP_DSS_OVL_MGR_LCD,
|
||||
@ -583,6 +592,8 @@ struct omap_dss_device {
|
||||
|
||||
enum omap_dss_display_state state;
|
||||
|
||||
enum omap_dss_audio_state audio_state;
|
||||
|
||||
/* platform specific */
|
||||
int (*platform_enable)(struct omap_dss_device *dssdev);
|
||||
void (*platform_disable)(struct omap_dss_device *dssdev);
|
||||
@ -595,6 +606,11 @@ struct omap_dss_hdmi_data
|
||||
int hpd_gpio;
|
||||
};
|
||||
|
||||
struct omap_dss_audio {
|
||||
struct snd_aes_iec958 *iec;
|
||||
struct snd_cea_861_aud_if *cea;
|
||||
};
|
||||
|
||||
struct omap_dss_driver {
|
||||
struct device_driver driver;
|
||||
|
||||
@ -642,6 +658,24 @@ struct omap_dss_driver {
|
||||
|
||||
int (*read_edid)(struct omap_dss_device *dssdev, u8 *buf, int len);
|
||||
bool (*detect)(struct omap_dss_device *dssdev);
|
||||
|
||||
/*
|
||||
* For display drivers that support audio. This encompasses
|
||||
* HDMI and DisplayPort at the moment.
|
||||
*/
|
||||
/*
|
||||
* Note: These functions might sleep. Do not call while
|
||||
* holding a spinlock/readlock.
|
||||
*/
|
||||
int (*audio_enable)(struct omap_dss_device *dssdev);
|
||||
void (*audio_disable)(struct omap_dss_device *dssdev);
|
||||
bool (*audio_supported)(struct omap_dss_device *dssdev);
|
||||
int (*audio_config)(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_audio *audio);
|
||||
/* Note: These functions may not sleep */
|
||||
int (*audio_start)(struct omap_dss_device *dssdev);
|
||||
void (*audio_stop)(struct omap_dss_device *dssdev);
|
||||
|
||||
};
|
||||
|
||||
int omap_dss_register_driver(struct omap_dss_driver *);
|
||||
|
Loading…
x
Reference in New Issue
Block a user