root/drivers/platform/x86/apple-gmux.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. gmux_pio_read8
  2. gmux_pio_write8
  3. gmux_pio_read32
  4. gmux_pio_write32
  5. gmux_index_wait_ready
  6. gmux_index_wait_complete
  7. gmux_index_read8
  8. gmux_index_write8
  9. gmux_index_read32
  10. gmux_index_write32
  11. gmux_read8
  12. gmux_write8
  13. gmux_read32
  14. gmux_write32
  15. gmux_is_indexed
  16. gmux_get_brightness
  17. gmux_update_status
  18. gmux_read_switch_state
  19. gmux_write_switch_state
  20. gmux_switchto
  21. gmux_switch_ddc
  22. gmux_set_discrete_state
  23. gmux_set_power_state
  24. gmux_get_client_id
  25. gmux_disable_interrupts
  26. gmux_enable_interrupts
  27. gmux_interrupt_get_status
  28. gmux_clear_interrupts
  29. gmux_notify_handler
  30. gmux_suspend
  31. gmux_resume
  32. is_thunderbolt
  33. gmux_probe
  34. gmux_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  *  Gmux driver for Apple laptops
   4  *
   5  *  Copyright (C) Canonical Ltd. <seth.forshee@canonical.com>
   6  *  Copyright (C) 2010-2012 Andreas Heider <andreas@meetr.de>
   7  *  Copyright (C) 2015 Lukas Wunner <lukas@wunner.de>
   8  */
   9 
  10 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  11 
  12 #include <linux/module.h>
  13 #include <linux/kernel.h>
  14 #include <linux/init.h>
  15 #include <linux/backlight.h>
  16 #include <linux/acpi.h>
  17 #include <linux/pnp.h>
  18 #include <linux/apple_bl.h>
  19 #include <linux/apple-gmux.h>
  20 #include <linux/slab.h>
  21 #include <linux/delay.h>
  22 #include <linux/pci.h>
  23 #include <linux/vga_switcheroo.h>
  24 #include <acpi/video.h>
  25 #include <asm/io.h>
  26 
  27 /**
  28  * DOC: Overview
  29  *
  30  * gmux is a microcontroller built into the MacBook Pro to support dual GPUs:
  31  * A `Lattice XP2`_ on pre-retinas, a `Renesas R4F2113`_ on retinas.
  32  *
  33  * (The MacPro6,1 2013 also has a gmux, however it is unclear why since it has
  34  * dual GPUs but no built-in display.)
  35  *
  36  * gmux is connected to the LPC bus of the southbridge. Its I/O ports are
  37  * accessed differently depending on the microcontroller: Driver functions
  38  * to access a pre-retina gmux are infixed ``_pio_``, those for a retina gmux
  39  * are infixed ``_index_``.
  40  *
  41  * .. _Lattice XP2:
  42  *     http://www.latticesemi.com/en/Products/FPGAandCPLD/LatticeXP2.aspx
  43  * .. _Renesas R4F2113:
  44  *     http://www.renesas.com/products/mpumcu/h8s/h8s2100/h8s2113/index.jsp
  45  */
  46 
  47 struct apple_gmux_data {
  48         unsigned long iostart;
  49         unsigned long iolen;
  50         bool indexed;
  51         struct mutex index_lock;
  52 
  53         struct backlight_device *bdev;
  54 
  55         /* switcheroo data */
  56         acpi_handle dhandle;
  57         int gpe;
  58         bool external_switchable;
  59         enum vga_switcheroo_client_id switch_state_display;
  60         enum vga_switcheroo_client_id switch_state_ddc;
  61         enum vga_switcheroo_client_id switch_state_external;
  62         enum vga_switcheroo_state power_state;
  63         struct completion powerchange_done;
  64 };
  65 
  66 static struct apple_gmux_data *apple_gmux_data;
  67 
  68 /*
  69  * gmux port offsets. Many of these are not yet used, but may be in the
  70  * future, and it's useful to have them documented here anyhow.
  71  */
  72 #define GMUX_PORT_VERSION_MAJOR         0x04
  73 #define GMUX_PORT_VERSION_MINOR         0x05
  74 #define GMUX_PORT_VERSION_RELEASE       0x06
  75 #define GMUX_PORT_SWITCH_DISPLAY        0x10
  76 #define GMUX_PORT_SWITCH_GET_DISPLAY    0x11
  77 #define GMUX_PORT_INTERRUPT_ENABLE      0x14
  78 #define GMUX_PORT_INTERRUPT_STATUS      0x16
  79 #define GMUX_PORT_SWITCH_DDC            0x28
  80 #define GMUX_PORT_SWITCH_EXTERNAL       0x40
  81 #define GMUX_PORT_SWITCH_GET_EXTERNAL   0x41
  82 #define GMUX_PORT_DISCRETE_POWER        0x50
  83 #define GMUX_PORT_MAX_BRIGHTNESS        0x70
  84 #define GMUX_PORT_BRIGHTNESS            0x74
  85 #define GMUX_PORT_VALUE                 0xc2
  86 #define GMUX_PORT_READ                  0xd0
  87 #define GMUX_PORT_WRITE                 0xd4
  88 
  89 #define GMUX_MIN_IO_LEN                 (GMUX_PORT_BRIGHTNESS + 4)
  90 
  91 #define GMUX_INTERRUPT_ENABLE           0xff
  92 #define GMUX_INTERRUPT_DISABLE          0x00
  93 
  94 #define GMUX_INTERRUPT_STATUS_ACTIVE    0
  95 #define GMUX_INTERRUPT_STATUS_DISPLAY   (1 << 0)
  96 #define GMUX_INTERRUPT_STATUS_POWER     (1 << 2)
  97 #define GMUX_INTERRUPT_STATUS_HOTPLUG   (1 << 3)
  98 
  99 #define GMUX_BRIGHTNESS_MASK            0x00ffffff
 100 #define GMUX_MAX_BRIGHTNESS             GMUX_BRIGHTNESS_MASK
 101 
 102 static u8 gmux_pio_read8(struct apple_gmux_data *gmux_data, int port)
 103 {
 104         return inb(gmux_data->iostart + port);
 105 }
 106 
 107 static void gmux_pio_write8(struct apple_gmux_data *gmux_data, int port,
 108                                u8 val)
 109 {
 110         outb(val, gmux_data->iostart + port);
 111 }
 112 
 113 static u32 gmux_pio_read32(struct apple_gmux_data *gmux_data, int port)
 114 {
 115         return inl(gmux_data->iostart + port);
 116 }
 117 
 118 static void gmux_pio_write32(struct apple_gmux_data *gmux_data, int port,
 119                              u32 val)
 120 {
 121         int i;
 122         u8 tmpval;
 123 
 124         for (i = 0; i < 4; i++) {
 125                 tmpval = (val >> (i * 8)) & 0xff;
 126                 outb(tmpval, gmux_data->iostart + port + i);
 127         }
 128 }
 129 
 130 static int gmux_index_wait_ready(struct apple_gmux_data *gmux_data)
 131 {
 132         int i = 200;
 133         u8 gwr = inb(gmux_data->iostart + GMUX_PORT_WRITE);
 134 
 135         while (i && (gwr & 0x01)) {
 136                 inb(gmux_data->iostart + GMUX_PORT_READ);
 137                 gwr = inb(gmux_data->iostart + GMUX_PORT_WRITE);
 138                 udelay(100);
 139                 i--;
 140         }
 141 
 142         return !!i;
 143 }
 144 
 145 static int gmux_index_wait_complete(struct apple_gmux_data *gmux_data)
 146 {
 147         int i = 200;
 148         u8 gwr = inb(gmux_data->iostart + GMUX_PORT_WRITE);
 149 
 150         while (i && !(gwr & 0x01)) {
 151                 gwr = inb(gmux_data->iostart + GMUX_PORT_WRITE);
 152                 udelay(100);
 153                 i--;
 154         }
 155 
 156         if (gwr & 0x01)
 157                 inb(gmux_data->iostart + GMUX_PORT_READ);
 158 
 159         return !!i;
 160 }
 161 
 162 static u8 gmux_index_read8(struct apple_gmux_data *gmux_data, int port)
 163 {
 164         u8 val;
 165 
 166         mutex_lock(&gmux_data->index_lock);
 167         gmux_index_wait_ready(gmux_data);
 168         outb((port & 0xff), gmux_data->iostart + GMUX_PORT_READ);
 169         gmux_index_wait_complete(gmux_data);
 170         val = inb(gmux_data->iostart + GMUX_PORT_VALUE);
 171         mutex_unlock(&gmux_data->index_lock);
 172 
 173         return val;
 174 }
 175 
 176 static void gmux_index_write8(struct apple_gmux_data *gmux_data, int port,
 177                               u8 val)
 178 {
 179         mutex_lock(&gmux_data->index_lock);
 180         outb(val, gmux_data->iostart + GMUX_PORT_VALUE);
 181         gmux_index_wait_ready(gmux_data);
 182         outb(port & 0xff, gmux_data->iostart + GMUX_PORT_WRITE);
 183         gmux_index_wait_complete(gmux_data);
 184         mutex_unlock(&gmux_data->index_lock);
 185 }
 186 
 187 static u32 gmux_index_read32(struct apple_gmux_data *gmux_data, int port)
 188 {
 189         u32 val;
 190 
 191         mutex_lock(&gmux_data->index_lock);
 192         gmux_index_wait_ready(gmux_data);
 193         outb((port & 0xff), gmux_data->iostart + GMUX_PORT_READ);
 194         gmux_index_wait_complete(gmux_data);
 195         val = inl(gmux_data->iostart + GMUX_PORT_VALUE);
 196         mutex_unlock(&gmux_data->index_lock);
 197 
 198         return val;
 199 }
 200 
 201 static void gmux_index_write32(struct apple_gmux_data *gmux_data, int port,
 202                                u32 val)
 203 {
 204         int i;
 205         u8 tmpval;
 206 
 207         mutex_lock(&gmux_data->index_lock);
 208 
 209         for (i = 0; i < 4; i++) {
 210                 tmpval = (val >> (i * 8)) & 0xff;
 211                 outb(tmpval, gmux_data->iostart + GMUX_PORT_VALUE + i);
 212         }
 213 
 214         gmux_index_wait_ready(gmux_data);
 215         outb(port & 0xff, gmux_data->iostart + GMUX_PORT_WRITE);
 216         gmux_index_wait_complete(gmux_data);
 217         mutex_unlock(&gmux_data->index_lock);
 218 }
 219 
 220 static u8 gmux_read8(struct apple_gmux_data *gmux_data, int port)
 221 {
 222         if (gmux_data->indexed)
 223                 return gmux_index_read8(gmux_data, port);
 224         else
 225                 return gmux_pio_read8(gmux_data, port);
 226 }
 227 
 228 static void gmux_write8(struct apple_gmux_data *gmux_data, int port, u8 val)
 229 {
 230         if (gmux_data->indexed)
 231                 gmux_index_write8(gmux_data, port, val);
 232         else
 233                 gmux_pio_write8(gmux_data, port, val);
 234 }
 235 
 236 static u32 gmux_read32(struct apple_gmux_data *gmux_data, int port)
 237 {
 238         if (gmux_data->indexed)
 239                 return gmux_index_read32(gmux_data, port);
 240         else
 241                 return gmux_pio_read32(gmux_data, port);
 242 }
 243 
 244 static void gmux_write32(struct apple_gmux_data *gmux_data, int port,
 245                              u32 val)
 246 {
 247         if (gmux_data->indexed)
 248                 gmux_index_write32(gmux_data, port, val);
 249         else
 250                 gmux_pio_write32(gmux_data, port, val);
 251 }
 252 
 253 static bool gmux_is_indexed(struct apple_gmux_data *gmux_data)
 254 {
 255         u16 val;
 256 
 257         outb(0xaa, gmux_data->iostart + 0xcc);
 258         outb(0x55, gmux_data->iostart + 0xcd);
 259         outb(0x00, gmux_data->iostart + 0xce);
 260 
 261         val = inb(gmux_data->iostart + 0xcc) |
 262                 (inb(gmux_data->iostart + 0xcd) << 8);
 263 
 264         if (val == 0x55aa)
 265                 return true;
 266 
 267         return false;
 268 }
 269 
 270 /**
 271  * DOC: Backlight control
 272  *
 273  * On single GPU MacBooks, the PWM signal for the backlight is generated by
 274  * the GPU. On dual GPU MacBook Pros by contrast, either GPU may be suspended
 275  * to conserve energy. Hence the PWM signal needs to be generated by a separate
 276  * backlight driver which is controlled by gmux. The earliest generation
 277  * MBP5 2008/09 uses a `TI LP8543`_ backlight driver. All newer models
 278  * use a `TI LP8545`_.
 279  *
 280  * .. _TI LP8543: http://www.ti.com/lit/ds/symlink/lp8543.pdf
 281  * .. _TI LP8545: http://www.ti.com/lit/ds/symlink/lp8545.pdf
 282  */
 283 
 284 static int gmux_get_brightness(struct backlight_device *bd)
 285 {
 286         struct apple_gmux_data *gmux_data = bl_get_data(bd);
 287         return gmux_read32(gmux_data, GMUX_PORT_BRIGHTNESS) &
 288                GMUX_BRIGHTNESS_MASK;
 289 }
 290 
 291 static int gmux_update_status(struct backlight_device *bd)
 292 {
 293         struct apple_gmux_data *gmux_data = bl_get_data(bd);
 294         u32 brightness = bd->props.brightness;
 295 
 296         if (bd->props.state & BL_CORE_SUSPENDED)
 297                 return 0;
 298 
 299         gmux_write32(gmux_data, GMUX_PORT_BRIGHTNESS, brightness);
 300 
 301         return 0;
 302 }
 303 
 304 static const struct backlight_ops gmux_bl_ops = {
 305         .options = BL_CORE_SUSPENDRESUME,
 306         .get_brightness = gmux_get_brightness,
 307         .update_status = gmux_update_status,
 308 };
 309 
 310 /**
 311  * DOC: Graphics mux
 312  *
 313  * On pre-retinas, the LVDS outputs of both GPUs feed into gmux which muxes
 314  * either of them to the panel. One of the tricks gmux has up its sleeve is
 315  * to lengthen the blanking interval of its output during a switch to
 316  * synchronize it with the GPU switched to. This allows for a flicker-free
 317  * switch that is imperceptible by the user (`US 8,687,007 B2`_).
 318  *
 319  * On retinas, muxing is no longer done by gmux itself, but by a separate
 320  * chip which is controlled by gmux. The chip is triple sourced, it is
 321  * either an `NXP CBTL06142`_, `TI HD3SS212`_ or `Pericom PI3VDP12412`_.
 322  * The panel is driven with eDP instead of LVDS since the pixel clock
 323  * required for retina resolution exceeds LVDS' limits.
 324  *
 325  * Pre-retinas are able to switch the panel's DDC pins separately.
 326  * This is handled by a `TI SN74LV4066A`_ which is controlled by gmux.
 327  * The inactive GPU can thus probe the panel's EDID without switching over
 328  * the entire panel. Retinas lack this functionality as the chips used for
 329  * eDP muxing are incapable of switching the AUX channel separately (see
 330  * the linked data sheets, Pericom would be capable but this is unused).
 331  * However the retina panel has the NO_AUX_HANDSHAKE_LINK_TRAINING bit set
 332  * in its DPCD, allowing the inactive GPU to skip the AUX handshake and
 333  * set up the output with link parameters pre-calibrated by the active GPU.
 334  *
 335  * The external DP port is only fully switchable on the first two unibody
 336  * MacBook Pro generations, MBP5 2008/09 and MBP6 2010. This is done by an
 337  * `NXP CBTL06141`_ which is controlled by gmux. It's the predecessor of the
 338  * eDP mux on retinas, the difference being support for 2.7 versus 5.4 Gbit/s.
 339  *
 340  * The following MacBook Pro generations replaced the external DP port with a
 341  * combined DP/Thunderbolt port and lost the ability to switch it between GPUs,
 342  * connecting it either to the discrete GPU or the Thunderbolt controller.
 343  * Oddly enough, while the full port is no longer switchable, AUX and HPD
 344  * are still switchable by way of an `NXP CBTL03062`_ (on pre-retinas
 345  * MBP8 2011 and MBP9 2012) or two `TI TS3DS10224`_ (on retinas) under the
 346  * control of gmux. Since the integrated GPU is missing the main link,
 347  * external displays appear to it as phantoms which fail to link-train.
 348  *
 349  * gmux receives the HPD signal of all display connectors and sends an
 350  * interrupt on hotplug. On generations which cannot switch external ports,
 351  * the discrete GPU can then be woken to drive the newly connected display.
 352  * The ability to switch AUX on these generations could be used to improve
 353  * reliability of hotplug detection by having the integrated GPU poll the
 354  * ports while the discrete GPU is asleep, but currently we do not make use
 355  * of this feature.
 356  *
 357  * Our switching policy for the external port is that on those generations
 358  * which are able to switch it fully, the port is switched together with the
 359  * panel when IGD / DIS commands are issued to vga_switcheroo. It is thus
 360  * possible to drive e.g. a beamer on battery power with the integrated GPU.
 361  * The user may manually switch to the discrete GPU if more performance is
 362  * needed.
 363  *
 364  * On all newer generations, the external port can only be driven by the
 365  * discrete GPU. If a display is plugged in while the panel is switched to
 366  * the integrated GPU, *both* GPUs will be in use for maximum performance.
 367  * To decrease power consumption, the user may manually switch to the
 368  * discrete GPU, thereby suspending the integrated GPU.
 369  *
 370  * gmux' initial switch state on bootup is user configurable via the EFI
 371  * variable ``gpu-power-prefs-fa4ce28d-b62f-4c99-9cc3-6815686e30f9`` (5th byte,
 372  * 1 = IGD, 0 = DIS). Based on this setting, the EFI firmware tells gmux to
 373  * switch the panel and the external DP connector and allocates a framebuffer
 374  * for the selected GPU.
 375  *
 376  * .. _US 8,687,007 B2: http://pimg-fpiw.uspto.gov/fdd/07/870/086/0.pdf
 377  * .. _NXP CBTL06141:   http://www.nxp.com/documents/data_sheet/CBTL06141.pdf
 378  * .. _NXP CBTL06142:   http://www.nxp.com/documents/data_sheet/CBTL06141.pdf
 379  * .. _TI HD3SS212:     http://www.ti.com/lit/ds/symlink/hd3ss212.pdf
 380  * .. _Pericom PI3VDP12412: https://www.pericom.com/assets/Datasheets/PI3VDP12412.pdf
 381  * .. _TI SN74LV4066A:  http://www.ti.com/lit/ds/symlink/sn74lv4066a.pdf
 382  * .. _NXP CBTL03062:   http://pdf.datasheetarchive.com/indexerfiles/Datasheets-SW16/DSASW00308511.pdf
 383  * .. _TI TS3DS10224:   http://www.ti.com/lit/ds/symlink/ts3ds10224.pdf
 384  */
 385 
 386 static void gmux_read_switch_state(struct apple_gmux_data *gmux_data)
 387 {
 388         if (gmux_read8(gmux_data, GMUX_PORT_SWITCH_DDC) == 1)
 389                 gmux_data->switch_state_ddc = VGA_SWITCHEROO_IGD;
 390         else
 391                 gmux_data->switch_state_ddc = VGA_SWITCHEROO_DIS;
 392 
 393         if (gmux_read8(gmux_data, GMUX_PORT_SWITCH_DISPLAY) == 2)
 394                 gmux_data->switch_state_display = VGA_SWITCHEROO_IGD;
 395         else
 396                 gmux_data->switch_state_display = VGA_SWITCHEROO_DIS;
 397 
 398         if (gmux_read8(gmux_data, GMUX_PORT_SWITCH_EXTERNAL) == 2)
 399                 gmux_data->switch_state_external = VGA_SWITCHEROO_IGD;
 400         else
 401                 gmux_data->switch_state_external = VGA_SWITCHEROO_DIS;
 402 }
 403 
 404 static void gmux_write_switch_state(struct apple_gmux_data *gmux_data)
 405 {
 406         if (gmux_data->switch_state_ddc == VGA_SWITCHEROO_IGD)
 407                 gmux_write8(gmux_data, GMUX_PORT_SWITCH_DDC, 1);
 408         else
 409                 gmux_write8(gmux_data, GMUX_PORT_SWITCH_DDC, 2);
 410 
 411         if (gmux_data->switch_state_display == VGA_SWITCHEROO_IGD)
 412                 gmux_write8(gmux_data, GMUX_PORT_SWITCH_DISPLAY, 2);
 413         else
 414                 gmux_write8(gmux_data, GMUX_PORT_SWITCH_DISPLAY, 3);
 415 
 416         if (gmux_data->switch_state_external == VGA_SWITCHEROO_IGD)
 417                 gmux_write8(gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 2);
 418         else
 419                 gmux_write8(gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 3);
 420 }
 421 
 422 static int gmux_switchto(enum vga_switcheroo_client_id id)
 423 {
 424         apple_gmux_data->switch_state_ddc = id;
 425         apple_gmux_data->switch_state_display = id;
 426         if (apple_gmux_data->external_switchable)
 427                 apple_gmux_data->switch_state_external = id;
 428 
 429         gmux_write_switch_state(apple_gmux_data);
 430 
 431         return 0;
 432 }
 433 
 434 static int gmux_switch_ddc(enum vga_switcheroo_client_id id)
 435 {
 436         enum vga_switcheroo_client_id old_ddc_owner =
 437                 apple_gmux_data->switch_state_ddc;
 438 
 439         if (id == old_ddc_owner)
 440                 return id;
 441 
 442         pr_debug("Switching DDC from %d to %d\n", old_ddc_owner, id);
 443         apple_gmux_data->switch_state_ddc = id;
 444 
 445         if (id == VGA_SWITCHEROO_IGD)
 446                 gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 1);
 447         else
 448                 gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 2);
 449 
 450         return old_ddc_owner;
 451 }
 452 
 453 /**
 454  * DOC: Power control
 455  *
 456  * gmux is able to cut power to the discrete GPU. It automatically takes care
 457  * of the correct sequence to tear down and bring up the power rails for
 458  * core voltage, VRAM and PCIe.
 459  */
 460 
 461 static int gmux_set_discrete_state(struct apple_gmux_data *gmux_data,
 462                                    enum vga_switcheroo_state state)
 463 {
 464         reinit_completion(&gmux_data->powerchange_done);
 465 
 466         if (state == VGA_SWITCHEROO_ON) {
 467                 gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 1);
 468                 gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 3);
 469                 pr_debug("Discrete card powered up\n");
 470         } else {
 471                 gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 1);
 472                 gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 0);
 473                 pr_debug("Discrete card powered down\n");
 474         }
 475 
 476         gmux_data->power_state = state;
 477 
 478         if (gmux_data->gpe >= 0 &&
 479             !wait_for_completion_interruptible_timeout(&gmux_data->powerchange_done,
 480                                                        msecs_to_jiffies(200)))
 481                 pr_warn("Timeout waiting for gmux switch to complete\n");
 482 
 483         return 0;
 484 }
 485 
 486 static int gmux_set_power_state(enum vga_switcheroo_client_id id,
 487                                 enum vga_switcheroo_state state)
 488 {
 489         if (id == VGA_SWITCHEROO_IGD)
 490                 return 0;
 491 
 492         return gmux_set_discrete_state(apple_gmux_data, state);
 493 }
 494 
 495 static enum vga_switcheroo_client_id gmux_get_client_id(struct pci_dev *pdev)
 496 {
 497         /*
 498          * Early Macbook Pros with switchable graphics use nvidia
 499          * integrated graphics. Hardcode that the 9400M is integrated.
 500          */
 501         if (pdev->vendor == PCI_VENDOR_ID_INTEL)
 502                 return VGA_SWITCHEROO_IGD;
 503         else if (pdev->vendor == PCI_VENDOR_ID_NVIDIA &&
 504                  pdev->device == 0x0863)
 505                 return VGA_SWITCHEROO_IGD;
 506         else
 507                 return VGA_SWITCHEROO_DIS;
 508 }
 509 
 510 static const struct vga_switcheroo_handler gmux_handler_indexed = {
 511         .switchto = gmux_switchto,
 512         .power_state = gmux_set_power_state,
 513         .get_client_id = gmux_get_client_id,
 514 };
 515 
 516 static const struct vga_switcheroo_handler gmux_handler_classic = {
 517         .switchto = gmux_switchto,
 518         .switch_ddc = gmux_switch_ddc,
 519         .power_state = gmux_set_power_state,
 520         .get_client_id = gmux_get_client_id,
 521 };
 522 
 523 /**
 524  * DOC: Interrupt
 525  *
 526  * gmux is also connected to a GPIO pin of the southbridge and thereby is able
 527  * to trigger an ACPI GPE. On the MBP5 2008/09 it's GPIO pin 22 of the Nvidia
 528  * MCP79, on all following generations it's GPIO pin 6 of the Intel PCH.
 529  * The GPE merely signals that an interrupt occurred, the actual type of event
 530  * is identified by reading a gmux register.
 531  */
 532 
 533 static inline void gmux_disable_interrupts(struct apple_gmux_data *gmux_data)
 534 {
 535         gmux_write8(gmux_data, GMUX_PORT_INTERRUPT_ENABLE,
 536                     GMUX_INTERRUPT_DISABLE);
 537 }
 538 
 539 static inline void gmux_enable_interrupts(struct apple_gmux_data *gmux_data)
 540 {
 541         gmux_write8(gmux_data, GMUX_PORT_INTERRUPT_ENABLE,
 542                     GMUX_INTERRUPT_ENABLE);
 543 }
 544 
 545 static inline u8 gmux_interrupt_get_status(struct apple_gmux_data *gmux_data)
 546 {
 547         return gmux_read8(gmux_data, GMUX_PORT_INTERRUPT_STATUS);
 548 }
 549 
 550 static void gmux_clear_interrupts(struct apple_gmux_data *gmux_data)
 551 {
 552         u8 status;
 553 
 554         /* to clear interrupts write back current status */
 555         status = gmux_interrupt_get_status(gmux_data);
 556         gmux_write8(gmux_data, GMUX_PORT_INTERRUPT_STATUS, status);
 557 }
 558 
 559 static void gmux_notify_handler(acpi_handle device, u32 value, void *context)
 560 {
 561         u8 status;
 562         struct pnp_dev *pnp = (struct pnp_dev *)context;
 563         struct apple_gmux_data *gmux_data = pnp_get_drvdata(pnp);
 564 
 565         status = gmux_interrupt_get_status(gmux_data);
 566         gmux_disable_interrupts(gmux_data);
 567         pr_debug("Notify handler called: status %d\n", status);
 568 
 569         gmux_clear_interrupts(gmux_data);
 570         gmux_enable_interrupts(gmux_data);
 571 
 572         if (status & GMUX_INTERRUPT_STATUS_POWER)
 573                 complete(&gmux_data->powerchange_done);
 574 }
 575 
 576 static int gmux_suspend(struct device *dev)
 577 {
 578         struct pnp_dev *pnp = to_pnp_dev(dev);
 579         struct apple_gmux_data *gmux_data = pnp_get_drvdata(pnp);
 580 
 581         gmux_disable_interrupts(gmux_data);
 582         return 0;
 583 }
 584 
 585 static int gmux_resume(struct device *dev)
 586 {
 587         struct pnp_dev *pnp = to_pnp_dev(dev);
 588         struct apple_gmux_data *gmux_data = pnp_get_drvdata(pnp);
 589 
 590         gmux_enable_interrupts(gmux_data);
 591         gmux_write_switch_state(gmux_data);
 592         if (gmux_data->power_state == VGA_SWITCHEROO_OFF)
 593                 gmux_set_discrete_state(gmux_data, gmux_data->power_state);
 594         return 0;
 595 }
 596 
 597 static int is_thunderbolt(struct device *dev, void *data)
 598 {
 599         return to_pci_dev(dev)->is_thunderbolt;
 600 }
 601 
 602 static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
 603 {
 604         struct apple_gmux_data *gmux_data;
 605         struct resource *res;
 606         struct backlight_properties props;
 607         struct backlight_device *bdev;
 608         u8 ver_major, ver_minor, ver_release;
 609         int ret = -ENXIO;
 610         acpi_status status;
 611         unsigned long long gpe;
 612 
 613         if (apple_gmux_data)
 614                 return -EBUSY;
 615 
 616         gmux_data = kzalloc(sizeof(*gmux_data), GFP_KERNEL);
 617         if (!gmux_data)
 618                 return -ENOMEM;
 619         pnp_set_drvdata(pnp, gmux_data);
 620 
 621         res = pnp_get_resource(pnp, IORESOURCE_IO, 0);
 622         if (!res) {
 623                 pr_err("Failed to find gmux I/O resource\n");
 624                 goto err_free;
 625         }
 626 
 627         gmux_data->iostart = res->start;
 628         gmux_data->iolen = res->end - res->start;
 629 
 630         if (gmux_data->iolen < GMUX_MIN_IO_LEN) {
 631                 pr_err("gmux I/O region too small (%lu < %u)\n",
 632                        gmux_data->iolen, GMUX_MIN_IO_LEN);
 633                 goto err_free;
 634         }
 635 
 636         if (!request_region(gmux_data->iostart, gmux_data->iolen,
 637                             "Apple gmux")) {
 638                 pr_err("gmux I/O already in use\n");
 639                 goto err_free;
 640         }
 641 
 642         /*
 643          * Invalid version information may indicate either that the gmux
 644          * device isn't present or that it's a new one that uses indexed
 645          * io
 646          */
 647 
 648         ver_major = gmux_read8(gmux_data, GMUX_PORT_VERSION_MAJOR);
 649         ver_minor = gmux_read8(gmux_data, GMUX_PORT_VERSION_MINOR);
 650         ver_release = gmux_read8(gmux_data, GMUX_PORT_VERSION_RELEASE);
 651         if (ver_major == 0xff && ver_minor == 0xff && ver_release == 0xff) {
 652                 if (gmux_is_indexed(gmux_data)) {
 653                         u32 version;
 654                         mutex_init(&gmux_data->index_lock);
 655                         gmux_data->indexed = true;
 656                         version = gmux_read32(gmux_data,
 657                                 GMUX_PORT_VERSION_MAJOR);
 658                         ver_major = (version >> 24) & 0xff;
 659                         ver_minor = (version >> 16) & 0xff;
 660                         ver_release = (version >> 8) & 0xff;
 661                 } else {
 662                         pr_info("gmux device not present\n");
 663                         ret = -ENODEV;
 664                         goto err_release;
 665                 }
 666         }
 667         pr_info("Found gmux version %d.%d.%d [%s]\n", ver_major, ver_minor,
 668                 ver_release, (gmux_data->indexed ? "indexed" : "classic"));
 669 
 670         memset(&props, 0, sizeof(props));
 671         props.type = BACKLIGHT_PLATFORM;
 672         props.max_brightness = gmux_read32(gmux_data, GMUX_PORT_MAX_BRIGHTNESS);
 673 
 674         /*
 675          * Currently it's assumed that the maximum brightness is less than
 676          * 2^24 for compatibility with old gmux versions. Cap the max
 677          * brightness at this value, but print a warning if the hardware
 678          * reports something higher so that it can be fixed.
 679          */
 680         if (WARN_ON(props.max_brightness > GMUX_MAX_BRIGHTNESS))
 681                 props.max_brightness = GMUX_MAX_BRIGHTNESS;
 682 
 683         bdev = backlight_device_register("gmux_backlight", &pnp->dev,
 684                                          gmux_data, &gmux_bl_ops, &props);
 685         if (IS_ERR(bdev)) {
 686                 ret = PTR_ERR(bdev);
 687                 goto err_release;
 688         }
 689 
 690         gmux_data->bdev = bdev;
 691         bdev->props.brightness = gmux_get_brightness(bdev);
 692         backlight_update_status(bdev);
 693 
 694         /*
 695          * The backlight situation on Macs is complicated. If the gmux is
 696          * present it's the best choice, because it always works for
 697          * backlight control and supports more levels than other options.
 698          * Disable the other backlight choices.
 699          */
 700         acpi_video_set_dmi_backlight_type(acpi_backlight_vendor);
 701         apple_bl_unregister();
 702 
 703         gmux_data->power_state = VGA_SWITCHEROO_ON;
 704 
 705         gmux_data->dhandle = ACPI_HANDLE(&pnp->dev);
 706         if (!gmux_data->dhandle) {
 707                 pr_err("Cannot find acpi handle for pnp device %s\n",
 708                        dev_name(&pnp->dev));
 709                 ret = -ENODEV;
 710                 goto err_notify;
 711         }
 712 
 713         status = acpi_evaluate_integer(gmux_data->dhandle, "GMGP", NULL, &gpe);
 714         if (ACPI_SUCCESS(status)) {
 715                 gmux_data->gpe = (int)gpe;
 716 
 717                 status = acpi_install_notify_handler(gmux_data->dhandle,
 718                                                      ACPI_DEVICE_NOTIFY,
 719                                                      &gmux_notify_handler, pnp);
 720                 if (ACPI_FAILURE(status)) {
 721                         pr_err("Install notify handler failed: %s\n",
 722                                acpi_format_exception(status));
 723                         ret = -ENODEV;
 724                         goto err_notify;
 725                 }
 726 
 727                 status = acpi_enable_gpe(NULL, gmux_data->gpe);
 728                 if (ACPI_FAILURE(status)) {
 729                         pr_err("Cannot enable gpe: %s\n",
 730                                acpi_format_exception(status));
 731                         goto err_enable_gpe;
 732                 }
 733         } else {
 734                 pr_warn("No GPE found for gmux\n");
 735                 gmux_data->gpe = -1;
 736         }
 737 
 738         /*
 739          * If Thunderbolt is present, the external DP port is not fully
 740          * switchable. Force its AUX channel to the discrete GPU.
 741          */
 742         gmux_data->external_switchable =
 743                 !bus_for_each_dev(&pci_bus_type, NULL, NULL, is_thunderbolt);
 744         if (!gmux_data->external_switchable)
 745                 gmux_write8(gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 3);
 746 
 747         apple_gmux_data = gmux_data;
 748         init_completion(&gmux_data->powerchange_done);
 749         gmux_enable_interrupts(gmux_data);
 750         gmux_read_switch_state(gmux_data);
 751 
 752         /*
 753          * Retina MacBook Pros cannot switch the panel's AUX separately
 754          * and need eDP pre-calibration. They are distinguishable from
 755          * pre-retinas by having an "indexed" gmux.
 756          *
 757          * Pre-retina MacBook Pros can switch the panel's DDC separately.
 758          */
 759         if (gmux_data->indexed)
 760                 ret = vga_switcheroo_register_handler(&gmux_handler_indexed,
 761                                               VGA_SWITCHEROO_NEEDS_EDP_CONFIG);
 762         else
 763                 ret = vga_switcheroo_register_handler(&gmux_handler_classic,
 764                                               VGA_SWITCHEROO_CAN_SWITCH_DDC);
 765         if (ret) {
 766                 pr_err("Failed to register vga_switcheroo handler\n");
 767                 goto err_register_handler;
 768         }
 769 
 770         return 0;
 771 
 772 err_register_handler:
 773         gmux_disable_interrupts(gmux_data);
 774         apple_gmux_data = NULL;
 775         if (gmux_data->gpe >= 0)
 776                 acpi_disable_gpe(NULL, gmux_data->gpe);
 777 err_enable_gpe:
 778         if (gmux_data->gpe >= 0)
 779                 acpi_remove_notify_handler(gmux_data->dhandle,
 780                                            ACPI_DEVICE_NOTIFY,
 781                                            &gmux_notify_handler);
 782 err_notify:
 783         backlight_device_unregister(bdev);
 784 err_release:
 785         release_region(gmux_data->iostart, gmux_data->iolen);
 786 err_free:
 787         kfree(gmux_data);
 788         return ret;
 789 }
 790 
 791 static void gmux_remove(struct pnp_dev *pnp)
 792 {
 793         struct apple_gmux_data *gmux_data = pnp_get_drvdata(pnp);
 794 
 795         vga_switcheroo_unregister_handler();
 796         gmux_disable_interrupts(gmux_data);
 797         if (gmux_data->gpe >= 0) {
 798                 acpi_disable_gpe(NULL, gmux_data->gpe);
 799                 acpi_remove_notify_handler(gmux_data->dhandle,
 800                                            ACPI_DEVICE_NOTIFY,
 801                                            &gmux_notify_handler);
 802         }
 803 
 804         backlight_device_unregister(gmux_data->bdev);
 805 
 806         release_region(gmux_data->iostart, gmux_data->iolen);
 807         apple_gmux_data = NULL;
 808         kfree(gmux_data);
 809 
 810         acpi_video_register();
 811         apple_bl_register();
 812 }
 813 
 814 static const struct pnp_device_id gmux_device_ids[] = {
 815         {GMUX_ACPI_HID, 0},
 816         {"", 0}
 817 };
 818 
 819 static const struct dev_pm_ops gmux_dev_pm_ops = {
 820         .suspend = gmux_suspend,
 821         .resume = gmux_resume,
 822 };
 823 
 824 static struct pnp_driver gmux_pnp_driver = {
 825         .name           = "apple-gmux",
 826         .probe          = gmux_probe,
 827         .remove         = gmux_remove,
 828         .id_table       = gmux_device_ids,
 829         .driver         = {
 830                         .pm = &gmux_dev_pm_ops,
 831         },
 832 };
 833 
 834 module_pnp_driver(gmux_pnp_driver);
 835 MODULE_AUTHOR("Seth Forshee <seth.forshee@canonical.com>");
 836 MODULE_DESCRIPTION("Apple Gmux Driver");
 837 MODULE_LICENSE("GPL");
 838 MODULE_DEVICE_TABLE(pnp, gmux_device_ids);

/* [<][>][^][v][top][bottom][index][help] */