mirror of
https://github.com/torvalds/linux.git
synced 2024-11-13 07:31:45 +00:00
Merge branch 'topic/intel-lpe-audio-dp' into for-next
Merged more patches for Intel LPE audio driver, now to support DP audio.
This commit is contained in:
commit
374a504025
@ -3401,7 +3401,8 @@ int intel_lpe_audio_init(struct drm_i915_private *dev_priv);
|
||||
void intel_lpe_audio_teardown(struct drm_i915_private *dev_priv);
|
||||
void intel_lpe_audio_irq_handler(struct drm_i915_private *dev_priv);
|
||||
void intel_lpe_audio_notify(struct drm_i915_private *dev_priv,
|
||||
void *eld, int port, int tmds_clk_speed);
|
||||
void *eld, int port, int pipe, int tmds_clk_speed,
|
||||
bool dp_output, int link_rate);
|
||||
|
||||
/* intel_i2c.c */
|
||||
extern int intel_setup_gmbus(struct drm_device *dev);
|
||||
|
@ -2061,6 +2061,16 @@ enum skl_disp_power_wells {
|
||||
#define I915_HDMI_LPE_AUDIO_BASE (VLV_DISPLAY_BASE + 0x65000)
|
||||
#define I915_HDMI_LPE_AUDIO_SIZE 0x1000
|
||||
|
||||
/* DisplayPort Audio w/ LPE */
|
||||
#define _VLV_AUD_PORT_EN_B_DBG (VLV_DISPLAY_BASE + 0x62F20)
|
||||
#define _VLV_AUD_PORT_EN_C_DBG (VLV_DISPLAY_BASE + 0x62F30)
|
||||
#define _VLV_AUD_PORT_EN_D_DBG (VLV_DISPLAY_BASE + 0x62F34)
|
||||
#define VLV_AUD_PORT_EN_DBG(port) _MMIO_PORT3((port) - PORT_B, \
|
||||
_VLV_AUD_PORT_EN_B_DBG, \
|
||||
_VLV_AUD_PORT_EN_C_DBG, \
|
||||
_VLV_AUD_PORT_EN_D_DBG)
|
||||
#define VLV_AMP_MUTE (1 << 1)
|
||||
|
||||
#define GEN6_BSD_RNCID _MMIO(0x12198)
|
||||
|
||||
#define GEN7_FF_THREAD_MODE _MMIO(0x20a0)
|
||||
|
@ -624,16 +624,28 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder,
|
||||
dev_priv->av_enc_map[pipe] = intel_encoder;
|
||||
mutex_unlock(&dev_priv->av_mutex);
|
||||
|
||||
/* audio drivers expect pipe = -1 to indicate Non-MST cases */
|
||||
if (intel_encoder->type != INTEL_OUTPUT_DP_MST)
|
||||
pipe = -1;
|
||||
|
||||
if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify)
|
||||
if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) {
|
||||
/* audio drivers expect pipe = -1 to indicate Non-MST cases */
|
||||
if (intel_encoder->type != INTEL_OUTPUT_DP_MST)
|
||||
pipe = -1;
|
||||
acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr,
|
||||
(int) port, (int) pipe);
|
||||
}
|
||||
|
||||
intel_lpe_audio_notify(dev_priv, connector->eld, port,
|
||||
crtc_state->port_clock);
|
||||
switch (intel_encoder->type) {
|
||||
case INTEL_OUTPUT_HDMI:
|
||||
intel_lpe_audio_notify(dev_priv, connector->eld, port, pipe,
|
||||
crtc_state->port_clock,
|
||||
false, 0);
|
||||
break;
|
||||
case INTEL_OUTPUT_DP:
|
||||
intel_lpe_audio_notify(dev_priv, connector->eld, port, pipe,
|
||||
adjusted_mode->crtc_clock,
|
||||
true, crtc_state->port_clock);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -660,15 +672,15 @@ void intel_audio_codec_disable(struct intel_encoder *intel_encoder)
|
||||
dev_priv->av_enc_map[pipe] = NULL;
|
||||
mutex_unlock(&dev_priv->av_mutex);
|
||||
|
||||
/* audio drivers expect pipe = -1 to indicate Non-MST cases */
|
||||
if (intel_encoder->type != INTEL_OUTPUT_DP_MST)
|
||||
pipe = -1;
|
||||
|
||||
if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify)
|
||||
if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) {
|
||||
/* audio drivers expect pipe = -1 to indicate Non-MST cases */
|
||||
if (intel_encoder->type != INTEL_OUTPUT_DP_MST)
|
||||
pipe = -1;
|
||||
acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr,
|
||||
(int) port, (int) pipe);
|
||||
}
|
||||
|
||||
intel_lpe_audio_notify(dev_priv, NULL, port, 0);
|
||||
intel_lpe_audio_notify(dev_priv, NULL, port, pipe, 0, false, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -332,10 +332,12 @@ void intel_lpe_audio_teardown(struct drm_i915_private *dev_priv)
|
||||
* Notify lpe audio driver of eld change.
|
||||
*/
|
||||
void intel_lpe_audio_notify(struct drm_i915_private *dev_priv,
|
||||
void *eld, int port, int tmds_clk_speed)
|
||||
void *eld, int port, int pipe, int tmds_clk_speed,
|
||||
bool dp_output, int link_rate)
|
||||
{
|
||||
unsigned long irq_flags;
|
||||
struct intel_hdmi_lpe_audio_pdata *pdata = NULL;
|
||||
u32 audio_enable;
|
||||
|
||||
if (!HAS_LPE_AUDIO(dev_priv))
|
||||
return;
|
||||
@ -345,23 +347,38 @@ void intel_lpe_audio_notify(struct drm_i915_private *dev_priv,
|
||||
|
||||
spin_lock_irqsave(&pdata->lpe_audio_slock, irq_flags);
|
||||
|
||||
audio_enable = I915_READ(VLV_AUD_PORT_EN_DBG(port));
|
||||
|
||||
if (eld != NULL) {
|
||||
memcpy(pdata->eld.eld_data, eld,
|
||||
HDMI_MAX_ELD_BYTES);
|
||||
pdata->eld.port_id = port;
|
||||
pdata->eld.pipe_id = pipe;
|
||||
pdata->hdmi_connected = true;
|
||||
|
||||
pdata->dp_output = dp_output;
|
||||
if (tmds_clk_speed)
|
||||
pdata->tmds_clock_speed = tmds_clk_speed;
|
||||
if (link_rate)
|
||||
pdata->link_rate = link_rate;
|
||||
|
||||
/* Unmute the amp for both DP and HDMI */
|
||||
I915_WRITE(VLV_AUD_PORT_EN_DBG(port),
|
||||
audio_enable & ~VLV_AMP_MUTE);
|
||||
|
||||
} else {
|
||||
memset(pdata->eld.eld_data, 0,
|
||||
HDMI_MAX_ELD_BYTES);
|
||||
pdata->hdmi_connected = false;
|
||||
pdata->dp_output = false;
|
||||
|
||||
/* Mute the amp for both DP and HDMI */
|
||||
I915_WRITE(VLV_AUD_PORT_EN_DBG(port),
|
||||
audio_enable | VLV_AMP_MUTE);
|
||||
}
|
||||
|
||||
if (pdata->notify_audio_lpe)
|
||||
pdata->notify_audio_lpe(
|
||||
(eld != NULL) ? &pdata->eld : NULL);
|
||||
pdata->notify_audio_lpe(dev_priv->lpe_audio.platdev);
|
||||
else
|
||||
pdata->notify_pending = true;
|
||||
|
||||
|
@ -27,10 +27,13 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/spinlock_types.h>
|
||||
|
||||
struct platform_device;
|
||||
|
||||
#define HDMI_MAX_ELD_BYTES 128
|
||||
|
||||
struct intel_hdmi_lpe_audio_eld {
|
||||
int port_id;
|
||||
int pipe_id;
|
||||
unsigned char eld_data[HDMI_MAX_ELD_BYTES];
|
||||
};
|
||||
|
||||
@ -38,8 +41,10 @@ struct intel_hdmi_lpe_audio_pdata {
|
||||
bool notify_pending;
|
||||
int tmds_clock_speed;
|
||||
bool hdmi_connected;
|
||||
bool dp_output;
|
||||
int link_rate;
|
||||
struct intel_hdmi_lpe_audio_eld eld;
|
||||
void (*notify_audio_lpe)(void *audio_ptr);
|
||||
void (*notify_audio_lpe)(struct platform_device *pdev);
|
||||
spinlock_t lpe_audio_slock;
|
||||
};
|
||||
|
||||
|
@ -396,6 +396,7 @@ static int snd_intelhad_prog_audio_ctrl_v2(struct snd_pcm_substream *substream,
|
||||
else
|
||||
cfg_val.cfg_regx_v2.layout = LAYOUT1;
|
||||
|
||||
cfg_val.cfg_regx_v2.val_bit = 1;
|
||||
had_write_register(AUD_CONFIG, cfg_val.cfg_regval);
|
||||
return 0;
|
||||
}
|
||||
@ -447,6 +448,7 @@ static int snd_intelhad_prog_audio_ctrl_v1(struct snd_pcm_substream *substream,
|
||||
|
||||
}
|
||||
|
||||
cfg_val.cfg_regx.val_bit = 1;
|
||||
had_write_register(AUD_CONFIG, cfg_val.cfg_regval);
|
||||
return 0;
|
||||
}
|
||||
@ -548,6 +550,7 @@ void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata)
|
||||
}
|
||||
|
||||
had_get_caps(HAD_GET_ELD, &intelhaddata->eeld);
|
||||
had_get_caps(HAD_GET_DP_OUTPUT, &intelhaddata->dp_output);
|
||||
|
||||
pr_debug("eeld.speaker_allocation_block = %x\n",
|
||||
intelhaddata->eeld.speaker_allocation_block);
|
||||
@ -685,7 +688,7 @@ static void snd_intelhad_prog_dip_v1(struct snd_pcm_substream *substream,
|
||||
|
||||
/*Calculte the byte wide checksum for all valid DIP words*/
|
||||
for (i = 0; i < BYTES_PER_WORD; i++)
|
||||
checksum += (INFO_FRAME_WORD1 >> i*BITS_PER_BYTE) & MASK_BYTE0;
|
||||
checksum += (HDMI_INFO_FRAME_WORD1 >> i*BITS_PER_BYTE) & MASK_BYTE0;
|
||||
for (i = 0; i < BYTES_PER_WORD; i++)
|
||||
checksum += (frame2.fr2_val >> i*BITS_PER_BYTE) & MASK_BYTE0;
|
||||
for (i = 0; i < BYTES_PER_WORD; i++)
|
||||
@ -693,7 +696,7 @@ static void snd_intelhad_prog_dip_v1(struct snd_pcm_substream *substream,
|
||||
|
||||
frame2.fr2_regx.chksum = -(checksum);
|
||||
|
||||
had_write_register(AUD_HDMIW_INFOFR, INFO_FRAME_WORD1);
|
||||
had_write_register(AUD_HDMIW_INFOFR, HDMI_INFO_FRAME_WORD1);
|
||||
had_write_register(AUD_HDMIW_INFOFR, frame2.fr2_val);
|
||||
had_write_register(AUD_HDMIW_INFOFR, frame3.fr3_val);
|
||||
|
||||
@ -722,28 +725,35 @@ static void snd_intelhad_prog_dip_v2(struct snd_pcm_substream *substream,
|
||||
union aud_info_frame2 frame2 = {.fr2_val = 0};
|
||||
union aud_info_frame3 frame3 = {.fr3_val = 0};
|
||||
u8 checksum = 0;
|
||||
u32 info_frame;
|
||||
int channels;
|
||||
|
||||
channels = substream->runtime->channels;
|
||||
|
||||
had_write_register(AUD_CNTL_ST, ctrl_state.ctrl_val);
|
||||
|
||||
frame2.fr2_regx.chnl_cnt = substream->runtime->channels - 1;
|
||||
if (intelhaddata->dp_output) {
|
||||
info_frame = DP_INFO_FRAME_WORD1;
|
||||
frame2.fr2_val = 1;
|
||||
} else {
|
||||
info_frame = HDMI_INFO_FRAME_WORD1;
|
||||
frame2.fr2_regx.chnl_cnt = substream->runtime->channels - 1;
|
||||
|
||||
frame3.fr3_regx.chnl_alloc = snd_intelhad_channel_allocation(
|
||||
intelhaddata, channels);
|
||||
frame3.fr3_regx.chnl_alloc = snd_intelhad_channel_allocation(
|
||||
intelhaddata, channels);
|
||||
|
||||
/*Calculte the byte wide checksum for all valid DIP words*/
|
||||
for (i = 0; i < BYTES_PER_WORD; i++)
|
||||
checksum += (INFO_FRAME_WORD1 >> i*BITS_PER_BYTE) & MASK_BYTE0;
|
||||
for (i = 0; i < BYTES_PER_WORD; i++)
|
||||
checksum += (frame2.fr2_val >> i*BITS_PER_BYTE) & MASK_BYTE0;
|
||||
for (i = 0; i < BYTES_PER_WORD; i++)
|
||||
checksum += (frame3.fr3_val >> i*BITS_PER_BYTE) & MASK_BYTE0;
|
||||
/*Calculte the byte wide checksum for all valid DIP words*/
|
||||
for (i = 0; i < BYTES_PER_WORD; i++)
|
||||
checksum += (info_frame >> i*BITS_PER_BYTE) & MASK_BYTE0;
|
||||
for (i = 0; i < BYTES_PER_WORD; i++)
|
||||
checksum += (frame2.fr2_val >> i*BITS_PER_BYTE) & MASK_BYTE0;
|
||||
for (i = 0; i < BYTES_PER_WORD; i++)
|
||||
checksum += (frame3.fr3_val >> i*BITS_PER_BYTE) & MASK_BYTE0;
|
||||
|
||||
frame2.fr2_regx.chksum = -(checksum);
|
||||
frame2.fr2_regx.chksum = -(checksum);
|
||||
}
|
||||
|
||||
had_write_register(AUD_HDMIW_INFOFR_v2, INFO_FRAME_WORD1);
|
||||
had_write_register(AUD_HDMIW_INFOFR_v2, info_frame);
|
||||
had_write_register(AUD_HDMIW_INFOFR_v2, frame2.fr2_val);
|
||||
had_write_register(AUD_HDMIW_INFOFR_v2, frame3.fr3_val);
|
||||
|
||||
@ -839,6 +849,85 @@ int snd_intelhad_read_len(struct snd_intelhad *intelhaddata)
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int had_calculate_maud_value(u32 aud_samp_freq, u32 link_rate)
|
||||
{
|
||||
u32 maud_val;
|
||||
|
||||
/* Select maud according to DP 1.2 spec*/
|
||||
if (link_rate == DP_2_7_GHZ) {
|
||||
switch (aud_samp_freq) {
|
||||
case AUD_SAMPLE_RATE_32:
|
||||
maud_val = AUD_SAMPLE_RATE_32_DP_2_7_MAUD_VAL;
|
||||
break;
|
||||
|
||||
case AUD_SAMPLE_RATE_44_1:
|
||||
maud_val = AUD_SAMPLE_RATE_44_1_DP_2_7_MAUD_VAL;
|
||||
break;
|
||||
|
||||
case AUD_SAMPLE_RATE_48:
|
||||
maud_val = AUD_SAMPLE_RATE_48_DP_2_7_MAUD_VAL;
|
||||
break;
|
||||
|
||||
case AUD_SAMPLE_RATE_88_2:
|
||||
maud_val = AUD_SAMPLE_RATE_88_2_DP_2_7_MAUD_VAL;
|
||||
break;
|
||||
|
||||
case AUD_SAMPLE_RATE_96:
|
||||
maud_val = AUD_SAMPLE_RATE_96_DP_2_7_MAUD_VAL;
|
||||
break;
|
||||
|
||||
case AUD_SAMPLE_RATE_176_4:
|
||||
maud_val = AUD_SAMPLE_RATE_176_4_DP_2_7_MAUD_VAL;
|
||||
break;
|
||||
|
||||
case HAD_MAX_RATE:
|
||||
maud_val = HAD_MAX_RATE_DP_2_7_MAUD_VAL;
|
||||
break;
|
||||
|
||||
default:
|
||||
maud_val = -EINVAL;
|
||||
break;
|
||||
}
|
||||
} else if (link_rate == DP_1_62_GHZ) {
|
||||
switch (aud_samp_freq) {
|
||||
case AUD_SAMPLE_RATE_32:
|
||||
maud_val = AUD_SAMPLE_RATE_32_DP_1_62_MAUD_VAL;
|
||||
break;
|
||||
|
||||
case AUD_SAMPLE_RATE_44_1:
|
||||
maud_val = AUD_SAMPLE_RATE_44_1_DP_1_62_MAUD_VAL;
|
||||
break;
|
||||
|
||||
case AUD_SAMPLE_RATE_48:
|
||||
maud_val = AUD_SAMPLE_RATE_48_DP_1_62_MAUD_VAL;
|
||||
break;
|
||||
|
||||
case AUD_SAMPLE_RATE_88_2:
|
||||
maud_val = AUD_SAMPLE_RATE_88_2_DP_1_62_MAUD_VAL;
|
||||
break;
|
||||
|
||||
case AUD_SAMPLE_RATE_96:
|
||||
maud_val = AUD_SAMPLE_RATE_96_DP_1_62_MAUD_VAL;
|
||||
break;
|
||||
|
||||
case AUD_SAMPLE_RATE_176_4:
|
||||
maud_val = AUD_SAMPLE_RATE_176_4_DP_1_62_MAUD_VAL;
|
||||
break;
|
||||
|
||||
case HAD_MAX_RATE:
|
||||
maud_val = HAD_MAX_RATE_DP_1_62_MAUD_VAL;
|
||||
break;
|
||||
|
||||
default:
|
||||
maud_val = -EINVAL;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
maud_val = -EINVAL;
|
||||
|
||||
return maud_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_intelhad_prog_cts_v1 - Program HDMI audio CTS value
|
||||
*
|
||||
@ -849,8 +938,9 @@ int snd_intelhad_read_len(struct snd_intelhad *intelhaddata)
|
||||
*
|
||||
* Program CTS register based on the audio and display sampling frequency
|
||||
*/
|
||||
static void snd_intelhad_prog_cts_v1(u32 aud_samp_freq, u32 tmds, u32 n_param,
|
||||
struct snd_intelhad *intelhaddata)
|
||||
static void snd_intelhad_prog_cts_v1(u32 aud_samp_freq, u32 tmds,
|
||||
u32 link_rate, u32 n_param,
|
||||
struct snd_intelhad *intelhaddata)
|
||||
{
|
||||
u32 cts_val;
|
||||
u64 dividend, divisor;
|
||||
@ -874,18 +964,24 @@ static void snd_intelhad_prog_cts_v1(u32 aud_samp_freq, u32 tmds, u32 n_param,
|
||||
*
|
||||
* Program CTS register based on the audio and display sampling frequency
|
||||
*/
|
||||
static void snd_intelhad_prog_cts_v2(u32 aud_samp_freq, u32 tmds, u32 n_param,
|
||||
struct snd_intelhad *intelhaddata)
|
||||
static void snd_intelhad_prog_cts_v2(u32 aud_samp_freq, u32 tmds,
|
||||
u32 link_rate, u32 n_param,
|
||||
struct snd_intelhad *intelhaddata)
|
||||
{
|
||||
u32 cts_val;
|
||||
u64 dividend, divisor;
|
||||
|
||||
/* Calculate CTS according to HDMI 1.3a spec*/
|
||||
dividend = (u64)tmds * n_param*1000;
|
||||
divisor = 128 * aud_samp_freq;
|
||||
cts_val = div64_u64(dividend, divisor);
|
||||
if (intelhaddata->dp_output) {
|
||||
/* Substitute cts_val with Maud according to DP 1.2 spec*/
|
||||
cts_val = had_calculate_maud_value(aud_samp_freq, link_rate);
|
||||
} else {
|
||||
/* Calculate CTS according to HDMI 1.3a spec*/
|
||||
dividend = (u64)tmds * n_param*1000;
|
||||
divisor = 128 * aud_samp_freq;
|
||||
cts_val = div64_u64(dividend, divisor);
|
||||
}
|
||||
pr_debug("TMDS value=%d, N value=%d, CTS Value=%d\n",
|
||||
tmds, n_param, cts_val);
|
||||
tmds, n_param, cts_val);
|
||||
had_write_register(AUD_HDMI_CTS, (BIT(24) | cts_val));
|
||||
}
|
||||
|
||||
@ -970,7 +1066,18 @@ static int snd_intelhad_prog_n_v2(u32 aud_samp_freq, u32 *n_param,
|
||||
{
|
||||
s32 n_val;
|
||||
|
||||
n_val = had_calculate_n_value(aud_samp_freq);
|
||||
if (intelhaddata->dp_output) {
|
||||
/*
|
||||
* According to DP specs, Maud and Naud values hold
|
||||
* a relationship, which is stated as:
|
||||
* Maud/Naud = 512 * fs / f_LS_Clk
|
||||
* where, fs is the sampling frequency of the audio stream
|
||||
* and Naud is 32768 for Async clock.
|
||||
*/
|
||||
|
||||
n_val = DP_NAUD_VAL;
|
||||
} else
|
||||
n_val = had_calculate_n_value(aud_samp_freq);
|
||||
|
||||
if (n_val < 0)
|
||||
return n_val;
|
||||
@ -1343,6 +1450,7 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream)
|
||||
{
|
||||
int retval;
|
||||
u32 disp_samp_freq, n_param;
|
||||
u32 link_rate = 0;
|
||||
struct snd_intelhad *intelhaddata;
|
||||
struct snd_pcm_runtime *runtime;
|
||||
struct had_pvt_data *had_stream;
|
||||
@ -1387,6 +1495,7 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream)
|
||||
}
|
||||
|
||||
had_get_caps(HAD_GET_ELD, &intelhaddata->eeld);
|
||||
had_get_caps(HAD_GET_DP_OUTPUT, &intelhaddata->dp_output);
|
||||
|
||||
retval = intelhaddata->ops->prog_n(substream->runtime->rate, &n_param,
|
||||
intelhaddata);
|
||||
@ -1394,8 +1503,14 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream)
|
||||
pr_err("programming N value failed %#x\n", retval);
|
||||
goto prep_end;
|
||||
}
|
||||
|
||||
if (intelhaddata->dp_output)
|
||||
had_get_caps(HAD_GET_LINK_RATE, &link_rate);
|
||||
|
||||
|
||||
intelhaddata->ops->prog_cts(substream->runtime->rate,
|
||||
disp_samp_freq, n_param, intelhaddata);
|
||||
disp_samp_freq, link_rate,
|
||||
n_param, intelhaddata);
|
||||
|
||||
intelhaddata->ops->prog_dip(substream, intelhaddata);
|
||||
|
||||
@ -1503,6 +1618,7 @@ int hdmi_audio_mode_change(struct snd_pcm_substream *substream)
|
||||
{
|
||||
int retval = 0;
|
||||
u32 disp_samp_freq, n_param;
|
||||
u32 link_rate = 0;
|
||||
struct snd_intelhad *intelhaddata;
|
||||
|
||||
intelhaddata = snd_pcm_substream_chip(substream);
|
||||
@ -1523,8 +1639,13 @@ int hdmi_audio_mode_change(struct snd_pcm_substream *substream)
|
||||
pr_err("programming N value failed %#x\n", retval);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (intelhaddata->dp_output)
|
||||
had_get_caps(HAD_GET_LINK_RATE, &link_rate);
|
||||
|
||||
intelhaddata->ops->prog_cts(substream->runtime->rate,
|
||||
disp_samp_freq, n_param, intelhaddata);
|
||||
disp_samp_freq, link_rate,
|
||||
n_param, intelhaddata);
|
||||
|
||||
/* Enable Audio */
|
||||
intelhaddata->ops->enable_audio(substream, 1);
|
||||
|
@ -44,7 +44,8 @@
|
||||
#define MAX_CAP_STREAMS 0
|
||||
#define HDMI_AUDIO_DRIVER "hdmi-audio"
|
||||
|
||||
#define INFO_FRAME_WORD1 0x000a0184
|
||||
#define HDMI_INFO_FRAME_WORD1 0x000a0184
|
||||
#define DP_INFO_FRAME_WORD1 0x00441b84
|
||||
#define FIFO_THRESHOLD 0xFE
|
||||
#define DMA_FIFO_THRESHOLD 0x7
|
||||
#define BYTES_PER_WORD 0x4
|
||||
@ -134,6 +135,7 @@ struct snd_intelhad {
|
||||
struct ring_buf_info buf_info[HAD_NUM_OF_RING_BUFS];
|
||||
struct pcm_stream_info stream_info;
|
||||
union otm_hdmi_eld_t eeld;
|
||||
bool dp_output;
|
||||
enum intel_had_aud_buf_type curr_buf;
|
||||
int valid_buf_cnt;
|
||||
unsigned int aes_bits;
|
||||
@ -156,8 +158,8 @@ struct had_ops {
|
||||
void (*reset_audio)(u8 reset);
|
||||
int (*prog_n)(u32 aud_samp_freq, u32 *n_param,
|
||||
struct snd_intelhad *intelhaddata);
|
||||
void (*prog_cts)(u32 aud_samp_freq, u32 tmds, u32 n_param,
|
||||
struct snd_intelhad *intelhaddata);
|
||||
void (*prog_cts)(u32 aud_samp_freq, u32 tmds, u32 link_rate,
|
||||
u32 n_param, struct snd_intelhad *intelhaddata);
|
||||
int (*audio_ctrl)(struct snd_pcm_substream *substream,
|
||||
struct snd_intelhad *intelhaddata);
|
||||
void (*prog_dip)(struct snd_pcm_substream *substream,
|
||||
|
@ -48,6 +48,8 @@ struct hdmi_lpe_audio_ctx {
|
||||
struct snd_intel_had_interface *had_interface;
|
||||
void *had_pvt_data;
|
||||
int tmds_clock_speed;
|
||||
bool dp_output;
|
||||
int link_rate;
|
||||
unsigned int had_config_offset;
|
||||
int hdmi_audio_interrupt_mask;
|
||||
struct work_struct hdmi_audio_wq;
|
||||
@ -187,6 +189,15 @@ static int hdmi_audio_write(u32 reg, u32 val)
|
||||
|
||||
dev_dbg(&hlpe_pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__, reg, val);
|
||||
|
||||
if (ctx->dp_output) {
|
||||
if ((reg == AUDIO_HDMI_CONFIG_A) ||
|
||||
(reg == AUDIO_HDMI_CONFIG_B) ||
|
||||
(reg == AUDIO_HDMI_CONFIG_C)) {
|
||||
if (val & AUD_CONFIG_VALID_BIT)
|
||||
val = val | AUD_CONFIG_DP_MODE |
|
||||
AUD_CONFIG_BLOCK_BIT;
|
||||
}
|
||||
}
|
||||
iowrite32(val, (ctx->mmio_start+reg));
|
||||
|
||||
return 0;
|
||||
@ -220,6 +231,16 @@ static int hdmi_audio_rmw(u32 reg, u32 val, u32 mask)
|
||||
val_tmp = (val & mask) |
|
||||
((ioread32(ctx->mmio_start + reg)) & ~mask);
|
||||
|
||||
if (ctx->dp_output) {
|
||||
if ((reg == AUDIO_HDMI_CONFIG_A) ||
|
||||
(reg == AUDIO_HDMI_CONFIG_B) ||
|
||||
(reg == AUDIO_HDMI_CONFIG_C)) {
|
||||
if (val_tmp & AUD_CONFIG_VALID_BIT)
|
||||
val_tmp = val_tmp | AUD_CONFIG_DP_MODE |
|
||||
AUD_CONFIG_BLOCK_BIT;
|
||||
}
|
||||
}
|
||||
|
||||
iowrite32(val_tmp, (ctx->mmio_start+reg));
|
||||
dev_dbg(&hlpe_pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__,
|
||||
reg, val_tmp);
|
||||
@ -249,7 +270,18 @@ static int hdmi_audio_get_caps(enum had_caps_list get_element,
|
||||
/* ToDo: Verify if sampling freq logic is correct */
|
||||
*(u32 *)capabilities = ctx->tmds_clock_speed;
|
||||
dev_dbg(&hlpe_pdev->dev, "%s: tmds_clock_speed = 0x%x\n",
|
||||
__func__, ctx->tmds_clock_speed);
|
||||
__func__, ctx->tmds_clock_speed);
|
||||
break;
|
||||
case HAD_GET_LINK_RATE:
|
||||
/* ToDo: Verify if sampling freq logic is correct */
|
||||
*(u32 *)capabilities = ctx->link_rate;
|
||||
dev_dbg(&hlpe_pdev->dev, "%s: link rate = 0x%x\n",
|
||||
__func__, ctx->link_rate);
|
||||
break;
|
||||
case HAD_GET_DP_OUTPUT:
|
||||
*(u32 *)capabilities = ctx->dp_output;
|
||||
dev_dbg(&hlpe_pdev->dev, "%s: dp_output = %d\n",
|
||||
__func__, ctx->dp_output);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -407,15 +439,14 @@ static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void notify_audio_lpe(void *audio_ptr)
|
||||
static void notify_audio_lpe(struct platform_device *pdev)
|
||||
{
|
||||
struct hdmi_lpe_audio_ctx *ctx = get_hdmi_context();
|
||||
struct intel_hdmi_lpe_audio_pdata *pdata = hlpe_pdev->dev.platform_data;
|
||||
struct intel_hdmi_lpe_audio_eld *eld = audio_ptr;
|
||||
struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev);
|
||||
struct intel_hdmi_lpe_audio_pdata *pdata = pdev->dev.platform_data;
|
||||
|
||||
if (pdata->hdmi_connected != true) {
|
||||
|
||||
dev_dbg(&hlpe_pdev->dev, "%s: Event: HAD_NOTIFY_HOT_UNPLUG\n",
|
||||
dev_dbg(&pdev->dev, "%s: Event: HAD_NOTIFY_HOT_UNPLUG\n",
|
||||
__func__);
|
||||
|
||||
if (hlpe_state == hdmi_connector_status_connected) {
|
||||
@ -426,10 +457,27 @@ static void notify_audio_lpe(void *audio_ptr)
|
||||
mid_hdmi_audio_signal_event(
|
||||
HAD_EVENT_HOT_UNPLUG);
|
||||
} else
|
||||
dev_dbg(&hlpe_pdev->dev, "%s: Already Unplugged!\n",
|
||||
dev_dbg(&pdev->dev, "%s: Already Unplugged!\n",
|
||||
__func__);
|
||||
|
||||
} else if (eld != NULL) {
|
||||
} else {
|
||||
struct intel_hdmi_lpe_audio_eld *eld = &pdata->eld;
|
||||
|
||||
switch (eld->pipe_id) {
|
||||
case 0:
|
||||
ctx->had_config_offset = AUDIO_HDMI_CONFIG_A;
|
||||
break;
|
||||
case 1:
|
||||
ctx->had_config_offset = AUDIO_HDMI_CONFIG_B;
|
||||
break;
|
||||
case 2:
|
||||
ctx->had_config_offset = AUDIO_HDMI_CONFIG_C;
|
||||
break;
|
||||
default:
|
||||
dev_dbg(&pdev->dev, "Invalid pipe %d\n",
|
||||
eld->pipe_id);
|
||||
break;
|
||||
}
|
||||
|
||||
hdmi_set_eld(eld->eld_data);
|
||||
|
||||
@ -437,15 +485,16 @@ static void notify_audio_lpe(void *audio_ptr)
|
||||
|
||||
hlpe_state = hdmi_connector_status_connected;
|
||||
|
||||
dev_dbg(&hlpe_pdev->dev, "%s: HAD_NOTIFY_ELD : port = %d, tmds = %d\n",
|
||||
dev_dbg(&pdev->dev, "%s: HAD_NOTIFY_ELD : port = %d, tmds = %d\n",
|
||||
__func__, eld->port_id, pdata->tmds_clock_speed);
|
||||
|
||||
if (pdata->tmds_clock_speed) {
|
||||
ctx->tmds_clock_speed = pdata->tmds_clock_speed;
|
||||
ctx->dp_output = pdata->dp_output;
|
||||
ctx->link_rate = pdata->link_rate;
|
||||
mid_hdmi_audio_signal_event(HAD_EVENT_MODE_CHANGING);
|
||||
}
|
||||
} else
|
||||
dev_dbg(&hlpe_pdev->dev, "%s: Event: NULL EDID!!\n", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -526,15 +575,15 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev)
|
||||
ctx->mmio_start = mmio_start;
|
||||
ctx->tmds_clock_speed = DIS_SAMPLE_RATE_148_5;
|
||||
|
||||
if (pci_dev_present(cherryview_ids)) {
|
||||
if (pci_dev_present(cherryview_ids))
|
||||
dev_dbg(&hlpe_pdev->dev, "%s: Cherrytrail LPE - Detected\n",
|
||||
__func__);
|
||||
ctx->had_config_offset = AUDIO_HDMI_CONFIG_C;
|
||||
} else {
|
||||
else
|
||||
dev_dbg(&hlpe_pdev->dev, "%s: Baytrail LPE - Assume\n",
|
||||
__func__);
|
||||
ctx->had_config_offset = AUDIO_HDMI_CONFIG_A;
|
||||
}
|
||||
|
||||
/* assume pipe A as default */
|
||||
ctx->had_config_offset = AUDIO_HDMI_CONFIG_A;
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
|
||||
@ -556,7 +605,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev)
|
||||
if (pdata->notify_pending) {
|
||||
|
||||
dev_dbg(&hlpe_pdev->dev, "%s: handle pending notification\n", __func__);
|
||||
notify_audio_lpe(&pdata->eld);
|
||||
notify_audio_lpe(pdev);
|
||||
pdata->notify_pending = false;
|
||||
}
|
||||
spin_unlock_irqrestore(&pdata->lpe_audio_slock, flag_irq);
|
||||
|
@ -31,6 +31,10 @@
|
||||
#include <sound/control.h>
|
||||
#include <sound/pcm.h>
|
||||
|
||||
#define AUD_CONFIG_VALID_BIT (1<<9)
|
||||
#define AUD_CONFIG_DP_MODE (1<<15)
|
||||
#define AUD_CONFIG_BLOCK_BIT (1<<7)
|
||||
|
||||
#define HMDI_LPE_AUDIO_DRIVER_NAME "intel-hdmi-lpe-audio"
|
||||
#define HAD_MAX_DEVICES 1
|
||||
#define HAD_MIN_CHANNEL 2
|
||||
@ -68,6 +72,29 @@
|
||||
#define HAD_MAX_DIP_WORDS 16
|
||||
#define INTEL_HAD "IntelHdmiLpeAudio"
|
||||
|
||||
/* DP Link Rates */
|
||||
#define DP_2_7_GHZ 270000
|
||||
#define DP_1_62_GHZ 162000
|
||||
|
||||
/* Maud Values */
|
||||
#define AUD_SAMPLE_RATE_32_DP_2_7_MAUD_VAL 1988
|
||||
#define AUD_SAMPLE_RATE_44_1_DP_2_7_MAUD_VAL 2740
|
||||
#define AUD_SAMPLE_RATE_48_DP_2_7_MAUD_VAL 2982
|
||||
#define AUD_SAMPLE_RATE_88_2_DP_2_7_MAUD_VAL 5480
|
||||
#define AUD_SAMPLE_RATE_96_DP_2_7_MAUD_VAL 5965
|
||||
#define AUD_SAMPLE_RATE_176_4_DP_2_7_MAUD_VAL 10961
|
||||
#define HAD_MAX_RATE_DP_2_7_MAUD_VAL 11930
|
||||
#define AUD_SAMPLE_RATE_32_DP_1_62_MAUD_VAL 3314
|
||||
#define AUD_SAMPLE_RATE_44_1_DP_1_62_MAUD_VAL 4567
|
||||
#define AUD_SAMPLE_RATE_48_DP_1_62_MAUD_VAL 4971
|
||||
#define AUD_SAMPLE_RATE_88_2_DP_1_62_MAUD_VAL 9134
|
||||
#define AUD_SAMPLE_RATE_96_DP_1_62_MAUD_VAL 9942
|
||||
#define AUD_SAMPLE_RATE_176_4_DP_1_62_MAUD_VAL 18268
|
||||
#define HAD_MAX_RATE_DP_1_62_MAUD_VAL 19884
|
||||
|
||||
/* Naud Value */
|
||||
#define DP_NAUD_VAL 32768
|
||||
|
||||
/* _AUD_CONFIG register MASK */
|
||||
#define AUD_CONFIG_MASK_UNDERRUN 0xC0000000
|
||||
#define AUD_CONFIG_MASK_SRDBG 0x00000002
|
||||
@ -618,6 +645,8 @@ enum hdmi_connector_status {
|
||||
enum had_caps_list {
|
||||
HAD_GET_ELD = 1,
|
||||
HAD_GET_DISPLAY_RATE,
|
||||
HAD_GET_DP_OUTPUT,
|
||||
HAD_GET_LINK_RATE,
|
||||
HAD_SET_ENABLE_AUDIO,
|
||||
HAD_SET_DISABLE_AUDIO,
|
||||
HAD_SET_ENABLE_AUDIO_INT,
|
||||
|
Loading…
Reference in New Issue
Block a user