diff options
Diffstat (limited to 'drivers/platform/x86/apple-gmux.c')
-rw-r--r-- | drivers/platform/x86/apple-gmux.c | 48 |
1 files changed, 47 insertions, 1 deletions
diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c index 66d6d22c239c..6808715003f6 100644 --- a/drivers/platform/x86/apple-gmux.c +++ b/drivers/platform/x86/apple-gmux.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
23 | #include <linux/pci.h> | 23 | #include <linux/pci.h> |
24 | #include <linux/vga_switcheroo.h> | 24 | #include <linux/vga_switcheroo.h> |
25 | #include <linux/vgaarb.h> | ||
25 | #include <acpi/video.h> | 26 | #include <acpi/video.h> |
26 | #include <asm/io.h> | 27 | #include <asm/io.h> |
27 | 28 | ||
@@ -31,6 +32,7 @@ struct apple_gmux_data { | |||
31 | bool indexed; | 32 | bool indexed; |
32 | struct mutex index_lock; | 33 | struct mutex index_lock; |
33 | 34 | ||
35 | struct pci_dev *pdev; | ||
34 | struct backlight_device *bdev; | 36 | struct backlight_device *bdev; |
35 | 37 | ||
36 | /* switcheroo data */ | 38 | /* switcheroo data */ |
@@ -415,6 +417,23 @@ static int gmux_resume(struct device *dev) | |||
415 | return 0; | 417 | return 0; |
416 | } | 418 | } |
417 | 419 | ||
420 | static struct pci_dev *gmux_get_io_pdev(void) | ||
421 | { | ||
422 | struct pci_dev *pdev = NULL; | ||
423 | |||
424 | while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev))) { | ||
425 | u16 cmd; | ||
426 | |||
427 | pci_read_config_word(pdev, PCI_COMMAND, &cmd); | ||
428 | if (!(cmd & PCI_COMMAND_IO)) | ||
429 | continue; | ||
430 | |||
431 | return pdev; | ||
432 | } | ||
433 | |||
434 | return NULL; | ||
435 | } | ||
436 | |||
418 | static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) | 437 | static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) |
419 | { | 438 | { |
420 | struct apple_gmux_data *gmux_data; | 439 | struct apple_gmux_data *gmux_data; |
@@ -425,6 +444,7 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) | |||
425 | int ret = -ENXIO; | 444 | int ret = -ENXIO; |
426 | acpi_status status; | 445 | acpi_status status; |
427 | unsigned long long gpe; | 446 | unsigned long long gpe; |
447 | struct pci_dev *pdev = NULL; | ||
428 | 448 | ||
429 | if (apple_gmux_data) | 449 | if (apple_gmux_data) |
430 | return -EBUSY; | 450 | return -EBUSY; |
@@ -475,7 +495,7 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) | |||
475 | ver_minor = (version >> 16) & 0xff; | 495 | ver_minor = (version >> 16) & 0xff; |
476 | ver_release = (version >> 8) & 0xff; | 496 | ver_release = (version >> 8) & 0xff; |
477 | } else { | 497 | } else { |
478 | pr_info("gmux device not present\n"); | 498 | pr_info("gmux device not present or IO disabled\n"); |
479 | ret = -ENODEV; | 499 | ret = -ENODEV; |
480 | goto err_release; | 500 | goto err_release; |
481 | } | 501 | } |
@@ -483,6 +503,23 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) | |||
483 | pr_info("Found gmux version %d.%d.%d [%s]\n", ver_major, ver_minor, | 503 | pr_info("Found gmux version %d.%d.%d [%s]\n", ver_major, ver_minor, |
484 | ver_release, (gmux_data->indexed ? "indexed" : "classic")); | 504 | ver_release, (gmux_data->indexed ? "indexed" : "classic")); |
485 | 505 | ||
506 | /* | ||
507 | * Apple systems with gmux are EFI based and normally don't use | ||
508 | * VGA. In addition changing IO+MEM ownership between IGP and dGPU | ||
509 | * disables IO/MEM used for backlight control on some systems. | ||
510 | * Lock IO+MEM to GPU with active IO to prevent switch. | ||
511 | */ | ||
512 | pdev = gmux_get_io_pdev(); | ||
513 | if (pdev && vga_tryget(pdev, | ||
514 | VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM)) { | ||
515 | pr_err("IO+MEM vgaarb-locking for PCI:%s failed\n", | ||
516 | pci_name(pdev)); | ||
517 | ret = -EBUSY; | ||
518 | goto err_release; | ||
519 | } else if (pdev) | ||
520 | pr_info("locked IO for PCI:%s\n", pci_name(pdev)); | ||
521 | gmux_data->pdev = pdev; | ||
522 | |||
486 | memset(&props, 0, sizeof(props)); | 523 | memset(&props, 0, sizeof(props)); |
487 | props.type = BACKLIGHT_PLATFORM; | 524 | props.type = BACKLIGHT_PLATFORM; |
488 | props.max_brightness = gmux_read32(gmux_data, GMUX_PORT_MAX_BRIGHTNESS); | 525 | props.max_brightness = gmux_read32(gmux_data, GMUX_PORT_MAX_BRIGHTNESS); |
@@ -574,6 +611,10 @@ err_enable_gpe: | |||
574 | err_notify: | 611 | err_notify: |
575 | backlight_device_unregister(bdev); | 612 | backlight_device_unregister(bdev); |
576 | err_release: | 613 | err_release: |
614 | if (gmux_data->pdev) | ||
615 | vga_put(gmux_data->pdev, | ||
616 | VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM); | ||
617 | pci_dev_put(pdev); | ||
577 | release_region(gmux_data->iostart, gmux_data->iolen); | 618 | release_region(gmux_data->iostart, gmux_data->iolen); |
578 | err_free: | 619 | err_free: |
579 | kfree(gmux_data); | 620 | kfree(gmux_data); |
@@ -593,6 +634,11 @@ static void gmux_remove(struct pnp_dev *pnp) | |||
593 | &gmux_notify_handler); | 634 | &gmux_notify_handler); |
594 | } | 635 | } |
595 | 636 | ||
637 | if (gmux_data->pdev) { | ||
638 | vga_put(gmux_data->pdev, | ||
639 | VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM); | ||
640 | pci_dev_put(gmux_data->pdev); | ||
641 | } | ||
596 | backlight_device_unregister(gmux_data->bdev); | 642 | backlight_device_unregister(gmux_data->bdev); |
597 | 643 | ||
598 | release_region(gmux_data->iostart, gmux_data->iolen); | 644 | release_region(gmux_data->iostart, gmux_data->iolen); |