From 88e3a6f0ba3d65bcb797f6f28506b2c58ec56eda Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 5 May 2015 16:49:35 -0400 Subject: [PATCH] drm/radeon: handle audio for PX Need to delay runtime pm if the audio driver is not loaded. Bug: https://bugs.freedesktop.org/show_bug.cgi?id=90321 Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/radeon_device.c | 15 +++++++++++++++ drivers/gpu/drm/radeon/radeon_drv.c | 8 ++++++++ drivers/gpu/drm/radeon/radeon_kms.c | 34 +++++++++++++++++++++++++++++++++- 4 files changed, 57 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index d2abe48..224dcfa 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -2450,6 +2450,7 @@ struct radeon_device { struct dev_pm_domain vga_pm_domain; bool have_disp_power_ref; u32 px_quirk_flags; + struct pci_dev *hdmi_audio_device; /* tracking pinned memory */ u64 vram_pin_size; diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index b7ca4c5..5828a71 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -161,6 +161,21 @@ static void radeon_device_handle_px_quirks(struct radeon_device *rdev) rdev->flags &= ~RADEON_IS_PX; } +bool radeon_is_hdmi_audio_driver_loaded(struct drm_device *dev) +{ + struct radeon_device *rdev = dev->dev_private; + + /* if we have a hdmi audio device - make sure it has a driver loaded */ + if (rdev->hdmi_audio_device) { + if (rdev->hdmi_audio_device->driver) + return true; + else + return false; + } + /* return true if there is no audio device */ + return true; +} + /** * radeon_program_register_sequence - program an array of registers. * diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 7d620d4..ad291cd 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -128,6 +128,7 @@ extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, int *vpos, int *hpos, ktime_t *stime, ktime_t *etime); extern bool radeon_is_px(struct drm_device *dev); +extern bool radeon_is_hdmi_audio_driver_loaded(struct drm_device *dev); extern const struct drm_ioctl_desc radeon_ioctls_kms[]; extern int radeon_max_kms_ioctl; int radeon_mmap(struct file *filp, struct vm_area_struct *vma); @@ -505,6 +506,13 @@ static int radeon_pmops_runtime_idle(struct device *dev) return -EBUSY; } + /* if we have a hdmi audio device - make sure it has a driver loaded */ + if (!radeon_is_hdmi_audio_driver_loaded(drm_dev)) { + DRM_DEBUG_DRIVER("failing to power off - no HDMI audio driver loaded\n"); + pm_runtime_mark_last_busy(dev); + return -EBUSY; + } + list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head) { if (crtc->enabled) { DRM_DEBUG_DRIVER("failing to power off - crtc active\n"); diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 7b2a733..35c65d5 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -42,6 +42,33 @@ bool radeon_has_atpx(void); static inline bool radeon_has_atpx(void) { return false; } #endif +#define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403 + +static void +radeon_get_hdmi_audio_dev(struct radeon_device *rdev) +{ + struct pci_dev *pdev = rdev->pdev; + + if (!pdev) { + DRM_INFO("not a PCI device; no HDMI\n"); + rdev->hdmi_audio_device = NULL; + return; + } + + /* subfunction one is a hdmi audio device? */ + rdev->hdmi_audio_device = pci_get_bus_and_slot((unsigned int)pdev->bus->number, + PCI_DEVFN(PCI_SLOT(pdev->devfn), 1)); + + if (!rdev->hdmi_audio_device) + return; + + if ((rdev->hdmi_audio_device->class >> 8) != PCI_CLASS_MULTIMEDIA_HD_AUDIO) { + pci_dev_put(rdev->hdmi_audio_device); + rdev->hdmi_audio_device = NULL; + return; + } +} + /** * radeon_driver_unload_kms - Main unload function for KMS. * @@ -68,7 +95,10 @@ int radeon_driver_unload_kms(struct drm_device *dev) radeon_kfd_device_fini(rdev); radeon_acpi_fini(rdev); - + + if (rdev->hdmi_audio_device) + pci_dev_put(rdev->hdmi_audio_device); + radeon_modeset_fini(rdev); radeon_device_fini(rdev); @@ -136,6 +166,8 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags) if (r) dev_err(&dev->pdev->dev, "Fatal error during modeset init\n"); + radeon_get_hdmi_audio_dev(rdev); + /* Call ACPI methods: require modeset init * but failure is not fatal */ -- 1.8.3.1