diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 97ace4c..a0682f2 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1682,6 +1682,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) dev_priv->ums.mm_suspended = 1; } + intel_eld_contxt_init(dev); + i915_setup_sysfs(dev); if (INTEL_INFO(dev)->num_pipes) { @@ -1752,6 +1754,8 @@ int i915_driver_unload(struct drm_device *dev) intel_display_set_init_power(dev, true); intel_power_domains_remove(dev); + intel_eld_contxt_remove(dev); + i915_teardown_sysfs(dev); if (dev_priv->mm.inactive_shrinker.scan_objects) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 9ece015..fd8d9dc 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1034,6 +1034,12 @@ struct i915_ums_state { int mm_suspended; }; +struct i915_eld_contxt { + struct drm_encoder *drm_encoder ; + struct drm_display_mode *mode; + bool set_eld_contxt; +}; + #define MAX_L3_SLICES 2 struct intel_l3_parity { u32 *remap_info[MAX_L3_SLICES]; @@ -1590,6 +1596,8 @@ typedef struct drm_i915_private { struct i915_dri1_state dri1; /* Old ums support infrastructure, same warning applies. */ struct i915_ums_state ums; + + struct i915_eld_contxt eld_contxt; } drm_i915_private_t; static inline struct drm_i915_private *to_i915(const struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9410797..aaa5fbe 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -42,6 +42,7 @@ #include #include #include +#include static void intel_increase_pllclock(struct drm_crtc *crtc); static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on); @@ -7478,28 +7479,95 @@ static void ironlake_write_eld(struct drm_connector *connector, I915_WRITE(aud_cntrl_st2, i); } +void intel_write_eld_contxt (struct drm_device *dev) +{ + struct drm_crtc *crtc; + struct drm_display_mode *mode; + struct drm_encoder *encoder; + struct drm_connector *connector; + struct drm_i915_private *dev_priv = dev->dev_private; + struct i915_eld_contxt * eld_contxt = &dev_priv-> eld_contxt; + + /* Check if the write_eld is already defered + * and waiting for audio cb to do write_eld + */ + if (eld_contxt->set_eld_contxt == false) + eld_contxt->set_eld_contxt = true; + else if (eld_contxt->set_eld_contxt == true) { + encoder = eld_contxt->drm_encoder; + crtc = encoder->crtc; + mode = eld_contxt->mode; + + connector = drm_select_eld(encoder, mode); + if (!connector) + return; + + DRM_DEBUG_DRIVER("ELD on [CONNECTOR:%d:%s], [ENCODER:%d:%s]\n", + connector->base.id, + drm_get_connector_name(connector), + connector->encoder->base.id, + drm_get_encoder_name(connector->encoder)); + + connector->eld[6] = drm_av_sync_delay(connector, mode) / 2; + + if (dev_priv->display.write_eld){ + dev_priv->display.write_eld(connector, crtc, mode); + } + } +} + +static struct i915_eld_contxt * eld_contxt_ptr; +void i915_write_eld_cb(void) +{ + struct drm_i915_private *dev_priv; + + if (WARN_ON(!eld_contxt_ptr)) + return; + + dev_priv = container_of(eld_contxt_ptr, struct drm_i915_private, + eld_contxt); + intel_write_eld_contxt (dev_priv->dev); +} +EXPORT_SYMBOL_GPL(i915_write_eld_cb); + void intel_write_eld(struct drm_encoder *encoder, struct drm_display_mode *mode) { - struct drm_crtc *crtc = encoder->crtc; - struct drm_connector *connector; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct i915_eld_contxt * eld_contxt = &dev_priv-> eld_contxt; - connector = drm_select_eld(encoder, mode); - if (!connector) - return; + eld_contxt->drm_encoder = encoder; + eld_contxt->mode = mode; - DRM_DEBUG_DRIVER("ELD on [CONNECTOR:%d:%s], [ENCODER:%d:%s]\n", - connector->base.id, - drm_get_connector_name(connector), - connector->encoder->base.id, - drm_get_encoder_name(connector->encoder)); + if (eld_contxt->set_eld_contxt == false) { + /* Defering write_eld till the audio device is ready + * otherwise audio is reading null ELD data. + * Audio cb handles write_eld when it is ready + */ + eld_contxt->set_eld_contxt = true; + } + else if (eld_contxt->set_eld_contxt == true) { + intel_write_eld_contxt (dev_priv->dev); + } +} + +int intel_eld_contxt_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct i915_eld_contxt * eld_contxt = &dev_priv-> eld_contxt; - connector->eld[6] = drm_av_sync_delay(connector, mode) / 2; + eld_contxt->drm_encoder = NULL; + eld_contxt->mode = NULL; + eld_contxt->set_eld_contxt = false; + eld_contxt_ptr = eld_contxt; - if (dev_priv->display.write_eld) - dev_priv->display.write_eld(connector, crtc, mode); + return 0; +} + +void intel_eld_contxt_remove(struct drm_device *dev) +{ + eld_contxt_ptr = NULL; } static void i845_update_cursor(struct drm_crtc *crtc, u32 base) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index e0d6a2b..1dd8d83 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -749,6 +749,9 @@ void hsw_enable_ips(struct intel_crtc *crtc); void hsw_disable_ips(struct intel_crtc *crtc); void intel_display_set_init_power(struct drm_device *dev, bool enable); int valleyview_get_vco(struct drm_i915_private *dev_priv); +void intel_write_eld_contxt (struct drm_device *dev); +int intel_eld_contxt_init(struct drm_device *dev); +void intel_eld_contxt_remove(struct drm_device *dev); /* intel_dp.c */ void intel_dp_init(struct drm_device *dev, int output_reg, enum port port); diff --git a/include/drm/i915_powerwell.h b/include/drm/i915_powerwell.h index d715ca1..f585351 100644 --- a/include/drm/i915_powerwell.h +++ b/include/drm/i915_powerwell.h @@ -34,4 +34,6 @@ extern void i915_request_power_well(void); extern void i915_release_power_well(void); extern int i915_get_cdclk_freq(void); +/* Move below callback from powerwell to proper hda_i915 interface*/ +extern void i915_write_eld_cb(void); #endif /* _I915_POWERWELL_H_ */ diff --git a/sound/pci/hda/hda_i915.c b/sound/pci/hda/hda_i915.c index e7b2d84..8ce6d18 100644 --- a/sound/pci/hda/hda_i915.c +++ b/sound/pci/hda/hda_i915.c @@ -35,6 +35,7 @@ static void (*get_power)(void); static void (*put_power)(void); static int (*get_cdclk)(void); +static void (*write_eld)(void); void hda_display_power(bool enable) { @@ -129,3 +130,27 @@ int hda_i915_exit(void) return 0; } + +int hda_i915_eld_init(void) +{ + int err = 0; + + write_eld = symbol_request(i915_write_eld_cb); + if (!write_eld) { + snd_printk(KERN_WARNING "hda-i915: write_eld symbol get fail\n"); + return -ENODEV; + } + + write_eld(); + return err; +} + +int hda_i915_eld_exit(void) +{ + if (write_eld) { + symbol_put(i915_write_eld_cb); + write_eld = NULL; + } + + return 0; +} diff --git a/sound/pci/hda/hda_i915.h b/sound/pci/hda/hda_i915.h index fe3940e..6d97030 100644 --- a/sound/pci/hda/hda_i915.h +++ b/sound/pci/hda/hda_i915.h @@ -34,4 +34,7 @@ static inline int hda_i915_exit(void) } #endif +int hda_i915_eld_init(void); +int hda_i915_eld_exit(void); + #endif diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 0d4f243..558541f 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -960,6 +960,8 @@ static int azx_free(struct azx *chip) hda_display_power(false); hda_i915_exit(); } + + hda_i915_eld_exit(); kfree(hda); return 0; @@ -1750,6 +1752,12 @@ static int azx_probe_continue(struct azx *chip) if (err < 0) goto out_free; + err = hda_i915_eld_init(); + if (err < 0) { + snd_printk(KERN_ERR SFX "Error request write eld from i915\n"); + goto out_free; + } + chip->running = 1; power_down_all_codecs(chip); azx_notifier_register(chip);