Am Mittwoch, den 24.07.2013, 17:13 +1000 schrieb Dave Airlie:
> 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

keep*s*

> 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

Should that go into some header?

> +
> +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? */

Just function as in <domain>:<bus>:<slot>.<func>?

> +     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);

Just one space after device?

> +             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 a define for this nevertheless?

> +}
> +
> +static void
>  nouveau_switcheroo_set_state(struct pci_dev *pdev,
>                            enum vga_switcheroo_state state)
>  {
> @@ -37,6 +53,7 @@ nouveau_switcheroo_set_state(struct pci_dev *pdev,
>               dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
>               nouveau_pmops_resume(&pdev->dev);
>               drm_kms_helper_poll_enable(dev);
> +             nouveau_reenable_hdmi_device(dev);
>               dev->switch_power_state = DRM_SWITCH_POWER_ON;
>       } else {
>               printk(KERN_ERR "VGA switcheroo: switched nouveau off\n");

Otherwise this looks good,


Thanks,

Paul
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 198 bytes
Desc: This is a digitally signed message part
URL: 
<http://lists.freedesktop.org/archives/dri-devel/attachments/20130724/3c7d7caf/attachment.pgp>

Reply via email to