[Nouveau] [PATCH] [RFC] drm/nouveau: bring back hdmi audio device after switcheroo power down

Dave Airlie airlied at gmail.com
Wed Jul 24 17:05:04 PDT 2013


On Wed, Jul 24, 2013 at 11:38 PM, Maarten Lankhorst
<maarten.lankhorst at canonical.com> wrote:
> 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);

much nicer,

>
> Could this be added in core/engine/disp/hdminv84.c nv84_hdmi_ctrl to get the same effect?
>
Don't think so its nothing to do with the hdmi audio part on the
device, it just controls the PCI sub function appearing/disappearing.

Dave.


More information about the Nouveau mailing list