drm/nouveau: bring back hdmi audio device after switcheroo power down
Subsystems (3)
Dave Airlie
maintainerRFC PATCH 1/1 drm/nouveau: bring back hdmi audio device after switcheroo power down
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.
--- 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(+)
drivers/gpu/drm/nouveau/nouveau_drm.c +32 -0
@@ -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 ; }
drivers/gpu/drm/nouveau/nouveau_drm.h +2 -0
@@ -129,6 +129,8 @@ struct nouveau_drm {/* power management */ struct nouveau_pm *pm; + +struct pci_dev *hdmi_device; }; static inline struct nouveau_drm *
drivers/gpu/drm/nouveau/nouveau_vga.c +17 -0
@@ -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); +} + +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" );
Signature · 1 line
1.8.2.1
Am Mittwoch, den 24.07.2013, 17:13 +1000 schrieb Dave Airlie:
Quoted 2 lines
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*
Quoted 19 lines
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 <[email protected]>--- 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(+)drivers/gpu/drm/nouveau/nouveau_drm.c +0
-0
drivers/gpu/drm/nouveau/nouveau_drm.c static int nouveau_drm_probe(struct pci_dev *pdev, · line 299
Quoted 4 lines
drivers/gpu/drm/nouveau/nouveau_drm.c +1
-0@@ -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?
drivers/gpu/drm/nouveau/nouveau_drm.c static int nouveau_drm_probe(struct pci_dev *pdev, · line 307
Quoted 8 lines
drivers/gpu/drm/nouveau/nouveau_drm.c +8
-0+ +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>?
drivers/gpu/drm/nouveau/nouveau_drm.c static int nouveau_drm_probe(struct pci_dev *pdev, · line 312
Quoted 5 lines
drivers/gpu/drm/nouveau/nouveau_drm.c +5
-0+ 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?
Quoted 66 lines
drivers/gpu/drm/nouveau/nouveau_drm.c +18
-0+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 ; }drivers/gpu/drm/nouveau/nouveau_drm.h +2
-0@@ -129,6 +129,8 @@ struct nouveau_drm {/* power management */ struct nouveau_pm *pm; + +struct pci_dev *hdmi_device; }; static inline struct nouveau_drm *drivers/gpu/drm/nouveau/nouveau_vga.c +3
-0@@ -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);
drivers/gpu/drm/nouveau/nouveau_vga.c nouveau_vga_set_decode(void *priv, bool state) · line 42
Quoted 10 lines
drivers/gpu/drm/nouveau/nouveau_vga.c +10
-0+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?
Quoted 7 lines
drivers/gpu/drm/nouveau/nouveau_vga.c +3
-0+} + +static void nouveau_switcheroo_set_state (struct pci_dev *pdev,enum vga_switcheroo_state state) {
drivers/gpu/drm/nouveau/nouveau_vga.c nouveau_switcheroo_set_state(struct pci_dev *pdev, · line 59
Quoted 7 lines
drivers/gpu/drm/nouveau/nouveau_vga.c +1
-0@@ -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
_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
Quoted 9 lines · 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 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.
Sorry for a stupid question, but how do you test "optimus power switch" ? (I have a laptop with hybrid Optimus graphics, so I could test..)
Thanks,
-- Pasi
A message that is not in the archive (sent off-list or not yet received): 1374650022-17865-1-git-send-email-airlied-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org
Op 24-07-13 09:13, Dave Airlie schreef:
Quoted 105 lines
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 <[email protected]>--- 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(+)drivers/gpu/drm/nouveau/nouveau_drm.c +32
-0@@ -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 ; }drivers/gpu/drm/nouveau/nouveau_drm.h +2
-0@@ -129,6 +129,8 @@ struct nouveau_drm {/* power management */ struct nouveau_pm *pm; + +struct pci_dev *hdmi_device; }; static inline struct nouveau_drm *drivers/gpu/drm/nouveau/nouveau_vga.c +4
-0@@ -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);
drivers/gpu/drm/nouveau/nouveau_vga.c nouveau_vga_set_decode(void *priv, bool state) · line 43
Quoted 10 lines
drivers/gpu/drm/nouveau/nouveau_vga.c +10
-0+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
A message that is not in the archive (sent off-list or not yet received): [email protected]
Quoted 101 lines · Maarten Lankhorst
Op 24-07-13 09:13, Dave Airlie schreef:
Quoted 100 lines
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 <[email protected]>--- 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(+)drivers/gpu/drm/nouveau/nouveau_drm.c +32
-0@@ -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 ; }drivers/gpu/drm/nouveau/nouveau_drm.h +2
-0@@ -129,6 +129,8 @@ struct nouveau_drm {/* power management */ struct nouveau_pm *pm; + +struct pci_dev *hdmi_device; }; static inline struct nouveau_drm *drivers/gpu/drm/nouveau/nouveau_vga.c +0
-0@@ -27,6 +27,22 @@ nouveau_vga_set_decode(void *priv, bool state) }
Quoted 16 lines
Quoted 5 lines
drivers/gpu/drm/nouveau/nouveau_vga.c +4
-0static void +nouveau_reenable_hdmi_device (struct drm_device *dev) +{ +struct nouveau_drm *drm =nouveau_drm (dev); +struct nouveau_device *device =nv_device (drm->device);drivers/gpu/drm/nouveau/nouveau_vga.c nouveau_vga_set_decode(void *priv, bool state) · line 43
Quoted 10 lines
drivers/gpu/drm/nouveau/nouveau_vga.c +10
-0+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,
Quoted 3 lines
Could this be added in
core/engine/disp/hdminv84.cnv84_hdmi_ctrlto 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.