|
@@ -57,6 +57,63 @@
|
|
|
* struct &i915_audio_component_audio_ops @audio_ops is called from i915 driver.
|
|
|
*/
|
|
|
|
|
|
+/* DP N/M table */
|
|
|
+#define LC_540M 540000
|
|
|
+#define LC_270M 270000
|
|
|
+#define LC_162M 162000
|
|
|
+
|
|
|
+struct dp_aud_n_m {
|
|
|
+ int sample_rate;
|
|
|
+ int clock;
|
|
|
+ u16 m;
|
|
|
+ u16 n;
|
|
|
+};
|
|
|
+
|
|
|
+/* Values according to DP 1.4 Table 2-104 */
|
|
|
+static const struct dp_aud_n_m dp_aud_n_m[] = {
|
|
|
+ { 32000, LC_162M, 1024, 10125 },
|
|
|
+ { 44100, LC_162M, 784, 5625 },
|
|
|
+ { 48000, LC_162M, 512, 3375 },
|
|
|
+ { 64000, LC_162M, 2048, 10125 },
|
|
|
+ { 88200, LC_162M, 1568, 5625 },
|
|
|
+ { 96000, LC_162M, 1024, 3375 },
|
|
|
+ { 128000, LC_162M, 4096, 10125 },
|
|
|
+ { 176400, LC_162M, 3136, 5625 },
|
|
|
+ { 192000, LC_162M, 2048, 3375 },
|
|
|
+ { 32000, LC_270M, 1024, 16875 },
|
|
|
+ { 44100, LC_270M, 784, 9375 },
|
|
|
+ { 48000, LC_270M, 512, 5625 },
|
|
|
+ { 64000, LC_270M, 2048, 16875 },
|
|
|
+ { 88200, LC_270M, 1568, 9375 },
|
|
|
+ { 96000, LC_270M, 1024, 5625 },
|
|
|
+ { 128000, LC_270M, 4096, 16875 },
|
|
|
+ { 176400, LC_270M, 3136, 9375 },
|
|
|
+ { 192000, LC_270M, 2048, 5625 },
|
|
|
+ { 32000, LC_540M, 1024, 33750 },
|
|
|
+ { 44100, LC_540M, 784, 18750 },
|
|
|
+ { 48000, LC_540M, 512, 11250 },
|
|
|
+ { 64000, LC_540M, 2048, 33750 },
|
|
|
+ { 88200, LC_540M, 1568, 18750 },
|
|
|
+ { 96000, LC_540M, 1024, 11250 },
|
|
|
+ { 128000, LC_540M, 4096, 33750 },
|
|
|
+ { 176400, LC_540M, 3136, 18750 },
|
|
|
+ { 192000, LC_540M, 2048, 11250 },
|
|
|
+};
|
|
|
+
|
|
|
+static const struct dp_aud_n_m *
|
|
|
+audio_config_dp_get_n_m(struct intel_crtc *intel_crtc, int rate)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < ARRAY_SIZE(dp_aud_n_m); i++) {
|
|
|
+ if (rate == dp_aud_n_m[i].sample_rate &&
|
|
|
+ intel_crtc->config->port_clock == dp_aud_n_m[i].clock)
|
|
|
+ return &dp_aud_n_m[i];
|
|
|
+ }
|
|
|
+
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
static const struct {
|
|
|
int clock;
|
|
|
u32 config;
|
|
@@ -225,16 +282,43 @@ hsw_dp_audio_config_update(struct intel_crtc *intel_crtc, enum port port,
|
|
|
const struct drm_display_mode *adjusted_mode)
|
|
|
{
|
|
|
struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
|
|
|
+ struct i915_audio_component *acomp = dev_priv->audio_component;
|
|
|
+ int rate = acomp ? acomp->aud_sample_rate[port] : 0;
|
|
|
+ const struct dp_aud_n_m *nm = audio_config_dp_get_n_m(intel_crtc, rate);
|
|
|
enum pipe pipe = intel_crtc->pipe;
|
|
|
u32 tmp;
|
|
|
|
|
|
+ if (nm)
|
|
|
+ DRM_DEBUG_KMS("using Maud %u, Naud %u\n", nm->m, nm->n);
|
|
|
+ else
|
|
|
+ DRM_DEBUG_KMS("using automatic Maud, Naud\n");
|
|
|
+
|
|
|
tmp = I915_READ(HSW_AUD_CFG(pipe));
|
|
|
tmp &= ~AUD_CONFIG_N_VALUE_INDEX;
|
|
|
tmp &= ~AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK;
|
|
|
tmp &= ~AUD_CONFIG_N_PROG_ENABLE;
|
|
|
tmp |= AUD_CONFIG_N_VALUE_INDEX;
|
|
|
|
|
|
+ if (nm) {
|
|
|
+ tmp &= ~AUD_CONFIG_N_MASK;
|
|
|
+ tmp |= AUD_CONFIG_N(nm->n);
|
|
|
+ tmp |= AUD_CONFIG_N_PROG_ENABLE;
|
|
|
+ }
|
|
|
+
|
|
|
I915_WRITE(HSW_AUD_CFG(pipe), tmp);
|
|
|
+
|
|
|
+ tmp = I915_READ(HSW_AUD_M_CTS_ENABLE(pipe));
|
|
|
+ tmp &= ~AUD_CONFIG_M_MASK;
|
|
|
+ tmp &= ~AUD_M_CTS_M_VALUE_INDEX;
|
|
|
+ tmp &= ~AUD_M_CTS_M_PROG_ENABLE;
|
|
|
+
|
|
|
+ if (nm) {
|
|
|
+ tmp |= nm->m;
|
|
|
+ tmp |= AUD_M_CTS_M_VALUE_INDEX;
|
|
|
+ tmp |= AUD_M_CTS_M_PROG_ENABLE;
|
|
|
+ }
|
|
|
+
|
|
|
+ I915_WRITE(HSW_AUD_M_CTS_ENABLE(pipe), tmp);
|
|
|
}
|
|
|
|
|
|
static void
|
|
@@ -266,6 +350,12 @@ hsw_hdmi_audio_config_update(struct intel_crtc *intel_crtc, enum port port,
|
|
|
}
|
|
|
|
|
|
I915_WRITE(HSW_AUD_CFG(pipe), tmp);
|
|
|
+
|
|
|
+ tmp = I915_READ(HSW_AUD_M_CTS_ENABLE(pipe));
|
|
|
+ tmp &= ~AUD_CONFIG_M_MASK;
|
|
|
+ tmp &= ~AUD_M_CTS_M_VALUE_INDEX;
|
|
|
+ tmp |= AUD_M_CTS_M_PROG_ENABLE;
|
|
|
+ I915_WRITE(HSW_AUD_M_CTS_ENABLE(pipe), tmp);
|
|
|
}
|
|
|
|
|
|
static void
|
|
@@ -686,7 +776,8 @@ static int i915_audio_component_sync_audio_rate(struct device *kdev, int port,
|
|
|
/* 1. get the pipe */
|
|
|
intel_encoder = get_saved_enc(dev_priv, port, pipe);
|
|
|
if (!intel_encoder || !intel_encoder->base.crtc ||
|
|
|
- intel_encoder->type != INTEL_OUTPUT_HDMI) {
|
|
|
+ (intel_encoder->type != INTEL_OUTPUT_HDMI &&
|
|
|
+ intel_encoder->type != INTEL_OUTPUT_DP)) {
|
|
|
DRM_DEBUG_KMS("Not valid for port %c\n", port_name(port));
|
|
|
err = -ENODEV;
|
|
|
goto unlock;
|