Lines Matching +full:mux +full:- +full:delay +full:- +full:config +full:- +full:us

1 // SPDX-License-Identifier: GPL-2.0-only
6 * Copyright (C) 2010-2012 Andreas Heider <andreas@meetr.de>
19 #include <linux/apple-gmux.h>
21 #include <linux/delay.h>
32 * A `Lattice XP2`_ on pre-retinas, a `Renesas R4F2113`_ on pre-T2 retinas.
37 * and has a GPIO to switch the eDP mux. The Intel CPU can interact with
41 * dual GPUs but no built-in display.)
45 * to access a pre-retina gmux are infixed ``_pio_``, those for a pre-T2
54 * https://www.nxp.com/docs/en/data-sheet/PCAL6524.pdf
63 const struct apple_gmux_config *config; member
112 return inb(gmux_data->iostart + port); in gmux_pio_read8()
118 outb(val, gmux_data->iostart + port); in gmux_pio_write8()
123 return inl(gmux_data->iostart + port); in gmux_pio_read32()
134 outb(tmpval, gmux_data->iostart + port + i); in gmux_pio_write32()
141 u8 gwr = inb(gmux_data->iostart + GMUX_PORT_WRITE); in gmux_index_wait_ready()
144 inb(gmux_data->iostart + GMUX_PORT_READ); in gmux_index_wait_ready()
145 gwr = inb(gmux_data->iostart + GMUX_PORT_WRITE); in gmux_index_wait_ready()
147 i--; in gmux_index_wait_ready()
156 u8 gwr = inb(gmux_data->iostart + GMUX_PORT_WRITE); in gmux_index_wait_complete()
159 gwr = inb(gmux_data->iostart + GMUX_PORT_WRITE); in gmux_index_wait_complete()
161 i--; in gmux_index_wait_complete()
165 inb(gmux_data->iostart + GMUX_PORT_READ); in gmux_index_wait_complete()
174 mutex_lock(&gmux_data->index_lock); in gmux_index_read8()
176 outb((port & 0xff), gmux_data->iostart + GMUX_PORT_READ); in gmux_index_read8()
178 val = inb(gmux_data->iostart + GMUX_PORT_VALUE); in gmux_index_read8()
179 mutex_unlock(&gmux_data->index_lock); in gmux_index_read8()
187 mutex_lock(&gmux_data->index_lock); in gmux_index_write8()
188 outb(val, gmux_data->iostart + GMUX_PORT_VALUE); in gmux_index_write8()
190 outb(port & 0xff, gmux_data->iostart + GMUX_PORT_WRITE); in gmux_index_write8()
192 mutex_unlock(&gmux_data->index_lock); in gmux_index_write8()
199 mutex_lock(&gmux_data->index_lock); in gmux_index_read32()
201 outb((port & 0xff), gmux_data->iostart + GMUX_PORT_READ); in gmux_index_read32()
203 val = inl(gmux_data->iostart + GMUX_PORT_VALUE); in gmux_index_read32()
204 mutex_unlock(&gmux_data->index_lock); in gmux_index_read32()
215 mutex_lock(&gmux_data->index_lock); in gmux_index_write32()
219 outb(tmpval, gmux_data->iostart + GMUX_PORT_VALUE + i); in gmux_index_write32()
223 outb(port & 0xff, gmux_data->iostart + GMUX_PORT_WRITE); in gmux_index_write32()
225 mutex_unlock(&gmux_data->index_lock); in gmux_index_write32()
231 u8 gwr = ioread8(gmux_data->iomem_base + GMUX_MMIO_COMMAND_SEND); in gmux_mmio_wait()
234 gwr = ioread8(gmux_data->iomem_base + GMUX_MMIO_COMMAND_SEND); in gmux_mmio_wait()
236 i--; in gmux_mmio_wait()
246 mutex_lock(&gmux_data->index_lock); in gmux_mmio_read8()
248 iowrite8((port & 0xff), gmux_data->iomem_base + GMUX_MMIO_PORT_SELECT); in gmux_mmio_read8()
250 gmux_data->iomem_base + GMUX_MMIO_COMMAND_SEND); in gmux_mmio_read8()
252 val = ioread8(gmux_data->iomem_base); in gmux_mmio_read8()
253 mutex_unlock(&gmux_data->index_lock); in gmux_mmio_read8()
261 mutex_lock(&gmux_data->index_lock); in gmux_mmio_write8()
263 iowrite8(val, gmux_data->iomem_base); in gmux_mmio_write8()
265 iowrite8(port & 0xff, gmux_data->iomem_base + GMUX_MMIO_PORT_SELECT); in gmux_mmio_write8()
267 gmux_data->iomem_base + GMUX_MMIO_COMMAND_SEND); in gmux_mmio_write8()
270 mutex_unlock(&gmux_data->index_lock); in gmux_mmio_write8()
277 mutex_lock(&gmux_data->index_lock); in gmux_mmio_read32()
279 iowrite8((port & 0xff), gmux_data->iomem_base + GMUX_MMIO_PORT_SELECT); in gmux_mmio_read32()
281 gmux_data->iomem_base + GMUX_MMIO_COMMAND_SEND); in gmux_mmio_read32()
283 val = ioread32be(gmux_data->iomem_base); in gmux_mmio_read32()
284 mutex_unlock(&gmux_data->index_lock); in gmux_mmio_read32()
292 mutex_lock(&gmux_data->index_lock); in gmux_mmio_write32()
293 iowrite32be(val, gmux_data->iomem_base); in gmux_mmio_write32()
294 iowrite8(port & 0xff, gmux_data->iomem_base + GMUX_MMIO_PORT_SELECT); in gmux_mmio_write32()
296 gmux_data->iomem_base + GMUX_MMIO_COMMAND_SEND); in gmux_mmio_write32()
298 mutex_unlock(&gmux_data->index_lock); in gmux_mmio_write32()
303 return gmux_data->config->read8(gmux_data, port); in gmux_read8()
308 return gmux_data->config->write8(gmux_data, port, val); in gmux_write8()
313 return gmux_data->config->read32(gmux_data, port); in gmux_read32()
319 return gmux_data->config->write32(gmux_data, port, val); in gmux_write32()
360 * DOC: Graphics mux
362 * On pre-retinas, the LVDS outputs of both GPUs feed into gmux which muxes
365 * synchronize it with the GPU switched to. This allows for a flicker-free
366 * switch that is imperceptible by the user (`US 8,687,007 B2`_).
374 * Pre-retinas are able to switch the panel's DDC pins separately.
382 * set up the output with link parameters pre-calibrated by the active GPU.
387 * eDP mux on retinas, the difference being support for 2.7 versus 5.4 Gbit/s.
393 * are still switchable by way of an `NXP CBTL03062`_ (on pre-retinas
394 * MBP8 2011 and MBP9 2012) or two `TI TS3DS10224`_ (on pre-t2 retinas) under
396 * external displays appear to it as phantoms which fail to link-train.
420 * variable ``gpu-power-prefs-fa4ce28d-b62f-4c99-9cc3-6815686e30f9`` (5th byte,
425 * .. _US 8,687,007 B2: https://pimg-fpiw.uspto.gov/fdd/07/870/086/0.pdf
431 …* .. _NXP CBTL03062: http://pdf.datasheetarchive.com/indexerfiles/Datasheets-SW16/DSASW00308511.…
438 gmux_data->switch_state_ddc = VGA_SWITCHEROO_IGD; in gmux_read_switch_state()
440 gmux_data->switch_state_ddc = VGA_SWITCHEROO_DIS; in gmux_read_switch_state()
443 gmux_data->switch_state_display = VGA_SWITCHEROO_DIS; in gmux_read_switch_state()
445 gmux_data->switch_state_display = VGA_SWITCHEROO_IGD; in gmux_read_switch_state()
448 gmux_data->switch_state_external = VGA_SWITCHEROO_IGD; in gmux_read_switch_state()
450 gmux_data->switch_state_external = VGA_SWITCHEROO_DIS; in gmux_read_switch_state()
455 if (gmux_data->switch_state_ddc == VGA_SWITCHEROO_IGD) in gmux_write_switch_state()
460 if (gmux_data->switch_state_display == VGA_SWITCHEROO_IGD) in gmux_write_switch_state()
465 if (gmux_data->switch_state_external == VGA_SWITCHEROO_IGD) in gmux_write_switch_state()
473 apple_gmux_data->switch_state_ddc = id; in gmux_switchto()
474 apple_gmux_data->switch_state_display = id; in gmux_switchto()
475 if (apple_gmux_data->external_switchable) in gmux_switchto()
476 apple_gmux_data->switch_state_external = id; in gmux_switchto()
486 apple_gmux_data->switch_state_ddc; in gmux_switch_ddc()
492 apple_gmux_data->switch_state_ddc = id; in gmux_switch_ddc()
513 reinit_completion(&gmux_data->powerchange_done); in gmux_set_discrete_state()
525 gmux_data->power_state = state; in gmux_set_discrete_state()
527 if (gmux_data->gpe >= 0 && in gmux_set_discrete_state()
528 !wait_for_completion_interruptible_timeout(&gmux_data->powerchange_done, in gmux_set_discrete_state()
550 if (pdev->vendor == PCI_VENDOR_ID_INTEL) in gmux_get_client_id()
552 else if (pdev->vendor == PCI_VENDOR_ID_NVIDIA && in gmux_get_client_id()
553 pdev->device == 0x0863) in gmux_get_client_id()
628 * Because Linux masquerades as Darwin, it ends up in the notification-only code
629 * path. On MMIO gmux's, this seems to lead to us being unable to clear interrupts,
659 if (gmux_data->config == &apple_gmux_mmio) in gmux_clear_interrupts()
660 acpi_execute_simple_method(gmux_data->dhandle, "GMSP", 0); in gmux_clear_interrupts()
677 complete(&gmux_data->powerchange_done); in gmux_notify_handler()
686 * # cat /sys/kernel/debug/apple_gmux/selected_port_data | xxd -p
697 struct apple_gmux_data *gmux_data = file->private_data; in gmux_selected_port_data_write()
700 return -EINVAL; in gmux_selected_port_data_write()
706 return -EFAULT; in gmux_selected_port_data_write()
708 gmux_write8(gmux_data, gmux_data->selected_port, data); in gmux_selected_port_data_write()
713 return -EFAULT; in gmux_selected_port_data_write()
715 gmux_write32(gmux_data, gmux_data->selected_port, data); in gmux_selected_port_data_write()
717 return -EINVAL; in gmux_selected_port_data_write()
725 struct apple_gmux_data *gmux_data = file->private_data; in gmux_selected_port_data_read()
728 data = gmux_read32(gmux_data, gmux_data->selected_port); in gmux_selected_port_data_read()
741 gmux_data->debug_dentry = debugfs_create_dir(KBUILD_MODNAME, NULL); in gmux_init_debugfs()
743 debugfs_create_u8("selected_port", 0644, gmux_data->debug_dentry, in gmux_init_debugfs()
744 &gmux_data->selected_port); in gmux_init_debugfs()
745 debugfs_create_file("selected_port_data", 0644, gmux_data->debug_dentry, in gmux_init_debugfs()
751 debugfs_remove_recursive(gmux_data->debug_dentry); in gmux_fini_debugfs()
770 if (gmux_data->power_state == VGA_SWITCHEROO_OFF) in gmux_resume()
771 gmux_set_discrete_state(gmux_data, gmux_data->power_state); in gmux_resume()
777 return to_pci_dev(dev)->is_thunderbolt; in is_thunderbolt()
788 int ret = -ENXIO; in gmux_probe()
795 return -EBUSY; in gmux_probe()
799 return -ENODEV; in gmux_probe()
804 return -ENOMEM; in gmux_probe()
809 gmux_data->config = &apple_gmux_mmio; in gmux_probe()
810 mutex_init(&gmux_data->index_lock); in gmux_probe()
813 gmux_data->iostart = res->start; in gmux_probe()
815 gmux_data->iolen = 16; in gmux_probe()
816 if (!request_mem_region(gmux_data->iostart, gmux_data->iolen, in gmux_probe()
821 gmux_data->iomem_base = ioremap(gmux_data->iostart, gmux_data->iolen); in gmux_probe()
822 if (!gmux_data->iomem_base) { in gmux_probe()
828 gmux_data->config = &apple_gmux_index; in gmux_probe()
829 mutex_init(&gmux_data->index_lock); in gmux_probe()
832 gmux_data->config = &apple_gmux_pio; in gmux_probe()
837 gmux_data->iostart = res->start; in gmux_probe()
838 gmux_data->iolen = resource_size(res); in gmux_probe()
840 if (!request_region(gmux_data->iostart, gmux_data->iolen, in gmux_probe()
847 if (gmux_data->config->read_version_as_u32) { in gmux_probe()
858 ver_release, gmux_data->config->name); in gmux_probe()
887 bdev = backlight_device_register("gmux_backlight", &pnp->dev, in gmux_probe()
894 gmux_data->bdev = bdev; in gmux_probe()
895 bdev->props.brightness = gmux_get_brightness(bdev); in gmux_probe()
899 gmux_data->power_state = VGA_SWITCHEROO_ON; in gmux_probe()
901 gmux_data->dhandle = ACPI_HANDLE(&pnp->dev); in gmux_probe()
902 if (!gmux_data->dhandle) { in gmux_probe()
904 dev_name(&pnp->dev)); in gmux_probe()
905 ret = -ENODEV; in gmux_probe()
909 status = acpi_evaluate_integer(gmux_data->dhandle, "GMGP", NULL, &gpe); in gmux_probe()
911 gmux_data->gpe = (int)gpe; in gmux_probe()
913 status = acpi_install_notify_handler(gmux_data->dhandle, in gmux_probe()
919 ret = -ENODEV; in gmux_probe()
923 status = acpi_enable_gpe(NULL, gmux_data->gpe); in gmux_probe()
931 gmux_data->gpe = -1; in gmux_probe()
938 gmux_data->external_switchable = in gmux_probe()
940 if (!gmux_data->external_switchable) in gmux_probe()
944 init_completion(&gmux_data->powerchange_done); in gmux_probe()
950 * and need eDP pre-calibration. They are distinguishable from in gmux_probe()
951 * pre-retinas by having an "indexed" or "T2" gmux. in gmux_probe()
953 * Pre-retina MacBook Pros can switch the panel's DDC separately. in gmux_probe()
955 ret = vga_switcheroo_register_handler(gmux_data->config->gmux_handler, in gmux_probe()
956 gmux_data->config->handler_flags); in gmux_probe()
968 if (gmux_data->gpe >= 0) in gmux_probe()
969 acpi_disable_gpe(NULL, gmux_data->gpe); in gmux_probe()
971 if (gmux_data->gpe >= 0) in gmux_probe()
972 acpi_remove_notify_handler(gmux_data->dhandle, in gmux_probe()
978 if (gmux_data->iomem_base) in gmux_probe()
979 iounmap(gmux_data->iomem_base); in gmux_probe()
981 if (gmux_data->config->resource_type == IORESOURCE_MEM) in gmux_probe()
982 release_mem_region(gmux_data->iostart, gmux_data->iolen); in gmux_probe()
984 release_region(gmux_data->iostart, gmux_data->iolen); in gmux_probe()
997 if (gmux_data->gpe >= 0) { in gmux_remove()
998 acpi_disable_gpe(NULL, gmux_data->gpe); in gmux_remove()
999 acpi_remove_notify_handler(gmux_data->dhandle, in gmux_remove()
1004 backlight_device_unregister(gmux_data->bdev); in gmux_remove()
1006 if (gmux_data->iomem_base) { in gmux_remove()
1007 iounmap(gmux_data->iomem_base); in gmux_remove()
1008 release_mem_region(gmux_data->iostart, gmux_data->iolen); in gmux_remove()
1010 release_region(gmux_data->iostart, gmux_data->iolen); in gmux_remove()
1026 .name = "apple-gmux",