diff options
| -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 b9429fbf1cd8..e743b03f50da 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); |
