[Nouveau] [PATCH] [RFC] drm/nouveau: bring back hdmi audio device after switcheroo power down
Maarten Lankhorst
maarten.lankhorst at canonical.com
Wed Jul 24 06:38:35 PDT 2013
Op 24-07-13 09:13, Dave Airlie schreef:
> After a full device powerdown via the optimus power switch, we seem
> to lose the HDMI device completely on power on, this keep track of
> whether we had a hdmi audio sub function device at power on, and
> pokes a magic register to make it reappear after the optimus power
> switch is thrown.
>
> This at least works on my NVC4 machine, probably needs testing on
> a few other laptops with other nvidia GPUs.
>
> Signed-off-by: Dave Airlie <airlied at redhat.com>
> ---
> drivers/gpu/drm/nouveau/nouveau_drm.c | 32 ++++++++++++++++++++++++++++++++
> drivers/gpu/drm/nouveau/nouveau_drm.h | 2 ++
> drivers/gpu/drm/nouveau/nouveau_vga.c | 17 +++++++++++++++++
> 3 files changed, 51 insertions(+)
>
> diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
> index 6197266..12a6240 100644
> --- a/drivers/gpu/drm/nouveau/nouveau_drm.c
> +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
> @@ -296,6 +296,31 @@ static int nouveau_drm_probe(struct pci_dev *pdev,
> return 0;
> }
>
> +#define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403
> +
> +static void
> +nouveau_get_hdmi_dev(struct drm_device *dev)
> +{
> + struct nouveau_drm *drm = dev->dev_private;
> + struct pci_dev *pdev = dev->pdev;
> +
> + /* subfunction one is a hdmi audio device? */
> + drm->hdmi_device = pci_get_bus_and_slot((unsigned int)pdev->bus->number,
> + PCI_DEVFN(PCI_SLOT(pdev->devfn), 1));
> +
> + if (!drm->hdmi_device) {
> + DRM_INFO("hdmi device not found %d %d %d\n", pdev->bus->number, PCI_SLOT(pdev->devfn), 1);
> + return;
> + }
> +
> + if ((drm->hdmi_device->class >> 8) != PCI_CLASS_MULTIMEDIA_HD_AUDIO) {
> + DRM_INFO("possible hdmi device not audio %d\n", drm->hdmi_device->class);
> + pci_dev_put(drm->hdmi_device);
> + drm->hdmi_device = NULL;
> + return;
> + }
> +}
> +
> static int
> nouveau_drm_load(struct drm_device *dev, unsigned long flags)
> {
> @@ -314,6 +339,8 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
> INIT_LIST_HEAD(&drm->clients);
> spin_lock_init(&drm->tile.lock);
>
> + nouveau_get_hdmi_dev(dev);
> +
> /* make sure AGP controller is in a consistent state before we
> * (possibly) execute vbios init tables (see nouveau_agp.h)
> */
> @@ -400,6 +427,9 @@ fail_ttm:
> nouveau_agp_fini(drm);
> nouveau_vga_fini(drm);
> fail_device:
> + if (drm->hdmi_device)
> + pci_dev_put(drm->hdmi_device);
> +
> nouveau_cli_destroy(&drm->client);
> return ret;
> }
> @@ -424,6 +454,8 @@ nouveau_drm_unload(struct drm_device *dev)
> nouveau_agp_fini(drm);
> nouveau_vga_fini(drm);
>
> + if (drm->hdmi_device)
> + pci_dev_put(drm->hdmi_device);
> nouveau_cli_destroy(&drm->client);
> return 0;
> }
> diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.h b/drivers/gpu/drm/nouveau/nouveau_drm.h
> index 41ff7e0..f276e37 100644
> --- a/drivers/gpu/drm/nouveau/nouveau_drm.h
> +++ b/drivers/gpu/drm/nouveau/nouveau_drm.h
> @@ -129,6 +129,8 @@ struct nouveau_drm {
>
> /* power management */
> struct nouveau_pm *pm;
> +
> + struct pci_dev *hdmi_device;
> };
>
> static inline struct nouveau_drm *
> diff --git a/drivers/gpu/drm/nouveau/nouveau_vga.c b/drivers/gpu/drm/nouveau/nouveau_vga.c
> index 25d3495..d8af49c 100644
> --- a/drivers/gpu/drm/nouveau/nouveau_vga.c
> +++ b/drivers/gpu/drm/nouveau/nouveau_vga.c
> @@ -27,6 +27,22 @@ nouveau_vga_set_decode(void *priv, bool state)
> }
>
> static void
> +nouveau_reenable_hdmi_device(struct drm_device *dev)
> +{
> + struct nouveau_drm *drm = nouveau_drm(dev);
> + struct nouveau_device *device = nv_device(drm->device);
> + uint32_t val;
> +
> + if (!drm->hdmi_device)
> + return;
> +
> + /* write magic value into magic place */
> + val = nv_rd32(device, 0x88488);
> + val |= (1 << 25);
> + nv_wr32(device, 0x88488, val);
> +}
use nv_mask(dev, 0x88488, 0x02000000, 0x02000000);
Could this be added in core/engine/disp/hdminv84.c nv84_hdmi_ctrl to get the same effect?
~Maarten
More information about the Nouveau
mailing list