Missing amdgpu firmware files

2015-10-27 Thread Seth Forshee
On Tue, Oct 27, 2015 at 04:10:33PM +, Deucher, Alexander wrote:
> > -Original Message-
> > From: Seth Forshee [mailto:seth.forshee at canonical.com]
> > Sent: Tuesday, October 27, 2015 12:06 PM
> > To: Koenig, Christian
> > Cc: Deucher, Alexander; Oded Gabbay; dri-devel at lists.freedesktop.org
> > Subject: Re: Missing amdgpu firmware files
> > 
> > On Tue, Oct 27, 2015 at 04:47:53PM +0100, Christian König wrote:
> > > Well that's strange. Essentially those are just duplicates to the
> > > existing files and the driver should fallback to them.
> > >
> > > IIRC the radeon/*_sdma1.bin files are only requested when you try to
> > > use CIK support with amdgpu which isn't a good idea in a production
> > > environment.
> > >
> > > What's the link for the bug reports? It's most likely just people
> > > trying to use the driver with hardware which it isn't supposed to be
> > > used with.
> > 
> > There have been a few reports that the firmware is missing, but only one
> > I see where the user actually reports any display problems.
> > 
> >  http://bugs.launchpad.net/bugs/1510405
> > 
> > Of course it's possible that he is jumping to conclusions about the
> > missing firmware files causing his display issues.
> 
> The driver refuses to load if the firmware is missing.  However, as Christian 
> mentioned, you will only get those messages if you've enabled CIK support 
> amdgpu which we don't recommend (controlled by CONFIG_DRM_AMDGPU_CIK).  
> Radeon does not require the additional firmware.

Got it, thanks. I'll disable it.

Seth



Missing amdgpu firmware files

2015-10-27 Thread Seth Forshee
On Tue, Oct 27, 2015 at 04:47:53PM +0100, Christian König wrote:
> Well that's strange. Essentially those are just duplicates to the
> existing files and the driver should fallback to them.
> 
> IIRC the radeon/*_sdma1.bin files are only requested when you try to
> use CIK support with amdgpu which isn't a good idea in a production
> environment.
> 
> What's the link for the bug reports? It's most likely just people
> trying to use the driver with hardware which it isn't supposed to be
> used with.

There have been a few reports that the firmware is missing, but only one
I see where the user actually reports any display problems.

 http://bugs.launchpad.net/bugs/1510405

Of course it's possible that he is jumping to conclusions about the
missing firmware files causing his display issues.

Thanks,
Seth



Missing amdgpu firmware files

2015-10-27 Thread Seth Forshee
I've received reports from Ubuntu users about missing amdgpu firmware
files with 4.2 kernels. The driver calls out a number of
radeon/*_sdma1.bin files that are not present in the linux-firmware git
repo. Are these files available anywhere (under a license that allows
redistribution), and will they be pushed up to linux-firmware anytime
soon?

Thanks,
Seth



Re: [PATCH v5 0/4] Fix Win8 backlight issue

2013-10-12 Thread Seth Forshee
On Sat, Oct 12, 2013 at 04:44:30AM -0700, Josh Boyer wrote:
 On Fri, Oct 11, 2013 at 4:27 PM, Rafael J. Wysocki r...@rjwysocki.net wrote:
  On Friday, October 11, 2013 06:01:43 PM Josh Boyer wrote:
  On Fri, Oct 11, 2013 at 6:10 PM, Rafael J. Wysocki r...@rjwysocki.net 
  wrote:
   On Friday, October 11, 2013 12:42:43 PM Josh Boyer wrote:
   On Fri, Oct 11, 2013 at 9:27 AM, Aaron Lu aaron...@intel.com wrote:
v5:
1 Introduce video.use_native_backlight module parameter and set its
  value to false by default as suggested by Rafael. For Win8 systems
  which have broken ACPI video backlight control, the parameter can be
  set to 1 in kernel cmdline to skip registering ACPI video's 
backlight
  interface. Due to this change, the 
acpi_video_verify_backlight_support
  is moved from video_detect.c to video.c - patch 3/4;
  
   That's a fairly untenable position for distro kernels to be in.  They
   now have to ask every user that reports an issue with the backlight to
   try setting that option on the command line.  While I appreciate the
   setting breaks things for some people, doesn't the Win8 issue impact
   far more people?  Shouldn't it be defaulted to true?
  
   Well, we have a rule in the kernel not to introduce regressions for 
   users even
   if they are minority.
  
   If nothing else, can you add a config option for the default so
   distros can use that to decide which way to default it and then work
   on fixing the remaining users that have troubles?
  
   The current plan is to create a blacklist of systems where that option 
   should
   be set.  We actually already have one, but it is at the _OSI() level, 
   which
   is overkill in my view and may affect things beyond backlight.  Along 
   with that
   we will debug systems where setting that option (to true) causes 
   problems to
   happen, so that we'll be able to drop it going forward (hopefully).
  
   Of course, distro kernels may always change the default to true if they 
   want.
 
  They can, but they'd need to either patch the kernel to do so, or code
  it in userspace bootloader configs.  Having a config option they can
  set to change the default makes it reasonable and contained within the
  kernel.
 
  If we are to use a Kconfig option, why don't we use one instead of rather 
  than
  in addition to a command line option?  Say, we have
  CONFIG_ACPI_VIDEO_WIN8_WORKAROUND and if that is set, the code will work 
  like
  the previous version of the Aaron's patchset (the one without
  video.use_native_backlight)?
 
  Opinions?
 
 If you only have a config option, users can't override the distro
 settings.  If you simply have a config option for the default value,
 the distros can set it without having to carry a patch (the primary
 benefit), but users can still override that without having to rebuild
 a kernel.

It sounds like the blacklist and the default value of the parameter
would be inherently tied together, i.e. the blacklist essentially
overrides the default value for specific machines. So when the config
option were flipped from its default the blacklist wouldn't work
anymore, and you'd need a second blacklist for machines which require
video.use_native_backlight=n. I doubt anyone wants to see that happen,
so I think we have to pick one value or the other for the default and
make it configurable only via the command line.

Seth

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 0/3] Fix backlight issues on some Windows 8 systems

2013-06-11 Thread Seth Forshee
On Sun, Jun 09, 2013 at 07:01:36PM -0400, Matthew Garrett wrote:
> Windows 8 introduced new policy for backlight control by pushing it out to
> graphics drivers. This appears to have coincided with a range of vendors
> adding Windows 8 checks to their backlight control code which trigger either
> awkward behaviour (Lenovo) or complete brokenness (some Dells). The simplest
> thing to do would be to just disable ACPI backlight control entirely if the
> firmware indicates Windows 8 support, but it's entirely possible that
> individual graphics drivers might still make use of the ACPI functionality in
> preference to native control.
> 
> The first two patches in this series are picked from other patchesets aimed at
> solving similar problems. The last simply unregisters ACPI backlight control
> on Windows 8 systems when using an Intel GPU. Similar code could be added to
> other drivers, but I'm reluctant to do so without further investigation as
> to the behaviour of the vendor drivers under Windows.

I've received some feedback from user testing of these patches (don't
have an affected machine myself) and the feedback is mostly good. One
user reported it didn't work, but I that machine may have discrete
graphics (waiting to hear back from the user).

The main drawback I see with any approach like this one is that the
backlight remains broken for users of proprietary graphics drivers.

Seth


Re: [PATCH 0/3] Fix backlight issues on some Windows 8 systems

2013-06-11 Thread Seth Forshee
On Sun, Jun 09, 2013 at 07:01:36PM -0400, Matthew Garrett wrote:
 Windows 8 introduced new policy for backlight control by pushing it out to
 graphics drivers. This appears to have coincided with a range of vendors
 adding Windows 8 checks to their backlight control code which trigger either
 awkward behaviour (Lenovo) or complete brokenness (some Dells). The simplest
 thing to do would be to just disable ACPI backlight control entirely if the
 firmware indicates Windows 8 support, but it's entirely possible that
 individual graphics drivers might still make use of the ACPI functionality in
 preference to native control.
 
 The first two patches in this series are picked from other patchesets aimed at
 solving similar problems. The last simply unregisters ACPI backlight control
 on Windows 8 systems when using an Intel GPU. Similar code could be added to
 other drivers, but I'm reluctant to do so without further investigation as
 to the behaviour of the vendor drivers under Windows.

I've received some feedback from user testing of these patches (don't
have an affected machine myself) and the feedback is mostly good. One
user reported it didn't work, but I that machine may have discrete
graphics (waiting to hear back from the user).

The main drawback I see with any approach like this one is that the
backlight remains broken for users of proprietary graphics drivers.

Seth
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 0/7] Fixes for hybrid graphics Apple machines

2012-09-10 Thread Seth Forshee
Many hybrid graphics Apple laptops fail to set up LVDS on the secondary
GPU due to missing or incorrect mode information for the panel at init
time. The only way to get the LVDS mode on these machines is via the
DDC, but this is muxed to the active GPU at boot. However, the graphics
mux on these machines supports muxing the i2c idependently of the
display, making it possible for the secondary graphics driver to read
the EDID without a full display switch.

In order to support this, these patches modify vga_switcheroo to allow
muxing of the DDC idependently of the display. apple-gmux is updated to
support this new functionality, and drm_get_edid() is modified to switch
the DDC mux as needed.

For this to work we also need to ensure that sufficient switcheroo
suport is available before initializing the secondary GPU. This is done
by adding any non-active GPUs that try to initialize before switcheroo
is ready to a list and initializing these devices once switcheroo
becomes ready. This behavior is restricted to Apple laptops to prevent
causing problems on other machines.

Thanks,
Seth

Seth Forshee (7):
  vga_switcheroo: Add support for switching only the DDC
  vga_switcheroo: Add helper function to get the active client
  vga_switcheroo: Add notifier call chain for switcheroo events
  apple-gmux: Add switch_ddc support
  drm/edid: Switch DDC when reading the EDID
  drm/pci: Add drm_put_pci_dev()
  drm/pci: Defer initialization of secondary graphics devices until
switcheroo is ready

 drivers/gpu/drm/ast/ast_drv.c |2 +-
 drivers/gpu/drm/cirrus/cirrus_drv.c   |2 +-
 drivers/gpu/drm/drm_drv.c |3 +
 drivers/gpu/drm/drm_edid.c|   17 
 drivers/gpu/drm/drm_pci.c |  172 +
 drivers/gpu/drm/gma500/psb_drv.c  |2 +-
 drivers/gpu/drm/i915/i915_drv.c   |2 +-
 drivers/gpu/drm/mgag200/mgag200_drv.c |2 +-
 drivers/gpu/drm/nouveau/nouveau_drv.c |2 +-
 drivers/gpu/drm/radeon/radeon_drv.c   |2 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_drv.c   |2 +-
 drivers/gpu/vga/vga_switcheroo.c  |   87 -
 drivers/platform/x86/apple-gmux.c |   12 ++-
 include/drm/drmP.h|3 +
 include/linux/vga_switcheroo.h|   20 
 15 files changed, 302 insertions(+), 28 deletions(-)

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 1/7] vga_switcheroo: Add support for switching only the DDC

2012-09-10 Thread Seth Forshee
During graphics driver initialization its useful to be able to mux only
the DDC to the inactive client in order to read the EDID. Add a
switch_ddc callback to allow capable handlers to provide this
functionality, and add vga_switcheroo_switch_ddc() to allow DRM to mux
only the DDC.

Signed-off-by: Seth Forshee seth.fors...@canonical.com
---
 drivers/gpu/vga/vga_switcheroo.c |   39 +-
 include/linux/vga_switcheroo.h   |4 
 2 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index e25cf31..ea6bcc2 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -252,6 +252,29 @@ void vga_switcheroo_client_fb_set(struct pci_dev *pdev,
 }
 EXPORT_SYMBOL(vga_switcheroo_client_fb_set);
 
+int vga_switcheroo_switch_ddc(struct pci_dev *pdev)
+{
+   int ret = 0;
+   int id;
+
+   mutex_lock(vgasr_mutex);
+
+   if (!vgasr_priv.handler) {
+   ret = -ENODEV;
+   goto out;
+   }
+
+   if (vgasr_priv.handler-switch_ddc) {
+   id = vgasr_priv.handler-get_client_id(pdev);
+   ret = vgasr_priv.handler-switch_ddc(id);
+   }
+
+out:
+   mutex_unlock(vgasr_mutex);
+   return ret;
+}
+EXPORT_SYMBOL(vga_switcheroo_switch_ddc);
+
 static int vga_switcheroo_show(struct seq_file *m, void *v)
 {
struct vga_switcheroo_client *client;
@@ -342,9 +365,15 @@ static int vga_switchto_stage2(struct 
vga_switcheroo_client *new_client)
fb_notifier_call_chain(FB_EVENT_REMAP_ALL_CONSOLE, event);
}
 
+   if (vgasr_priv.handler-switch_ddc) {
+   ret = vgasr_priv.handler-switch_ddc(new_client-id);
+   if (ret)
+   return ret;
+   }
+
ret = vgasr_priv.handler-switchto(new_client-id);
if (ret)
-   return ret;
+   goto restore_ddc;
 
if (new_client-ops-reprobe)
new_client-ops-reprobe(new_client-pdev);
@@ -356,6 +385,14 @@ static int vga_switchto_stage2(struct 
vga_switcheroo_client *new_client)
 
new_client-active = true;
return 0;
+
+restore_ddc:
+   if (vgasr_priv.handler-switch_ddc) {
+   int id = (new_client-id == VGA_SWITCHEROO_IGD) ?
+   VGA_SWITCHEROO_DIS : VGA_SWITCHEROO_IGD;
+   ret = vgasr_priv.handler-switch_ddc(id);
+   }
+   return ret;
 }
 
 static bool check_can_switch(void)
diff --git a/include/linux/vga_switcheroo.h b/include/linux/vga_switcheroo.h
index ddb419c..b0d0839 100644
--- a/include/linux/vga_switcheroo.h
+++ b/include/linux/vga_switcheroo.h
@@ -29,6 +29,7 @@ enum vga_switcheroo_client_id {
 };
 
 struct vga_switcheroo_handler {
+   int (*switch_ddc)(enum vga_switcheroo_client_id id);
int (*switchto)(enum vga_switcheroo_client_id id);
int (*power_state)(enum vga_switcheroo_client_id id,
   enum vga_switcheroo_state state);
@@ -53,6 +54,8 @@ int vga_switcheroo_register_audio_client(struct pci_dev *pdev,
 void vga_switcheroo_client_fb_set(struct pci_dev *dev,
  struct fb_info *info);
 
+int vga_switcheroo_switch_ddc(struct pci_dev *pdev);
+
 int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler);
 void vga_switcheroo_unregister_handler(void);
 
@@ -66,6 +69,7 @@ static inline void vga_switcheroo_unregister_client(struct 
pci_dev *dev) {}
 static inline int vga_switcheroo_register_client(struct pci_dev *dev,
const struct vga_switcheroo_client_ops *ops) { return 0; }
 static inline void vga_switcheroo_client_fb_set(struct pci_dev *dev, struct 
fb_info *info) {}
+static inline void vga_switcheroo_switch_ddc(struct pci_dev *pdev) { return 
NULL; }
 static inline int vga_switcheroo_register_handler(struct 
vga_switcheroo_handler *handler) { return 0; }
 static inline int vga_switcheroo_register_audio_client(struct pci_dev *pdev,
const struct vga_switcheroo_client_ops *ops,
-- 
1.7.9.5

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 3/7] vga_switcheroo: Add notifier call chain for switcheroo events

2012-09-10 Thread Seth Forshee
DRM needs to be notified of client and handler registration in order to
defer initialization of the secondary GPU until the EDID can be read
from the LVDS panel. To support this add a notifier call chain to
vga_switcheroo for subscribing to switcheroo events. Events are
generated for registration and unregistration of handlers and clients.

Signed-off-by: Seth Forshee seth.fors...@canonical.com
---
 drivers/gpu/vga/vga_switcheroo.c |   34 ++
 include/linux/vga_switcheroo.h   |   14 ++
 2 files changed, 48 insertions(+)

diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index e53f67d..d5cd274 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -24,6 +24,7 @@
 #include linux/fs.h
 #include linux/debugfs.h
 #include linux/fb.h
+#include linux/notifier.h
 
 #include linux/pci.h
 #include linux/vga_switcheroo.h
@@ -70,6 +71,28 @@ static struct vgasr_priv vgasr_priv = {
.clients = LIST_HEAD_INIT(vgasr_priv.clients),
 };
 
+static BLOCKING_NOTIFIER_HEAD(vga_switcheroo_notifier_list);
+
+int vga_switcheroo_register_notifier(struct notifier_block *nb)
+{
+   return blocking_notifier_chain_register(vga_switcheroo_notifier_list,
+   nb);
+}
+EXPORT_SYMBOL(vga_switcheroo_register_notifier);
+
+int vga_switcheroo_unregister_notifier(struct notifier_block *nb)
+{
+   return blocking_notifier_chain_unregister(vga_switcheroo_notifier_list,
+ nb);
+}
+EXPORT_SYMBOL(vga_switcheroo_unregister_notifier);
+
+static int vga_switcheroo_notifier_call_chain(enum vga_switcheroo_event event)
+{
+   return blocking_notifier_call_chain(vga_switcheroo_notifier_list,
+   event, NULL);
+}
+
 static bool vga_switcheroo_ready(void)
 {
/* we're ready if we get two clients + handler */
@@ -113,10 +136,18 @@ int vga_switcheroo_register_handler(struct 
vga_switcheroo_handler *handler)
vga_switcheroo_enable();
}
mutex_unlock(vgasr_mutex);
+
+   vga_switcheroo_notifier_call_chain(VGA_SWITCHEROO_HANDLER_REGISTERED);
return 0;
 }
 EXPORT_SYMBOL(vga_switcheroo_register_handler);
 
+bool vga_switcheroo_handler_registered(void)
+{
+   return !!vgasr_priv.handler;
+}
+EXPORT_SYMBOL(vga_switcheroo_handler_registered);
+
 void vga_switcheroo_unregister_handler(void)
 {
mutex_lock(vgasr_mutex);
@@ -127,6 +158,7 @@ void vga_switcheroo_unregister_handler(void)
vgasr_priv.active = false;
}
mutex_unlock(vgasr_mutex);
+   vga_switcheroo_notifier_call_chain(VGA_SWITCHEROO_HANDLER_UNREGISTERED);
 }
 EXPORT_SYMBOL(vga_switcheroo_unregister_handler);
 
@@ -156,6 +188,7 @@ static int register_client(struct pci_dev *pdev,
vga_switcheroo_enable();
}
mutex_unlock(vgasr_mutex);
+   vga_switcheroo_notifier_call_chain(VGA_SWITCHEROO_CLIENT_REGISTERED);
return 0;
 }
 
@@ -250,6 +283,7 @@ void vga_switcheroo_unregister_client(struct pci_dev *pdev)
vgasr_priv.active = false;
}
mutex_unlock(vgasr_mutex);
+   vga_switcheroo_notifier_call_chain(VGA_SWITCHEROO_CLIENT_UNREGISTERED);
 }
 EXPORT_SYMBOL(vga_switcheroo_unregister_client);
 
diff --git a/include/linux/vga_switcheroo.h b/include/linux/vga_switcheroo.h
index e361858..c3d7c6f 100644
--- a/include/linux/vga_switcheroo.h
+++ b/include/linux/vga_switcheroo.h
@@ -11,6 +11,7 @@
 #define _LINUX_VGA_SWITCHEROO_H_
 
 #include linux/fb.h
+#include linux/notifier.h
 
 struct pci_dev;
 
@@ -28,6 +29,13 @@ enum vga_switcheroo_client_id {
VGA_SWITCHEROO_MAX_CLIENTS,
 };
 
+enum vga_switcheroo_event {
+   VGA_SWITCHEROO_CLIENT_REGISTERED,
+   VGA_SWITCHEROO_CLIENT_UNREGISTERED,
+   VGA_SWITCHEROO_HANDLER_REGISTERED,
+   VGA_SWITCHEROO_HANDLER_UNREGISTERED,
+};
+
 struct vga_switcheroo_handler {
int (*switch_ddc)(enum vga_switcheroo_client_id id);
int (*switchto)(enum vga_switcheroo_client_id id);
@@ -44,6 +52,9 @@ struct vga_switcheroo_client_ops {
 };
 
 #if defined(CONFIG_VGA_SWITCHEROO)
+int vga_switcheroo_register_notifier(struct notifier_block *nb);
+int vga_switcheroo_unregister_notifier(struct notifier_block *nb);
+bool vga_switcheroo_handler_registered(void);
 void vga_switcheroo_unregister_client(struct pci_dev *dev);
 int vga_switcheroo_register_client(struct pci_dev *dev,
   const struct vga_switcheroo_client_ops *ops);
@@ -66,6 +77,9 @@ int vga_switcheroo_get_client_state(struct pci_dev *dev);
 
 #else
 
+static inline int vga_switcheroo_register_notifier(struct notifier_block *nb) 
{ return 0; }
+static inline int vga_switcheroo_unregister_notifier(struct notifier_block 
*nb) { return 0; }
+static inline bool vga_switcheroo_handler_registered(void) { return false; }
 static inline void

[PATCH 4/7] apple-gmux: Add switch_ddc support

2012-09-10 Thread Seth Forshee
The gmux allows muxing the DDC independently from the display, so
support this functionality. This will allow reading the EDID for the
inactive GPU, fixing issues with machines that either don't have a VBT
or have invalid mode data in the VBT.

Signed-off-by: Seth Forshee seth.fors...@canonical.com
---
 drivers/platform/x86/apple-gmux.c |   12 ++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/platform/x86/apple-gmux.c 
b/drivers/platform/x86/apple-gmux.c
index dfb1a92..d1e372d 100644
--- a/drivers/platform/x86/apple-gmux.c
+++ b/drivers/platform/x86/apple-gmux.c
@@ -269,14 +269,21 @@ static const struct backlight_ops gmux_bl_ops = {
.update_status = gmux_update_status,
 };
 
+static int gmux_switch_ddc(enum vga_switcheroo_client_id id)
+{
+   if (id == VGA_SWITCHEROO_IGD)
+   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 1);
+   else
+   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 2);
+   return 0;
+}
+
 static int gmux_switchto(enum vga_switcheroo_client_id id)
 {
if (id == VGA_SWITCHEROO_IGD) {
-   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 1);
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DISPLAY, 2);
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 2);
} else {
-   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 2);
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DISPLAY, 3);
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 3);
}
@@ -343,6 +350,7 @@ gmux_active_client(struct apple_gmux_data *gmux_data)
 }
 
 static struct vga_switcheroo_handler gmux_handler = {
+   .switch_ddc = gmux_switch_ddc,
.switchto = gmux_switchto,
.power_state = gmux_set_power_state,
.get_client_id = gmux_get_client_id,
-- 
1.7.9.5

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 5/7] drm/edid: Switch DDC when reading the EDID

2012-09-10 Thread Seth Forshee
Some dual graphics machines support muxing the DDC separately from the
display, so make use of this functionality when reading the EDID on the
inactive GPU. Also serialize drm_get_edid() with a mutex to avoid races
on the DDC mux state.

Signed-off-by: Seth Forshee seth.fors...@canonical.com
---
 drivers/gpu/drm/drm_edid.c |   17 +
 1 file changed, 17 insertions(+)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index b7ee230..b389269 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -31,6 +31,7 @@
 #include linux/slab.h
 #include linux/i2c.h
 #include linux/module.h
+#include linux/vga_switcheroo.h
 #include drmP.h
 #include drm_edid.h
 #include drm_edid_modes.h
@@ -82,6 +83,8 @@ struct detailed_mode_closure {
 #define LEVEL_GTF2 2
 #define LEVEL_CVT  3
 
+static DEFINE_MUTEX(drm_edid_mutex);
+
 static struct edid_quirk {
char vendor[4];
int product_id;
@@ -398,12 +401,26 @@ struct edid *drm_get_edid(struct drm_connector *connector,
  struct i2c_adapter *adapter)
 {
struct edid *edid = NULL;
+   struct pci_dev *pdev = connector-dev-pdev;
+   struct pci_dev *active_pdev = NULL;
+
+   mutex_lock(drm_edid_mutex);
+
+   if (pdev) {
+   active_pdev = vga_switcheroo_get_active_client();
+   if (active_pdev != pdev)
+   vga_switcheroo_switch_ddc(pdev);
+   }
 
if (drm_probe_ddc(adapter))
edid = (struct edid *)drm_do_get_edid(connector, adapter);
 
+   if (active_pdev  active_pdev != pdev)
+   vga_switcheroo_switch_ddc(active_pdev);
+
connector-display_info.raw_edid = (char *)edid;
 
+   mutex_unlock(drm_edid_mutex);
return edid;
 
 }
-- 
1.7.9.5

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 6/7] drm/pci: Add drm_put_pci_dev()

2012-09-10 Thread Seth Forshee
When deferred initialization support for pci devices is added some
additional cleanup will be needed. Add a pci-specific put function to
serve this purpose, and convert the pci drivers over to using it. For
now it just calls drm_put_dev(), so this commit has no functional
change.

Signed-off-by: Seth Forshee seth.fors...@canonical.com
---
 drivers/gpu/drm/ast/ast_drv.c |2 +-
 drivers/gpu/drm/cirrus/cirrus_drv.c   |2 +-
 drivers/gpu/drm/drm_pci.c |8 +++-
 drivers/gpu/drm/gma500/psb_drv.c  |2 +-
 drivers/gpu/drm/i915/i915_drv.c   |2 +-
 drivers/gpu/drm/mgag200/mgag200_drv.c |2 +-
 drivers/gpu/drm/nouveau/nouveau_drv.c |2 +-
 drivers/gpu/drm/radeon/radeon_drv.c   |2 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_drv.c   |2 +-
 include/drm/drmP.h|1 +
 10 files changed, 16 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c
index d0c4574..001298d 100644
--- a/drivers/gpu/drm/ast/ast_drv.c
+++ b/drivers/gpu/drm/ast/ast_drv.c
@@ -72,7 +72,7 @@ ast_pci_remove(struct pci_dev *pdev)
 {
struct drm_device *dev = pci_get_drvdata(pdev);
 
-   drm_put_dev(dev);
+   drm_put_pci_dev(dev);
 }
 
 
diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.c 
b/drivers/gpu/drm/cirrus/cirrus_drv.c
index 7053140..c7ca02b 100644
--- a/drivers/gpu/drm/cirrus/cirrus_drv.c
+++ b/drivers/gpu/drm/cirrus/cirrus_drv.c
@@ -64,7 +64,7 @@ static void cirrus_pci_remove(struct pci_dev *pdev)
 {
struct drm_device *dev = pci_get_drvdata(pdev);
 
-   drm_put_dev(dev);
+   drm_put_pci_dev(dev);
 }
 
 static const struct file_operations cirrus_driver_fops = {
diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c
index 5320364..55eb824 100644
--- a/drivers/gpu/drm/drm_pci.c
+++ b/drivers/gpu/drm/drm_pci.c
@@ -388,6 +388,12 @@ err_g1:
 }
 EXPORT_SYMBOL(drm_get_pci_dev);
 
+void drm_put_pci_dev(struct drm_device *dev)
+{
+   drm_put_dev(dev);
+}
+EXPORT_SYMBOL(drm_put_pci_dev);
+
 /**
  * PCI device initialization. Called direct from modules at load time.
  *
@@ -460,7 +466,7 @@ void drm_pci_exit(struct drm_driver *driver, struct 
pci_driver *pdriver)
pci_unregister_driver(pdriver);
} else {
list_for_each_entry_safe(dev, tmp, driver-device_list, 
driver_item)
-   drm_put_dev(dev);
+   drm_put_pci_dev(dev);
}
DRM_INFO(Module unloaded\n);
 }
diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c
index 0c47374..d7c3c9c 100644
--- a/drivers/gpu/drm/gma500/psb_drv.c
+++ b/drivers/gpu/drm/gma500/psb_drv.c
@@ -585,7 +585,7 @@ static void psb_driver_preclose(struct drm_device *dev, 
struct drm_file *priv)
 static void psb_remove(struct pci_dev *pdev)
 {
struct drm_device *dev = pci_get_drvdata(pdev);
-   drm_put_dev(dev);
+   drm_put_pci_dev(dev);
 }
 
 static const struct dev_pm_ops psb_pm_ops = {
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index a24ffbe..86ae5a2 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -856,7 +856,7 @@ i915_pci_remove(struct pci_dev *pdev)
 {
struct drm_device *dev = pci_get_drvdata(pdev);
 
-   drm_put_dev(dev);
+   drm_put_pci_dev(dev);
 }
 
 static int i915_pm_suspend(struct device *dev)
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c 
b/drivers/gpu/drm/mgag200/mgag200_drv.c
index ea1024d..a3b0a4a 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.c
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.c
@@ -73,7 +73,7 @@ static void mga_pci_remove(struct pci_dev *pdev)
 {
struct drm_device *dev = pci_get_drvdata(pdev);
 
-   drm_put_dev(dev);
+   drm_put_pci_dev(dev);
 }
 
 static const struct file_operations mgag200_driver_fops = {
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c 
b/drivers/gpu/drm/nouveau/nouveau_drv.c
index 9a36f5f..b74b02a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.c
@@ -168,7 +168,7 @@ nouveau_pci_remove(struct pci_dev *pdev)
 {
struct drm_device *dev = pci_get_drvdata(pdev);
 
-   drm_put_dev(dev);
+   drm_put_pci_dev(dev);
 }
 
 int
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c 
b/drivers/gpu/drm/radeon/radeon_drv.c
index 8c593ea..05d2ebc 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -310,7 +310,7 @@ radeon_pci_remove(struct pci_dev *pdev)
 {
struct drm_device *dev = pci_get_drvdata(pdev);
 
-   drm_put_dev(dev);
+   drm_put_pci_dev(dev);
 }
 
 static int
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c 
b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index 4d9edea..cf901cc 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -982,7 +982,7 @@ static void vmw_remove(struct pci_dev *pdev)
 {
struct drm_device *dev = pci_get_drvdata(pdev

[PATCH 7/7] drm/pci: Defer initialization of secondary graphics devices until switcheroo is ready

2012-09-10 Thread Seth Forshee
Many Apple laptops with hybrid graphics require switching the i2c mux to
the integrated GPU when that device is being initialized in order to get
correct mode information for the LVDS panel. This requires that switcheroo
is ready at the time the device is initialized, which is not guaranteed.

To support this, delay calling the driver load() callback until the
vga_switcheroo handler and active client have been registered. This is
restricted to Apple notebooks via DMI data to avoid causing problems on
machines without switcheroo support.

Signed-off-by: Seth Forshee seth.fors...@canonical.com
---
 drivers/gpu/drm/drm_drv.c |3 +
 drivers/gpu/drm/drm_pci.c |  164 -
 include/drm/drmP.h|2 +
 3 files changed, 153 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 9238de4..124fd8a 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -276,6 +276,8 @@ static int __init drm_core_init(void)
goto err_p3;
}
 
+   drm_pci_module_init();
+
DRM_INFO(Initialized %s %d.%d.%d %s\n,
 CORE_NAME, CORE_MAJOR, CORE_MINOR, CORE_PATCHLEVEL, CORE_DATE);
return 0;
@@ -291,6 +293,7 @@ err_p1:
 
 static void __exit drm_core_exit(void)
 {
+   drm_pci_module_exit();
remove_proc_entry(dri, NULL);
debugfs_remove(drm_debugfs_root);
drm_sysfs_destroy();
diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c
index 55eb824..a5c9068 100644
--- a/drivers/gpu/drm/drm_pci.c
+++ b/drivers/gpu/drm/drm_pci.c
@@ -40,6 +40,10 @@
 #include linux/slab.h
 #include linux/dma-mapping.h
 #include linux/export.h
+#include linux/dmi.h
+#include linux/notifier.h
+#include linux/vgaarb.h
+#include linux/vga_switcheroo.h
 #include drmP.h
 
 /**/
@@ -297,19 +301,8 @@ static struct drm_bus drm_pci_bus = {
.agp_init = drm_pci_agp_init,
 };
 
-/**
- * Register.
- *
- * \param pdev - PCI device structure
- * \param ent entry from the PCI ID table with device type flags
- * \return zero on success or a negative number on failure.
- *
- * Attempt to gets inter module drm information. If we are first
- * then register the character device and inter module information.
- * Try and register, if we fail to register, backout previous work.
- */
-int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
-   struct drm_driver *driver)
+int __drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
+ struct drm_driver *driver)
 {
struct drm_device *dev;
int ret;
@@ -334,8 +327,6 @@ int drm_get_pci_dev(struct pci_dev *pdev, const struct 
pci_device_id *ent,
dev-hose = pdev-sysdata;
 #endif
 
-   mutex_lock(drm_global_mutex);
-
if ((ret = drm_fill_in_dev(dev, ent, driver))) {
printk(KERN_ERR DRM: Fill_in_dev failed.\n);
goto err_g2;
@@ -371,7 +362,6 @@ int drm_get_pci_dev(struct pci_dev *pdev, const struct 
pci_device_id *ent,
 driver-name, driver-major, driver-minor, driver-patchlevel,
 driver-date, pci_name(pdev), dev-primary-index);
 
-   mutex_unlock(drm_global_mutex);
return 0;
 
 err_g4:
@@ -386,10 +376,140 @@ err_g1:
mutex_unlock(drm_global_mutex);
return ret;
 }
+
+/*
+ * List of machines that require delaying initialization of the secondary
+ * GPU until vga_switcheroo is ready.
+ */
+static struct dmi_system_id deferred_init_dmi_table[] = {
+   {
+   .ident = Apple Laptop,
+   .matches = {
+   DMI_MATCH(DMI_SYS_VENDOR, Apple Inc.),
+   DMI_MATCH(DMI_CHASSIS_TYPE, 10), /* Notebook */
+   },
+   },
+};
+
+struct deferred_init_data {
+   struct list_head list;
+   struct pci_dev *pdev;
+   const struct pci_device_id *ent;
+   struct drm_driver *driver;
+};
+
+static LIST_HEAD(deferred_init_list);
+
+static bool drm_pci_switcheroo_ready(void)
+{
+   if (!vga_switcheroo_handler_registered())
+   return false;
+   if (!vga_switcheroo_get_active_client())
+   return false;
+   return true;
+}
+
+static void drm_deferred_init_work_fn(struct work_struct *work)
+{
+   struct deferred_init_data *di_data, *temp;
+
+   mutex_lock(drm_global_mutex);
+
+   if (!drm_pci_switcheroo_ready()) {
+   mutex_unlock(drm_global_mutex);
+   return;
+   }
+
+   list_for_each_entry_safe(di_data, temp, deferred_init_list, list) {
+   if (__drm_get_pci_dev(di_data-pdev, di_data-ent,
+ di_data-driver))
+   DRM_ERROR(pci device initialization failed\n);
+   list_del(di_data-list);
+   kfree(di_data);
+   }
+   mutex_unlock

Re: [PATCH 0/7] Fixes for hybrid graphics Apple machines

2012-09-10 Thread Seth Forshee
On Fri, Sep 07, 2012 at 10:35:04PM +0100, Dave Airlie wrote:
 On Fri, Sep 7, 2012 at 4:22 PM, Seth Forshee seth.fors...@canonical.com 
 wrote:
  Many hybrid graphics Apple laptops fail to set up LVDS on the secondary
  GPU due to missing or incorrect mode information for the panel at init
  time. The only way to get the LVDS mode on these machines is via the
  DDC, but this is muxed to the active GPU at boot. However, the graphics
  mux on these machines supports muxing the i2c idependently of the
  display, making it possible for the secondary graphics driver to read
  the EDID without a full display switch.
 
  In order to support this, these patches modify vga_switcheroo to allow
  muxing of the DDC idependently of the display. apple-gmux is updated to
  support this new functionality, and drm_get_edid() is modified to switch
  the DDC mux as needed.
 
  For this to work we also need to ensure that sufficient switcheroo
  suport is available before initializing the secondary GPU. This is done
  by adding any non-active GPUs that try to initialize before switcheroo
  is ready to a list and initializing these devices once switcheroo
  becomes ready. This behavior is restricted to Apple laptops to prevent
  causing problems on other machines.
 
 I hate this idea, no delaying stuff. We either need to have some sort
 of enforced ordering or make some stuff only work built-in.
 
 But sticking things on a delayed list just in case seems wrong to me.

I really don't like it either. My preferred solution would be to have
i915 register the LVDS connector whenever we can reasonably expect that
an LVDS panel might be present, then treat the panel as disconnected
until we can get the mode information. I was headed down this path with
the first patches I sent, but both Daniel and Matthew responded
unfavorably to this approach.

Otherwise I'm open to suggestions on how enforcing the ordering of the
device initializations. Forcing apple-gmux to be built-in or making i915
depend on it might solve the problem, but I don't find either of these
to be very desirable either.

Thanks,
Seth

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 0/7] Fixes for hybrid graphics Apple machines

2012-09-08 Thread Seth Forshee
On Fri, Sep 07, 2012 at 10:35:04PM +0100, Dave Airlie wrote:
> On Fri, Sep 7, 2012 at 4:22 PM, Seth Forshee  
> wrote:
> > Many hybrid graphics Apple laptops fail to set up LVDS on the secondary
> > GPU due to missing or incorrect mode information for the panel at init
> > time. The only way to get the LVDS mode on these machines is via the
> > DDC, but this is muxed to the active GPU at boot. However, the graphics
> > mux on these machines supports muxing the i2c idependently of the
> > display, making it possible for the secondary graphics driver to read
> > the EDID without a full display switch.
> >
> > In order to support this, these patches modify vga_switcheroo to allow
> > muxing of the DDC idependently of the display. apple-gmux is updated to
> > support this new functionality, and drm_get_edid() is modified to switch
> > the DDC mux as needed.
> >
> > For this to work we also need to ensure that sufficient switcheroo
> > suport is available before initializing the secondary GPU. This is done
> > by adding any non-active GPUs that try to initialize before switcheroo
> > is ready to a list and initializing these devices once switcheroo
> > becomes ready. This behavior is restricted to Apple laptops to prevent
> > causing problems on other machines.
> 
> I hate this idea, no delaying stuff. We either need to have some sort
> of enforced ordering or make some stuff only work built-in.
> 
> But sticking things on a delayed list just in case seems wrong to me.

I really don't like it either. My preferred solution would be to have
i915 register the LVDS connector whenever we can reasonably expect that
an LVDS panel might be present, then treat the panel as disconnected
until we can get the mode information. I was headed down this path with
the first patches I sent, but both Daniel and Matthew responded
unfavorably to this approach.

Otherwise I'm open to suggestions on how enforcing the ordering of the
device initializations. Forcing apple-gmux to be built-in or making i915
depend on it might solve the problem, but I don't find either of these
to be very desirable either.

Thanks,
Seth



[PATCH 7/7] drm/pci: Defer initialization of secondary graphics devices until switcheroo is ready

2012-09-07 Thread Seth Forshee
Many Apple laptops with hybrid graphics require switching the i2c mux to
the integrated GPU when that device is being initialized in order to get
correct mode information for the LVDS panel. This requires that switcheroo
is ready at the time the device is initialized, which is not guaranteed.

To support this, delay calling the driver load() callback until the
vga_switcheroo handler and active client have been registered. This is
restricted to Apple notebooks via DMI data to avoid causing problems on
machines without switcheroo support.

Signed-off-by: Seth Forshee 
---
 drivers/gpu/drm/drm_drv.c |3 +
 drivers/gpu/drm/drm_pci.c |  164 -
 include/drm/drmP.h|2 +
 3 files changed, 153 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 9238de4..124fd8a 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -276,6 +276,8 @@ static int __init drm_core_init(void)
goto err_p3;
}

+   drm_pci_module_init();
+
DRM_INFO("Initialized %s %d.%d.%d %s\n",
 CORE_NAME, CORE_MAJOR, CORE_MINOR, CORE_PATCHLEVEL, CORE_DATE);
return 0;
@@ -291,6 +293,7 @@ err_p1:

 static void __exit drm_core_exit(void)
 {
+   drm_pci_module_exit();
remove_proc_entry("dri", NULL);
debugfs_remove(drm_debugfs_root);
drm_sysfs_destroy();
diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c
index 55eb824..a5c9068 100644
--- a/drivers/gpu/drm/drm_pci.c
+++ b/drivers/gpu/drm/drm_pci.c
@@ -40,6 +40,10 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
+#include 
 #include "drmP.h"

 /**/
@@ -297,19 +301,8 @@ static struct drm_bus drm_pci_bus = {
.agp_init = drm_pci_agp_init,
 };

-/**
- * Register.
- *
- * \param pdev - PCI device structure
- * \param ent entry from the PCI ID table with device type flags
- * \return zero on success or a negative number on failure.
- *
- * Attempt to gets inter module "drm" information. If we are first
- * then register the character device and inter module information.
- * Try and register, if we fail to register, backout previous work.
- */
-int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
-   struct drm_driver *driver)
+int __drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
+ struct drm_driver *driver)
 {
struct drm_device *dev;
int ret;
@@ -334,8 +327,6 @@ int drm_get_pci_dev(struct pci_dev *pdev, const struct 
pci_device_id *ent,
dev->hose = pdev->sysdata;
 #endif

-   mutex_lock(_global_mutex);
-
if ((ret = drm_fill_in_dev(dev, ent, driver))) {
printk(KERN_ERR "DRM: Fill_in_dev failed.\n");
goto err_g2;
@@ -371,7 +362,6 @@ int drm_get_pci_dev(struct pci_dev *pdev, const struct 
pci_device_id *ent,
 driver->name, driver->major, driver->minor, driver->patchlevel,
 driver->date, pci_name(pdev), dev->primary->index);

-   mutex_unlock(_global_mutex);
return 0;

 err_g4:
@@ -386,10 +376,140 @@ err_g1:
mutex_unlock(_global_mutex);
return ret;
 }
+
+/*
+ * List of machines that require delaying initialization of the secondary
+ * GPU until vga_switcheroo is ready.
+ */
+static struct dmi_system_id deferred_init_dmi_table[] = {
+   {
+   .ident = "Apple Laptop",
+   .matches = {
+   DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+   DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */
+   },
+   },
+};
+
+struct deferred_init_data {
+   struct list_head list;
+   struct pci_dev *pdev;
+   const struct pci_device_id *ent;
+   struct drm_driver *driver;
+};
+
+static LIST_HEAD(deferred_init_list);
+
+static bool drm_pci_switcheroo_ready(void)
+{
+   if (!vga_switcheroo_handler_registered())
+   return false;
+   if (!vga_switcheroo_get_active_client())
+   return false;
+   return true;
+}
+
+static void drm_deferred_init_work_fn(struct work_struct *work)
+{
+   struct deferred_init_data *di_data, *temp;
+
+   mutex_lock(_global_mutex);
+
+   if (!drm_pci_switcheroo_ready()) {
+   mutex_unlock(_global_mutex);
+   return;
+   }
+
+   list_for_each_entry_safe(di_data, temp, _init_list, list) {
+   if (__drm_get_pci_dev(di_data->pdev, di_data->ent,
+ di_data->driver))
+   DRM_ERROR("pci device initialization failed\n");
+   list_del(_data->list);
+   kfree(di_data);
+   }
+   mutex_unlock(_globa

[PATCH 6/7] drm/pci: Add drm_put_pci_dev()

2012-09-07 Thread Seth Forshee
When deferred initialization support for pci devices is added some
additional cleanup will be needed. Add a pci-specific put function to
serve this purpose, and convert the pci drivers over to using it. For
now it just calls drm_put_dev(), so this commit has no functional
change.

Signed-off-by: Seth Forshee 
---
 drivers/gpu/drm/ast/ast_drv.c |2 +-
 drivers/gpu/drm/cirrus/cirrus_drv.c   |2 +-
 drivers/gpu/drm/drm_pci.c |8 +++-
 drivers/gpu/drm/gma500/psb_drv.c  |2 +-
 drivers/gpu/drm/i915/i915_drv.c   |2 +-
 drivers/gpu/drm/mgag200/mgag200_drv.c |2 +-
 drivers/gpu/drm/nouveau/nouveau_drv.c |2 +-
 drivers/gpu/drm/radeon/radeon_drv.c   |2 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_drv.c   |2 +-
 include/drm/drmP.h|1 +
 10 files changed, 16 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c
index d0c4574..001298d 100644
--- a/drivers/gpu/drm/ast/ast_drv.c
+++ b/drivers/gpu/drm/ast/ast_drv.c
@@ -72,7 +72,7 @@ ast_pci_remove(struct pci_dev *pdev)
 {
struct drm_device *dev = pci_get_drvdata(pdev);

-   drm_put_dev(dev);
+   drm_put_pci_dev(dev);
 }


diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.c 
b/drivers/gpu/drm/cirrus/cirrus_drv.c
index 7053140..c7ca02b 100644
--- a/drivers/gpu/drm/cirrus/cirrus_drv.c
+++ b/drivers/gpu/drm/cirrus/cirrus_drv.c
@@ -64,7 +64,7 @@ static void cirrus_pci_remove(struct pci_dev *pdev)
 {
struct drm_device *dev = pci_get_drvdata(pdev);

-   drm_put_dev(dev);
+   drm_put_pci_dev(dev);
 }

 static const struct file_operations cirrus_driver_fops = {
diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c
index 5320364..55eb824 100644
--- a/drivers/gpu/drm/drm_pci.c
+++ b/drivers/gpu/drm/drm_pci.c
@@ -388,6 +388,12 @@ err_g1:
 }
 EXPORT_SYMBOL(drm_get_pci_dev);

+void drm_put_pci_dev(struct drm_device *dev)
+{
+   drm_put_dev(dev);
+}
+EXPORT_SYMBOL(drm_put_pci_dev);
+
 /**
  * PCI device initialization. Called direct from modules at load time.
  *
@@ -460,7 +466,7 @@ void drm_pci_exit(struct drm_driver *driver, struct 
pci_driver *pdriver)
pci_unregister_driver(pdriver);
} else {
list_for_each_entry_safe(dev, tmp, >device_list, 
driver_item)
-   drm_put_dev(dev);
+   drm_put_pci_dev(dev);
}
DRM_INFO("Module unloaded\n");
 }
diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c
index 0c47374..d7c3c9c 100644
--- a/drivers/gpu/drm/gma500/psb_drv.c
+++ b/drivers/gpu/drm/gma500/psb_drv.c
@@ -585,7 +585,7 @@ static void psb_driver_preclose(struct drm_device *dev, 
struct drm_file *priv)
 static void psb_remove(struct pci_dev *pdev)
 {
struct drm_device *dev = pci_get_drvdata(pdev);
-   drm_put_dev(dev);
+   drm_put_pci_dev(dev);
 }

 static const struct dev_pm_ops psb_pm_ops = {
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index a24ffbe..86ae5a2 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -856,7 +856,7 @@ i915_pci_remove(struct pci_dev *pdev)
 {
struct drm_device *dev = pci_get_drvdata(pdev);

-   drm_put_dev(dev);
+   drm_put_pci_dev(dev);
 }

 static int i915_pm_suspend(struct device *dev)
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c 
b/drivers/gpu/drm/mgag200/mgag200_drv.c
index ea1024d..a3b0a4a 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.c
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.c
@@ -73,7 +73,7 @@ static void mga_pci_remove(struct pci_dev *pdev)
 {
struct drm_device *dev = pci_get_drvdata(pdev);

-   drm_put_dev(dev);
+   drm_put_pci_dev(dev);
 }

 static const struct file_operations mgag200_driver_fops = {
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c 
b/drivers/gpu/drm/nouveau/nouveau_drv.c
index 9a36f5f..b74b02a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.c
@@ -168,7 +168,7 @@ nouveau_pci_remove(struct pci_dev *pdev)
 {
struct drm_device *dev = pci_get_drvdata(pdev);

-   drm_put_dev(dev);
+   drm_put_pci_dev(dev);
 }

 int
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c 
b/drivers/gpu/drm/radeon/radeon_drv.c
index 8c593ea..05d2ebc 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -310,7 +310,7 @@ radeon_pci_remove(struct pci_dev *pdev)
 {
struct drm_device *dev = pci_get_drvdata(pdev);

-   drm_put_dev(dev);
+   drm_put_pci_dev(dev);
 }

 static int
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c 
b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index 4d9edea..cf901cc 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -982,7 +982,7 @@ static void vmw_remove(struct pci_dev *pdev)
 {
struct drm_device *dev = pci_get_drvdata(pdev);

-   dr

[PATCH 5/7] drm/edid: Switch DDC when reading the EDID

2012-09-07 Thread Seth Forshee
Some dual graphics machines support muxing the DDC separately from the
display, so make use of this functionality when reading the EDID on the
inactive GPU. Also serialize drm_get_edid() with a mutex to avoid races
on the DDC mux state.

Signed-off-by: Seth Forshee 
---
 drivers/gpu/drm/drm_edid.c |   17 +
 1 file changed, 17 insertions(+)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index b7ee230..b389269 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -31,6 +31,7 @@
 #include 
 #include 
 #include 
+#include 
 #include "drmP.h"
 #include "drm_edid.h"
 #include "drm_edid_modes.h"
@@ -82,6 +83,8 @@ struct detailed_mode_closure {
 #define LEVEL_GTF2 2
 #define LEVEL_CVT  3

+static DEFINE_MUTEX(drm_edid_mutex);
+
 static struct edid_quirk {
char vendor[4];
int product_id;
@@ -398,12 +401,26 @@ struct edid *drm_get_edid(struct drm_connector *connector,
  struct i2c_adapter *adapter)
 {
struct edid *edid = NULL;
+   struct pci_dev *pdev = connector->dev->pdev;
+   struct pci_dev *active_pdev = NULL;
+
+   mutex_lock(_edid_mutex);
+
+   if (pdev) {
+   active_pdev = vga_switcheroo_get_active_client();
+   if (active_pdev != pdev)
+   vga_switcheroo_switch_ddc(pdev);
+   }

if (drm_probe_ddc(adapter))
edid = (struct edid *)drm_do_get_edid(connector, adapter);

+   if (active_pdev && active_pdev != pdev)
+   vga_switcheroo_switch_ddc(active_pdev);
+
connector->display_info.raw_edid = (char *)edid;

+   mutex_unlock(_edid_mutex);
return edid;

 }
-- 
1.7.9.5



[PATCH 4/7] apple-gmux: Add switch_ddc support

2012-09-07 Thread Seth Forshee
The gmux allows muxing the DDC independently from the display, so
support this functionality. This will allow reading the EDID for the
inactive GPU, fixing issues with machines that either don't have a VBT
or have invalid mode data in the VBT.

Signed-off-by: Seth Forshee 
---
 drivers/platform/x86/apple-gmux.c |   12 ++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/platform/x86/apple-gmux.c 
b/drivers/platform/x86/apple-gmux.c
index dfb1a92..d1e372d 100644
--- a/drivers/platform/x86/apple-gmux.c
+++ b/drivers/platform/x86/apple-gmux.c
@@ -269,14 +269,21 @@ static const struct backlight_ops gmux_bl_ops = {
.update_status = gmux_update_status,
 };

+static int gmux_switch_ddc(enum vga_switcheroo_client_id id)
+{
+   if (id == VGA_SWITCHEROO_IGD)
+   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 1);
+   else
+   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 2);
+   return 0;
+}
+
 static int gmux_switchto(enum vga_switcheroo_client_id id)
 {
if (id == VGA_SWITCHEROO_IGD) {
-   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 1);
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DISPLAY, 2);
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 2);
} else {
-   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 2);
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DISPLAY, 3);
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 3);
}
@@ -343,6 +350,7 @@ gmux_active_client(struct apple_gmux_data *gmux_data)
 }

 static struct vga_switcheroo_handler gmux_handler = {
+   .switch_ddc = gmux_switch_ddc,
.switchto = gmux_switchto,
.power_state = gmux_set_power_state,
.get_client_id = gmux_get_client_id,
-- 
1.7.9.5



[PATCH 3/7] vga_switcheroo: Add notifier call chain for switcheroo events

2012-09-07 Thread Seth Forshee
DRM needs to be notified of client and handler registration in order to
defer initialization of the secondary GPU until the EDID can be read
from the LVDS panel. To support this add a notifier call chain to
vga_switcheroo for subscribing to switcheroo events. Events are
generated for registration and unregistration of handlers and clients.

Signed-off-by: Seth Forshee 
---
 drivers/gpu/vga/vga_switcheroo.c |   34 ++
 include/linux/vga_switcheroo.h   |   14 ++
 2 files changed, 48 insertions(+)

diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index e53f67d..d5cd274 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -24,6 +24,7 @@
 #include 
 #include 
 #include 
+#include 

 #include 
 #include 
@@ -70,6 +71,28 @@ static struct vgasr_priv vgasr_priv = {
.clients = LIST_HEAD_INIT(vgasr_priv.clients),
 };

+static BLOCKING_NOTIFIER_HEAD(vga_switcheroo_notifier_list);
+
+int vga_switcheroo_register_notifier(struct notifier_block *nb)
+{
+   return blocking_notifier_chain_register(_switcheroo_notifier_list,
+   nb);
+}
+EXPORT_SYMBOL(vga_switcheroo_register_notifier);
+
+int vga_switcheroo_unregister_notifier(struct notifier_block *nb)
+{
+   return blocking_notifier_chain_unregister(_switcheroo_notifier_list,
+ nb);
+}
+EXPORT_SYMBOL(vga_switcheroo_unregister_notifier);
+
+static int vga_switcheroo_notifier_call_chain(enum vga_switcheroo_event event)
+{
+   return blocking_notifier_call_chain(_switcheroo_notifier_list,
+   event, NULL);
+}
+
 static bool vga_switcheroo_ready(void)
 {
/* we're ready if we get two clients + handler */
@@ -113,10 +136,18 @@ int vga_switcheroo_register_handler(struct 
vga_switcheroo_handler *handler)
vga_switcheroo_enable();
}
mutex_unlock(_mutex);
+
+   vga_switcheroo_notifier_call_chain(VGA_SWITCHEROO_HANDLER_REGISTERED);
return 0;
 }
 EXPORT_SYMBOL(vga_switcheroo_register_handler);

+bool vga_switcheroo_handler_registered(void)
+{
+   return !!vgasr_priv.handler;
+}
+EXPORT_SYMBOL(vga_switcheroo_handler_registered);
+
 void vga_switcheroo_unregister_handler(void)
 {
mutex_lock(_mutex);
@@ -127,6 +158,7 @@ void vga_switcheroo_unregister_handler(void)
vgasr_priv.active = false;
}
mutex_unlock(_mutex);
+   vga_switcheroo_notifier_call_chain(VGA_SWITCHEROO_HANDLER_UNREGISTERED);
 }
 EXPORT_SYMBOL(vga_switcheroo_unregister_handler);

@@ -156,6 +188,7 @@ static int register_client(struct pci_dev *pdev,
vga_switcheroo_enable();
}
mutex_unlock(_mutex);
+   vga_switcheroo_notifier_call_chain(VGA_SWITCHEROO_CLIENT_REGISTERED);
return 0;
 }

@@ -250,6 +283,7 @@ void vga_switcheroo_unregister_client(struct pci_dev *pdev)
vgasr_priv.active = false;
}
mutex_unlock(_mutex);
+   vga_switcheroo_notifier_call_chain(VGA_SWITCHEROO_CLIENT_UNREGISTERED);
 }
 EXPORT_SYMBOL(vga_switcheroo_unregister_client);

diff --git a/include/linux/vga_switcheroo.h b/include/linux/vga_switcheroo.h
index e361858..c3d7c6f 100644
--- a/include/linux/vga_switcheroo.h
+++ b/include/linux/vga_switcheroo.h
@@ -11,6 +11,7 @@
 #define _LINUX_VGA_SWITCHEROO_H_

 #include 
+#include 

 struct pci_dev;

@@ -28,6 +29,13 @@ enum vga_switcheroo_client_id {
VGA_SWITCHEROO_MAX_CLIENTS,
 };

+enum vga_switcheroo_event {
+   VGA_SWITCHEROO_CLIENT_REGISTERED,
+   VGA_SWITCHEROO_CLIENT_UNREGISTERED,
+   VGA_SWITCHEROO_HANDLER_REGISTERED,
+   VGA_SWITCHEROO_HANDLER_UNREGISTERED,
+};
+
 struct vga_switcheroo_handler {
int (*switch_ddc)(enum vga_switcheroo_client_id id);
int (*switchto)(enum vga_switcheroo_client_id id);
@@ -44,6 +52,9 @@ struct vga_switcheroo_client_ops {
 };

 #if defined(CONFIG_VGA_SWITCHEROO)
+int vga_switcheroo_register_notifier(struct notifier_block *nb);
+int vga_switcheroo_unregister_notifier(struct notifier_block *nb);
+bool vga_switcheroo_handler_registered(void);
 void vga_switcheroo_unregister_client(struct pci_dev *dev);
 int vga_switcheroo_register_client(struct pci_dev *dev,
   const struct vga_switcheroo_client_ops *ops);
@@ -66,6 +77,9 @@ int vga_switcheroo_get_client_state(struct pci_dev *dev);

 #else

+static inline int vga_switcheroo_register_notifier(struct notifier_block *nb) 
{ return 0; }
+static inline int vga_switcheroo_unregister_notifier(struct notifier_block 
*nb) { return 0; }
+static inline bool vga_switcheroo_handler_registered(void) { return false; }
 static inline void vga_switcheroo_unregister_client(struct pci_dev *dev) {}
 static inline int vga_switcheroo_register_client(struct pci_dev *dev,
const struct vga_switcheroo_client_ops *ops) { return 0

[PATCH 2/7] vga_switcheroo: Add helper function to get the active client

2012-09-07 Thread Seth Forshee
Add vga_switcheroo_get_active_client() to allow drivers to get the
active video client. This will be used by drivers wishing to temporarily
mux only the DDC to the inactive client.

Signed-off-by: Seth Forshee 
---
 drivers/gpu/vga/vga_switcheroo.c |   14 ++
 include/linux/vga_switcheroo.h   |2 ++
 2 files changed, 16 insertions(+)

diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index ea6bcc2..e53f67d 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -205,6 +205,20 @@ find_active_client(struct list_head *head)
return NULL;
 }

+struct pci_dev *vga_switcheroo_get_active_client(void)
+{
+   struct vga_switcheroo_client *client;
+   struct pci_dev *pdev = NULL;
+
+   mutex_lock(_mutex);
+   client = find_active_client(_priv.clients);
+   if (client)
+   pdev = client->pdev;
+   mutex_unlock(_mutex);
+   return pdev;
+}
+EXPORT_SYMBOL(vga_switcheroo_get_active_client);
+
 int vga_switcheroo_get_client_state(struct pci_dev *pdev)
 {
struct vga_switcheroo_client *client;
diff --git a/include/linux/vga_switcheroo.h b/include/linux/vga_switcheroo.h
index b0d0839..e361858 100644
--- a/include/linux/vga_switcheroo.h
+++ b/include/linux/vga_switcheroo.h
@@ -61,6 +61,7 @@ void vga_switcheroo_unregister_handler(void);

 int vga_switcheroo_process_delayed_switch(void);

+struct pci_dev *vga_switcheroo_get_active_client(void);
 int vga_switcheroo_get_client_state(struct pci_dev *dev);

 #else
@@ -76,6 +77,7 @@ static inline int vga_switcheroo_register_audio_client(struct 
pci_dev *pdev,
int id, bool active) { return 0; }
 static inline void vga_switcheroo_unregister_handler(void) {}
 static inline int vga_switcheroo_process_delayed_switch(void) { return 0; }
+static inline struct pci_dev *vga_switcheroo_get_active_client(void) { return 
NULL; }
 static inline int vga_switcheroo_get_client_state(struct pci_dev *dev) { 
return VGA_SWITCHEROO_ON; }


-- 
1.7.9.5



[PATCH 1/7] vga_switcheroo: Add support for switching only the DDC

2012-09-07 Thread Seth Forshee
During graphics driver initialization its useful to be able to mux only
the DDC to the inactive client in order to read the EDID. Add a
switch_ddc callback to allow capable handlers to provide this
functionality, and add vga_switcheroo_switch_ddc() to allow DRM to mux
only the DDC.

Signed-off-by: Seth Forshee 
---
 drivers/gpu/vga/vga_switcheroo.c |   39 +-
 include/linux/vga_switcheroo.h   |4 
 2 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index e25cf31..ea6bcc2 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -252,6 +252,29 @@ void vga_switcheroo_client_fb_set(struct pci_dev *pdev,
 }
 EXPORT_SYMBOL(vga_switcheroo_client_fb_set);

+int vga_switcheroo_switch_ddc(struct pci_dev *pdev)
+{
+   int ret = 0;
+   int id;
+
+   mutex_lock(_mutex);
+
+   if (!vgasr_priv.handler) {
+   ret = -ENODEV;
+   goto out;
+   }
+
+   if (vgasr_priv.handler->switch_ddc) {
+   id = vgasr_priv.handler->get_client_id(pdev);
+   ret = vgasr_priv.handler->switch_ddc(id);
+   }
+
+out:
+   mutex_unlock(_mutex);
+   return ret;
+}
+EXPORT_SYMBOL(vga_switcheroo_switch_ddc);
+
 static int vga_switcheroo_show(struct seq_file *m, void *v)
 {
struct vga_switcheroo_client *client;
@@ -342,9 +365,15 @@ static int vga_switchto_stage2(struct 
vga_switcheroo_client *new_client)
fb_notifier_call_chain(FB_EVENT_REMAP_ALL_CONSOLE, );
}

+   if (vgasr_priv.handler->switch_ddc) {
+   ret = vgasr_priv.handler->switch_ddc(new_client->id);
+   if (ret)
+   return ret;
+   }
+
ret = vgasr_priv.handler->switchto(new_client->id);
if (ret)
-   return ret;
+   goto restore_ddc;

if (new_client->ops->reprobe)
new_client->ops->reprobe(new_client->pdev);
@@ -356,6 +385,14 @@ static int vga_switchto_stage2(struct 
vga_switcheroo_client *new_client)

new_client->active = true;
return 0;
+
+restore_ddc:
+   if (vgasr_priv.handler->switch_ddc) {
+   int id = (new_client->id == VGA_SWITCHEROO_IGD) ?
+   VGA_SWITCHEROO_DIS : VGA_SWITCHEROO_IGD;
+   ret = vgasr_priv.handler->switch_ddc(id);
+   }
+   return ret;
 }

 static bool check_can_switch(void)
diff --git a/include/linux/vga_switcheroo.h b/include/linux/vga_switcheroo.h
index ddb419c..b0d0839 100644
--- a/include/linux/vga_switcheroo.h
+++ b/include/linux/vga_switcheroo.h
@@ -29,6 +29,7 @@ enum vga_switcheroo_client_id {
 };

 struct vga_switcheroo_handler {
+   int (*switch_ddc)(enum vga_switcheroo_client_id id);
int (*switchto)(enum vga_switcheroo_client_id id);
int (*power_state)(enum vga_switcheroo_client_id id,
   enum vga_switcheroo_state state);
@@ -53,6 +54,8 @@ int vga_switcheroo_register_audio_client(struct pci_dev *pdev,
 void vga_switcheroo_client_fb_set(struct pci_dev *dev,
  struct fb_info *info);

+int vga_switcheroo_switch_ddc(struct pci_dev *pdev);
+
 int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler);
 void vga_switcheroo_unregister_handler(void);

@@ -66,6 +69,7 @@ static inline void vga_switcheroo_unregister_client(struct 
pci_dev *dev) {}
 static inline int vga_switcheroo_register_client(struct pci_dev *dev,
const struct vga_switcheroo_client_ops *ops) { return 0; }
 static inline void vga_switcheroo_client_fb_set(struct pci_dev *dev, struct 
fb_info *info) {}
+static inline void vga_switcheroo_switch_ddc(struct pci_dev *pdev) { return 
NULL; }
 static inline int vga_switcheroo_register_handler(struct 
vga_switcheroo_handler *handler) { return 0; }
 static inline int vga_switcheroo_register_audio_client(struct pci_dev *pdev,
const struct vga_switcheroo_client_ops *ops,
-- 
1.7.9.5



[PATCH 0/7] Fixes for hybrid graphics Apple machines

2012-09-07 Thread Seth Forshee
Many hybrid graphics Apple laptops fail to set up LVDS on the secondary
GPU due to missing or incorrect mode information for the panel at init
time. The only way to get the LVDS mode on these machines is via the
DDC, but this is muxed to the active GPU at boot. However, the graphics
mux on these machines supports muxing the i2c idependently of the
display, making it possible for the secondary graphics driver to read
the EDID without a full display switch.

In order to support this, these patches modify vga_switcheroo to allow
muxing of the DDC idependently of the display. apple-gmux is updated to
support this new functionality, and drm_get_edid() is modified to switch
the DDC mux as needed.

For this to work we also need to ensure that sufficient switcheroo
suport is available before initializing the secondary GPU. This is done
by adding any non-active GPUs that try to initialize before switcheroo
is ready to a list and initializing these devices once switcheroo
becomes ready. This behavior is restricted to Apple laptops to prevent
causing problems on other machines.

Thanks,
Seth

Seth Forshee (7):
  vga_switcheroo: Add support for switching only the DDC
  vga_switcheroo: Add helper function to get the active client
  vga_switcheroo: Add notifier call chain for switcheroo events
  apple-gmux: Add switch_ddc support
  drm/edid: Switch DDC when reading the EDID
  drm/pci: Add drm_put_pci_dev()
  drm/pci: Defer initialization of secondary graphics devices until
switcheroo is ready

 drivers/gpu/drm/ast/ast_drv.c |2 +-
 drivers/gpu/drm/cirrus/cirrus_drv.c   |2 +-
 drivers/gpu/drm/drm_drv.c |3 +
 drivers/gpu/drm/drm_edid.c|   17 
 drivers/gpu/drm/drm_pci.c |  172 +
 drivers/gpu/drm/gma500/psb_drv.c  |2 +-
 drivers/gpu/drm/i915/i915_drv.c   |2 +-
 drivers/gpu/drm/mgag200/mgag200_drv.c |2 +-
 drivers/gpu/drm/nouveau/nouveau_drv.c |2 +-
 drivers/gpu/drm/radeon/radeon_drv.c   |2 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_drv.c   |2 +-
 drivers/gpu/vga/vga_switcheroo.c  |   87 -
 drivers/platform/x86/apple-gmux.c |   12 ++-
 include/drm/drmP.h|3 +
 include/linux/vga_switcheroo.h|   20 
 15 files changed, 302 insertions(+), 28 deletions(-)



[RFC PATCH 1/7] vga_switcheroo: Add support for switching only the DDC

2012-08-21 Thread Seth Forshee
During graphics driver initialization its useful to be able to mux only
the DDC to the inactive client in order to read the EDID. Add a
switch_ddc callback to allow capable handlers to provide this
functionality, and add vga_switcheroo_switch_ddc() to allow DRM to mux
only the DDC.

Signed-off-by: Seth Forshee seth.fors...@canonical.com
---
 drivers/gpu/vga/vga_switcheroo.c |   39 +-
 include/linux/vga_switcheroo.h   |4 
 2 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index e25cf31..ea6bcc2 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -252,6 +252,29 @@ void vga_switcheroo_client_fb_set(struct pci_dev *pdev,
 }
 EXPORT_SYMBOL(vga_switcheroo_client_fb_set);
 
+int vga_switcheroo_switch_ddc(struct pci_dev *pdev)
+{
+   int ret = 0;
+   int id;
+
+   mutex_lock(vgasr_mutex);
+
+   if (!vgasr_priv.handler) {
+   ret = -ENODEV;
+   goto out;
+   }
+
+   if (vgasr_priv.handler-switch_ddc) {
+   id = vgasr_priv.handler-get_client_id(pdev);
+   ret = vgasr_priv.handler-switch_ddc(id);
+   }
+
+out:
+   mutex_unlock(vgasr_mutex);
+   return ret;
+}
+EXPORT_SYMBOL(vga_switcheroo_switch_ddc);
+
 static int vga_switcheroo_show(struct seq_file *m, void *v)
 {
struct vga_switcheroo_client *client;
@@ -342,9 +365,15 @@ static int vga_switchto_stage2(struct 
vga_switcheroo_client *new_client)
fb_notifier_call_chain(FB_EVENT_REMAP_ALL_CONSOLE, event);
}
 
+   if (vgasr_priv.handler-switch_ddc) {
+   ret = vgasr_priv.handler-switch_ddc(new_client-id);
+   if (ret)
+   return ret;
+   }
+
ret = vgasr_priv.handler-switchto(new_client-id);
if (ret)
-   return ret;
+   goto restore_ddc;
 
if (new_client-ops-reprobe)
new_client-ops-reprobe(new_client-pdev);
@@ -356,6 +385,14 @@ static int vga_switchto_stage2(struct 
vga_switcheroo_client *new_client)
 
new_client-active = true;
return 0;
+
+restore_ddc:
+   if (vgasr_priv.handler-switch_ddc) {
+   int id = (new_client-id == VGA_SWITCHEROO_IGD) ?
+   VGA_SWITCHEROO_DIS : VGA_SWITCHEROO_IGD;
+   ret = vgasr_priv.handler-switch_ddc(id);
+   }
+   return ret;
 }
 
 static bool check_can_switch(void)
diff --git a/include/linux/vga_switcheroo.h b/include/linux/vga_switcheroo.h
index ddb419c..b0d0839 100644
--- a/include/linux/vga_switcheroo.h
+++ b/include/linux/vga_switcheroo.h
@@ -29,6 +29,7 @@ enum vga_switcheroo_client_id {
 };
 
 struct vga_switcheroo_handler {
+   int (*switch_ddc)(enum vga_switcheroo_client_id id);
int (*switchto)(enum vga_switcheroo_client_id id);
int (*power_state)(enum vga_switcheroo_client_id id,
   enum vga_switcheroo_state state);
@@ -53,6 +54,8 @@ int vga_switcheroo_register_audio_client(struct pci_dev *pdev,
 void vga_switcheroo_client_fb_set(struct pci_dev *dev,
  struct fb_info *info);
 
+int vga_switcheroo_switch_ddc(struct pci_dev *pdev);
+
 int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler);
 void vga_switcheroo_unregister_handler(void);
 
@@ -66,6 +69,7 @@ static inline void vga_switcheroo_unregister_client(struct 
pci_dev *dev) {}
 static inline int vga_switcheroo_register_client(struct pci_dev *dev,
const struct vga_switcheroo_client_ops *ops) { return 0; }
 static inline void vga_switcheroo_client_fb_set(struct pci_dev *dev, struct 
fb_info *info) {}
+static inline void vga_switcheroo_switch_ddc(struct pci_dev *pdev) { return 
NULL; }
 static inline int vga_switcheroo_register_handler(struct 
vga_switcheroo_handler *handler) { return 0; }
 static inline int vga_switcheroo_register_audio_client(struct pci_dev *pdev,
const struct vga_switcheroo_client_ops *ops,
-- 
1.7.9.5

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


[RFC PATCH 2/7] vga_switcheroo: Add helper function to get the active client

2012-08-21 Thread Seth Forshee
Add vga_switcheroo_get_active_client() to allow drivers to get the
active video client. This will be used by drivers wishing to temporarily
mux only the DDC to the inactive client.

Signed-off-by: Seth Forshee seth.fors...@canonical.com
---
 drivers/gpu/vga/vga_switcheroo.c |   14 ++
 include/linux/vga_switcheroo.h   |2 ++
 2 files changed, 16 insertions(+)

diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index ea6bcc2..e53f67d 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -205,6 +205,20 @@ find_active_client(struct list_head *head)
return NULL;
 }
 
+struct pci_dev *vga_switcheroo_get_active_client(void)
+{
+   struct vga_switcheroo_client *client;
+   struct pci_dev *pdev = NULL;
+
+   mutex_lock(vgasr_mutex);
+   client = find_active_client(vgasr_priv.clients);
+   if (client)
+   pdev = client-pdev;
+   mutex_unlock(vgasr_mutex);
+   return pdev;
+}
+EXPORT_SYMBOL(vga_switcheroo_get_active_client);
+
 int vga_switcheroo_get_client_state(struct pci_dev *pdev)
 {
struct vga_switcheroo_client *client;
diff --git a/include/linux/vga_switcheroo.h b/include/linux/vga_switcheroo.h
index b0d0839..e361858 100644
--- a/include/linux/vga_switcheroo.h
+++ b/include/linux/vga_switcheroo.h
@@ -61,6 +61,7 @@ void vga_switcheroo_unregister_handler(void);
 
 int vga_switcheroo_process_delayed_switch(void);
 
+struct pci_dev *vga_switcheroo_get_active_client(void);
 int vga_switcheroo_get_client_state(struct pci_dev *dev);
 
 #else
@@ -76,6 +77,7 @@ static inline int vga_switcheroo_register_audio_client(struct 
pci_dev *pdev,
int id, bool active) { return 0; }
 static inline void vga_switcheroo_unregister_handler(void) {}
 static inline int vga_switcheroo_process_delayed_switch(void) { return 0; }
+static inline struct pci_dev *vga_switcheroo_get_active_client(void) { return 
NULL; }
 static inline int vga_switcheroo_get_client_state(struct pci_dev *dev) { 
return VGA_SWITCHEROO_ON; }
 
 
-- 
1.7.9.5

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


[RFC PATCH 4/7] apple-gmux: Add switch_ddc support

2012-08-21 Thread Seth Forshee
The gmux allows muxing the DDC independently from the display, so
support this functionality. This will allow reading the EDID for the
inactive GPU, fixing issues with machines that either don't have a VBT
or have invalid mode data in the VBT.

Signed-off-by: Seth Forshee seth.fors...@canonical.com
---
 drivers/platform/x86/apple-gmux.c |   12 ++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/platform/x86/apple-gmux.c 
b/drivers/platform/x86/apple-gmux.c
index c72e81e..f702e90 100644
--- a/drivers/platform/x86/apple-gmux.c
+++ b/drivers/platform/x86/apple-gmux.c
@@ -269,14 +269,21 @@ static const struct backlight_ops gmux_bl_ops = {
.update_status = gmux_update_status,
 };
 
+static int gmux_switch_ddc(enum vga_switcheroo_client_id id)
+{
+   if (id == VGA_SWITCHEROO_IGD)
+   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 1);
+   else
+   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 2);
+   return 0;
+}
+
 static int gmux_switchto(enum vga_switcheroo_client_id id)
 {
if (id == VGA_SWITCHEROO_IGD) {
-   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 1);
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DISPLAY, 2);
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 2);
} else {
-   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 2);
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DISPLAY, 3);
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 3);
}
@@ -343,6 +350,7 @@ gmux_active_client(struct apple_gmux_data *gmux_data)
 }
 
 static struct vga_switcheroo_handler gmux_handler = {
+   .switch_ddc = gmux_switch_ddc,
.switchto = gmux_switchto,
.power_state = gmux_set_power_state,
.get_client_id = gmux_get_client_id,
-- 
1.7.9.5

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


[RFC PATCH 5/7] drm/edid: Switch DDC when reading the EDID

2012-08-21 Thread Seth Forshee
Some dual graphics machines support muxing the DDC separately from the
display, so make use of this functionality when reading the EDID on the
inactive GPU. Also serialize drm_get_edid() with a mutex to avoid races
on the DDC mux state.

Signed-off-by: Seth Forshee seth.fors...@canonical.com
---
 drivers/gpu/drm/drm_edid.c |   17 +
 1 file changed, 17 insertions(+)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index a8743c3..1a4b661 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -31,6 +31,7 @@
 #include linux/slab.h
 #include linux/i2c.h
 #include linux/module.h
+#include linux/vga_switcheroo.h
 #include drmP.h
 #include drm_edid.h
 #include drm_edid_modes.h
@@ -82,6 +83,8 @@ struct detailed_mode_closure {
 #define LEVEL_GTF2 2
 #define LEVEL_CVT  3
 
+static DEFINE_MUTEX(drm_edid_mutex);
+
 static struct edid_quirk {
char vendor[4];
int product_id;
@@ -395,12 +398,26 @@ struct edid *drm_get_edid(struct drm_connector *connector,
  struct i2c_adapter *adapter)
 {
struct edid *edid = NULL;
+   struct pci_dev *pdev = connector-dev-pdev;
+   struct pci_dev *active_pdev = NULL;
+
+   mutex_lock(drm_edid_mutex);
+
+   if (pdev) {
+   active_pdev = vga_switcheroo_get_active_client();
+   if (active_pdev != pdev)
+   vga_switcheroo_switch_ddc(pdev);
+   }
 
if (drm_probe_ddc(adapter))
edid = (struct edid *)drm_do_get_edid(connector, adapter);
 
+   if (active_pdev  active_pdev != pdev)
+   vga_switcheroo_switch_ddc(active_pdev);
+
connector-display_info.raw_edid = (char *)edid;
 
+   mutex_unlock(drm_edid_mutex);
return edid;
 
 }
-- 
1.7.9.5

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


[RFC PATCH 6/7] drm/pci: Add drm_put_pci_dev()

2012-08-21 Thread Seth Forshee
When deferred initialization support for pci devices is added some
additional cleanup will be needed. Add a pci-specific put function to
serve this purpose, and convert the pci drivers over to using it. For
now it just calls drm_put_dev(), so this commit has no functional
change.

Signed-off-by: Seth Forshee seth.fors...@canonical.com
---
 drivers/gpu/drm/ast/ast_drv.c |2 +-
 drivers/gpu/drm/cirrus/cirrus_drv.c   |2 +-
 drivers/gpu/drm/drm_pci.c |6 ++
 drivers/gpu/drm/gma500/psb_drv.c  |2 +-
 drivers/gpu/drm/i915/i915_drv.c   |2 +-
 drivers/gpu/drm/mgag200/mgag200_drv.c |2 +-
 drivers/gpu/drm/nouveau/nouveau_drv.c |2 +-
 drivers/gpu/drm/radeon/radeon_drv.c   |2 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_drv.c   |2 +-
 include/drm/drmP.h|1 +
 10 files changed, 15 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c
index d0c4574..001298d 100644
--- a/drivers/gpu/drm/ast/ast_drv.c
+++ b/drivers/gpu/drm/ast/ast_drv.c
@@ -72,7 +72,7 @@ ast_pci_remove(struct pci_dev *pdev)
 {
struct drm_device *dev = pci_get_drvdata(pdev);
 
-   drm_put_dev(dev);
+   drm_put_pci_dev(dev);
 }
 
 
diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.c 
b/drivers/gpu/drm/cirrus/cirrus_drv.c
index 7053140..c7ca02b 100644
--- a/drivers/gpu/drm/cirrus/cirrus_drv.c
+++ b/drivers/gpu/drm/cirrus/cirrus_drv.c
@@ -64,7 +64,7 @@ static void cirrus_pci_remove(struct pci_dev *pdev)
 {
struct drm_device *dev = pci_get_drvdata(pdev);
 
-   drm_put_dev(dev);
+   drm_put_pci_dev(dev);
 }
 
 static const struct file_operations cirrus_driver_fops = {
diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c
index 5320364..4896c96 100644
--- a/drivers/gpu/drm/drm_pci.c
+++ b/drivers/gpu/drm/drm_pci.c
@@ -388,6 +388,12 @@ err_g1:
 }
 EXPORT_SYMBOL(drm_get_pci_dev);
 
+void drm_put_pci_dev(struct drm_device *dev)
+{
+   drm_put_dev(dev);
+}
+EXPORT_SYMBOL(drm_put_pci_dev);
+
 /**
  * PCI device initialization. Called direct from modules at load time.
  *
diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c
index 0c47374..d7c3c9c 100644
--- a/drivers/gpu/drm/gma500/psb_drv.c
+++ b/drivers/gpu/drm/gma500/psb_drv.c
@@ -585,7 +585,7 @@ static void psb_driver_preclose(struct drm_device *dev, 
struct drm_file *priv)
 static void psb_remove(struct pci_dev *pdev)
 {
struct drm_device *dev = pci_get_drvdata(pdev);
-   drm_put_dev(dev);
+   drm_put_pci_dev(dev);
 }
 
 static const struct dev_pm_ops psb_pm_ops = {
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index a24ffbe..86ae5a2 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -856,7 +856,7 @@ i915_pci_remove(struct pci_dev *pdev)
 {
struct drm_device *dev = pci_get_drvdata(pdev);
 
-   drm_put_dev(dev);
+   drm_put_pci_dev(dev);
 }
 
 static int i915_pm_suspend(struct device *dev)
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c 
b/drivers/gpu/drm/mgag200/mgag200_drv.c
index ea1024d..a3b0a4a 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.c
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.c
@@ -73,7 +73,7 @@ static void mga_pci_remove(struct pci_dev *pdev)
 {
struct drm_device *dev = pci_get_drvdata(pdev);
 
-   drm_put_dev(dev);
+   drm_put_pci_dev(dev);
 }
 
 static const struct file_operations mgag200_driver_fops = {
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c 
b/drivers/gpu/drm/nouveau/nouveau_drv.c
index 9a36f5f..b74b02a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.c
@@ -168,7 +168,7 @@ nouveau_pci_remove(struct pci_dev *pdev)
 {
struct drm_device *dev = pci_get_drvdata(pdev);
 
-   drm_put_dev(dev);
+   drm_put_pci_dev(dev);
 }
 
 int
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c 
b/drivers/gpu/drm/radeon/radeon_drv.c
index d7269f4..298697a 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -308,7 +308,7 @@ radeon_pci_remove(struct pci_dev *pdev)
 {
struct drm_device *dev = pci_get_drvdata(pdev);
 
-   drm_put_dev(dev);
+   drm_put_pci_dev(dev);
 }
 
 static int
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c 
b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index 4d9edea..cf901cc 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -982,7 +982,7 @@ static void vmw_remove(struct pci_dev *pdev)
 {
struct drm_device *dev = pci_get_drvdata(pdev);
 
-   drm_put_dev(dev);
+   drm_put_pci_dev(dev);
 }
 
 static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val,
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index d6b67bb..eb99e96 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -1748,6 +1748,7 @@ extern void drm_pci_exit(struct drm_driver *driver, 
struct pci_driver *pdriver);
 extern

[RFC PATCH 7/7] drm/pci: Defer initialization of secondary graphics devices until switcheroo is ready

2012-08-20 Thread Seth Forshee
On Mon, Aug 20, 2012 at 04:57:41PM +0100, Matthew Garrett wrote:
> On Mon, Aug 20, 2012 at 10:56:33AM -0500, Seth Forshee wrote:
> > On Mon, Aug 20, 2012 at 04:36:40PM +0100, Matthew Garrett wrote:
> > > Won't this break the multiple cards with independent outputs case?
> > 
> > Yes, if they don't have a switcheroo handler. I only have experience
> > with one such machine, which had optimus graphics. My recollection is
> > that it did have a switcheroo handler, which was only capable of
> > controlling power to the discrete card.
> 
> So if I have a desktop machine and install two graphics cards?

Yeah, that would likely be broken.

I'm not sure how we support both of these cases without doing something
more like what I originally proposed, i.e. registering the LVDS
connector even if it doesn't look like a panel is attached. I still
honestly favor that approach, although it does come with its own set of
challenges.

The only other option I can come up with is to reprobe LVDS after
switcheroo and add the connector at that time. I haven't investigated
this option in detail, but at first glance it looks like there are at
least some places where DRM isn't prepared to cope with adding
connectors after initialization.



[RFC PATCH 7/7] drm/pci: Defer initialization of secondary graphics devices until switcheroo is ready

2012-08-20 Thread Seth Forshee
On Mon, Aug 20, 2012 at 04:36:40PM +0100, Matthew Garrett wrote:
> On Mon, Aug 20, 2012 at 10:31:04AM -0500, Seth Forshee wrote:
> > +   /*
> > +* For secondary graphics devices shouldn't be initialized
> > +* until the handler and primary graphics device have been
> > +* registered with vga_switcheroo.
> > +*
> > +* FIXME: Is vga_default_device() reliable enough for this
> > +* purpose?
> > +*
> > +* FIXME: If vga_switcheroo is disabled secondary devices
> > +* never gets initialized. Is this okay? Maybe it is, since
> > +* we can't switch to the secondary GPU anyway.
> > +*/
> 
> Won't this break the multiple cards with independent outputs case?

Yes, if they don't have a switcheroo handler. I only have experience
with one such machine, which had optimus graphics. My recollection is
that it did have a switcheroo handler, which was only capable of
controlling power to the discrete card.



[RFC PATCH 7/7] drm/pci: Defer initialization of secondary graphics devices until switcheroo is ready

2012-08-20 Thread Seth Forshee
Deferring initiailzation of the secondary GPU until switcheroo is ready
will allow successfully reading the EDID in systems which support muxing
the DDC seperately from the display.

Signed-off-by: Seth Forshee 
---
 drivers/gpu/drm/drm_drv.c |3 +
 drivers/gpu/drm/drm_pci.c |  141 +++--
 include/drm/drmP.h|2 +
 3 files changed, 129 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 9238de4..124fd8a 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -276,6 +276,8 @@ static int __init drm_core_init(void)
goto err_p3;
}

+   drm_pci_module_init();
+
DRM_INFO("Initialized %s %d.%d.%d %s\n",
 CORE_NAME, CORE_MAJOR, CORE_MINOR, CORE_PATCHLEVEL, CORE_DATE);
return 0;
@@ -291,6 +293,7 @@ err_p1:

 static void __exit drm_core_exit(void)
 {
+   drm_pci_module_exit();
remove_proc_entry("dri", NULL);
debugfs_remove(drm_debugfs_root);
drm_sysfs_destroy();
diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c
index 4896c96..9da0cd2 100644
--- a/drivers/gpu/drm/drm_pci.c
+++ b/drivers/gpu/drm/drm_pci.c
@@ -40,6 +40,9 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
 #include "drmP.h"

 /**/
@@ -297,19 +300,8 @@ static struct drm_bus drm_pci_bus = {
.agp_init = drm_pci_agp_init,
 };

-/**
- * Register.
- *
- * \param pdev - PCI device structure
- * \param ent entry from the PCI ID table with device type flags
- * \return zero on success or a negative number on failure.
- *
- * Attempt to gets inter module "drm" information. If we are first
- * then register the character device and inter module information.
- * Try and register, if we fail to register, backout previous work.
- */
-int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
-   struct drm_driver *driver)
+int __drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
+ struct drm_driver *driver)
 {
struct drm_device *dev;
int ret;
@@ -334,8 +326,6 @@ int drm_get_pci_dev(struct pci_dev *pdev, const struct 
pci_device_id *ent,
dev->hose = pdev->sysdata;
 #endif

-   mutex_lock(_global_mutex);
-
if ((ret = drm_fill_in_dev(dev, ent, driver))) {
printk(KERN_ERR "DRM: Fill_in_dev failed.\n");
goto err_g2;
@@ -371,7 +361,6 @@ int drm_get_pci_dev(struct pci_dev *pdev, const struct 
pci_device_id *ent,
 driver->name, driver->major, driver->minor, driver->patchlevel,
 driver->date, pci_name(pdev), dev->primary->index);

-   mutex_unlock(_global_mutex);
return 0;

 err_g4:
@@ -386,10 +375,116 @@ err_g1:
mutex_unlock(_global_mutex);
return ret;
 }
+
+struct deferred_init_data {
+   struct list_head list;
+   struct pci_dev *pdev;
+   const struct pci_device_id *ent;
+   struct drm_driver *driver;
+};
+
+static LIST_HEAD(deferred_init_list);
+
+static void drm_deferred_init_work_fn(struct work_struct *work)
+{
+   struct deferred_init_data *di_data, *temp;
+
+   mutex_lock(_global_mutex);
+
+   if (!vga_switcheroo_handler_registered() ||
+   !vga_switcheroo_get_active_client()) {
+   mutex_unlock(_global_mutex);
+   return;
+   }
+
+   list_for_each_entry_safe(di_data, temp, _init_list, list) {
+   if (__drm_get_pci_dev(di_data->pdev, di_data->ent,
+ di_data->driver))
+   DRM_ERROR("pci device initialization failed\n");
+   list_del(_data->list);
+   kfree(di_data);
+   }
+   mutex_unlock(_global_mutex);
+}
+static DECLARE_WORK(deferred_init_work, drm_deferred_init_work_fn);
+
+static int drm_switcheroo_notifier_fn(struct notifier_block *nb,
+ unsigned long val, void *unused)
+{
+   if (val == VGA_SWITCHEROO_CLIENT_REGISTERED ||
+   val == VGA_SWITCHEROO_HANDLER_REGISTERED)
+   queue_work(system_nrt_wq, _init_work);
+   return NOTIFY_OK;
+}
+static struct notifier_block drm_switcheroo_notifier = {
+   .notifier_call = drm_switcheroo_notifier_fn,
+};
+
+/**
+ * Register.
+ *
+ * \param pdev - PCI device structure
+ * \param ent entry from the PCI ID table with device type flags
+ * \return zero on success or a negative number on failure.
+ *
+ * Attempt to gets inter module "drm" information. If we are first
+ * then register the character device and inter module information.
+ * Try and register, if we fail to register, backout previous work.
+ */
+int drm_get_pci_dev(struct pci_dev *pdev, const struct pc

[RFC PATCH 5/7] drm/edid: Switch DDC when reading the EDID

2012-08-20 Thread Seth Forshee
Some dual graphics machines support muxing the DDC separately from the
display, so make use of this functionality when reading the EDID on the
inactive GPU. Also serialize drm_get_edid() with a mutex to avoid races
on the DDC mux state.

Signed-off-by: Seth Forshee 
---
 drivers/gpu/drm/drm_edid.c |   17 +
 1 file changed, 17 insertions(+)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index a8743c3..1a4b661 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -31,6 +31,7 @@
 #include 
 #include 
 #include 
+#include 
 #include "drmP.h"
 #include "drm_edid.h"
 #include "drm_edid_modes.h"
@@ -82,6 +83,8 @@ struct detailed_mode_closure {
 #define LEVEL_GTF2 2
 #define LEVEL_CVT  3

+static DEFINE_MUTEX(drm_edid_mutex);
+
 static struct edid_quirk {
char vendor[4];
int product_id;
@@ -395,12 +398,26 @@ struct edid *drm_get_edid(struct drm_connector *connector,
  struct i2c_adapter *adapter)
 {
struct edid *edid = NULL;
+   struct pci_dev *pdev = connector->dev->pdev;
+   struct pci_dev *active_pdev = NULL;
+
+   mutex_lock(_edid_mutex);
+
+   if (pdev) {
+   active_pdev = vga_switcheroo_get_active_client();
+   if (active_pdev != pdev)
+   vga_switcheroo_switch_ddc(pdev);
+   }

if (drm_probe_ddc(adapter))
edid = (struct edid *)drm_do_get_edid(connector, adapter);

+   if (active_pdev && active_pdev != pdev)
+   vga_switcheroo_switch_ddc(active_pdev);
+
connector->display_info.raw_edid = (char *)edid;

+   mutex_unlock(_edid_mutex);
return edid;

 }
-- 
1.7.9.5



[RFC PATCH 4/7] apple-gmux: Add switch_ddc support

2012-08-20 Thread Seth Forshee
The gmux allows muxing the DDC independently from the display, so
support this functionality. This will allow reading the EDID for the
inactive GPU, fixing issues with machines that either don't have a VBT
or have invalid mode data in the VBT.

Signed-off-by: Seth Forshee 
---
 drivers/platform/x86/apple-gmux.c |   12 ++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/platform/x86/apple-gmux.c 
b/drivers/platform/x86/apple-gmux.c
index c72e81e..f702e90 100644
--- a/drivers/platform/x86/apple-gmux.c
+++ b/drivers/platform/x86/apple-gmux.c
@@ -269,14 +269,21 @@ static const struct backlight_ops gmux_bl_ops = {
.update_status = gmux_update_status,
 };

+static int gmux_switch_ddc(enum vga_switcheroo_client_id id)
+{
+   if (id == VGA_SWITCHEROO_IGD)
+   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 1);
+   else
+   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 2);
+   return 0;
+}
+
 static int gmux_switchto(enum vga_switcheroo_client_id id)
 {
if (id == VGA_SWITCHEROO_IGD) {
-   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 1);
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DISPLAY, 2);
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 2);
} else {
-   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 2);
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DISPLAY, 3);
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 3);
}
@@ -343,6 +350,7 @@ gmux_active_client(struct apple_gmux_data *gmux_data)
 }

 static struct vga_switcheroo_handler gmux_handler = {
+   .switch_ddc = gmux_switch_ddc,
.switchto = gmux_switchto,
.power_state = gmux_set_power_state,
.get_client_id = gmux_get_client_id,
-- 
1.7.9.5



[RFC PATCH 3/7] vga_switcheroo: Add notifier call chain for switcheroo events

2012-08-20 Thread Seth Forshee
DRM needs to be notified of client and handler registration in order to
defer initialization of the secondary GPU until the EDID can be read
from the LVDS panel. To support this add a notifier call chain to
vga_switcheroo for subscribing to switcheroo events. Events are
generated for registration and unregistration of handlers and clients.

Signed-off-by: Seth Forshee 
---
 drivers/gpu/vga/vga_switcheroo.c |   34 ++
 include/linux/vga_switcheroo.h   |   14 ++
 2 files changed, 48 insertions(+)

diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index e53f67d..d5cd274 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -24,6 +24,7 @@
 #include 
 #include 
 #include 
+#include 

 #include 
 #include 
@@ -70,6 +71,28 @@ static struct vgasr_priv vgasr_priv = {
.clients = LIST_HEAD_INIT(vgasr_priv.clients),
 };

+static BLOCKING_NOTIFIER_HEAD(vga_switcheroo_notifier_list);
+
+int vga_switcheroo_register_notifier(struct notifier_block *nb)
+{
+   return blocking_notifier_chain_register(_switcheroo_notifier_list,
+   nb);
+}
+EXPORT_SYMBOL(vga_switcheroo_register_notifier);
+
+int vga_switcheroo_unregister_notifier(struct notifier_block *nb)
+{
+   return blocking_notifier_chain_unregister(_switcheroo_notifier_list,
+ nb);
+}
+EXPORT_SYMBOL(vga_switcheroo_unregister_notifier);
+
+static int vga_switcheroo_notifier_call_chain(enum vga_switcheroo_event event)
+{
+   return blocking_notifier_call_chain(_switcheroo_notifier_list,
+   event, NULL);
+}
+
 static bool vga_switcheroo_ready(void)
 {
/* we're ready if we get two clients + handler */
@@ -113,10 +136,18 @@ int vga_switcheroo_register_handler(struct 
vga_switcheroo_handler *handler)
vga_switcheroo_enable();
}
mutex_unlock(_mutex);
+
+   vga_switcheroo_notifier_call_chain(VGA_SWITCHEROO_HANDLER_REGISTERED);
return 0;
 }
 EXPORT_SYMBOL(vga_switcheroo_register_handler);

+bool vga_switcheroo_handler_registered(void)
+{
+   return !!vgasr_priv.handler;
+}
+EXPORT_SYMBOL(vga_switcheroo_handler_registered);
+
 void vga_switcheroo_unregister_handler(void)
 {
mutex_lock(_mutex);
@@ -127,6 +158,7 @@ void vga_switcheroo_unregister_handler(void)
vgasr_priv.active = false;
}
mutex_unlock(_mutex);
+   vga_switcheroo_notifier_call_chain(VGA_SWITCHEROO_HANDLER_UNREGISTERED);
 }
 EXPORT_SYMBOL(vga_switcheroo_unregister_handler);

@@ -156,6 +188,7 @@ static int register_client(struct pci_dev *pdev,
vga_switcheroo_enable();
}
mutex_unlock(_mutex);
+   vga_switcheroo_notifier_call_chain(VGA_SWITCHEROO_CLIENT_REGISTERED);
return 0;
 }

@@ -250,6 +283,7 @@ void vga_switcheroo_unregister_client(struct pci_dev *pdev)
vgasr_priv.active = false;
}
mutex_unlock(_mutex);
+   vga_switcheroo_notifier_call_chain(VGA_SWITCHEROO_CLIENT_UNREGISTERED);
 }
 EXPORT_SYMBOL(vga_switcheroo_unregister_client);

diff --git a/include/linux/vga_switcheroo.h b/include/linux/vga_switcheroo.h
index e361858..c3d7c6f 100644
--- a/include/linux/vga_switcheroo.h
+++ b/include/linux/vga_switcheroo.h
@@ -11,6 +11,7 @@
 #define _LINUX_VGA_SWITCHEROO_H_

 #include 
+#include 

 struct pci_dev;

@@ -28,6 +29,13 @@ enum vga_switcheroo_client_id {
VGA_SWITCHEROO_MAX_CLIENTS,
 };

+enum vga_switcheroo_event {
+   VGA_SWITCHEROO_CLIENT_REGISTERED,
+   VGA_SWITCHEROO_CLIENT_UNREGISTERED,
+   VGA_SWITCHEROO_HANDLER_REGISTERED,
+   VGA_SWITCHEROO_HANDLER_UNREGISTERED,
+};
+
 struct vga_switcheroo_handler {
int (*switch_ddc)(enum vga_switcheroo_client_id id);
int (*switchto)(enum vga_switcheroo_client_id id);
@@ -44,6 +52,9 @@ struct vga_switcheroo_client_ops {
 };

 #if defined(CONFIG_VGA_SWITCHEROO)
+int vga_switcheroo_register_notifier(struct notifier_block *nb);
+int vga_switcheroo_unregister_notifier(struct notifier_block *nb);
+bool vga_switcheroo_handler_registered(void);
 void vga_switcheroo_unregister_client(struct pci_dev *dev);
 int vga_switcheroo_register_client(struct pci_dev *dev,
   const struct vga_switcheroo_client_ops *ops);
@@ -66,6 +77,9 @@ int vga_switcheroo_get_client_state(struct pci_dev *dev);

 #else

+static inline int vga_switcheroo_register_notifier(struct notifier_block *nb) 
{ return 0; }
+static inline int vga_switcheroo_unregister_notifier(struct notifier_block 
*nb) { return 0; }
+static inline bool vga_switcheroo_handler_registered(void) { return false; }
 static inline void vga_switcheroo_unregister_client(struct pci_dev *dev) {}
 static inline int vga_switcheroo_register_client(struct pci_dev *dev,
const struct vga_switcheroo_client_ops *ops) { return 0

[RFC PATCH 2/7] vga_switcheroo: Add helper function to get the active client

2012-08-20 Thread Seth Forshee
Add vga_switcheroo_get_active_client() to allow drivers to get the
active video client. This will be used by drivers wishing to temporarily
mux only the DDC to the inactive client.

Signed-off-by: Seth Forshee 
---
 drivers/gpu/vga/vga_switcheroo.c |   14 ++
 include/linux/vga_switcheroo.h   |2 ++
 2 files changed, 16 insertions(+)

diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index ea6bcc2..e53f67d 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -205,6 +205,20 @@ find_active_client(struct list_head *head)
return NULL;
 }

+struct pci_dev *vga_switcheroo_get_active_client(void)
+{
+   struct vga_switcheroo_client *client;
+   struct pci_dev *pdev = NULL;
+
+   mutex_lock(_mutex);
+   client = find_active_client(_priv.clients);
+   if (client)
+   pdev = client->pdev;
+   mutex_unlock(_mutex);
+   return pdev;
+}
+EXPORT_SYMBOL(vga_switcheroo_get_active_client);
+
 int vga_switcheroo_get_client_state(struct pci_dev *pdev)
 {
struct vga_switcheroo_client *client;
diff --git a/include/linux/vga_switcheroo.h b/include/linux/vga_switcheroo.h
index b0d0839..e361858 100644
--- a/include/linux/vga_switcheroo.h
+++ b/include/linux/vga_switcheroo.h
@@ -61,6 +61,7 @@ void vga_switcheroo_unregister_handler(void);

 int vga_switcheroo_process_delayed_switch(void);

+struct pci_dev *vga_switcheroo_get_active_client(void);
 int vga_switcheroo_get_client_state(struct pci_dev *dev);

 #else
@@ -76,6 +77,7 @@ static inline int vga_switcheroo_register_audio_client(struct 
pci_dev *pdev,
int id, bool active) { return 0; }
 static inline void vga_switcheroo_unregister_handler(void) {}
 static inline int vga_switcheroo_process_delayed_switch(void) { return 0; }
+static inline struct pci_dev *vga_switcheroo_get_active_client(void) { return 
NULL; }
 static inline int vga_switcheroo_get_client_state(struct pci_dev *dev) { 
return VGA_SWITCHEROO_ON; }


-- 
1.7.9.5



[RFC PATCH 1/7] vga_switcheroo: Add support for switching only the DDC

2012-08-20 Thread Seth Forshee
During graphics driver initialization its useful to be able to mux only
the DDC to the inactive client in order to read the EDID. Add a
switch_ddc callback to allow capable handlers to provide this
functionality, and add vga_switcheroo_switch_ddc() to allow DRM to mux
only the DDC.

Signed-off-by: Seth Forshee 
---
 drivers/gpu/vga/vga_switcheroo.c |   39 +-
 include/linux/vga_switcheroo.h   |4 
 2 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index e25cf31..ea6bcc2 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -252,6 +252,29 @@ void vga_switcheroo_client_fb_set(struct pci_dev *pdev,
 }
 EXPORT_SYMBOL(vga_switcheroo_client_fb_set);

+int vga_switcheroo_switch_ddc(struct pci_dev *pdev)
+{
+   int ret = 0;
+   int id;
+
+   mutex_lock(_mutex);
+
+   if (!vgasr_priv.handler) {
+   ret = -ENODEV;
+   goto out;
+   }
+
+   if (vgasr_priv.handler->switch_ddc) {
+   id = vgasr_priv.handler->get_client_id(pdev);
+   ret = vgasr_priv.handler->switch_ddc(id);
+   }
+
+out:
+   mutex_unlock(_mutex);
+   return ret;
+}
+EXPORT_SYMBOL(vga_switcheroo_switch_ddc);
+
 static int vga_switcheroo_show(struct seq_file *m, void *v)
 {
struct vga_switcheroo_client *client;
@@ -342,9 +365,15 @@ static int vga_switchto_stage2(struct 
vga_switcheroo_client *new_client)
fb_notifier_call_chain(FB_EVENT_REMAP_ALL_CONSOLE, );
}

+   if (vgasr_priv.handler->switch_ddc) {
+   ret = vgasr_priv.handler->switch_ddc(new_client->id);
+   if (ret)
+   return ret;
+   }
+
ret = vgasr_priv.handler->switchto(new_client->id);
if (ret)
-   return ret;
+   goto restore_ddc;

if (new_client->ops->reprobe)
new_client->ops->reprobe(new_client->pdev);
@@ -356,6 +385,14 @@ static int vga_switchto_stage2(struct 
vga_switcheroo_client *new_client)

new_client->active = true;
return 0;
+
+restore_ddc:
+   if (vgasr_priv.handler->switch_ddc) {
+   int id = (new_client->id == VGA_SWITCHEROO_IGD) ?
+   VGA_SWITCHEROO_DIS : VGA_SWITCHEROO_IGD;
+   ret = vgasr_priv.handler->switch_ddc(id);
+   }
+   return ret;
 }

 static bool check_can_switch(void)
diff --git a/include/linux/vga_switcheroo.h b/include/linux/vga_switcheroo.h
index ddb419c..b0d0839 100644
--- a/include/linux/vga_switcheroo.h
+++ b/include/linux/vga_switcheroo.h
@@ -29,6 +29,7 @@ enum vga_switcheroo_client_id {
 };

 struct vga_switcheroo_handler {
+   int (*switch_ddc)(enum vga_switcheroo_client_id id);
int (*switchto)(enum vga_switcheroo_client_id id);
int (*power_state)(enum vga_switcheroo_client_id id,
   enum vga_switcheroo_state state);
@@ -53,6 +54,8 @@ int vga_switcheroo_register_audio_client(struct pci_dev *pdev,
 void vga_switcheroo_client_fb_set(struct pci_dev *dev,
  struct fb_info *info);

+int vga_switcheroo_switch_ddc(struct pci_dev *pdev);
+
 int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler);
 void vga_switcheroo_unregister_handler(void);

@@ -66,6 +69,7 @@ static inline void vga_switcheroo_unregister_client(struct 
pci_dev *dev) {}
 static inline int vga_switcheroo_register_client(struct pci_dev *dev,
const struct vga_switcheroo_client_ops *ops) { return 0; }
 static inline void vga_switcheroo_client_fb_set(struct pci_dev *dev, struct 
fb_info *info) {}
+static inline void vga_switcheroo_switch_ddc(struct pci_dev *pdev) { return 
NULL; }
 static inline int vga_switcheroo_register_handler(struct 
vga_switcheroo_handler *handler) { return 0; }
 static inline int vga_switcheroo_register_audio_client(struct pci_dev *pdev,
const struct vga_switcheroo_client_ops *ops,
-- 
1.7.9.5



[RFC PATCH 3/5] drm/i915: register LVDS connector even if we can't get a panel mode

2012-08-20 Thread Seth Forshee
On Fri, Aug 10, 2012 at 05:19:48PM -0500, Seth Forshee wrote:
> First, I don't have a solution for the ordering of initialization. It
> just happens to work out for me right now.

Okay, I've got a proof-of-concept implementation of delaying secondary
GPU initialization until the i2c can be muxed over to that card. It's
not exactly pretty, but it is working. I'd really like to get some
feedback on the concept and implementation before spending more time on
it. Patches follow.

One problem I'm aware of is if the switcheroo handler is in the driver
for the secondary GPU. I think this was the case for a machine I used to
have with Optimus graphics. In that scenario the secondary graphics
device is never initialized because the switcheroo handler is registered
during initialization of the secondary device. The driver load method
would need to be split up to cope with this.

Thanks,
Seth



[PATCH v2 0/3] Display switching support for Apple laptops

2012-08-18 Thread Seth Forshee
This series adds display switching support for Apple laptops. The first
two patches contain preparatory changes to vga_switcheroo, and the third
contains the changes to support display switching with the gmux.

While these patches will allow switching the display mux, most Macbook
owners will not be able to switch GPUs in practice until the graphics
drivers are updated to deal with missing or incorrect vbios information
on Apple machines. These patches do fix an issue seen by some users of
Linux on Macbooks, however. These users will switch to the internal GPU
in OS X and then reboot into Linux to save power, but after S3 the gmux
gets reset to the discrete GPU. Adding the display mux support will fix
this problem by restoring the gmux state during resume.

v2: Disable interrupts during suspend and re-enable them during resume
to fix timeouts waiting for switching to complete after S3

Thanks,
Seth


Andreas Heider (1):
  apple-gmux: Add display mux support

Seth Forshee (2):
  vga_switcheroo: Don't require handler init callback
  vga_switcheroo: Remove assumptions about registration/unregistration
ordering

 drivers/gpu/drm/nouveau/nouveau_acpi.c |6 -
 drivers/gpu/vga/vga_switcheroo.c   |   61 +
 drivers/platform/x86/apple-gmux.c  |  224 
 3 files changed, 262 insertions(+), 29 deletions(-)

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 1/3] vga_switcheroo: Don't require handler init callback

2012-08-18 Thread Seth Forshee
This callback is a no-op in nouveau, and the upcoming apple-gmux
switcheroo support won't require it either. Rather than forcing drivers
to stub it out, just make it optional and remove the callback from
nouveau.

Signed-off-by: Seth Forshee seth.fors...@canonical.com
---
 drivers/gpu/drm/nouveau/nouveau_acpi.c |6 --
 drivers/gpu/vga/vga_switcheroo.c   |3 ++-
 2 files changed, 2 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c 
b/drivers/gpu/drm/nouveau/nouveau_acpi.c
index fc841e8..26ebffe 100644
--- a/drivers/gpu/drm/nouveau/nouveau_acpi.c
+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c
@@ -211,11 +211,6 @@ static int nouveau_dsm_power_state(enum 
vga_switcheroo_client_id id,
return nouveau_dsm_set_discrete_state(nouveau_dsm_priv.dhandle, state);
 }
 
-static int nouveau_dsm_init(void)
-{
-   return 0;
-}
-
 static int nouveau_dsm_get_client_id(struct pci_dev *pdev)
 {
/* easy option one - intel vendor ID means Integrated */
@@ -232,7 +227,6 @@ static int nouveau_dsm_get_client_id(struct pci_dev *pdev)
 static struct vga_switcheroo_handler nouveau_dsm_handler = {
.switchto = nouveau_dsm_switchto,
.power_state = nouveau_dsm_power_state,
-   .init = nouveau_dsm_init,
.get_client_id = nouveau_dsm_get_client_id,
 };
 
diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index 5b3c7d1..ec9069d 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -98,7 +98,8 @@ static void vga_switcheroo_enable(void)
struct vga_switcheroo_client *client;
 
/* call the handler to init */
-   vgasr_priv.handler-init();
+   if (vgasr_priv.handler-init)
+   vgasr_priv.handler-init();
 
list_for_each_entry(client, vgasr_priv.clients, list) {
if (client-id != -1)
-- 
1.7.9.5

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 2/3] vga_switcheroo: Remove assumptions about registration/unregistration ordering

2012-08-18 Thread Seth Forshee
vga_switcheroo assumes that the handler will be registered before the
last client, otherwise switching will not be enabled. Likewise it's
assumed that the handler will not be unregistered without at least one
client also being unregistered, otherwise switching will remain enabled
despite no longer having a handler. These assumptions cannot be enforced
if the handler is in a separate driver from both clients, as with the
gmux found in Apple laptops. Remove this assumption.

Signed-off-by: Seth Forshee seth.fors...@canonical.com
---
 drivers/gpu/vga/vga_switcheroo.c |   58 +++---
 1 file changed, 36 insertions(+), 22 deletions(-)

diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index ec9069d..e25cf31 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -70,27 +70,12 @@ static struct vgasr_priv vgasr_priv = {
.clients = LIST_HEAD_INIT(vgasr_priv.clients),
 };
 
-int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler)
-{
-   mutex_lock(vgasr_mutex);
-   if (vgasr_priv.handler) {
-   mutex_unlock(vgasr_mutex);
-   return -EINVAL;
-   }
-
-   vgasr_priv.handler = handler;
-   mutex_unlock(vgasr_mutex);
-   return 0;
-}
-EXPORT_SYMBOL(vga_switcheroo_register_handler);
-
-void vga_switcheroo_unregister_handler(void)
+static bool vga_switcheroo_ready(void)
 {
-   mutex_lock(vgasr_mutex);
-   vgasr_priv.handler = NULL;
-   mutex_unlock(vgasr_mutex);
+   /* we're ready if we get two clients + handler */
+   return !vgasr_priv.active 
+  vgasr_priv.registered_clients == 2  vgasr_priv.handler;
 }
-EXPORT_SYMBOL(vga_switcheroo_unregister_handler);
 
 static void vga_switcheroo_enable(void)
 {
@@ -114,6 +99,37 @@ static void vga_switcheroo_enable(void)
vgasr_priv.active = true;
 }
 
+int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler)
+{
+   mutex_lock(vgasr_mutex);
+   if (vgasr_priv.handler) {
+   mutex_unlock(vgasr_mutex);
+   return -EINVAL;
+   }
+
+   vgasr_priv.handler = handler;
+   if (vga_switcheroo_ready()) {
+   printk(KERN_INFO vga_switcheroo: enabled\n);
+   vga_switcheroo_enable();
+   }
+   mutex_unlock(vgasr_mutex);
+   return 0;
+}
+EXPORT_SYMBOL(vga_switcheroo_register_handler);
+
+void vga_switcheroo_unregister_handler(void)
+{
+   mutex_lock(vgasr_mutex);
+   vgasr_priv.handler = NULL;
+   if (vgasr_priv.active) {
+   pr_info(vga_switcheroo: disabled\n);
+   vga_switcheroo_debugfs_fini(vgasr_priv);
+   vgasr_priv.active = false;
+   }
+   mutex_unlock(vgasr_mutex);
+}
+EXPORT_SYMBOL(vga_switcheroo_unregister_handler);
+
 static int register_client(struct pci_dev *pdev,
   const struct vga_switcheroo_client_ops *ops,
   int id, bool active)
@@ -135,9 +151,7 @@ static int register_client(struct pci_dev *pdev,
if (client_is_vga(client))
vgasr_priv.registered_clients++;
 
-   /* if we get two clients + handler */
-   if (!vgasr_priv.active 
-   vgasr_priv.registered_clients == 2  vgasr_priv.handler) {
+   if (vga_switcheroo_ready()) {
printk(KERN_INFO vga_switcheroo: enabled\n);
vga_switcheroo_enable();
}
-- 
1.7.9.5

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 3/3] apple-gmux: Add display mux support

2012-08-18 Thread Seth Forshee
From: Andreas Heider andr...@meetr.de

Add support for the gmux display muxing functionality and register a mux
handler with vga_switcheroo.

Signed-off-by: Andreas Heider andr...@meetr.de
Signed-off-by: Seth Forshee seth.fors...@canonical.com
---
 drivers/platform/x86/apple-gmux.c |  224 +
 1 file changed, 224 insertions(+)

diff --git a/drivers/platform/x86/apple-gmux.c 
b/drivers/platform/x86/apple-gmux.c
index 612b6f6..c72e81e 100644
--- a/drivers/platform/x86/apple-gmux.c
+++ b/drivers/platform/x86/apple-gmux.c
@@ -2,6 +2,7 @@
  *  Gmux driver for Apple laptops
  *
  *  Copyright (C) Canonical Ltd. seth.fors...@canonical.com
+ *  Copyright (C) 2010-2012 Andreas Heider andr...@meetr.de
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2 as
@@ -19,6 +20,8 @@
 #include linux/apple_bl.h
 #include linux/slab.h
 #include linux/delay.h
+#include linux/pci.h
+#include linux/vga_switcheroo.h
 #include acpi/video.h
 #include asm/io.h
 
@@ -29,8 +32,17 @@ struct apple_gmux_data {
struct mutex index_lock;
 
struct backlight_device *bdev;
+
+   /* switcheroo data */
+   acpi_handle dhandle;
+   int gpe;
+   enum vga_switcheroo_client_id resume_client_id;
+   enum vga_switcheroo_state power_state;
+   struct completion powerchange_done;
 };
 
+static struct apple_gmux_data *apple_gmux_data;
+
 /*
  * gmux port offsets. Many of these are not yet used, but may be in the
  * future, and it's useful to have them documented here anyhow.
@@ -257,6 +269,146 @@ static const struct backlight_ops gmux_bl_ops = {
.update_status = gmux_update_status,
 };
 
+static int gmux_switchto(enum vga_switcheroo_client_id id)
+{
+   if (id == VGA_SWITCHEROO_IGD) {
+   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 1);
+   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DISPLAY, 2);
+   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 2);
+   } else {
+   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 2);
+   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DISPLAY, 3);
+   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 3);
+   }
+
+   return 0;
+}
+
+static int gmux_set_discrete_state(struct apple_gmux_data *gmux_data,
+  enum vga_switcheroo_state state)
+{
+   INIT_COMPLETION(gmux_data-powerchange_done);
+
+   if (state == VGA_SWITCHEROO_ON) {
+   gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 1);
+   gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 3);
+   pr_debug(Discrete card powered up\n);
+   } else {
+   gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 1);
+   gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 0);
+   pr_debug(Discrete card powered down\n);
+   }
+
+   gmux_data-power_state = state;
+
+   if (gmux_data-gpe = 0 
+   
!wait_for_completion_interruptible_timeout(gmux_data-powerchange_done,
+  msecs_to_jiffies(200)))
+   pr_warn(Timeout waiting for gmux switch to complete\n);
+
+   return 0;
+}
+
+static int gmux_set_power_state(enum vga_switcheroo_client_id id,
+   enum vga_switcheroo_state state)
+{
+   if (id == VGA_SWITCHEROO_IGD)
+   return 0;
+
+   return gmux_set_discrete_state(apple_gmux_data, state);
+}
+
+static int gmux_get_client_id(struct pci_dev *pdev)
+{
+   /*
+* Early Macbook Pros with switchable graphics use nvidia
+* integrated graphics. Hardcode that the 9400M is integrated.
+*/
+   if (pdev-vendor == PCI_VENDOR_ID_INTEL)
+   return VGA_SWITCHEROO_IGD;
+   else if (pdev-vendor == PCI_VENDOR_ID_NVIDIA 
+pdev-device == 0x0863)
+   return VGA_SWITCHEROO_IGD;
+   else
+   return VGA_SWITCHEROO_DIS;
+}
+
+static enum vga_switcheroo_client_id
+gmux_active_client(struct apple_gmux_data *gmux_data)
+{
+   if (gmux_read8(gmux_data, GMUX_PORT_SWITCH_DISPLAY) == 2)
+   return VGA_SWITCHEROO_IGD;
+
+   return VGA_SWITCHEROO_DIS;
+}
+
+static struct vga_switcheroo_handler gmux_handler = {
+   .switchto = gmux_switchto,
+   .power_state = gmux_set_power_state,
+   .get_client_id = gmux_get_client_id,
+};
+
+static inline void gmux_disable_interrupts(struct apple_gmux_data *gmux_data)
+{
+   gmux_write8(gmux_data, GMUX_PORT_INTERRUPT_ENABLE,
+   GMUX_INTERRUPT_DISABLE);
+}
+
+static inline void gmux_enable_interrupts(struct apple_gmux_data *gmux_data)
+{
+   gmux_write8(gmux_data, GMUX_PORT_INTERRUPT_ENABLE,
+   GMUX_INTERRUPT_ENABLE);
+}
+
+static inline u8 gmux_interrupt_get_status(struct apple_gmux_data *gmux_data

[PATCH v2 3/3] apple-gmux: Add display mux support

2012-08-17 Thread Seth Forshee
From: Andreas Heider <andr...@meetr.de>

Add support for the gmux display muxing functionality and register a mux
handler with vga_switcheroo.

Signed-off-by: Andreas Heider 
Signed-off-by: Seth Forshee 
---
 drivers/platform/x86/apple-gmux.c |  224 +
 1 file changed, 224 insertions(+)

diff --git a/drivers/platform/x86/apple-gmux.c 
b/drivers/platform/x86/apple-gmux.c
index 612b6f6..c72e81e 100644
--- a/drivers/platform/x86/apple-gmux.c
+++ b/drivers/platform/x86/apple-gmux.c
@@ -2,6 +2,7 @@
  *  Gmux driver for Apple laptops
  *
  *  Copyright (C) Canonical Ltd. 
+ *  Copyright (C) 2010-2012 Andreas Heider 
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2 as
@@ -19,6 +20,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 #include 
 #include 

@@ -29,8 +32,17 @@ struct apple_gmux_data {
struct mutex index_lock;

struct backlight_device *bdev;
+
+   /* switcheroo data */
+   acpi_handle dhandle;
+   int gpe;
+   enum vga_switcheroo_client_id resume_client_id;
+   enum vga_switcheroo_state power_state;
+   struct completion powerchange_done;
 };

+static struct apple_gmux_data *apple_gmux_data;
+
 /*
  * gmux port offsets. Many of these are not yet used, but may be in the
  * future, and it's useful to have them documented here anyhow.
@@ -257,6 +269,146 @@ static const struct backlight_ops gmux_bl_ops = {
.update_status = gmux_update_status,
 };

+static int gmux_switchto(enum vga_switcheroo_client_id id)
+{
+   if (id == VGA_SWITCHEROO_IGD) {
+   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 1);
+   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DISPLAY, 2);
+   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 2);
+   } else {
+   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 2);
+   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DISPLAY, 3);
+   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 3);
+   }
+
+   return 0;
+}
+
+static int gmux_set_discrete_state(struct apple_gmux_data *gmux_data,
+  enum vga_switcheroo_state state)
+{
+   INIT_COMPLETION(gmux_data->powerchange_done);
+
+   if (state == VGA_SWITCHEROO_ON) {
+   gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 1);
+   gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 3);
+   pr_debug("Discrete card powered up\n");
+   } else {
+   gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 1);
+   gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 0);
+   pr_debug("Discrete card powered down\n");
+   }
+
+   gmux_data->power_state = state;
+
+   if (gmux_data->gpe >= 0 &&
+   
!wait_for_completion_interruptible_timeout(_data->powerchange_done,
+  msecs_to_jiffies(200)))
+   pr_warn("Timeout waiting for gmux switch to complete\n");
+
+   return 0;
+}
+
+static int gmux_set_power_state(enum vga_switcheroo_client_id id,
+   enum vga_switcheroo_state state)
+{
+   if (id == VGA_SWITCHEROO_IGD)
+   return 0;
+
+   return gmux_set_discrete_state(apple_gmux_data, state);
+}
+
+static int gmux_get_client_id(struct pci_dev *pdev)
+{
+   /*
+* Early Macbook Pros with switchable graphics use nvidia
+* integrated graphics. Hardcode that the 9400M is integrated.
+*/
+   if (pdev->vendor == PCI_VENDOR_ID_INTEL)
+   return VGA_SWITCHEROO_IGD;
+   else if (pdev->vendor == PCI_VENDOR_ID_NVIDIA &&
+pdev->device == 0x0863)
+   return VGA_SWITCHEROO_IGD;
+   else
+   return VGA_SWITCHEROO_DIS;
+}
+
+static enum vga_switcheroo_client_id
+gmux_active_client(struct apple_gmux_data *gmux_data)
+{
+   if (gmux_read8(gmux_data, GMUX_PORT_SWITCH_DISPLAY) == 2)
+   return VGA_SWITCHEROO_IGD;
+
+   return VGA_SWITCHEROO_DIS;
+}
+
+static struct vga_switcheroo_handler gmux_handler = {
+   .switchto = gmux_switchto,
+   .power_state = gmux_set_power_state,
+   .get_client_id = gmux_get_client_id,
+};
+
+static inline void gmux_disable_interrupts(struct apple_gmux_data *gmux_data)
+{
+   gmux_write8(gmux_data, GMUX_PORT_INTERRUPT_ENABLE,
+   GMUX_INTERRUPT_DISABLE);
+}
+
+static inline void gmux_enable_interrupts(struct apple_gmux_data *gmux_data)
+{
+   gmux_write8(gmux_data, GMUX_PORT_INTERRUPT_ENABLE,
+   GMUX_INTERRUPT_ENABLE);
+}
+
+static inline u8 gmux_interrupt_get_status(struct apple_gmux_data *gmux_data)
+{
+   return gmux_read8(gmux_data, GMUX_PORT_INTERRUPT_STATUS);
+}
+
+static void g

[PATCH v2 2/3] vga_switcheroo: Remove assumptions about registration/unregistration ordering

2012-08-17 Thread Seth Forshee
vga_switcheroo assumes that the handler will be registered before the
last client, otherwise switching will not be enabled. Likewise it's
assumed that the handler will not be unregistered without at least one
client also being unregistered, otherwise switching will remain enabled
despite no longer having a handler. These assumptions cannot be enforced
if the handler is in a separate driver from both clients, as with the
gmux found in Apple laptops. Remove this assumption.

Signed-off-by: Seth Forshee 
---
 drivers/gpu/vga/vga_switcheroo.c |   58 +++---
 1 file changed, 36 insertions(+), 22 deletions(-)

diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index ec9069d..e25cf31 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -70,27 +70,12 @@ static struct vgasr_priv vgasr_priv = {
.clients = LIST_HEAD_INIT(vgasr_priv.clients),
 };

-int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler)
-{
-   mutex_lock(_mutex);
-   if (vgasr_priv.handler) {
-   mutex_unlock(_mutex);
-   return -EINVAL;
-   }
-
-   vgasr_priv.handler = handler;
-   mutex_unlock(_mutex);
-   return 0;
-}
-EXPORT_SYMBOL(vga_switcheroo_register_handler);
-
-void vga_switcheroo_unregister_handler(void)
+static bool vga_switcheroo_ready(void)
 {
-   mutex_lock(_mutex);
-   vgasr_priv.handler = NULL;
-   mutex_unlock(_mutex);
+   /* we're ready if we get two clients + handler */
+   return !vgasr_priv.active &&
+  vgasr_priv.registered_clients == 2 && vgasr_priv.handler;
 }
-EXPORT_SYMBOL(vga_switcheroo_unregister_handler);

 static void vga_switcheroo_enable(void)
 {
@@ -114,6 +99,37 @@ static void vga_switcheroo_enable(void)
vgasr_priv.active = true;
 }

+int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler)
+{
+   mutex_lock(_mutex);
+   if (vgasr_priv.handler) {
+   mutex_unlock(_mutex);
+   return -EINVAL;
+   }
+
+   vgasr_priv.handler = handler;
+   if (vga_switcheroo_ready()) {
+   printk(KERN_INFO "vga_switcheroo: enabled\n");
+   vga_switcheroo_enable();
+   }
+   mutex_unlock(_mutex);
+   return 0;
+}
+EXPORT_SYMBOL(vga_switcheroo_register_handler);
+
+void vga_switcheroo_unregister_handler(void)
+{
+   mutex_lock(_mutex);
+   vgasr_priv.handler = NULL;
+   if (vgasr_priv.active) {
+   pr_info("vga_switcheroo: disabled\n");
+   vga_switcheroo_debugfs_fini(_priv);
+   vgasr_priv.active = false;
+   }
+   mutex_unlock(_mutex);
+}
+EXPORT_SYMBOL(vga_switcheroo_unregister_handler);
+
 static int register_client(struct pci_dev *pdev,
   const struct vga_switcheroo_client_ops *ops,
   int id, bool active)
@@ -135,9 +151,7 @@ static int register_client(struct pci_dev *pdev,
if (client_is_vga(client))
vgasr_priv.registered_clients++;

-   /* if we get two clients + handler */
-   if (!vgasr_priv.active &&
-   vgasr_priv.registered_clients == 2 && vgasr_priv.handler) {
+   if (vga_switcheroo_ready()) {
printk(KERN_INFO "vga_switcheroo: enabled\n");
vga_switcheroo_enable();
}
-- 
1.7.9.5



[PATCH v2 1/3] vga_switcheroo: Don't require handler init callback

2012-08-17 Thread Seth Forshee
This callback is a no-op in nouveau, and the upcoming apple-gmux
switcheroo support won't require it either. Rather than forcing drivers
to stub it out, just make it optional and remove the callback from
nouveau.

Signed-off-by: Seth Forshee 
---
 drivers/gpu/drm/nouveau/nouveau_acpi.c |6 --
 drivers/gpu/vga/vga_switcheroo.c   |3 ++-
 2 files changed, 2 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c 
b/drivers/gpu/drm/nouveau/nouveau_acpi.c
index fc841e8..26ebffe 100644
--- a/drivers/gpu/drm/nouveau/nouveau_acpi.c
+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c
@@ -211,11 +211,6 @@ static int nouveau_dsm_power_state(enum 
vga_switcheroo_client_id id,
return nouveau_dsm_set_discrete_state(nouveau_dsm_priv.dhandle, state);
 }

-static int nouveau_dsm_init(void)
-{
-   return 0;
-}
-
 static int nouveau_dsm_get_client_id(struct pci_dev *pdev)
 {
/* easy option one - intel vendor ID means Integrated */
@@ -232,7 +227,6 @@ static int nouveau_dsm_get_client_id(struct pci_dev *pdev)
 static struct vga_switcheroo_handler nouveau_dsm_handler = {
.switchto = nouveau_dsm_switchto,
.power_state = nouveau_dsm_power_state,
-   .init = nouveau_dsm_init,
.get_client_id = nouveau_dsm_get_client_id,
 };

diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index 5b3c7d1..ec9069d 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -98,7 +98,8 @@ static void vga_switcheroo_enable(void)
struct vga_switcheroo_client *client;

/* call the handler to init */
-   vgasr_priv.handler->init();
+   if (vgasr_priv.handler->init)
+   vgasr_priv.handler->init();

list_for_each_entry(client, _priv.clients, list) {
if (client->id != -1)
-- 
1.7.9.5



[PATCH v2 0/3] Display switching support for Apple laptops

2012-08-17 Thread Seth Forshee
This series adds display switching support for Apple laptops. The first
two patches contain preparatory changes to vga_switcheroo, and the third
contains the changes to support display switching with the gmux.

While these patches will allow switching the display mux, most Macbook
owners will not be able to switch GPUs in practice until the graphics
drivers are updated to deal with missing or incorrect vbios information
on Apple machines. These patches do fix an issue seen by some users of
Linux on Macbooks, however. These users will switch to the internal GPU
in OS X and then reboot into Linux to save power, but after S3 the gmux
gets reset to the discrete GPU. Adding the display mux support will fix
this problem by restoring the gmux state during resume.

v2: Disable interrupts during suspend and re-enable them during resume
to fix timeouts waiting for switching to complete after S3

Thanks,
Seth


Andreas Heider (1):
  apple-gmux: Add display mux support

Seth Forshee (2):
  vga_switcheroo: Don't require handler init callback
  vga_switcheroo: Remove assumptions about registration/unregistration
ordering

 drivers/gpu/drm/nouveau/nouveau_acpi.c |6 -
 drivers/gpu/vga/vga_switcheroo.c   |   61 +
 drivers/platform/x86/apple-gmux.c  |  224 
 3 files changed, 262 insertions(+), 29 deletions(-)



[PATCH 0/3] Display switching support for Apple laptops

2012-08-15 Thread Seth Forshee
This series adds display switching support for Apple laptops. The first
two patches contain preparatory changes to vga_switcheroo, and the third
contains the changes to support display switching with the gmux.

While these patches will allow switching the display mux, most Macbook
owners will not be able to switch GPUs in practice until the graphics
drivers are updated to deal with missing or incorrect vbios information
on Apple machines. These patches do fix an issue seen by some users of
Linux on Macbooks, however. These users will switch to the internal GPU
in OS X and then reboot into Linux to save power, but after S3 the gmux
gets reset to the discrete GPU. Adding the display mux support will fix
this problem by restoring the gmux state during resume.

Thanks,
Seth


Andreas Heider (1):
  apple-gmux: Add display mux support

Seth Forshee (2):
  vga_switcheroo: Don't require handler init callback
  vga_switcheroo: Remove assumptions about registration/unregistration
ordering

 drivers/gpu/drm/nouveau/nouveau_acpi.c |6 -
 drivers/gpu/vga/vga_switcheroo.c   |   61 +
 drivers/platform/x86/apple-gmux.c  |  222 
 3 files changed, 260 insertions(+), 29 deletions(-)

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 1/3] vga_switcheroo: Don't require handler init callback

2012-08-15 Thread Seth Forshee
This callback is a no-op in nouveau, and the upcoming apple-gmux
switcheroo support won't require it either. Rather than forcing drivers
to stub it out, just make it optional and remove the callback from
nouveau.

Signed-off-by: Seth Forshee seth.fors...@canonical.com
---
 drivers/gpu/drm/nouveau/nouveau_acpi.c |6 --
 drivers/gpu/vga/vga_switcheroo.c   |3 ++-
 2 files changed, 2 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c 
b/drivers/gpu/drm/nouveau/nouveau_acpi.c
index fc841e8..26ebffe 100644
--- a/drivers/gpu/drm/nouveau/nouveau_acpi.c
+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c
@@ -211,11 +211,6 @@ static int nouveau_dsm_power_state(enum 
vga_switcheroo_client_id id,
return nouveau_dsm_set_discrete_state(nouveau_dsm_priv.dhandle, state);
 }
 
-static int nouveau_dsm_init(void)
-{
-   return 0;
-}
-
 static int nouveau_dsm_get_client_id(struct pci_dev *pdev)
 {
/* easy option one - intel vendor ID means Integrated */
@@ -232,7 +227,6 @@ static int nouveau_dsm_get_client_id(struct pci_dev *pdev)
 static struct vga_switcheroo_handler nouveau_dsm_handler = {
.switchto = nouveau_dsm_switchto,
.power_state = nouveau_dsm_power_state,
-   .init = nouveau_dsm_init,
.get_client_id = nouveau_dsm_get_client_id,
 };
 
diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index 5b3c7d1..ec9069d 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -98,7 +98,8 @@ static void vga_switcheroo_enable(void)
struct vga_switcheroo_client *client;
 
/* call the handler to init */
-   vgasr_priv.handler-init();
+   if (vgasr_priv.handler-init)
+   vgasr_priv.handler-init();
 
list_for_each_entry(client, vgasr_priv.clients, list) {
if (client-id != -1)
-- 
1.7.9.5

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 2/3] vga_switcheroo: Remove assumptions about registration/unregistration ordering

2012-08-15 Thread Seth Forshee
vga_switcheroo assumes that the handler will be registered before the
last client, otherwise switching will not be enabled. Likewise it's
assumed that the handler will not be unregistered without at least one
client also being unregistered, otherwise switching will remain enabled
despite no longer having a handler. These assumptions cannot be enforced
if the handler is in a separate driver from both clients, as with the
gmux found in Apple laptops. Remove this assumption.

Signed-off-by: Seth Forshee seth.fors...@canonical.com
---
 drivers/gpu/vga/vga_switcheroo.c |   58 +++---
 1 file changed, 36 insertions(+), 22 deletions(-)

diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index ec9069d..e25cf31 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -70,27 +70,12 @@ static struct vgasr_priv vgasr_priv = {
.clients = LIST_HEAD_INIT(vgasr_priv.clients),
 };
 
-int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler)
-{
-   mutex_lock(vgasr_mutex);
-   if (vgasr_priv.handler) {
-   mutex_unlock(vgasr_mutex);
-   return -EINVAL;
-   }
-
-   vgasr_priv.handler = handler;
-   mutex_unlock(vgasr_mutex);
-   return 0;
-}
-EXPORT_SYMBOL(vga_switcheroo_register_handler);
-
-void vga_switcheroo_unregister_handler(void)
+static bool vga_switcheroo_ready(void)
 {
-   mutex_lock(vgasr_mutex);
-   vgasr_priv.handler = NULL;
-   mutex_unlock(vgasr_mutex);
+   /* we're ready if we get two clients + handler */
+   return !vgasr_priv.active 
+  vgasr_priv.registered_clients == 2  vgasr_priv.handler;
 }
-EXPORT_SYMBOL(vga_switcheroo_unregister_handler);
 
 static void vga_switcheroo_enable(void)
 {
@@ -114,6 +99,37 @@ static void vga_switcheroo_enable(void)
vgasr_priv.active = true;
 }
 
+int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler)
+{
+   mutex_lock(vgasr_mutex);
+   if (vgasr_priv.handler) {
+   mutex_unlock(vgasr_mutex);
+   return -EINVAL;
+   }
+
+   vgasr_priv.handler = handler;
+   if (vga_switcheroo_ready()) {
+   printk(KERN_INFO vga_switcheroo: enabled\n);
+   vga_switcheroo_enable();
+   }
+   mutex_unlock(vgasr_mutex);
+   return 0;
+}
+EXPORT_SYMBOL(vga_switcheroo_register_handler);
+
+void vga_switcheroo_unregister_handler(void)
+{
+   mutex_lock(vgasr_mutex);
+   vgasr_priv.handler = NULL;
+   if (vgasr_priv.active) {
+   pr_info(vga_switcheroo: disabled\n);
+   vga_switcheroo_debugfs_fini(vgasr_priv);
+   vgasr_priv.active = false;
+   }
+   mutex_unlock(vgasr_mutex);
+}
+EXPORT_SYMBOL(vga_switcheroo_unregister_handler);
+
 static int register_client(struct pci_dev *pdev,
   const struct vga_switcheroo_client_ops *ops,
   int id, bool active)
@@ -135,9 +151,7 @@ static int register_client(struct pci_dev *pdev,
if (client_is_vga(client))
vgasr_priv.registered_clients++;
 
-   /* if we get two clients + handler */
-   if (!vgasr_priv.active 
-   vgasr_priv.registered_clients == 2  vgasr_priv.handler) {
+   if (vga_switcheroo_ready()) {
printk(KERN_INFO vga_switcheroo: enabled\n);
vga_switcheroo_enable();
}
-- 
1.7.9.5

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 3/3] apple-gmux: Add display mux support

2012-08-15 Thread Seth Forshee
From: Andreas Heider andr...@meetr.de

Add support for the gmux display muxing functionality and register a mux
handler with vga_switcheroo.

Signed-off-by: Andreas Heider andr...@meetr.de
Signed-off-by: Seth Forshee seth.fors...@canonical.com
---
 drivers/platform/x86/apple-gmux.c |  222 +
 1 file changed, 222 insertions(+)

diff --git a/drivers/platform/x86/apple-gmux.c 
b/drivers/platform/x86/apple-gmux.c
index 612b6f6..6dc9e80 100644
--- a/drivers/platform/x86/apple-gmux.c
+++ b/drivers/platform/x86/apple-gmux.c
@@ -2,6 +2,7 @@
  *  Gmux driver for Apple laptops
  *
  *  Copyright (C) Canonical Ltd. seth.fors...@canonical.com
+ *  Copyright (C) 2010-2012 Andreas Heider andr...@meetr.de
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2 as
@@ -19,6 +20,8 @@
 #include linux/apple_bl.h
 #include linux/slab.h
 #include linux/delay.h
+#include linux/pci.h
+#include linux/vga_switcheroo.h
 #include acpi/video.h
 #include asm/io.h
 
@@ -29,8 +32,17 @@ struct apple_gmux_data {
struct mutex index_lock;
 
struct backlight_device *bdev;
+
+   /* switcheroo data */
+   acpi_handle dhandle;
+   int gpe;
+   enum vga_switcheroo_client_id resume_client_id;
+   enum vga_switcheroo_state power_state;
+   struct completion powerchange_done;
 };
 
+static struct apple_gmux_data *apple_gmux_data;
+
 /*
  * gmux port offsets. Many of these are not yet used, but may be in the
  * future, and it's useful to have them documented here anyhow.
@@ -257,6 +269,144 @@ static const struct backlight_ops gmux_bl_ops = {
.update_status = gmux_update_status,
 };
 
+static int gmux_switchto(enum vga_switcheroo_client_id id)
+{
+   if (id == VGA_SWITCHEROO_IGD) {
+   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 1);
+   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DISPLAY, 2);
+   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 2);
+   } else {
+   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 2);
+   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DISPLAY, 3);
+   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 3);
+   }
+
+   return 0;
+}
+
+static int gmux_set_discrete_state(struct apple_gmux_data *gmux_data,
+  enum vga_switcheroo_state state)
+{
+   INIT_COMPLETION(gmux_data-powerchange_done);
+
+   if (state == VGA_SWITCHEROO_ON) {
+   gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 1);
+   gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 3);
+   pr_debug(Discrete card powered up\n);
+   } else {
+   gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 1);
+   gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 0);
+   pr_debug(Discrete card powered down\n);
+   }
+
+   gmux_data-power_state = state;
+
+   if (gmux_data-gpe = 0 
+   
!wait_for_completion_interruptible_timeout(gmux_data-powerchange_done,
+  msecs_to_jiffies(200)))
+   pr_warn(Timeout waiting for gmux switch to complete\n);
+
+   return 0;
+}
+
+static int gmux_set_power_state(enum vga_switcheroo_client_id id,
+   enum vga_switcheroo_state state)
+{
+   if (id == VGA_SWITCHEROO_IGD)
+   return 0;
+
+   return gmux_set_discrete_state(apple_gmux_data, state);
+}
+
+static int gmux_get_client_id(struct pci_dev *pdev)
+{
+   /*
+* Early Macbook Pros with switchable graphics use nvidia
+* integrated graphics. Hardcode that the 9400M is integrated.
+*/
+   if (pdev-vendor == PCI_VENDOR_ID_INTEL)
+   return VGA_SWITCHEROO_IGD;
+   else if (pdev-vendor == PCI_VENDOR_ID_NVIDIA 
+pdev-device == 0x0863)
+   return VGA_SWITCHEROO_IGD;
+   else
+   return VGA_SWITCHEROO_DIS;
+}
+
+static enum vga_switcheroo_client_id
+gmux_active_client(struct apple_gmux_data *gmux_data)
+{
+   if (gmux_read8(gmux_data, GMUX_PORT_SWITCH_DISPLAY) == 2)
+   return VGA_SWITCHEROO_IGD;
+
+   return VGA_SWITCHEROO_DIS;
+}
+
+static struct vga_switcheroo_handler gmux_handler = {
+   .switchto = gmux_switchto,
+   .power_state = gmux_set_power_state,
+   .get_client_id = gmux_get_client_id,
+};
+
+static inline void gmux_disable_interrupts(struct apple_gmux_data *gmux_data)
+{
+   gmux_write8(gmux_data, GMUX_PORT_INTERRUPT_ENABLE,
+   GMUX_INTERRUPT_DISABLE);
+}
+
+static inline void gmux_enable_interrupts(struct apple_gmux_data *gmux_data)
+{
+   gmux_write8(gmux_data, GMUX_PORT_INTERRUPT_ENABLE,
+   GMUX_INTERRUPT_ENABLE);
+}
+
+static inline u8 gmux_interrupt_get_status(struct apple_gmux_data *gmux_data

[PATCH 3/3] apple-gmux: Add display mux support

2012-08-14 Thread Seth Forshee
From: Andreas Heider <andr...@meetr.de>

Add support for the gmux display muxing functionality and register a mux
handler with vga_switcheroo.

Signed-off-by: Andreas Heider 
Signed-off-by: Seth Forshee 
---
 drivers/platform/x86/apple-gmux.c |  222 +
 1 file changed, 222 insertions(+)

diff --git a/drivers/platform/x86/apple-gmux.c 
b/drivers/platform/x86/apple-gmux.c
index 612b6f6..6dc9e80 100644
--- a/drivers/platform/x86/apple-gmux.c
+++ b/drivers/platform/x86/apple-gmux.c
@@ -2,6 +2,7 @@
  *  Gmux driver for Apple laptops
  *
  *  Copyright (C) Canonical Ltd. 
+ *  Copyright (C) 2010-2012 Andreas Heider 
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2 as
@@ -19,6 +20,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 #include 
 #include 

@@ -29,8 +32,17 @@ struct apple_gmux_data {
struct mutex index_lock;

struct backlight_device *bdev;
+
+   /* switcheroo data */
+   acpi_handle dhandle;
+   int gpe;
+   enum vga_switcheroo_client_id resume_client_id;
+   enum vga_switcheroo_state power_state;
+   struct completion powerchange_done;
 };

+static struct apple_gmux_data *apple_gmux_data;
+
 /*
  * gmux port offsets. Many of these are not yet used, but may be in the
  * future, and it's useful to have them documented here anyhow.
@@ -257,6 +269,144 @@ static const struct backlight_ops gmux_bl_ops = {
.update_status = gmux_update_status,
 };

+static int gmux_switchto(enum vga_switcheroo_client_id id)
+{
+   if (id == VGA_SWITCHEROO_IGD) {
+   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 1);
+   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DISPLAY, 2);
+   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 2);
+   } else {
+   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 2);
+   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DISPLAY, 3);
+   gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 3);
+   }
+
+   return 0;
+}
+
+static int gmux_set_discrete_state(struct apple_gmux_data *gmux_data,
+  enum vga_switcheroo_state state)
+{
+   INIT_COMPLETION(gmux_data->powerchange_done);
+
+   if (state == VGA_SWITCHEROO_ON) {
+   gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 1);
+   gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 3);
+   pr_debug("Discrete card powered up\n");
+   } else {
+   gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 1);
+   gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 0);
+   pr_debug("Discrete card powered down\n");
+   }
+
+   gmux_data->power_state = state;
+
+   if (gmux_data->gpe >= 0 &&
+   
!wait_for_completion_interruptible_timeout(_data->powerchange_done,
+  msecs_to_jiffies(200)))
+   pr_warn("Timeout waiting for gmux switch to complete\n");
+
+   return 0;
+}
+
+static int gmux_set_power_state(enum vga_switcheroo_client_id id,
+   enum vga_switcheroo_state state)
+{
+   if (id == VGA_SWITCHEROO_IGD)
+   return 0;
+
+   return gmux_set_discrete_state(apple_gmux_data, state);
+}
+
+static int gmux_get_client_id(struct pci_dev *pdev)
+{
+   /*
+* Early Macbook Pros with switchable graphics use nvidia
+* integrated graphics. Hardcode that the 9400M is integrated.
+*/
+   if (pdev->vendor == PCI_VENDOR_ID_INTEL)
+   return VGA_SWITCHEROO_IGD;
+   else if (pdev->vendor == PCI_VENDOR_ID_NVIDIA &&
+pdev->device == 0x0863)
+   return VGA_SWITCHEROO_IGD;
+   else
+   return VGA_SWITCHEROO_DIS;
+}
+
+static enum vga_switcheroo_client_id
+gmux_active_client(struct apple_gmux_data *gmux_data)
+{
+   if (gmux_read8(gmux_data, GMUX_PORT_SWITCH_DISPLAY) == 2)
+   return VGA_SWITCHEROO_IGD;
+
+   return VGA_SWITCHEROO_DIS;
+}
+
+static struct vga_switcheroo_handler gmux_handler = {
+   .switchto = gmux_switchto,
+   .power_state = gmux_set_power_state,
+   .get_client_id = gmux_get_client_id,
+};
+
+static inline void gmux_disable_interrupts(struct apple_gmux_data *gmux_data)
+{
+   gmux_write8(gmux_data, GMUX_PORT_INTERRUPT_ENABLE,
+   GMUX_INTERRUPT_DISABLE);
+}
+
+static inline void gmux_enable_interrupts(struct apple_gmux_data *gmux_data)
+{
+   gmux_write8(gmux_data, GMUX_PORT_INTERRUPT_ENABLE,
+   GMUX_INTERRUPT_ENABLE);
+}
+
+static inline u8 gmux_interrupt_get_status(struct apple_gmux_data *gmux_data)
+{
+   return gmux_read8(gmux_data, GMUX_PORT_INTERRUPT_STATUS);
+}
+
+static void g

[PATCH 2/3] vga_switcheroo: Remove assumptions about registration/unregistration ordering

2012-08-14 Thread Seth Forshee
vga_switcheroo assumes that the handler will be registered before the
last client, otherwise switching will not be enabled. Likewise it's
assumed that the handler will not be unregistered without at least one
client also being unregistered, otherwise switching will remain enabled
despite no longer having a handler. These assumptions cannot be enforced
if the handler is in a separate driver from both clients, as with the
gmux found in Apple laptops. Remove this assumption.

Signed-off-by: Seth Forshee 
---
 drivers/gpu/vga/vga_switcheroo.c |   58 +++---
 1 file changed, 36 insertions(+), 22 deletions(-)

diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index ec9069d..e25cf31 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -70,27 +70,12 @@ static struct vgasr_priv vgasr_priv = {
.clients = LIST_HEAD_INIT(vgasr_priv.clients),
 };

-int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler)
-{
-   mutex_lock(_mutex);
-   if (vgasr_priv.handler) {
-   mutex_unlock(_mutex);
-   return -EINVAL;
-   }
-
-   vgasr_priv.handler = handler;
-   mutex_unlock(_mutex);
-   return 0;
-}
-EXPORT_SYMBOL(vga_switcheroo_register_handler);
-
-void vga_switcheroo_unregister_handler(void)
+static bool vga_switcheroo_ready(void)
 {
-   mutex_lock(_mutex);
-   vgasr_priv.handler = NULL;
-   mutex_unlock(_mutex);
+   /* we're ready if we get two clients + handler */
+   return !vgasr_priv.active &&
+  vgasr_priv.registered_clients == 2 && vgasr_priv.handler;
 }
-EXPORT_SYMBOL(vga_switcheroo_unregister_handler);

 static void vga_switcheroo_enable(void)
 {
@@ -114,6 +99,37 @@ static void vga_switcheroo_enable(void)
vgasr_priv.active = true;
 }

+int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler)
+{
+   mutex_lock(_mutex);
+   if (vgasr_priv.handler) {
+   mutex_unlock(_mutex);
+   return -EINVAL;
+   }
+
+   vgasr_priv.handler = handler;
+   if (vga_switcheroo_ready()) {
+   printk(KERN_INFO "vga_switcheroo: enabled\n");
+   vga_switcheroo_enable();
+   }
+   mutex_unlock(_mutex);
+   return 0;
+}
+EXPORT_SYMBOL(vga_switcheroo_register_handler);
+
+void vga_switcheroo_unregister_handler(void)
+{
+   mutex_lock(_mutex);
+   vgasr_priv.handler = NULL;
+   if (vgasr_priv.active) {
+   pr_info("vga_switcheroo: disabled\n");
+   vga_switcheroo_debugfs_fini(_priv);
+   vgasr_priv.active = false;
+   }
+   mutex_unlock(_mutex);
+}
+EXPORT_SYMBOL(vga_switcheroo_unregister_handler);
+
 static int register_client(struct pci_dev *pdev,
   const struct vga_switcheroo_client_ops *ops,
   int id, bool active)
@@ -135,9 +151,7 @@ static int register_client(struct pci_dev *pdev,
if (client_is_vga(client))
vgasr_priv.registered_clients++;

-   /* if we get two clients + handler */
-   if (!vgasr_priv.active &&
-   vgasr_priv.registered_clients == 2 && vgasr_priv.handler) {
+   if (vga_switcheroo_ready()) {
printk(KERN_INFO "vga_switcheroo: enabled\n");
vga_switcheroo_enable();
}
-- 
1.7.9.5



[PATCH 1/3] vga_switcheroo: Don't require handler init callback

2012-08-14 Thread Seth Forshee
This callback is a no-op in nouveau, and the upcoming apple-gmux
switcheroo support won't require it either. Rather than forcing drivers
to stub it out, just make it optional and remove the callback from
nouveau.

Signed-off-by: Seth Forshee 
---
 drivers/gpu/drm/nouveau/nouveau_acpi.c |6 --
 drivers/gpu/vga/vga_switcheroo.c   |3 ++-
 2 files changed, 2 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c 
b/drivers/gpu/drm/nouveau/nouveau_acpi.c
index fc841e8..26ebffe 100644
--- a/drivers/gpu/drm/nouveau/nouveau_acpi.c
+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c
@@ -211,11 +211,6 @@ static int nouveau_dsm_power_state(enum 
vga_switcheroo_client_id id,
return nouveau_dsm_set_discrete_state(nouveau_dsm_priv.dhandle, state);
 }

-static int nouveau_dsm_init(void)
-{
-   return 0;
-}
-
 static int nouveau_dsm_get_client_id(struct pci_dev *pdev)
 {
/* easy option one - intel vendor ID means Integrated */
@@ -232,7 +227,6 @@ static int nouveau_dsm_get_client_id(struct pci_dev *pdev)
 static struct vga_switcheroo_handler nouveau_dsm_handler = {
.switchto = nouveau_dsm_switchto,
.power_state = nouveau_dsm_power_state,
-   .init = nouveau_dsm_init,
.get_client_id = nouveau_dsm_get_client_id,
 };

diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index 5b3c7d1..ec9069d 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -98,7 +98,8 @@ static void vga_switcheroo_enable(void)
struct vga_switcheroo_client *client;

/* call the handler to init */
-   vgasr_priv.handler->init();
+   if (vgasr_priv.handler->init)
+   vgasr_priv.handler->init();

list_for_each_entry(client, _priv.clients, list) {
if (client->id != -1)
-- 
1.7.9.5



[PATCH 0/3] Display switching support for Apple laptops

2012-08-14 Thread Seth Forshee
This series adds display switching support for Apple laptops. The first
two patches contain preparatory changes to vga_switcheroo, and the third
contains the changes to support display switching with the gmux.

While these patches will allow switching the display mux, most Macbook
owners will not be able to switch GPUs in practice until the graphics
drivers are updated to deal with missing or incorrect vbios information
on Apple machines. These patches do fix an issue seen by some users of
Linux on Macbooks, however. These users will switch to the internal GPU
in OS X and then reboot into Linux to save power, but after S3 the gmux
gets reset to the discrete GPU. Adding the display mux support will fix
this problem by restoring the gmux state during resume.

Thanks,
Seth


Andreas Heider (1):
  apple-gmux: Add display mux support

Seth Forshee (2):
  vga_switcheroo: Don't require handler init callback
  vga_switcheroo: Remove assumptions about registration/unregistration
ordering

 drivers/gpu/drm/nouveau/nouveau_acpi.c |6 -
 drivers/gpu/vga/vga_switcheroo.c   |   61 +
 drivers/platform/x86/apple-gmux.c  |  222 
 3 files changed, 260 insertions(+), 29 deletions(-)



Re: [RFC PATCH 3/5] drm/i915: register LVDS connector even if we can't get a panel mode

2012-08-13 Thread Seth Forshee
On Mon, Aug 06, 2012 at 07:44:16AM +1000, Dave Airlie wrote:
  The correct approach is clearly to just have the drm core change the
  i2c mux before requesting edid, but that's made difficult because of the
  absence of ordering guarantees in initialisation. I don't like quirking
  this, since we're then back to the situation of potentially having to
  add every new piece of related hardware to the quirk list.
 
  The correct approach of switching the mux before we fetch the edid is
  actualy the one I fear will result in fragile code: Only run on few
  machines, and as you say with tons of funky interactions with the init
  sequence ordering. And I guess people will bitchmoan about the flickering
  this will cause ;-)
 
  As long as it's only apple shipping multi-gpu machines with
  broken/non-existing vbt, I'll happily stomach the quirk list entries.
  They're bad, but imo the lesser evil.
 
 Well in theory you can switch the ddc lines without switching the other lines,
 so we could do a mutex protected mux switch around edid retrival,
 
 Of course someone would have to code it up first then we could see how
 ugly it would be.

I coded it up, and it's not really too bad. I've put a dump of my local
changes below. But there are a couple of problems.

First, I don't have a solution for the ordering of initialization. It
just happens to work out for me right now.

Even so, the code only works if I delay loading i915. apple-gmux is
definitely initializing first so the i2c mux should be getting switched,
but the transactions are failing.

[   19.445658] [drm:gmbus_xfer], GMBUS [i915 gmbus panel] timed out after NAK 
[   19.445672] [drm:gmbus_xfer], GMBUS [i915 gmbus panel] NAK for addr: 0050 
r(1) 

But if I prevent i915 from being auto-loaded and load later on it works
fine. I haven't been able to figure out what's going on. Any ideas?

Thanks,
Seth


diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index a8743c3..3f18e8a 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -31,6 +31,7 @@
 #include linux/slab.h
 #include linux/i2c.h
 #include linux/module.h
+#include linux/vga_switcheroo.h
 #include drmP.h
 #include drm_edid.h
 #include drm_edid_modes.h
@@ -82,6 +83,8 @@ struct detailed_mode_closure {
 #define LEVEL_GTF2 2
 #define LEVEL_CVT  3
 
+static DEFINE_MUTEX(drm_edid_mutex);
+
 static struct edid_quirk {
char vendor[4];
int product_id;
@@ -395,12 +398,25 @@ struct edid *drm_get_edid(struct drm_connector *connector,
  struct i2c_adapter *adapter)
 {
struct edid *edid = NULL;
+   struct pci_dev *pdev = connector-dev-pdev;
+   struct pci_dev *active_pdev = NULL;
+
+   mutex_lock(drm_edid_mutex);
+
+   if (pdev) {
+   active_pdev = vga_switcheroo_get_active_client();
+   vga_switcheroo_switch_ddc(pdev);
+   }
 
if (drm_probe_ddc(adapter))
edid = (struct edid *)drm_do_get_edid(connector, adapter);
 
+   if (active_pdev)
+   vga_switcheroo_switch_ddc(active_pdev);
+
connector-display_info.raw_edid = (char *)edid;
 
+   mutex_unlock(drm_edid_mutex);
return edid;
 
 }
diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index e25cf31..e53f67d 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -205,6 +205,20 @@ find_active_client(struct list_head *head)
return NULL;
 }
 
+struct pci_dev *vga_switcheroo_get_active_client(void)
+{
+   struct vga_switcheroo_client *client;
+   struct pci_dev *pdev = NULL;
+
+   mutex_lock(vgasr_mutex);
+   client = find_active_client(vgasr_priv.clients);
+   if (client)
+   pdev = client-pdev;
+   mutex_unlock(vgasr_mutex);
+   return pdev;
+}
+EXPORT_SYMBOL(vga_switcheroo_get_active_client);
+
 int vga_switcheroo_get_client_state(struct pci_dev *pdev)
 {
struct vga_switcheroo_client *client;
@@ -252,6 +266,29 @@ void vga_switcheroo_client_fb_set(struct pci_dev *pdev,
 }
 EXPORT_SYMBOL(vga_switcheroo_client_fb_set);
 
+int vga_switcheroo_switch_ddc(struct pci_dev *pdev)
+{
+   int ret = 0;
+   int id;
+
+   mutex_lock(vgasr_mutex);
+
+   if (!vgasr_priv.handler) {
+   ret = -ENODEV;
+   goto out;
+   }
+
+   if (vgasr_priv.handler-switch_ddc) {
+   id = vgasr_priv.handler-get_client_id(pdev);
+   ret = vgasr_priv.handler-switch_ddc(id);
+   }
+
+out:
+   mutex_unlock(vgasr_mutex);
+   return ret;
+}
+EXPORT_SYMBOL(vga_switcheroo_switch_ddc);
+
 static int vga_switcheroo_show(struct seq_file *m, void *v)
 {
struct vga_switcheroo_client *client;
@@ -342,9 +379,15 @@ static int vga_switchto_stage2(struct 
vga_switcheroo_client *new_client)
fb_notifier_call_chain(FB_EVENT_REMAP_ALL_CONSOLE, event);
}
 
+   if (vgasr_priv.handler-switch_ddc) {
+  

[RFC PATCH 3/5] drm/i915: register LVDS connector even if we can't get a panel mode

2012-08-10 Thread Seth Forshee
On Mon, Aug 06, 2012 at 07:44:16AM +1000, Dave Airlie wrote:
> >> The "correct" approach is clearly to just have the drm core change the
> >> i2c mux before requesting edid, but that's made difficult because of the
> >> absence of ordering guarantees in initialisation. I don't like quirking
> >> this, since we're then back to the situation of potentially having to
> >> add every new piece of related hardware to the quirk list.
> >
> > The "correct" approach of switching the mux before we fetch the edid is
> > actualy the one I fear will result in fragile code: Only run on few
> > machines, and as you say with tons of funky interactions with the init
> > sequence ordering. And I guess people will bitch about the flickering
> > this will cause ;-)
> >
> > As long as it's only apple shipping multi-gpu machines with
> > broken/non-existing vbt, I'll happily stomach the quirk list entries.
> > They're bad, but imo the lesser evil.
> 
> Well in theory you can switch the ddc lines without switching the other lines,
> so we could do a mutex protected mux switch around edid retrival,
> 
> Of course someone would have to code it up first then we could see how
> ugly it would be.

I coded it up, and it's not really too bad. I've put a dump of my local
changes below. But there are a couple of problems.

First, I don't have a solution for the ordering of initialization. It
just happens to work out for me right now.

Even so, the code only works if I delay loading i915. apple-gmux is
definitely initializing first so the i2c mux should be getting switched,
but the transactions are failing.

[   19.445658] [drm:gmbus_xfer], GMBUS [i915 gmbus panel] timed out after NAK 
[   19.445672] [drm:gmbus_xfer], GMBUS [i915 gmbus panel] NAK for addr: 0050 
r(1) 

But if I prevent i915 from being auto-loaded and load later on it works
fine. I haven't been able to figure out what's going on. Any ideas?

Thanks,
Seth


diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index a8743c3..3f18e8a 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -31,6 +31,7 @@
 #include 
 #include 
 #include 
+#include 
 #include "drmP.h"
 #include "drm_edid.h"
 #include "drm_edid_modes.h"
@@ -82,6 +83,8 @@ struct detailed_mode_closure {
 #define LEVEL_GTF2 2
 #define LEVEL_CVT  3

+static DEFINE_MUTEX(drm_edid_mutex);
+
 static struct edid_quirk {
char vendor[4];
int product_id;
@@ -395,12 +398,25 @@ struct edid *drm_get_edid(struct drm_connector *connector,
  struct i2c_adapter *adapter)
 {
struct edid *edid = NULL;
+   struct pci_dev *pdev = connector->dev->pdev;
+   struct pci_dev *active_pdev = NULL;
+
+   mutex_lock(_edid_mutex);
+
+   if (pdev) {
+   active_pdev = vga_switcheroo_get_active_client();
+   vga_switcheroo_switch_ddc(pdev);
+   }

if (drm_probe_ddc(adapter))
edid = (struct edid *)drm_do_get_edid(connector, adapter);

+   if (active_pdev)
+   vga_switcheroo_switch_ddc(active_pdev);
+
connector->display_info.raw_edid = (char *)edid;

+   mutex_unlock(_edid_mutex);
return edid;

 }
diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index e25cf31..e53f67d 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -205,6 +205,20 @@ find_active_client(struct list_head *head)
return NULL;
 }

+struct pci_dev *vga_switcheroo_get_active_client(void)
+{
+   struct vga_switcheroo_client *client;
+   struct pci_dev *pdev = NULL;
+
+   mutex_lock(_mutex);
+   client = find_active_client(_priv.clients);
+   if (client)
+   pdev = client->pdev;
+   mutex_unlock(_mutex);
+   return pdev;
+}
+EXPORT_SYMBOL(vga_switcheroo_get_active_client);
+
 int vga_switcheroo_get_client_state(struct pci_dev *pdev)
 {
struct vga_switcheroo_client *client;
@@ -252,6 +266,29 @@ void vga_switcheroo_client_fb_set(struct pci_dev *pdev,
 }
 EXPORT_SYMBOL(vga_switcheroo_client_fb_set);

+int vga_switcheroo_switch_ddc(struct pci_dev *pdev)
+{
+   int ret = 0;
+   int id;
+
+   mutex_lock(_mutex);
+
+   if (!vgasr_priv.handler) {
+   ret = -ENODEV;
+   goto out;
+   }
+
+   if (vgasr_priv.handler->switch_ddc) {
+   id = vgasr_priv.handler->get_client_id(pdev);
+   ret = vgasr_priv.handler->switch_ddc(id);
+   }
+
+out:
+   mutex_unlock(_mutex);
+   return ret;
+}
+EXPORT_SYMBOL(vga_switcheroo_switch_ddc);
+
 static int vga_switcheroo_show(struct seq_file *m, void *v)
 {
struct vga_switcheroo_client *client;
@@ -342,9 +379,15 @@ static int vga_switchto_stage2(struct 
vga_switcheroo_client *new_client)
fb_notifier_call_chain(FB_EVENT_REMAP_ALL_CONSOLE, );
}

+   if (vgasr_priv.handler->switch_ddc) {
+   ret = 

Re: [RFC PATCH 3/5] drm/i915: register LVDS connector even if we can't get a panel mode

2012-08-07 Thread Seth Forshee
On Mon, Aug 06, 2012 at 01:23:17PM +0100, Matthew Garrett wrote:
 On Sun, Aug 05, 2012 at 11:40:16PM +0200, Daniel Vetter wrote:
 
  As long as it's only apple shipping multi-gpu machines with
  broken/non-existing vbt, I'll happily stomach the quirk list entries.
  They're bad, but imo the lesser evil.
 
 Doing this via quirks means that we'll always be broken on the hardware 
 at the point where it ships. Implementing the functionality means we 
 stand some chance of working out of the box.

I've been thinking some today about how this functionality might be
implemented.

It looks like the simplest way to let the inactive GPU have the i2c bus
temporarily is to have drm_get_edid() control the mux and serialize it
with a mutex. It should be pretty easy to make vga_switcheroo support
muxing the DDC separately from the display.

There is the problem of vga_switcheroo not really being operational
until it has two clients and a handler, and the graphics drivers not
registering clients until they've initialized LVDS. This probably won't
be too dificult to solve.

The bigger problem is still making sure the switcheroo handler is
registered, when it's needed, before trying to read the EDID. We could
potentially delay initializing non-active graphics devices until after a
switcheroo handler has been registered, but that's a problem if the
handler is implemented by the driver for the secondary GPU (is this ever
the case?). Otherwise we seem to be stuck with making i915 able to cope
with getting modes for LVDS after initialization, which kind of puts us
back where we started.

Any other ideas?

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


[RFC PATCH 3/5] drm/i915: register LVDS connector even if we can't get a panel mode

2012-08-06 Thread Seth Forshee
On Mon, Aug 06, 2012 at 01:23:17PM +0100, Matthew Garrett wrote:
> On Sun, Aug 05, 2012 at 11:40:16PM +0200, Daniel Vetter wrote:
> 
> > As long as it's only apple shipping multi-gpu machines with
> > broken/non-existing vbt, I'll happily stomach the quirk list entries.
> > They're bad, but imo the lesser evil.
> 
> Doing this via quirks means that we'll always be broken on the hardware 
> at the point where it ships. Implementing the functionality means we 
> stand some chance of working out of the box.

I've been thinking some today about how this functionality might be
implemented.

It looks like the simplest way to let the inactive GPU have the i2c bus
temporarily is to have drm_get_edid() control the mux and serialize it
with a mutex. It should be pretty easy to make vga_switcheroo support
muxing the DDC separately from the display.

There is the problem of vga_switcheroo not really being operational
until it has two clients and a handler, and the graphics drivers not
registering clients until they've initialized LVDS. This probably won't
be too dificult to solve.

The bigger problem is still making sure the switcheroo handler is
registered, when it's needed, before trying to read the EDID. We could
potentially delay initializing non-active graphics devices until after a
switcheroo handler has been registered, but that's a problem if the
handler is implemented by the driver for the secondary GPU (is this ever
the case?). Otherwise we seem to be stuck with making i915 able to cope
with getting modes for LVDS after initialization, which kind of puts us
back where we started.

Any other ideas?



[RFC PATCH 3/5] drm/i915: register LVDS connector even if we can't get a panel mode

2012-08-06 Thread Seth Forshee
On Sun, Aug 05, 2012 at 07:20:31PM -0400, Alex Deucher wrote:
> On Sun, Aug 5, 2012 at 5:44 PM, Dave Airlie  wrote:
> > On Mon, Aug 6, 2012 at 7:40 AM, Daniel Vetter  wrote:
> >> On Sun, Aug 05, 2012 at 10:18:38PM +0100, Matthew Garrett wrote:
> >>> On Sun, Aug 05, 2012 at 11:14:12PM +0200, Daniel Vetter wrote:
> >>>
> >>> > I like this approach more - the only other solution I see is to ask the
> >>> > currently active driver (i.e. radeon) at bootime for the right mode. 
> >>> > Which
> >>> > sounds much more hellish and fragile ...
> >>>
> >>> The "correct" approach is clearly to just have the drm core change the
> >>> i2c mux before requesting edid, but that's made difficult because of the
> >>> absence of ordering guarantees in initialisation. I don't like quirking
> >>> this, since we're then back to the situation of potentially having to
> >>> add every new piece of related hardware to the quirk list.
> >>
> >> The "correct" approach of switching the mux before we fetch the edid is
> >> actualy the one I fear will result in fragile code: Only run on few
> >> machines, and as you say with tons of funky interactions with the init
> >> sequence ordering. And I guess people will bitch about the flickering
> >> this will cause ;-)
> >>
> >> As long as it's only apple shipping multi-gpu machines with
> >> broken/non-existing vbt, I'll happily stomach the quirk list entries.
> >> They're bad, but imo the lesser evil.
> >
> > Well in theory you can switch the ddc lines without switching the other 
> > lines,
> > so we could do a mutex protected mux switch around edid retrival,
> >
> 
> Depends on the system.  On non-Macs, some systems have a single mux,
> others have a separate mux for i2c and display as specified in the
> ATPX ACPI methods.  Not sure how the Macs do it.  I've started
> cleaning up the PX radeon code along with a bunch of other radeon
> ralated ACPI fixes:
> http://cgit.freedesktop.org/~agd5f/linux/log/?h=acpi_patches

The Macs mux the i2c and display separately. However they don't support
the vendor ACPI interfaces for the mux. The driver that provides the
vga_switcheroo handler is separate from the graphics drivers, and the
same whether the discrete graphics are Radeon or nVidia.

Really to support this in any generic sort of way vga_switcheroo needs
to support muxing the DDC separately from the display, but as Matthew
pointed out the ordering of initialization could be a problem. Even if
we protect the DDC with a mutex how can we guarantee that the switcheroo
handler is registered to switch the DDC before i915 is ready to check
for an EDID?



[RFC PATCH 0/5] i915 changes for hybrid graphics support on Macbooks

2012-08-05 Thread Seth Forshee
The following patches are part of a larger series I've been working on
to get vga_switcheroo working on hybrid graphics Macbooks. Some of these
machines are not providing a VBT, and since the LVDS panel is connected
to the discrete GPU at boot we can't get a mode for the panel during
initialization. As a result the LVDS connector is not registered with
DRM, and graphics switching is not possible.

These patches fix this issue by registering the connector even if we
can't get a mode for the panel. If we don't have an EDID we check again
from the vga_switcheroo reprobe callback.

This is working, except for the framebuffer console which isn't
displaying when switched to the integrated GPU, which I still need to
debug. I'm not entirely sure whether or not this is the correct approach
though, so I wanted to go ahead and get some feedback on the patches now
to make sure I'm on the right track.

Thanks,
Seth


Andreas Heider (1):
  drm/i915: Add support for vga_switcheroo reprobe

Seth Forshee (4):
  drm/i915: separate out code to get EDID from LVDS panel
  drm/i915: register LVDS connector even if we can't get a panel mode
  drm/i915: make intel_lvds_get_edid() more robust
  drm/i915: check LVDS for EDID on GPU switches

 drivers/gpu/drm/i915/i915_dma.c   |9 ++-
 drivers/gpu/drm/i915/intel_drv.h  |1 +
 drivers/gpu/drm/i915/intel_lvds.c |  156 +
 3 files changed, 97 insertions(+), 69 deletions(-)

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


[RFC PATCH 1/5] drm/i915: Add support for vga_switcheroo reprobe

2012-08-05 Thread Seth Forshee
From: Andreas Heider andr...@meetr.de

Signed-off-by: Andreas Heider andr...@meetr.de
---
 drivers/gpu/drm/i915/i915_dma.c |8 +++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 9cf7dfe..5b5176d 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1263,6 +1263,12 @@ static void i915_switcheroo_set_state(struct pci_dev 
*pdev, enum vga_switcheroo_
}
 }
 
+static void i915_switcheroo_reprobe(struct pci_dev *pdev)
+{
+   struct drm_device *dev = pci_get_drvdata(pdev);
+   intel_fb_output_poll_changed(dev);
+}
+
 static bool i915_switcheroo_can_switch(struct pci_dev *pdev)
 {
struct drm_device *dev = pci_get_drvdata(pdev);
@@ -1276,7 +1282,7 @@ static bool i915_switcheroo_can_switch(struct pci_dev 
*pdev)
 
 static const struct vga_switcheroo_client_ops i915_switcheroo_ops = {
.set_gpu_state = i915_switcheroo_set_state,
-   .reprobe = NULL,
+   .reprobe = i915_switcheroo_reprobe,
.can_switch = i915_switcheroo_can_switch,
 };
 
-- 
1.7.9.5

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


[RFC PATCH 2/5] drm/i915: separate out code to get EDID from LVDS panel

2012-08-05 Thread Seth Forshee
This code will be reused to support hybrid graphics on some Apple
machines that can't get a mode for the LVDS panel at boot, so move it
into a new function named intel_lvds_get_edid().

Signed-off-by: Seth Forshee seth.fors...@canonical.com
---
 drivers/gpu/drm/i915/intel_lvds.c |   95 +
 1 file changed, 55 insertions(+), 40 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_lvds.c 
b/drivers/gpu/drm/i915/intel_lvds.c
index e05c0d3..5069137 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -46,6 +46,7 @@ struct intel_lvds {
 
struct edid *edid;
 
+   u8 i2c_pin;
int fitting_mode;
u32 pfit_control;
u32 pfit_pgm_ratios;
@@ -897,6 +898,54 @@ static bool intel_lvds_supported(struct drm_device *dev)
return IS_MOBILE(dev)  !IS_I830(dev);
 }
 
+static bool intel_lvds_get_edid(struct drm_device *dev)
+{
+   struct drm_i915_private *dev_priv = dev-dev_private;
+   struct drm_connector *connector = dev_priv-int_lvds_connector;
+   struct intel_lvds *intel_lvds = intel_attached_lvds(connector);
+   struct drm_display_mode *scan; /* *modes, *bios_mode; */
+
+   /*
+* Attempt to get the fixed panel mode from DDC.  Assume that the
+* preferred mode is the right one.
+*/
+   intel_lvds-edid = drm_get_edid(connector,
+   intel_gmbus_get_adapter(dev_priv,
+   
intel_lvds-i2c_pin));
+   if (intel_lvds-edid) {
+   if (drm_add_edid_modes(connector,
+  intel_lvds-edid)) {
+   drm_mode_connector_update_edid_property(connector,
+   
intel_lvds-edid);
+   } else {
+   kfree(intel_lvds-edid);
+   intel_lvds-edid = NULL;
+   }
+   }
+   if (!intel_lvds-edid) {
+   /* Didn't get an EDID, so
+* Set wide sync ranges so we get all modes
+* handed to valid_mode for checking
+*/
+   connector-display_info.min_vfreq = 0;
+   connector-display_info.max_vfreq = 200;
+   connector-display_info.min_hfreq = 0;
+   connector-display_info.max_hfreq = 200;
+   }
+
+   list_for_each_entry(scan, connector-probed_modes, head) {
+   if (scan-type  DRM_MODE_TYPE_PREFERRED) {
+   intel_lvds-fixed_mode =
+   drm_mode_duplicate(dev, scan);
+   intel_find_lvds_downclock(dev,
+ intel_lvds-fixed_mode,
+ connector);
+   return true;
+   }
+   }
+   return false;
+}
+
 /**
  * intel_lvds_init - setup LVDS connectors on this device
  * @dev: drm device
@@ -912,7 +961,6 @@ bool intel_lvds_init(struct drm_device *dev)
struct intel_connector *intel_connector;
struct drm_connector *connector;
struct drm_encoder *encoder;
-   struct drm_display_mode *scan; /* *modes, *bios_mode; */
struct drm_crtc *crtc;
u32 lvds;
int pipe;
@@ -955,9 +1003,11 @@ bool intel_lvds_init(struct drm_device *dev)
intel_lvds-pfit_control = I915_READ(PFIT_CONTROL);
}
 
+   intel_lvds-i2c_pin = pin;
intel_encoder = intel_lvds-base;
encoder = intel_encoder-base;
connector = intel_connector-base;
+   dev_priv-int_lvds_connector = connector;
drm_connector_init(dev, intel_connector-base, 
intel_lvds_connector_funcs,
   DRM_MODE_CONNECTOR_LVDS);
 
@@ -991,6 +1041,7 @@ bool intel_lvds_init(struct drm_device *dev)
  dev-mode_config.scaling_mode_property,
  DRM_MODE_SCALE_ASPECT);
intel_lvds-fitting_mode = DRM_MODE_SCALE_ASPECT;
+
/*
 * LVDS discovery:
 * 1) check for EDID on DDC
@@ -1001,44 +1052,8 @@ bool intel_lvds_init(struct drm_device *dev)
 *if closed, act like it's not there for now
 */
 
-   /*
-* Attempt to get the fixed panel mode from DDC.  Assume that the
-* preferred mode is the right one.
-*/
-   intel_lvds-edid = drm_get_edid(connector,
-   intel_gmbus_get_adapter(dev_priv,
-   pin));
-   if (intel_lvds-edid) {
-   if (drm_add_edid_modes(connector,
-  intel_lvds-edid)) {
-   drm_mode_connector_update_edid_property(connector,
-   
intel_lvds-edid);
-   } else

[RFC PATCH 3/5] drm/i915: register LVDS connector even if we can't get a panel mode

2012-08-05 Thread Seth Forshee
Some Apple hybrid graphics machines do not have the LVDS panel connected
to the integrated GPU at boot and also do not supply a VBT. The LVDS
connector is not registered as a result, making it impossible to support
graphics switching.

This patch changes intel_lvds_init() to register the connector even if
we can't find any panel modes. This makes it necessary to always check
intel_lvds-fixed_mode before use, as it could now be NULL.

Signed-off-by: Seth Forshee seth.fors...@canonical.com
---
 drivers/gpu/drm/i915/intel_lvds.c |   48 +++--
 1 file changed, 19 insertions(+), 29 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_lvds.c 
b/drivers/gpu/drm/i915/intel_lvds.c
index 5069137..c1ab632 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -161,6 +161,8 @@ static int intel_lvds_mode_valid(struct drm_connector 
*connector,
struct intel_lvds *intel_lvds = intel_attached_lvds(connector);
struct drm_display_mode *fixed_mode = intel_lvds-fixed_mode;
 
+   if (!fixed_mode)
+   return MODE_PANEL;
if (mode-hdisplay  fixed_mode-hdisplay)
return MODE_PANEL;
if (mode-vdisplay  fixed_mode-vdisplay)
@@ -262,7 +264,8 @@ static bool intel_lvds_mode_fixup(struct drm_encoder 
*encoder,
 * with the panel scaling set up to source from the H/VDisplay
 * of the original mode.
 */
-   intel_fixed_panel_mode(intel_lvds-fixed_mode, adjusted_mode);
+   if (intel_lvds-fixed_mode)
+   intel_fixed_panel_mode(intel_lvds-fixed_mode, adjusted_mode);
 
if (HAS_PCH_SPLIT(dev)) {
intel_pch_panel_fitting(dev, intel_lvds-fitting_mode,
@@ -461,12 +464,13 @@ static int intel_lvds_get_modes(struct drm_connector 
*connector)
 {
struct intel_lvds *intel_lvds = intel_attached_lvds(connector);
struct drm_device *dev = connector-dev;
-   struct drm_display_mode *mode;
+   struct drm_display_mode *mode = NULL;
 
if (intel_lvds-edid)
return drm_add_edid_modes(connector, intel_lvds-edid);
 
-   mode = drm_mode_duplicate(dev, intel_lvds-fixed_mode);
+   if (intel_lvds-fixed_mode)
+   mode = drm_mode_duplicate(dev, intel_lvds-fixed_mode);
if (mode == NULL)
return 0;
 
@@ -1073,26 +1077,21 @@ bool intel_lvds_init(struct drm_device *dev)
 */
 
/* Ironlake: FIXME if still fail, not try pipe mode now */
-   if (HAS_PCH_SPLIT(dev))
-   goto failed;
-
-   lvds = I915_READ(LVDS);
-   pipe = (lvds  LVDS_PIPEB_SELECT) ? 1 : 0;
-   crtc = intel_get_crtc_for_pipe(dev, pipe);
-
-   if (crtc  (lvds  LVDS_PORT_EN)) {
-   intel_lvds-fixed_mode = intel_crtc_mode_get(dev, crtc);
-   if (intel_lvds-fixed_mode) {
-   intel_lvds-fixed_mode-type |=
-   DRM_MODE_TYPE_PREFERRED;
-   goto out;
+   if (!HAS_PCH_SPLIT(dev)) {
+   lvds = I915_READ(LVDS);
+   pipe = (lvds  LVDS_PIPEB_SELECT) ? 1 : 0;
+   crtc = intel_get_crtc_for_pipe(dev, pipe);
+
+   if (crtc  (lvds  LVDS_PORT_EN)) {
+   intel_lvds-fixed_mode = intel_crtc_mode_get(dev, crtc);
+   if (intel_lvds-fixed_mode) {
+   intel_lvds-fixed_mode-type |=
+   DRM_MODE_TYPE_PREFERRED;
+   goto out;
+   }
}
}
 
-   /* If we still don't have a mode after all that, give up. */
-   if (!intel_lvds-fixed_mode)
-   goto failed;
-
 out:
/*
 * Unlock registers and just
@@ -1116,13 +1115,4 @@ out:
intel_panel_setup_backlight(dev);
 
return true;
-
-failed:
-   DRM_DEBUG_KMS(No LVDS modes found, disabling.\n);
-   dev_priv-int_lvds_connector = NULL;
-   drm_connector_cleanup(connector);
-   drm_encoder_cleanup(encoder);
-   kfree(intel_lvds);
-   kfree(intel_connector);
-   return false;
 }
-- 
1.7.9.5

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


[RFC PATCH 4/5] drm/i915: make intel_lvds_get_edid() more robust

2012-08-05 Thread Seth Forshee
intel_lvds_get_edid() needs to be called when switching GPUs, but it's
currently making assumptions that it will only be called once and that
there's always an LVDS connector present when it's called. Fix these
assumptions.

Signed-off-by: Seth Forshee seth.fors...@canonical.com
---
 drivers/gpu/drm/i915/intel_lvds.c |   17 -
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/intel_lvds.c 
b/drivers/gpu/drm/i915/intel_lvds.c
index c1ab632..9d05a90 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -906,9 +906,18 @@ static bool intel_lvds_get_edid(struct drm_device *dev)
 {
struct drm_i915_private *dev_priv = dev-dev_private;
struct drm_connector *connector = dev_priv-int_lvds_connector;
-   struct intel_lvds *intel_lvds = intel_attached_lvds(connector);
+   struct intel_lvds *intel_lvds;
struct drm_display_mode *scan; /* *modes, *bios_mode; */
 
+   if (!connector)
+   return false;
+
+   intel_lvds = intel_attached_lvds(connector);
+
+   /* If we already have an EDID, no need to check again */
+   if (intel_lvds-edid)
+   return true;
+
/*
 * Attempt to get the fixed panel mode from DDC.  Assume that the
 * preferred mode is the right one.
@@ -939,6 +948,12 @@ static bool intel_lvds_get_edid(struct drm_device *dev)
 
list_for_each_entry(scan, connector-probed_modes, head) {
if (scan-type  DRM_MODE_TYPE_PREFERRED) {
+   /*
+* If we already have a preferred mode from another
+* source, prefer the one from the EDID.
+*/
+   if (intel_lvds-fixed_mode)
+   drm_mode_destroy(dev, intel_lvds-fixed_mode);
intel_lvds-fixed_mode =
drm_mode_duplicate(dev, scan);
intel_find_lvds_downclock(dev,
-- 
1.7.9.5

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


[RFC PATCH 5/5] drm/i915: check LVDS for EDID on GPU switches

2012-08-05 Thread Seth Forshee
If the LVDS panel wasn't connected at boot then we won't have an EDID
for it. To fix this, call intel_lvds_get_edid() from the vga_switcheroo
reprobe callback.

Signed-off-by: Seth Forshee seth.fors...@canonical.com
---
 drivers/gpu/drm/i915/i915_dma.c   |1 +
 drivers/gpu/drm/i915/intel_drv.h  |1 +
 drivers/gpu/drm/i915/intel_lvds.c |2 +-
 3 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 5b5176d..c9c942e 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1266,6 +1266,7 @@ static void i915_switcheroo_set_state(struct pci_dev 
*pdev, enum vga_switcheroo_
 static void i915_switcheroo_reprobe(struct pci_dev *pdev)
 {
struct drm_device *dev = pci_get_drvdata(pdev);
+   intel_lvds_get_edid(dev);
intel_fb_output_poll_changed(dev);
 }
 
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 8435355..bcc14f9 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -356,6 +356,7 @@ extern void intel_dvo_init(struct drm_device *dev);
 extern void intel_tv_init(struct drm_device *dev);
 extern void intel_mark_busy(struct drm_device *dev,
struct drm_i915_gem_object *obj);
+extern bool intel_lvds_get_edid(struct drm_device *dev);
 extern bool intel_lvds_init(struct drm_device *dev);
 extern void intel_dp_init(struct drm_device *dev, int dp_reg);
 void
diff --git a/drivers/gpu/drm/i915/intel_lvds.c 
b/drivers/gpu/drm/i915/intel_lvds.c
index 9d05a90..39dbefc 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -902,7 +902,7 @@ static bool intel_lvds_supported(struct drm_device *dev)
return IS_MOBILE(dev)  !IS_I830(dev);
 }
 
-static bool intel_lvds_get_edid(struct drm_device *dev)
+bool intel_lvds_get_edid(struct drm_device *dev)
 {
struct drm_i915_private *dev_priv = dev-dev_private;
struct drm_connector *connector = dev_priv-int_lvds_connector;
-- 
1.7.9.5

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [RFC PATCH 3/5] drm/i915: register LVDS connector even if we can't get a panel mode

2012-08-05 Thread Seth Forshee
On Fri, Aug 03, 2012 at 05:14:16PM +0100, Matthew Garrett wrote:
 On Fri, Aug 03, 2012 at 11:02:19AM -0500, Seth Forshee wrote:
  Some Apple hybrid graphics machines do not have the LVDS panel connected
  to the integrated GPU at boot and also do not supply a VBT. The LVDS
  connector is not registered as a result, making it impossible to support
  graphics switching.
  
  This patch changes intel_lvds_init() to register the connector even if
  we can't find any panel modes. This makes it necessary to always check
  intel_lvds-fixed_mode before use, as it could now be NULL.
 
 This one kind of sucks. I think adding a quirk for this situation would 
 be justifiable, rather than doing it for all devices.

This is one of the things I wasn't so sure about. There are various
checks in intel_lvds_init() that can cause it to bail out before we try
to get the EDID, and I don't fully understand all of them. If non-laptop
machines are expected to bail out before the EDID check then the
approach I've taken seems reasonable. Otherwise adding a quirk probably
is a good idea.

Seth

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [RFC PATCH 3/5] drm/i915: register LVDS connector even if we can't get a panel mode

2012-08-05 Thread Seth Forshee
On Fri, Aug 03, 2012 at 05:27:02PM +0100, Matthew Garrett wrote:
 On Fri, Aug 03, 2012 at 11:24:51AM -0500, Seth Forshee wrote:
 
  This is one of the things I wasn't so sure about. There are various
  checks in intel_lvds_init() that can cause it to bail out before we try
  to get the EDID, and I don't fully understand all of them. If non-laptop
  machines are expected to bail out before the EDID check then the
  approach I've taken seems reasonable. Otherwise adding a quirk probably
  is a good idea.
 
 I know we've previously had problems with machines with phantom LVDS 
 hardware, but I'm not sure what the current state of affairs is.

It turns out that the framebuffer console issue is due to not having a
mode when initializing LVDS. As a result 1024x768 is getting used for
the framebuffer.

So quirking is going to fix this situation. In fact, with the changes
below switcheroo seems to work perfectly, without any of these patches
at all.


diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 627fe35..d83e5bc 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -503,6 +503,7 @@ typedef struct drm_i915_private {
enum intel_pch pch_type;
 
unsigned long quirks;
+   struct drm_display_mode *lvds_quirk_mode;
 
/* Register state */
bool modeset_on_lid;
diff --git a/drivers/gpu/drm/i915/intel_display.c 
b/drivers/gpu/drm/i915/intel_display.c
index f615976..c810177 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -7069,7 +7069,7 @@ static void intel_init_display(struct drm_device *dev)
  * resume, or other times.  This quirk makes sure that's the case for
  * affected systems.
  */
-static void quirk_pipea_force(struct drm_device *dev)
+static void quirk_pipea_force(struct drm_device *dev, void *data)
 {
struct drm_i915_private *dev_priv = dev-dev_private;
 
@@ -7080,7 +7080,7 @@ static void quirk_pipea_force(struct drm_device *dev)
 /*
  * Some machines (Lenovo U160) do not work with SSC on LVDS for some reason
  */
-static void quirk_ssc_force_disable(struct drm_device *dev)
+static void quirk_ssc_force_disable(struct drm_device *dev, void *data)
 {
struct drm_i915_private *dev_priv = dev-dev_private;
dev_priv-quirks |= QUIRK_LVDS_SSC_DISABLE;
@@ -7091,48 +7091,74 @@ static void quirk_ssc_force_disable(struct drm_device 
*dev)
  * A machine (e.g. Acer Aspire 5734Z) may need to invert the panel backlight
  * brightness value
  */
-static void quirk_invert_brightness(struct drm_device *dev)
+static void quirk_invert_brightness(struct drm_device *dev, void *data)
 {
struct drm_i915_private *dev_priv = dev-dev_private;
dev_priv-quirks |= QUIRK_INVERT_BRIGHTNESS;
DRM_INFO(applying inverted panel brightness quirk\n);
 }
 
+/*
+ * Some machines (e.g. certain Macbooks) may not be able to determine the
+ * LVDS mode during driver initialization
+ */
+static void quirk_lvds_panel_mode(struct drm_device *dev, void *data)
+{
+   struct drm_i915_private *dev_priv = dev-dev_private;
+   dev_priv-lvds_quirk_mode = data;
+   DRM_INFO(applying LVDS panel mode quirk: %p\n, data);
+}
+
+/* LVDS panel mode for Macbook Pro 8,2 */
+struct drm_display_mode mbp82_panel_mode = {
+   DRM_MODE(1440x900, DRM_MODE_TYPE_DRIVER, 88750, 1440, 1488, 1520,
+1600, 0, 900, 903, 909, 926, 0,
+DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC)
+};
+
 struct intel_quirk {
int device;
int subsystem_vendor;
int subsystem_device;
-   void (*hook)(struct drm_device *dev);
+   void (*hook)(struct drm_device *dev, void *data);
+   void *hook_data;
 };
 
 static struct intel_quirk intel_quirks[] = {
/* HP Mini needs pipe A force quirk (LP: #322104) */
-   { 0x27ae, 0x103c, 0x361a, quirk_pipea_force },
+   { 0x27ae, 0x103c, 0x361a, quirk_pipea_force, NULL },
 
/* Thinkpad R31 needs pipe A force quirk */
-   { 0x3577, 0x1014, 0x0505, quirk_pipea_force },
+   { 0x3577, 0x1014, 0x0505, quirk_pipea_force, NULL },
/* Toshiba Protege R-205, S-209 needs pipe A force quirk */
-   { 0x2592, 0x1179, 0x0001, quirk_pipea_force },
+   { 0x2592, 0x1179, 0x0001, quirk_pipea_force, NULL },
 
/* ThinkPad X30 needs pipe A force quirk (LP: #304614) */
-   { 0x3577,  0x1014, 0x0513, quirk_pipea_force },
+   { 0x3577,  0x1014, 0x0513, quirk_pipea_force, NULL },
/* ThinkPad X40 needs pipe A force quirk */
 
/* ThinkPad T60 needs pipe A force quirk (bug #16494) */
-   { 0x2782, 0x17aa, 0x201a, quirk_pipea_force },
+   { 0x2782, 0x17aa, 0x201a, quirk_pipea_force, NULL },
 
/* 855  before need to leave pipe A  dpll A up */
-   { 0x3582, PCI_ANY_ID, PCI_ANY_ID, quirk_pipea_force },
-   { 0x2562, PCI_ANY_ID, PCI_ANY_ID, quirk_pipea_force },
+   { 0x3582, PCI_ANY_ID, PCI_ANY_ID, quirk_pipea_force, NULL

[RFC PATCH 3/5] drm/i915: register LVDS connector even if we can't get a panel mode

2012-08-04 Thread Seth Forshee
On Fri, Aug 03, 2012 at 05:27:02PM +0100, Matthew Garrett wrote:
> On Fri, Aug 03, 2012 at 11:24:51AM -0500, Seth Forshee wrote:
> 
> > This is one of the things I wasn't so sure about. There are various
> > checks in intel_lvds_init() that can cause it to bail out before we try
> > to get the EDID, and I don't fully understand all of them. If non-laptop
> > machines are expected to bail out before the EDID check then the
> > approach I've taken seems reasonable. Otherwise adding a quirk probably
> > is a good idea.
> 
> I know we've previously had problems with machines with phantom LVDS 
> hardware, but I'm not sure what the current state of affairs is.

It turns out that the framebuffer console issue is due to not having a
mode when initializing LVDS. As a result 1024x768 is getting used for
the framebuffer.

So quirking is going to fix this situation. In fact, with the changes
below switcheroo seems to work perfectly, without any of these patches
at all.


diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 627fe35..d83e5bc 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -503,6 +503,7 @@ typedef struct drm_i915_private {
enum intel_pch pch_type;

unsigned long quirks;
+   struct drm_display_mode *lvds_quirk_mode;

/* Register state */
bool modeset_on_lid;
diff --git a/drivers/gpu/drm/i915/intel_display.c 
b/drivers/gpu/drm/i915/intel_display.c
index f615976..c810177 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -7069,7 +7069,7 @@ static void intel_init_display(struct drm_device *dev)
  * resume, or other times.  This quirk makes sure that's the case for
  * affected systems.
  */
-static void quirk_pipea_force(struct drm_device *dev)
+static void quirk_pipea_force(struct drm_device *dev, void *data)
 {
struct drm_i915_private *dev_priv = dev->dev_private;

@@ -7080,7 +7080,7 @@ static void quirk_pipea_force(struct drm_device *dev)
 /*
  * Some machines (Lenovo U160) do not work with SSC on LVDS for some reason
  */
-static void quirk_ssc_force_disable(struct drm_device *dev)
+static void quirk_ssc_force_disable(struct drm_device *dev, void *data)
 {
struct drm_i915_private *dev_priv = dev->dev_private;
dev_priv->quirks |= QUIRK_LVDS_SSC_DISABLE;
@@ -7091,48 +7091,74 @@ static void quirk_ssc_force_disable(struct drm_device 
*dev)
  * A machine (e.g. Acer Aspire 5734Z) may need to invert the panel backlight
  * brightness value
  */
-static void quirk_invert_brightness(struct drm_device *dev)
+static void quirk_invert_brightness(struct drm_device *dev, void *data)
 {
struct drm_i915_private *dev_priv = dev->dev_private;
dev_priv->quirks |= QUIRK_INVERT_BRIGHTNESS;
DRM_INFO("applying inverted panel brightness quirk\n");
 }

+/*
+ * Some machines (e.g. certain Macbooks) may not be able to determine the
+ * LVDS mode during driver initialization
+ */
+static void quirk_lvds_panel_mode(struct drm_device *dev, void *data)
+{
+   struct drm_i915_private *dev_priv = dev->dev_private;
+   dev_priv->lvds_quirk_mode = data;
+   DRM_INFO("applying LVDS panel mode quirk: %p\n", data);
+}
+
+/* LVDS panel mode for Macbook Pro 8,2 */
+struct drm_display_mode mbp82_panel_mode = {
+   DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 88750, 1440, 1488, 1520,
+1600, 0, 900, 903, 909, 926, 0,
+DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC)
+};
+
 struct intel_quirk {
int device;
int subsystem_vendor;
int subsystem_device;
-   void (*hook)(struct drm_device *dev);
+   void (*hook)(struct drm_device *dev, void *data);
+   void *hook_data;
 };

 static struct intel_quirk intel_quirks[] = {
/* HP Mini needs pipe A force quirk (LP: #322104) */
-   { 0x27ae, 0x103c, 0x361a, quirk_pipea_force },
+   { 0x27ae, 0x103c, 0x361a, quirk_pipea_force, NULL },

/* Thinkpad R31 needs pipe A force quirk */
-   { 0x3577, 0x1014, 0x0505, quirk_pipea_force },
+   { 0x3577, 0x1014, 0x0505, quirk_pipea_force, NULL },
/* Toshiba Protege R-205, S-209 needs pipe A force quirk */
-   { 0x2592, 0x1179, 0x0001, quirk_pipea_force },
+   { 0x2592, 0x1179, 0x0001, quirk_pipea_force, NULL },

/* ThinkPad X30 needs pipe A force quirk (LP: #304614) */
-   { 0x3577,  0x1014, 0x0513, quirk_pipea_force },
+   { 0x3577,  0x1014, 0x0513, quirk_pipea_force, NULL },
/* ThinkPad X40 needs pipe A force quirk */

/* ThinkPad T60 needs pipe A force quirk (bug #16494) */
-   { 0x2782, 0x17aa, 0x201a, quirk_pipea_force },
+   { 0x2782, 0x17aa, 0x201a, quirk_pipea_force, NULL },

/* 855 & before need to leave pipe A & dpll A up */
-   { 0x3582, PCI_ANY_ID, PCI_ANY_ID, quirk_pipea_fo

[RFC PATCH 3/5] drm/i915: register LVDS connector even if we can't get a panel mode

2012-08-03 Thread Seth Forshee
On Fri, Aug 03, 2012 at 05:14:16PM +0100, Matthew Garrett wrote:
> On Fri, Aug 03, 2012 at 11:02:19AM -0500, Seth Forshee wrote:
> > Some Apple hybrid graphics machines do not have the LVDS panel connected
> > to the integrated GPU at boot and also do not supply a VBT. The LVDS
> > connector is not registered as a result, making it impossible to support
> > graphics switching.
> > 
> > This patch changes intel_lvds_init() to register the connector even if
> > we can't find any panel modes. This makes it necessary to always check
> > intel_lvds->fixed_mode before use, as it could now be NULL.
> 
> This one kind of sucks. I think adding a quirk for this situation would 
> be justifiable, rather than doing it for all devices.

This is one of the things I wasn't so sure about. There are various
checks in intel_lvds_init() that can cause it to bail out before we try
to get the EDID, and I don't fully understand all of them. If non-laptop
machines are expected to bail out before the EDID check then the
approach I've taken seems reasonable. Otherwise adding a quirk probably
is a good idea.

Seth



[RFC PATCH 5/5] drm/i915: check LVDS for EDID on GPU switches

2012-08-03 Thread Seth Forshee
If the LVDS panel wasn't connected at boot then we won't have an EDID
for it. To fix this, call intel_lvds_get_edid() from the vga_switcheroo
reprobe callback.

Signed-off-by: Seth Forshee 
---
 drivers/gpu/drm/i915/i915_dma.c   |1 +
 drivers/gpu/drm/i915/intel_drv.h  |1 +
 drivers/gpu/drm/i915/intel_lvds.c |2 +-
 3 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 5b5176d..c9c942e 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1266,6 +1266,7 @@ static void i915_switcheroo_set_state(struct pci_dev 
*pdev, enum vga_switcheroo_
 static void i915_switcheroo_reprobe(struct pci_dev *pdev)
 {
struct drm_device *dev = pci_get_drvdata(pdev);
+   intel_lvds_get_edid(dev);
intel_fb_output_poll_changed(dev);
 }

diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 8435355..bcc14f9 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -356,6 +356,7 @@ extern void intel_dvo_init(struct drm_device *dev);
 extern void intel_tv_init(struct drm_device *dev);
 extern void intel_mark_busy(struct drm_device *dev,
struct drm_i915_gem_object *obj);
+extern bool intel_lvds_get_edid(struct drm_device *dev);
 extern bool intel_lvds_init(struct drm_device *dev);
 extern void intel_dp_init(struct drm_device *dev, int dp_reg);
 void
diff --git a/drivers/gpu/drm/i915/intel_lvds.c 
b/drivers/gpu/drm/i915/intel_lvds.c
index 9d05a90..39dbefc 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -902,7 +902,7 @@ static bool intel_lvds_supported(struct drm_device *dev)
return IS_MOBILE(dev) && !IS_I830(dev);
 }

-static bool intel_lvds_get_edid(struct drm_device *dev)
+bool intel_lvds_get_edid(struct drm_device *dev)
 {
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_connector *connector = dev_priv->int_lvds_connector;
-- 
1.7.9.5



[RFC PATCH 4/5] drm/i915: make intel_lvds_get_edid() more robust

2012-08-03 Thread Seth Forshee
intel_lvds_get_edid() needs to be called when switching GPUs, but it's
currently making assumptions that it will only be called once and that
there's always an LVDS connector present when it's called. Fix these
assumptions.

Signed-off-by: Seth Forshee 
---
 drivers/gpu/drm/i915/intel_lvds.c |   17 -
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/intel_lvds.c 
b/drivers/gpu/drm/i915/intel_lvds.c
index c1ab632..9d05a90 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -906,9 +906,18 @@ static bool intel_lvds_get_edid(struct drm_device *dev)
 {
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_connector *connector = dev_priv->int_lvds_connector;
-   struct intel_lvds *intel_lvds = intel_attached_lvds(connector);
+   struct intel_lvds *intel_lvds;
struct drm_display_mode *scan; /* *modes, *bios_mode; */

+   if (!connector)
+   return false;
+
+   intel_lvds = intel_attached_lvds(connector);
+
+   /* If we already have an EDID, no need to check again */
+   if (intel_lvds->edid)
+   return true;
+
/*
 * Attempt to get the fixed panel mode from DDC.  Assume that the
 * preferred mode is the right one.
@@ -939,6 +948,12 @@ static bool intel_lvds_get_edid(struct drm_device *dev)

list_for_each_entry(scan, >probed_modes, head) {
if (scan->type & DRM_MODE_TYPE_PREFERRED) {
+   /*
+* If we already have a preferred mode from another
+* source, prefer the one from the EDID.
+*/
+   if (intel_lvds->fixed_mode)
+   drm_mode_destroy(dev, intel_lvds->fixed_mode);
intel_lvds->fixed_mode =
drm_mode_duplicate(dev, scan);
intel_find_lvds_downclock(dev,
-- 
1.7.9.5



[RFC PATCH 3/5] drm/i915: register LVDS connector even if we can't get a panel mode

2012-08-03 Thread Seth Forshee
Some Apple hybrid graphics machines do not have the LVDS panel connected
to the integrated GPU at boot and also do not supply a VBT. The LVDS
connector is not registered as a result, making it impossible to support
graphics switching.

This patch changes intel_lvds_init() to register the connector even if
we can't find any panel modes. This makes it necessary to always check
intel_lvds->fixed_mode before use, as it could now be NULL.

Signed-off-by: Seth Forshee 
---
 drivers/gpu/drm/i915/intel_lvds.c |   48 +++--
 1 file changed, 19 insertions(+), 29 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_lvds.c 
b/drivers/gpu/drm/i915/intel_lvds.c
index 5069137..c1ab632 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -161,6 +161,8 @@ static int intel_lvds_mode_valid(struct drm_connector 
*connector,
struct intel_lvds *intel_lvds = intel_attached_lvds(connector);
struct drm_display_mode *fixed_mode = intel_lvds->fixed_mode;

+   if (!fixed_mode)
+   return MODE_PANEL;
if (mode->hdisplay > fixed_mode->hdisplay)
return MODE_PANEL;
if (mode->vdisplay > fixed_mode->vdisplay)
@@ -262,7 +264,8 @@ static bool intel_lvds_mode_fixup(struct drm_encoder 
*encoder,
 * with the panel scaling set up to source from the H/VDisplay
 * of the original mode.
 */
-   intel_fixed_panel_mode(intel_lvds->fixed_mode, adjusted_mode);
+   if (intel_lvds->fixed_mode)
+   intel_fixed_panel_mode(intel_lvds->fixed_mode, adjusted_mode);

if (HAS_PCH_SPLIT(dev)) {
intel_pch_panel_fitting(dev, intel_lvds->fitting_mode,
@@ -461,12 +464,13 @@ static int intel_lvds_get_modes(struct drm_connector 
*connector)
 {
struct intel_lvds *intel_lvds = intel_attached_lvds(connector);
struct drm_device *dev = connector->dev;
-   struct drm_display_mode *mode;
+   struct drm_display_mode *mode = NULL;

if (intel_lvds->edid)
return drm_add_edid_modes(connector, intel_lvds->edid);

-   mode = drm_mode_duplicate(dev, intel_lvds->fixed_mode);
+   if (intel_lvds->fixed_mode)
+   mode = drm_mode_duplicate(dev, intel_lvds->fixed_mode);
if (mode == NULL)
return 0;

@@ -1073,26 +1077,21 @@ bool intel_lvds_init(struct drm_device *dev)
 */

/* Ironlake: FIXME if still fail, not try pipe mode now */
-   if (HAS_PCH_SPLIT(dev))
-   goto failed;
-
-   lvds = I915_READ(LVDS);
-   pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0;
-   crtc = intel_get_crtc_for_pipe(dev, pipe);
-
-   if (crtc && (lvds & LVDS_PORT_EN)) {
-   intel_lvds->fixed_mode = intel_crtc_mode_get(dev, crtc);
-   if (intel_lvds->fixed_mode) {
-   intel_lvds->fixed_mode->type |=
-   DRM_MODE_TYPE_PREFERRED;
-   goto out;
+   if (!HAS_PCH_SPLIT(dev)) {
+   lvds = I915_READ(LVDS);
+   pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0;
+   crtc = intel_get_crtc_for_pipe(dev, pipe);
+
+   if (crtc && (lvds & LVDS_PORT_EN)) {
+   intel_lvds->fixed_mode = intel_crtc_mode_get(dev, crtc);
+   if (intel_lvds->fixed_mode) {
+   intel_lvds->fixed_mode->type |=
+   DRM_MODE_TYPE_PREFERRED;
+   goto out;
+   }
}
}

-   /* If we still don't have a mode after all that, give up. */
-   if (!intel_lvds->fixed_mode)
-   goto failed;
-
 out:
/*
 * Unlock registers and just
@@ -1116,13 +1115,4 @@ out:
intel_panel_setup_backlight(dev);

return true;
-
-failed:
-   DRM_DEBUG_KMS("No LVDS modes found, disabling.\n");
-   dev_priv->int_lvds_connector = NULL;
-   drm_connector_cleanup(connector);
-   drm_encoder_cleanup(encoder);
-   kfree(intel_lvds);
-   kfree(intel_connector);
-   return false;
 }
-- 
1.7.9.5



[RFC PATCH 2/5] drm/i915: separate out code to get EDID from LVDS panel

2012-08-03 Thread Seth Forshee
This code will be reused to support hybrid graphics on some Apple
machines that can't get a mode for the LVDS panel at boot, so move it
into a new function named intel_lvds_get_edid().

Signed-off-by: Seth Forshee 
---
 drivers/gpu/drm/i915/intel_lvds.c |   95 +
 1 file changed, 55 insertions(+), 40 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_lvds.c 
b/drivers/gpu/drm/i915/intel_lvds.c
index e05c0d3..5069137 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -46,6 +46,7 @@ struct intel_lvds {

struct edid *edid;

+   u8 i2c_pin;
int fitting_mode;
u32 pfit_control;
u32 pfit_pgm_ratios;
@@ -897,6 +898,54 @@ static bool intel_lvds_supported(struct drm_device *dev)
return IS_MOBILE(dev) && !IS_I830(dev);
 }

+static bool intel_lvds_get_edid(struct drm_device *dev)
+{
+   struct drm_i915_private *dev_priv = dev->dev_private;
+   struct drm_connector *connector = dev_priv->int_lvds_connector;
+   struct intel_lvds *intel_lvds = intel_attached_lvds(connector);
+   struct drm_display_mode *scan; /* *modes, *bios_mode; */
+
+   /*
+* Attempt to get the fixed panel mode from DDC.  Assume that the
+* preferred mode is the right one.
+*/
+   intel_lvds->edid = drm_get_edid(connector,
+   intel_gmbus_get_adapter(dev_priv,
+   
intel_lvds->i2c_pin));
+   if (intel_lvds->edid) {
+   if (drm_add_edid_modes(connector,
+  intel_lvds->edid)) {
+   drm_mode_connector_update_edid_property(connector,
+   
intel_lvds->edid);
+   } else {
+   kfree(intel_lvds->edid);
+   intel_lvds->edid = NULL;
+   }
+   }
+   if (!intel_lvds->edid) {
+   /* Didn't get an EDID, so
+* Set wide sync ranges so we get all modes
+* handed to valid_mode for checking
+*/
+   connector->display_info.min_vfreq = 0;
+   connector->display_info.max_vfreq = 200;
+   connector->display_info.min_hfreq = 0;
+   connector->display_info.max_hfreq = 200;
+   }
+
+   list_for_each_entry(scan, >probed_modes, head) {
+   if (scan->type & DRM_MODE_TYPE_PREFERRED) {
+   intel_lvds->fixed_mode =
+   drm_mode_duplicate(dev, scan);
+   intel_find_lvds_downclock(dev,
+ intel_lvds->fixed_mode,
+ connector);
+   return true;
+   }
+   }
+   return false;
+}
+
 /**
  * intel_lvds_init - setup LVDS connectors on this device
  * @dev: drm device
@@ -912,7 +961,6 @@ bool intel_lvds_init(struct drm_device *dev)
struct intel_connector *intel_connector;
struct drm_connector *connector;
struct drm_encoder *encoder;
-   struct drm_display_mode *scan; /* *modes, *bios_mode; */
struct drm_crtc *crtc;
u32 lvds;
int pipe;
@@ -955,9 +1003,11 @@ bool intel_lvds_init(struct drm_device *dev)
intel_lvds->pfit_control = I915_READ(PFIT_CONTROL);
}

+   intel_lvds->i2c_pin = pin;
intel_encoder = _lvds->base;
encoder = _encoder->base;
connector = _connector->base;
+   dev_priv->int_lvds_connector = connector;
drm_connector_init(dev, _connector->base, 
_lvds_connector_funcs,
   DRM_MODE_CONNECTOR_LVDS);

@@ -991,6 +1041,7 @@ bool intel_lvds_init(struct drm_device *dev)
  dev->mode_config.scaling_mode_property,
  DRM_MODE_SCALE_ASPECT);
intel_lvds->fitting_mode = DRM_MODE_SCALE_ASPECT;
+
/*
 * LVDS discovery:
 * 1) check for EDID on DDC
@@ -1001,44 +1052,8 @@ bool intel_lvds_init(struct drm_device *dev)
 *if closed, act like it's not there for now
 */

-   /*
-* Attempt to get the fixed panel mode from DDC.  Assume that the
-* preferred mode is the right one.
-*/
-   intel_lvds->edid = drm_get_edid(connector,
-   intel_gmbus_get_adapter(dev_priv,
-   pin));
-   if (intel_lvds->edid) {
-   if (drm_add_edid_modes(connector,
-  intel_lvds->edid)) {
-   drm_mode_connector_update_edid_property(connector,
-  

[RFC PATCH 1/5] drm/i915: Add support for vga_switcheroo reprobe

2012-08-03 Thread Seth Forshee
From: Andreas Heider 

Signed-off-by: Andreas Heider 
---
 drivers/gpu/drm/i915/i915_dma.c |8 +++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 9cf7dfe..5b5176d 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1263,6 +1263,12 @@ static void i915_switcheroo_set_state(struct pci_dev 
*pdev, enum vga_switcheroo_
}
 }

+static void i915_switcheroo_reprobe(struct pci_dev *pdev)
+{
+   struct drm_device *dev = pci_get_drvdata(pdev);
+   intel_fb_output_poll_changed(dev);
+}
+
 static bool i915_switcheroo_can_switch(struct pci_dev *pdev)
 {
struct drm_device *dev = pci_get_drvdata(pdev);
@@ -1276,7 +1282,7 @@ static bool i915_switcheroo_can_switch(struct pci_dev 
*pdev)

 static const struct vga_switcheroo_client_ops i915_switcheroo_ops = {
.set_gpu_state = i915_switcheroo_set_state,
-   .reprobe = NULL,
+   .reprobe = i915_switcheroo_reprobe,
.can_switch = i915_switcheroo_can_switch,
 };

-- 
1.7.9.5



[RFC PATCH 0/5] i915 changes for hybrid graphics support on Macbooks

2012-08-03 Thread Seth Forshee
The following patches are part of a larger series I've been working on
to get vga_switcheroo working on hybrid graphics Macbooks. Some of these
machines are not providing a VBT, and since the LVDS panel is connected
to the discrete GPU at boot we can't get a mode for the panel during
initialization. As a result the LVDS connector is not registered with
DRM, and graphics switching is not possible.

These patches fix this issue by registering the connector even if we
can't get a mode for the panel. If we don't have an EDID we check again
from the vga_switcheroo reprobe callback.

This is working, except for the framebuffer console which isn't
displaying when switched to the integrated GPU, which I still need to
debug. I'm not entirely sure whether or not this is the correct approach
though, so I wanted to go ahead and get some feedback on the patches now
to make sure I'm on the right track.

Thanks,
Seth


Andreas Heider (1):
  drm/i915: Add support for vga_switcheroo reprobe

Seth Forshee (4):
  drm/i915: separate out code to get EDID from LVDS panel
  drm/i915: register LVDS connector even if we can't get a panel mode
  drm/i915: make intel_lvds_get_edid() more robust
  drm/i915: check LVDS for EDID on GPU switches

 drivers/gpu/drm/i915/i915_dma.c   |9 ++-
 drivers/gpu/drm/i915/intel_drv.h  |1 +
 drivers/gpu/drm/i915/intel_lvds.c |  156 +
 3 files changed, 97 insertions(+), 69 deletions(-)



[PATCH v2] drm/i915: ignore pipe select bit when checking for LVDS register initialization

2012-06-14 Thread Seth Forshee
The Lenovo Thinkpad T410 has the LVDS_PIPEB_SELECT bit set in the LVDS
register when booted with the lid closed, even though the LVDS hasn't
really been initialized. Ignore this bit so that the VBT value will be
used instead.

Signed-off-by: Seth Forshee seth.fors...@canonical.com
---
 drivers/gpu/drm/i915/intel_display.c |2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c 
b/drivers/gpu/drm/i915/intel_display.c
index e0aa064..ae17526 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -434,7 +434,7 @@ static bool is_dual_link_lvds(struct drm_i915_private 
*dev_priv,
 * register is uninitialized.
 */
val = I915_READ(reg);
-   if (!(val  ~LVDS_DETECTED))
+   if (!(val  ~(LVDS_PIPE_MASK | LVDS_DETECTED)))
val = dev_priv-bios_lvds_val;
dev_priv-lvds_val = val;
}
-- 
1.7.9.5

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH v2] drm/i915: ignore pipe select bit when checking for LVDS register initialization

2012-06-14 Thread Seth Forshee
On Wed, Jun 13, 2012 at 09:46:15PM +0200, Daniel Vetter wrote:
 On Wed, Jun 13, 2012 at 01:46:58PM -0500, Seth Forshee wrote:
  The Lenovo Thinkpad T410 has the LVDS_PIPEB_SELECT bit set in the LVDS
  register when booted with the lid closed, even though the LVDS hasn't
  really been initialized. Ignore this bit so that the VBT value will be
  used instead.
  
  Signed-off-by: Seth Forshee seth.fors...@canonical.com
 Queued for -next, thanks for the patch. Chris had some reservations about
 the sanity of this patch, but given that it works around bios-insanity I'm
 gonna just take this chance to stab myself with lvds-machines blowing up
 left and right ;-)

Let's hope that doesn't happen ;)

I do find myself wondering though whether it might be better to prefer
the value from the VBT whenever there's one available, and only rely on
the actual register value as a fallback, since the bios can't be trusted
to initialize the register. I'm pretty ignorant about all this graphics
stuff though; I assume there's a reason it isn't done this way?

Seth

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2] drm/i915: ignore pipe select bit when checking for LVDS register initialization

2012-06-13 Thread Seth Forshee
On Wed, Jun 13, 2012 at 09:46:15PM +0200, Daniel Vetter wrote:
> On Wed, Jun 13, 2012 at 01:46:58PM -0500, Seth Forshee wrote:
> > The Lenovo Thinkpad T410 has the LVDS_PIPEB_SELECT bit set in the LVDS
> > register when booted with the lid closed, even though the LVDS hasn't
> > really been initialized. Ignore this bit so that the VBT value will be
> > used instead.
> > 
> > Signed-off-by: Seth Forshee 
> Queued for -next, thanks for the patch. Chris had some reservations about
> the sanity of this patch, but given that it works around bios-insanity I'm
> gonna just take this chance to stab myself with lvds-machines blowing up
> left and right ;-)

Let's hope that doesn't happen ;)

I do find myself wondering though whether it might be better to prefer
the value from the VBT whenever there's one available, and only rely on
the actual register value as a fallback, since the bios can't be trusted
to initialize the register. I'm pretty ignorant about all this graphics
stuff though; I assume there's a reason it isn't done this way?

Seth



[PATCH v2] drm/i915: ignore pipe select bit when checking for LVDS register initialization

2012-06-13 Thread Seth Forshee
The Lenovo Thinkpad T410 has the LVDS_PIPEB_SELECT bit set in the LVDS
register when booted with the lid closed, even though the LVDS hasn't
really been initialized. Ignore this bit so that the VBT value will be
used instead.

Signed-off-by: Seth Forshee 
---
 drivers/gpu/drm/i915/intel_display.c |2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c 
b/drivers/gpu/drm/i915/intel_display.c
index e0aa064..ae17526 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -434,7 +434,7 @@ static bool is_dual_link_lvds(struct drm_i915_private 
*dev_priv,
 * register is uninitialized.
 */
val = I915_READ(reg);
-   if (!(val & ~LVDS_DETECTED))
+   if (!(val & ~(LVDS_PIPE_MASK | LVDS_DETECTED)))
val = dev_priv->bios_lvds_val;
dev_priv->lvds_val = val;
}
-- 
1.7.9.5



i915: lvds panel always blank when booted with lid closed

2012-06-13 Thread Seth Forshee
When I boot my Thinkpad T410 in a docking station with the lid closed,
the lvds panel remains blank even when this output is active. This
happens up to and including 3.5-rc2.

I've determined that this happens because lvds isn't being initialized
by the bios when I boot this way, and booting with lvds_channel_mode=2
fixes the issue. I see that there's logic in is_dual_link_lvds()
intended to detect this situation, but it's failing because the T410 has
the LVDS_PIPEB_SELECT bit set. The simple patch below fixes my machine
by masking off this bit when determining whether or not lvds was
initialized by the bios.

I'm not sure though whether or not it's correct to expect that this bit
might be set when lvds hasn't been initialized. The alternative seems to
be quirking this machine as is done for some Macbooks. What is the
correct solution?

Thanks,
Seth




[PATCH] drm/i915: ignore LVDS_PIPEB_SELECT when checking for LVDS register initialization

2012-06-12 Thread Seth Forshee
The Lenovo Thinkpad T410 has this bit set in the LVDS register when
booted with the lid closed, even though the LVDS hasn't really been
initialized. Ignore this bit so that the VBT value will be used instead.

Signed-off-by: Seth Forshee 
---
 drivers/gpu/drm/i915/intel_display.c |2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c 
b/drivers/gpu/drm/i915/intel_display.c
index e0aa064..f81f249 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -434,7 +434,7 @@ static bool is_dual_link_lvds(struct drm_i915_private 
*dev_priv,
 * register is uninitialized.
 */
val = I915_READ(reg);
-   if (!(val & ~LVDS_DETECTED))
+   if (!(val & ~(LVDS_PIPEB_SELECT | LVDS_DETECTED)))
val = dev_priv->bios_lvds_val;
dev_priv->lvds_val = val;
}



[PATCH] drm/radeon/kms: disable output polling when suspended

2012-02-01 Thread Seth Forshee
Polling the outputs when the device is suspended can result in erroneous
status updates. Disable output polling during suspend to prevent this
from happening.

Signed-off-by: Seth Forshee 
Reviewed-by: Alex Deucher 
Cc: stable at vger.kernel.org
---
 drivers/gpu/drm/radeon/radeon_device.c |4 
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon_device.c 
b/drivers/gpu/drm/radeon/radeon_device.c
index cec51a5..49f7cb7 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -883,6 +883,8 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t 
state)
if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
return 0;

+   drm_kms_helper_poll_disable(dev);
+
/* turn off display hw */
list_for_each_entry(connector, >mode_config.connector_list, head) {
drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
@@ -972,6 +974,8 @@ int radeon_resume_kms(struct drm_device *dev)
list_for_each_entry(connector, >mode_config.connector_list, head) {
drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
}
+
+   drm_kms_helper_poll_enable(dev);
return 0;
 }

-- 
1.7.8.3



[PATCH] drm/radeon/kms: disable output polling when suspended

2012-02-01 Thread Seth Forshee
Polling the outputs when the device is suspended can result in erroneous
status updates. Disable output polling during suspend to prevent this
from happening.

Signed-off-by: Seth Forshee seth.fors...@canonical.com
Reviewed-by: Alex Deucher alexander.deuc...@amd.com
Cc: sta...@vger.kernel.org
---
 drivers/gpu/drm/radeon/radeon_device.c |4 
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon_device.c 
b/drivers/gpu/drm/radeon/radeon_device.c
index cec51a5..49f7cb7 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -883,6 +883,8 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t 
state)
if (dev-switch_power_state == DRM_SWITCH_POWER_OFF)
return 0;
 
+   drm_kms_helper_poll_disable(dev);
+
/* turn off display hw */
list_for_each_entry(connector, dev-mode_config.connector_list, head) {
drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
@@ -972,6 +974,8 @@ int radeon_resume_kms(struct drm_device *dev)
list_for_each_entry(connector, dev-mode_config.connector_list, head) {
drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
}
+
+   drm_kms_helper_poll_enable(dev);
return 0;
 }
 
-- 
1.7.8.3

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


radeon issues on MacBook Pro 8,2

2012-01-31 Thread Seth Forshee
On Fri, Jan 20, 2012 at 05:08:31PM -0600, Seth Forshee wrote:
> > Can you track down who is calling the connector->detect() callbacks
> > during suspend and resume?
> 
> I got two different stack traces, see below.
> 
> And to slightly amend my statement above, I'm only seeing the wrong
> status returned on the suspend side of things. The status during resume
> always seems to be correct.
> 
>  Pid: 49, comm: kworker/0:2 Tainted: G C O 3.2.0-10-generic #17-Ubuntu
>  Call Trace:
>   [] radeon_dp_detect+0x1de/0x230 [radeon]
>   [] output_poll_execute+0xbd/0x1a0 [drm_kms_helper]
>   [] ? drm_helper_mode_fill_fb_struct+0x30/0x30 
> [drm_kms_helper]
>   [] process_one_work+0x11a/0x480
>   [] worker_thread+0x164/0x370
>   [] ? manage_workers.isra.30+0x130/0x130
>   [] kthread+0x8c/0xa0
>   [] kernel_thread_helper+0x4/0x10
>   [] ? flush_kthread_worker+0xa0/0xa0
>   [] ? gs_change+0x13/0x13
> 
>  Pid: 49, comm: kworker/0:2 Tainted: G C O 3.2.0-10-generic #17-Ubuntu
>  Call Trace:
>   [] radeon_dp_detect+0x1de/0x230 [radeon]
>   [] drm_helper_probe_single_connector_modes+0x2c3/0x380 
> [drm_kms_helper]
>   [] drm_fb_helper_hotplug_event+0xf2/0x150 [drm_kms_helper]
>   [] radeon_fb_output_poll_changed+0x15/0x20 [radeon]
>   [] radeon_output_poll_changed+0x15/0x20 [radeon]
>   [] output_poll_execute+0x190/0x1a0 [drm_kms_helper]
>   [] ? drm_helper_mode_fill_fb_struct+0x30/0x30 
> [drm_kms_helper]
>   [] process_one_work+0x11a/0x480
>   [] worker_thread+0x164/0x370
>   [] ? manage_workers.isra.30+0x130/0x130
>   [] kthread+0x8c/0xa0
>   [] kernel_thread_helper+0x4/0x10
>   [] ? flush_kthread_worker+0xa0/0xa0
>   [] ? gs_change+0x13/0x13



[PATCH 1/1] drm/radeon/kms: disable output polling when suspended

2012-01-31 Thread Seth Forshee
Polling the outputs when the device is suspended can result in erroneous
status updates. Disable output polling during suspend to prevent this
from happening.

Signed-off-by: Seth Forshee 
---
 drivers/gpu/drm/radeon/radeon_device.c |4 
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon_device.c 
b/drivers/gpu/drm/radeon/radeon_device.c
index cec51a5..49f7cb7 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -883,6 +883,8 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t 
state)
if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
return 0;

+   drm_kms_helper_poll_disable(dev);
+
/* turn off display hw */
list_for_each_entry(connector, >mode_config.connector_list, head) {
drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
@@ -972,6 +974,8 @@ int radeon_resume_kms(struct drm_device *dev)
list_for_each_entry(connector, >mode_config.connector_list, head) {
drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
}
+
+   drm_kms_helper_poll_enable(dev);
return 0;
 }

-- 
1.7.8.3



Re: radeon issues on MacBook Pro 8,2

2012-01-31 Thread Seth Forshee
On Fri, Jan 20, 2012 at 05:08:31PM -0600, Seth Forshee wrote:
  Can you track down who is calling the connector-detect() callbacks
  during suspend and resume?
 
 I got two different stack traces, see below.
 
 And to slightly amend my statement above, I'm only seeing the wrong
 status returned on the suspend side of things. The status during resume
 always seems to be correct.
 
  Pid: 49, comm: kworker/0:2 Tainted: G C O 3.2.0-10-generic #17-Ubuntu
  Call Trace:
   [a03f5e1e] radeon_dp_detect+0x1de/0x230 [radeon]
   [a014ac6d] output_poll_execute+0xbd/0x1a0 [drm_kms_helper]
   [a014abb0] ? drm_helper_mode_fill_fb_struct+0x30/0x30 
 [drm_kms_helper]
   [81083dca] process_one_work+0x11a/0x480
   [81084b74] worker_thread+0x164/0x370
   [81084a10] ? manage_workers.isra.30+0x130/0x130
   [810893cc] kthread+0x8c/0xa0
   [81660674] kernel_thread_helper+0x4/0x10
   [81089340] ? flush_kthread_worker+0xa0/0xa0
   [81660670] ? gs_change+0x13/0x13
 
  Pid: 49, comm: kworker/0:2 Tainted: G C O 3.2.0-10-generic #17-Ubuntu
  Call Trace:
   [a03f5e1e] radeon_dp_detect+0x1de/0x230 [radeon]
   [a014b6b3] drm_helper_probe_single_connector_modes+0x2c3/0x380 
 [drm_kms_helper]
   [a0149d42] drm_fb_helper_hotplug_event+0xf2/0x150 [drm_kms_helper]
   [a03fe8d5] radeon_fb_output_poll_changed+0x15/0x20 [radeon]
   [a03f7b65] radeon_output_poll_changed+0x15/0x20 [radeon]
   [a014ad40] output_poll_execute+0x190/0x1a0 [drm_kms_helper]
   [a014abb0] ? drm_helper_mode_fill_fb_struct+0x30/0x30 
 [drm_kms_helper]
   [81083dca] process_one_work+0x11a/0x480
   [81084b74] worker_thread+0x164/0x370
   [81084a10] ? manage_workers.isra.30+0x130/0x130
   [810893cc] kthread+0x8c/0xa0
   [81660674] kernel_thread_helper+0x4/0x10
   [81089340] ? flush_kthread_worker+0xa0/0xa0
   [81660670] ? gs_change+0x13/0x13

From these traces it looks like all that really needs to happen is to
disable the output polling during suspend. The following patch seems to
get rid of the problems I'm seeing. Does this look okay to you?


From 0c01950f248c541198b7560793cf57c59b2c11f8 Mon Sep 17 00:00:00 2001
From: Seth Forshee seth.fors...@canonical.com
Date: Tue, 31 Jan 2012 15:37:02 -0600
Subject: [PATCH 1/1] drm/radeon/kms: disable output polling when suspended

Polling the outputs when the device is suspended can result in erroneous
status updates. Disable output polling during suspend to prevent this
from happening.

Signed-off-by: Seth Forshee seth.fors...@canonical.com
---
 drivers/gpu/drm/radeon/radeon_device.c |4 
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon_device.c 
b/drivers/gpu/drm/radeon/radeon_device.c
index cec51a5..49f7cb7 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -883,6 +883,8 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t 
state)
if (dev-switch_power_state == DRM_SWITCH_POWER_OFF)
return 0;
 
+   drm_kms_helper_poll_disable(dev);
+
/* turn off display hw */
list_for_each_entry(connector, dev-mode_config.connector_list, head) {
drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
@@ -972,6 +974,8 @@ int radeon_resume_kms(struct drm_device *dev)
list_for_each_entry(connector, dev-mode_config.connector_list, head) {
drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
}
+
+   drm_kms_helper_poll_enable(dev);
return 0;
 }
 
-- 
1.7.8.3

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: radeon issues on MacBook Pro 8,2

2012-01-21 Thread Seth Forshee
On Fri, Jan 20, 2012 at 02:38:37PM -0500, Alex Deucher wrote:
 On Fri, Jan 20, 2012 at 10:53 AM, Seth Forshee
 seth.fors...@canonical.com wrote:
  On Thu, Jan 19, 2012 at 02:53:17PM -0600, Seth Forshee wrote:
 2. Occasional long delays when suspending. When this happens I see
   messages like following in dmesg:
   
     [drm:atom_op_jump] *ERROR* atombios stuck in loop for more than 
5secs aborting
     [drm:atom_execute_table_locked] *ERROR* atombios stuck executing 
D44E (len 62, WS 0, PS 0) @ 0xD46A
   
   Sometimes one of suspend or resume hangs completely, but I can't
   tell which and am not sure whether or not it's related. I'm also
   testing a Mac Mini with the exact same card which does not seem to
   suffer from this issue.
   
   I ran a bisections that identified f8d0edd (drm/radeon/kms: improve
   DP detect logic) as introducing problems with suspend, and reverting
   this patch on top of 3.2.1 does seem to eliminate both issues.
   
  
   That patch doesn't really affect the modesetting paths directly; it
   looks like a red herring to me.
 
  Perhaps. I just started a run of 200 s3 cycles with the patch reverted
  to see if I can reproduce the issues. I can usually trigger the problem
  with 15 or fewer s3 cycles.
 
  The machine completed 200 s3 cycles with the patch reverted without long
  delays, hangs, or any atombios error messages. Without reverting it
  doesn't get through many at all before experiencing the errors and long
  delays or hangs.
 
  I added a printout of the connector status resulting from the logic that
  was changed by f8d0edd. With the logic prior to this commit it
  consistently returns the status as disconnected, which is correct as I
  have nothing connected. But with the improved logic the status is
  sometimes reported as connected, and these coincide with the atombios
  errors.
 
 
 Do any of the disconnected displayport connectors get misdetected as
 connected during normal operation or does it only happen during
 suspend/resume?

So far I've only seen them during suspend/resume.
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: radeon issues on MacBook Pro 8,2

2012-01-21 Thread Seth Forshee
On Fri, Jan 20, 2012 at 04:39:31PM -0500, Alex Deucher wrote:
 On Fri, Jan 20, 2012 at 4:12 PM, Seth Forshee
 seth.fors...@canonical.com wrote:
  On Fri, Jan 20, 2012 at 02:38:37PM -0500, Alex Deucher wrote:
  On Fri, Jan 20, 2012 at 10:53 AM, Seth Forshee
  seth.fors...@canonical.com wrote:
   On Thu, Jan 19, 2012 at 02:53:17PM -0600, Seth Forshee wrote:
  2. Occasional long delays when suspending. When this happens I see
    messages like following in dmesg:

      [drm:atom_op_jump] *ERROR* atombios stuck in loop for more 
 than 5secs aborting
      [drm:atom_execute_table_locked] *ERROR* atombios stuck 
 executing D44E (len 62, WS 0, PS 0) @ 0xD46A

    Sometimes one of suspend or resume hangs completely, but I can't
    tell which and am not sure whether or not it's related. I'm also
    testing a Mac Mini with the exact same card which does not seem 
 to
    suffer from this issue.

    I ran a bisections that identified f8d0edd (drm/radeon/kms: 
 improve
    DP detect logic) as introducing problems with suspend, and 
 reverting
    this patch on top of 3.2.1 does seem to eliminate both issues.

   
That patch doesn't really affect the modesetting paths directly; it
looks like a red herring to me.
  
   Perhaps. I just started a run of 200 s3 cycles with the patch reverted
   to see if I can reproduce the issues. I can usually trigger the problem
   with 15 or fewer s3 cycles.
  
   The machine completed 200 s3 cycles with the patch reverted without long
   delays, hangs, or any atombios error messages. Without reverting it
   doesn't get through many at all before experiencing the errors and long
   delays or hangs.
  
   I added a printout of the connector status resulting from the logic that
   was changed by f8d0edd. With the logic prior to this commit it
   consistently returns the status as disconnected, which is correct as I
   have nothing connected. But with the improved logic the status is
   sometimes reported as connected, and these coincide with the atombios
   errors.
  
 
  Do any of the disconnected displayport connectors get misdetected as
  connected during normal operation or does it only happen during
  suspend/resume?
 
  So far I've only seen them during suspend/resume.
 
 Can you track down who is calling the connector-detect() callbacks
 during suspend and resume?

I got two different stack traces, see below.

And to slightly amend my statement above, I'm only seeing the wrong
status returned on the suspend side of things. The status during resume
always seems to be correct.

 Pid: 49, comm: kworker/0:2 Tainted: G C O 3.2.0-10-generic #17-Ubuntu
 Call Trace:
  [a03f5e1e] radeon_dp_detect+0x1de/0x230 [radeon]
  [a014ac6d] output_poll_execute+0xbd/0x1a0 [drm_kms_helper]
  [a014abb0] ? drm_helper_mode_fill_fb_struct+0x30/0x30 
[drm_kms_helper]
  [81083dca] process_one_work+0x11a/0x480
  [81084b74] worker_thread+0x164/0x370
  [81084a10] ? manage_workers.isra.30+0x130/0x130
  [810893cc] kthread+0x8c/0xa0
  [81660674] kernel_thread_helper+0x4/0x10
  [81089340] ? flush_kthread_worker+0xa0/0xa0
  [81660670] ? gs_change+0x13/0x13

 Pid: 49, comm: kworker/0:2 Tainted: G C O 3.2.0-10-generic #17-Ubuntu
 Call Trace:
  [a03f5e1e] radeon_dp_detect+0x1de/0x230 [radeon]
  [a014b6b3] drm_helper_probe_single_connector_modes+0x2c3/0x380 
[drm_kms_helper]
  [a0149d42] drm_fb_helper_hotplug_event+0xf2/0x150 [drm_kms_helper]
  [a03fe8d5] radeon_fb_output_poll_changed+0x15/0x20 [radeon]
  [a03f7b65] radeon_output_poll_changed+0x15/0x20 [radeon]
  [a014ad40] output_poll_execute+0x190/0x1a0 [drm_kms_helper]
  [a014abb0] ? drm_helper_mode_fill_fb_struct+0x30/0x30 
[drm_kms_helper]
  [81083dca] process_one_work+0x11a/0x480
  [81084b74] worker_thread+0x164/0x370
  [81084a10] ? manage_workers.isra.30+0x130/0x130
  [810893cc] kthread+0x8c/0xa0
  [81660674] kernel_thread_helper+0x4/0x10
  [81089340] ? flush_kthread_worker+0xa0/0xa0
  [81660670] ? gs_change+0x13/0x13

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: radeon issues on MacBook Pro 8,2

2012-01-21 Thread Seth Forshee
On Fri, Jan 20, 2012 at 11:09:29PM +0200, Pasi Kärkkäinen wrote:
 On Thu, Jan 19, 2012 at 02:53:17PM -0600, Seth Forshee wrote:
  On Thu, Jan 19, 2012 at 02:48:52PM -0500, Alex Deucher wrote:
   On Thu, Jan 19, 2012 at 12:18 PM, Seth Forshee
   seth.fors...@canonical.com wrote:
I'm seeing several issues related to the radeon driver on a MacBook Pro
8,2 with the following graphics card:
   
 ATI Technologies Inc Whistler [AMD Radeon HD 6600M Series] [1002:6741]
   
All problems were observed when using kernel version 3.2.1. None are
seen when using fglrx.
   
 1. Excessive power draw. When using the radeon driver ACPI reports a
   power draw of about 30W on an idle desktop. Using fglrx brings this
   number down to 15W.
   
   The power saving features of the open source driver are not yet as
   good as the closed source driver.  Please see the power management
   section of this page (http://wiki.x.org/wiki/RadeonFeature) for more
   info on the options currently available.
  
  The dynpm option makes a small difference, saving about 2W. I did notice
  an ocassional flash on the screen with this option, and the same flash
  each time I changed the power options.
  
 
 Btw how do you measure the power draw? 

You can get the instantaneous rate from the data under
/proc/acpi/battery, but I use a tool called powerstat [1], written by my
colleague Colin King. The advantage of powerstat is that it samples the
ACPI data over a period of time and reports the average and standard
deviation. That way I have a better idea of how much power is really
being drawn and the quality of the value reported.

[1] http://kernel.ubuntu.com/git?p=cking/powerstat.git
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


radeon issues on MacBook Pro 8,2

2012-01-20 Thread Seth Forshee
On Fri, Jan 20, 2012 at 11:09:29PM +0200, Pasi K?rkk?inen wrote:
> On Thu, Jan 19, 2012 at 02:53:17PM -0600, Seth Forshee wrote:
> > On Thu, Jan 19, 2012 at 02:48:52PM -0500, Alex Deucher wrote:
> > > On Thu, Jan 19, 2012 at 12:18 PM, Seth Forshee
> > >  wrote:
> > > > I'm seeing several issues related to the radeon driver on a MacBook Pro
> > > > 8,2 with the following graphics card:
> > > >
> > > > ?ATI Technologies Inc Whistler [AMD Radeon HD 6600M Series] [1002:6741]
> > > >
> > > > All problems were observed when using kernel version 3.2.1. None are
> > > > seen when using fglrx.
> > > >
> > > > ?1. Excessive power draw. When using the radeon driver ACPI reports a
> > > > ? ?power draw of about 30W on an idle desktop. Using fglrx brings this
> > > > ? ?number down to 15W.
> > > 
> > > The power saving features of the open source driver are not yet as
> > > good as the closed source driver.  Please see the power management
> > > section of this page (http://wiki.x.org/wiki/RadeonFeature) for more
> > > info on the options currently available.
> > 
> > The dynpm option makes a small difference, saving about 2W. I did notice
> > an ocassional flash on the screen with this option, and the same flash
> > each time I changed the power options.
> > 
> 
> Btw how do you measure the power draw? 

You can get the instantaneous rate from the data under
/proc/acpi/battery, but I use a tool called powerstat [1], written by my
colleague Colin King. The advantage of powerstat is that it samples the
ACPI data over a period of time and reports the average and standard
deviation. That way I have a better idea of how much power is really
being drawn and the quality of the value reported.

[1] http://kernel.ubuntu.com/git?p=cking/powerstat.git


radeon issues on MacBook Pro 8,2

2012-01-20 Thread Seth Forshee
On Fri, Jan 20, 2012 at 04:39:31PM -0500, Alex Deucher wrote:
> On Fri, Jan 20, 2012 at 4:12 PM, Seth Forshee
>  wrote:
> > On Fri, Jan 20, 2012 at 02:38:37PM -0500, Alex Deucher wrote:
> >> On Fri, Jan 20, 2012 at 10:53 AM, Seth Forshee
> >>  wrote:
> >> > On Thu, Jan 19, 2012 at 02:53:17PM -0600, Seth Forshee wrote:
> >> >> > > ?2. Occasional long delays when suspending. When this happens I see
> >> >> > > ? ?messages like following in dmesg:
> >> >> > >
> >> >> > > ? ? ?[drm:atom_op_jump] *ERROR* atombios stuck in loop for more 
> >> >> > > than 5secs aborting
> >> >> > > ? ? ?[drm:atom_execute_table_locked] *ERROR* atombios stuck 
> >> >> > > executing D44E (len 62, WS 0, PS 0) @ 0xD46A
> >> >> > >
> >> >> > > ? ?Sometimes one of suspend or resume hangs completely, but I can't
> >> >> > > ? ?tell which and am not sure whether or not it's related. I'm also
> >> >> > > ? ?testing a Mac Mini with the exact same card which does not seem 
> >> >> > > to
> >> >> > > ? ?suffer from this issue.
> >> >> > >
> >> >> > > ? ?I ran a bisections that identified f8d0edd (drm/radeon/kms: 
> >> >> > > improve
> >> >> > > ? ?DP detect logic) as introducing problems with suspend, and 
> >> >> > > reverting
> >> >> > > ? ?this patch on top of 3.2.1 does seem to eliminate both issues.
> >> >> > >
> >> >> >
> >> >> > That patch doesn't really affect the modesetting paths directly; it
> >> >> > looks like a red herring to me.
> >> >>
> >> >> Perhaps. I just started a run of 200 s3 cycles with the patch reverted
> >> >> to see if I can reproduce the issues. I can usually trigger the problem
> >> >> with 15 or fewer s3 cycles.
> >> >
> >> > The machine completed 200 s3 cycles with the patch reverted without long
> >> > delays, hangs, or any atombios error messages. Without reverting it
> >> > doesn't get through many at all before experiencing the errors and long
> >> > delays or hangs.
> >> >
> >> > I added a printout of the connector status resulting from the logic that
> >> > was changed by f8d0edd. With the logic prior to this commit it
> >> > consistently returns the status as disconnected, which is correct as I
> >> > have nothing connected. But with the improved logic the status is
> >> > sometimes reported as connected, and these coincide with the atombios
> >> > errors.
> >> >
> >>
> >> Do any of the disconnected displayport connectors get misdetected as
> >> connected during normal operation or does it only happen during
> >> suspend/resume?
> >
> > So far I've only seen them during suspend/resume.
> 
> Can you track down who is calling the connector->detect() callbacks
> during suspend and resume?

I got two different stack traces, see below.

And to slightly amend my statement above, I'm only seeing the wrong
status returned on the suspend side of things. The status during resume
always seems to be correct.

 Pid: 49, comm: kworker/0:2 Tainted: G C O 3.2.0-10-generic #17-Ubuntu
 Call Trace:
  [] radeon_dp_detect+0x1de/0x230 [radeon]
  [] output_poll_execute+0xbd/0x1a0 [drm_kms_helper]
  [] ? drm_helper_mode_fill_fb_struct+0x30/0x30 
[drm_kms_helper]
  [] process_one_work+0x11a/0x480
  [] worker_thread+0x164/0x370
  [] ? manage_workers.isra.30+0x130/0x130
  [] kthread+0x8c/0xa0
  [] kernel_thread_helper+0x4/0x10
  [] ? flush_kthread_worker+0xa0/0xa0
  [] ? gs_change+0x13/0x13

 Pid: 49, comm: kworker/0:2 Tainted: G C O 3.2.0-10-generic #17-Ubuntu
 Call Trace:
  [] radeon_dp_detect+0x1de/0x230 [radeon]
  [] drm_helper_probe_single_connector_modes+0x2c3/0x380 
[drm_kms_helper]
  [] drm_fb_helper_hotplug_event+0xf2/0x150 [drm_kms_helper]
  [] radeon_fb_output_poll_changed+0x15/0x20 [radeon]
  [] radeon_output_poll_changed+0x15/0x20 [radeon]
  [] output_poll_execute+0x190/0x1a0 [drm_kms_helper]
  [] ? drm_helper_mode_fill_fb_struct+0x30/0x30 
[drm_kms_helper]
  [] process_one_work+0x11a/0x480
  [] worker_thread+0x164/0x370
  [] ? manage_workers.isra.30+0x130/0x130
  [] kthread+0x8c/0xa0
  [] kernel_thread_helper+0x4/0x10
  [] ? flush_kthread_worker+0xa0/0xa0
  [] ? gs_change+0x13/0x13



radeon issues on MacBook Pro 8,2

2012-01-20 Thread Seth Forshee
On Fri, Jan 20, 2012 at 02:38:37PM -0500, Alex Deucher wrote:
> On Fri, Jan 20, 2012 at 10:53 AM, Seth Forshee
>  wrote:
> > On Thu, Jan 19, 2012 at 02:53:17PM -0600, Seth Forshee wrote:
> >> > > ?2. Occasional long delays when suspending. When this happens I see
> >> > > ? ?messages like following in dmesg:
> >> > >
> >> > > ? ? ?[drm:atom_op_jump] *ERROR* atombios stuck in loop for more than 
> >> > > 5secs aborting
> >> > > ? ? ?[drm:atom_execute_table_locked] *ERROR* atombios stuck executing 
> >> > > D44E (len 62, WS 0, PS 0) @ 0xD46A
> >> > >
> >> > > ? ?Sometimes one of suspend or resume hangs completely, but I can't
> >> > > ? ?tell which and am not sure whether or not it's related. I'm also
> >> > > ? ?testing a Mac Mini with the exact same card which does not seem to
> >> > > ? ?suffer from this issue.
> >> > >
> >> > > ? ?I ran a bisections that identified f8d0edd (drm/radeon/kms: improve
> >> > > ? ?DP detect logic) as introducing problems with suspend, and reverting
> >> > > ? ?this patch on top of 3.2.1 does seem to eliminate both issues.
> >> > >
> >> >
> >> > That patch doesn't really affect the modesetting paths directly; it
> >> > looks like a red herring to me.
> >>
> >> Perhaps. I just started a run of 200 s3 cycles with the patch reverted
> >> to see if I can reproduce the issues. I can usually trigger the problem
> >> with 15 or fewer s3 cycles.
> >
> > The machine completed 200 s3 cycles with the patch reverted without long
> > delays, hangs, or any atombios error messages. Without reverting it
> > doesn't get through many at all before experiencing the errors and long
> > delays or hangs.
> >
> > I added a printout of the connector status resulting from the logic that
> > was changed by f8d0edd. With the logic prior to this commit it
> > consistently returns the status as disconnected, which is correct as I
> > have nothing connected. But with the improved logic the status is
> > sometimes reported as connected, and these coincide with the atombios
> > errors.
> >
> 
> Do any of the disconnected displayport connectors get misdetected as
> connected during normal operation or does it only happen during
> suspend/resume?

So far I've only seen them during suspend/resume.


radeon issues on MacBook Pro 8,2

2012-01-20 Thread Seth Forshee
On Thu, Jan 19, 2012 at 02:53:17PM -0600, Seth Forshee wrote:
> > > ?2. Occasional long delays when suspending. When this happens I see
> > > ? ?messages like following in dmesg:
> > >
> > > ? ? ?[drm:atom_op_jump] *ERROR* atombios stuck in loop for more than 
> > > 5secs aborting
> > > ? ? ?[drm:atom_execute_table_locked] *ERROR* atombios stuck executing 
> > > D44E (len 62, WS 0, PS 0) @ 0xD46A
> > >
> > > ? ?Sometimes one of suspend or resume hangs completely, but I can't
> > > ? ?tell which and am not sure whether or not it's related. I'm also
> > > ? ?testing a Mac Mini with the exact same card which does not seem to
> > > ? ?suffer from this issue.
> > >
> > > ? ?I ran a bisections that identified f8d0edd (drm/radeon/kms: improve
> > > ? ?DP detect logic) as introducing problems with suspend, and reverting
> > > ? ?this patch on top of 3.2.1 does seem to eliminate both issues.
> > >
> > 
> > That patch doesn't really affect the modesetting paths directly; it
> > looks like a red herring to me.
> 
> Perhaps. I just started a run of 200 s3 cycles with the patch reverted
> to see if I can reproduce the issues. I can usually trigger the problem
> with 15 or fewer s3 cycles.

The machine completed 200 s3 cycles with the patch reverted without long
delays, hangs, or any atombios error messages. Without reverting it
doesn't get through many at all before experiencing the errors and long
delays or hangs. 

I added a printout of the connector status resulting from the logic that
was changed by f8d0edd. With the logic prior to this commit it
consistently returns the status as disconnected, which is correct as I
have nothing connected. But with the improved logic the status is
sometimes reported as connected, and these coincide with the atombios
errors.

Seth


radeon issues on MacBook Pro 8,2

2012-01-19 Thread Seth Forshee
On Thu, Jan 19, 2012 at 02:48:52PM -0500, Alex Deucher wrote:
> On Thu, Jan 19, 2012 at 12:18 PM, Seth Forshee
>  wrote:
> > I'm seeing several issues related to the radeon driver on a MacBook Pro
> > 8,2 with the following graphics card:
> >
> > ?ATI Technologies Inc Whistler [AMD Radeon HD 6600M Series] [1002:6741]
> >
> > All problems were observed when using kernel version 3.2.1. None are
> > seen when using fglrx.
> >
> > ?1. Excessive power draw. When using the radeon driver ACPI reports a
> > ? ?power draw of about 30W on an idle desktop. Using fglrx brings this
> > ? ?number down to 15W.
> 
> The power saving features of the open source driver are not yet as
> good as the closed source driver.  Please see the power management
> section of this page (http://wiki.x.org/wiki/RadeonFeature) for more
> info on the options currently available.

The dynpm option makes a small difference, saving about 2W. I did notice
an ocassional flash on the screen with this option, and the same flash
each time I changed the power options.

The only thing that improves things significatnly is the "low" profile
method, which gets it down to about 18.5W.

> > ?2. Occasional long delays when suspending. When this happens I see
> > ? ?messages like following in dmesg:
> >
> > ? ? ?[drm:atom_op_jump] *ERROR* atombios stuck in loop for more than 5secs 
> > aborting
> > ? ? ?[drm:atom_execute_table_locked] *ERROR* atombios stuck executing D44E 
> > (len 62, WS 0, PS 0) @ 0xD46A
> >
> > ? ?Sometimes one of suspend or resume hangs completely, but I can't
> > ? ?tell which and am not sure whether or not it's related. I'm also
> > ? ?testing a Mac Mini with the exact same card which does not seem to
> > ? ?suffer from this issue.
> >
> > ? ?I ran a bisections that identified f8d0edd (drm/radeon/kms: improve
> > ? ?DP detect logic) as introducing problems with suspend, and reverting
> > ? ?this patch on top of 3.2.1 does seem to eliminate both issues.
> >
> 
> That patch doesn't really affect the modesetting paths directly; it
> looks like a red herring to me.

Perhaps. I just started a run of 200 s3 cycles with the patch reverted
to see if I can reproduce the issues. I can usually trigger the problem
with 15 or fewer s3 cycles.

> > ?3. When the LVDS panel is powered off and back on, the display
> > ? ?flickers, as if the backlight is cycling rapidly between low and
> > ? ?high brightness. If the panel is left on this effect gradually
> > ? ?lessens and is eventually no longer noticable. This is not seen with
> > ? ?fglrx.
> >
> 
> For the sake of tracking this properly, it would probably be best to file a 
> bug:
> https://bugs.freedesktop.org
> Product: DRI
> Component: DRM/Radeon
> What connectors does your card actually have on it?  Please attach a
> copy of your dmesg output and vbios:
> (as root)
> (use lspci to get the bus id)
> cd /sys/bus/pci/devices/
> echo 1 > rom
> cat rom > /tmp/vbios.rom
> echo 0 > rom
> 
> Also, keep in mind that this is a mac so it's likely there may be
> wonky mac specific problems.

I filed bug #44955 for the flickering issue.

Thanks,
Seth


radeon issues on MacBook Pro 8,2

2012-01-19 Thread Seth Forshee
I'm seeing several issues related to the radeon driver on a MacBook Pro
8,2 with the following graphics card:

  ATI Technologies Inc Whistler [AMD Radeon HD 6600M Series] [1002:6741]

All problems were observed when using kernel version 3.2.1. None are
seen when using fglrx.

 1. Excessive power draw. When using the radeon driver ACPI reports a
power draw of about 30W on an idle desktop. Using fglrx brings this
number down to 15W.

 2. Occasional long delays when suspending. When this happens I see
messages like following in dmesg:

  [drm:atom_op_jump] *ERROR* atombios stuck in loop for more than 5secs 
aborting
  [drm:atom_execute_table_locked] *ERROR* atombios stuck executing D44E 
(len 62, WS 0, PS 0) @ 0xD46A

Sometimes one of suspend or resume hangs completely, but I can't
tell which and am not sure whether or not it's related. I'm also
testing a Mac Mini with the exact same card which does not seem to
suffer from this issue.

I ran a bisections that identified f8d0edd (drm/radeon/kms: improve
DP detect logic) as introducing problems with suspend, and reverting
this patch on top of 3.2.1 does seem to eliminate both issues.

 3. When the LVDS panel is powered off and back on, the display
flickers, as if the backlight is cycling rapidly between low and
high brightness. If the panel is left on this effect gradually
lessens and is eventually no longer noticable. This is not seen with
fglrx.

Thanks,
Seth


Re: radeon issues on MacBook Pro 8,2

2012-01-19 Thread Seth Forshee
On Thu, Jan 19, 2012 at 02:48:52PM -0500, Alex Deucher wrote:
 On Thu, Jan 19, 2012 at 12:18 PM, Seth Forshee
 seth.fors...@canonical.com wrote:
  I'm seeing several issues related to the radeon driver on a MacBook Pro
  8,2 with the following graphics card:
 
   ATI Technologies Inc Whistler [AMD Radeon HD 6600M Series] [1002:6741]
 
  All problems were observed when using kernel version 3.2.1. None are
  seen when using fglrx.
 
   1. Excessive power draw. When using the radeon driver ACPI reports a
     power draw of about 30W on an idle desktop. Using fglrx brings this
     number down to 15W.
 
 The power saving features of the open source driver are not yet as
 good as the closed source driver.  Please see the power management
 section of this page (http://wiki.x.org/wiki/RadeonFeature) for more
 info on the options currently available.

The dynpm option makes a small difference, saving about 2W. I did notice
an ocassional flash on the screen with this option, and the same flash
each time I changed the power options.

The only thing that improves things significatnly is the low profile
method, which gets it down to about 18.5W.

   2. Occasional long delays when suspending. When this happens I see
     messages like following in dmesg:
 
       [drm:atom_op_jump] *ERROR* atombios stuck in loop for more than 5secs 
  aborting
       [drm:atom_execute_table_locked] *ERROR* atombios stuck executing D44E 
  (len 62, WS 0, PS 0) @ 0xD46A
 
     Sometimes one of suspend or resume hangs completely, but I can't
     tell which and am not sure whether or not it's related. I'm also
     testing a Mac Mini with the exact same card which does not seem to
     suffer from this issue.
 
     I ran a bisections that identified f8d0edd (drm/radeon/kms: improve
     DP detect logic) as introducing problems with suspend, and reverting
     this patch on top of 3.2.1 does seem to eliminate both issues.
 
 
 That patch doesn't really affect the modesetting paths directly; it
 looks like a red herring to me.

Perhaps. I just started a run of 200 s3 cycles with the patch reverted
to see if I can reproduce the issues. I can usually trigger the problem
with 15 or fewer s3 cycles.

   3. When the LVDS panel is powered off and back on, the display
     flickers, as if the backlight is cycling rapidly between low and
     high brightness. If the panel is left on this effect gradually
     lessens and is eventually no longer noticable. This is not seen with
     fglrx.
 
 
 For the sake of tracking this properly, it would probably be best to file a 
 bug:
 https://bugs.freedesktop.org
 Product: DRI
 Component: DRM/Radeon
 What connectors does your card actually have on it?  Please attach a
 copy of your dmesg output and vbios:
 (as root)
 (use lspci to get the bus id)
 cd /sys/bus/pci/devices/pci bus id
 echo 1  rom
 cat rom  /tmp/vbios.rom
 echo 0  rom
 
 Also, keep in mind that this is a mac so it's likely there may be
 wonky mac specific problems.

I filed bug #44955 for the flickering issue.

Thanks,
Seth
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel