1 /* SPDX-License-Identifier: GPL-2.0-only */
3 * apple-gmux.h - microcontroller built into dual GPU MacBook Pro & Mac Pro
4 * Copyright (C) 2015 Lukas Wunner <lukas@wunner.de>
7 #ifndef LINUX_APPLE_GMUX_H
8 #define LINUX_APPLE_GMUX_H
10 #include <linux/acpi.h>
12 #include <linux/pnp.h>
14 #define GMUX_ACPI_HID "APP000B"
17 * gmux port offsets. Many of these are not yet used, but may be in the
18 * future, and it's useful to have them documented here anyhow.
20 #define GMUX_PORT_VERSION_MAJOR 0x04
21 #define GMUX_PORT_VERSION_MINOR 0x05
22 #define GMUX_PORT_VERSION_RELEASE 0x06
23 #define GMUX_PORT_SWITCH_DISPLAY 0x10
24 #define GMUX_PORT_SWITCH_GET_DISPLAY 0x11
25 #define GMUX_PORT_INTERRUPT_ENABLE 0x14
26 #define GMUX_PORT_INTERRUPT_STATUS 0x16
27 #define GMUX_PORT_SWITCH_DDC 0x28
28 #define GMUX_PORT_SWITCH_EXTERNAL 0x40
29 #define GMUX_PORT_SWITCH_GET_EXTERNAL 0x41
30 #define GMUX_PORT_DISCRETE_POWER 0x50
31 #define GMUX_PORT_MAX_BRIGHTNESS 0x70
32 #define GMUX_PORT_BRIGHTNESS 0x74
33 #define GMUX_PORT_VALUE 0xc2
34 #define GMUX_PORT_READ 0xd0
35 #define GMUX_PORT_WRITE 0xd4
37 #define GMUX_MMIO_PORT_SELECT 0x0e
38 #define GMUX_MMIO_COMMAND_SEND 0x0f
40 #define GMUX_MMIO_READ 0x00
41 #define GMUX_MMIO_WRITE 0x40
43 #define GMUX_MIN_IO_LEN (GMUX_PORT_BRIGHTNESS + 4)
45 enum apple_gmux_type
{
47 APPLE_GMUX_TYPE_INDEXED
,
51 #if IS_ENABLED(CONFIG_APPLE_GMUX)
52 static inline bool apple_gmux_is_indexed(unsigned long iostart
)
56 outb(0xaa, iostart
+ 0xcc);
57 outb(0x55, iostart
+ 0xcd);
58 outb(0x00, iostart
+ 0xce);
60 val
= inb(iostart
+ 0xcc) | (inb(iostart
+ 0xcd) << 8);
67 static inline bool apple_gmux_is_mmio(unsigned long iostart
)
69 u8 __iomem
*iomem_base
= ioremap(iostart
, 16);
76 * If this is 0xff, then gmux must not be present, as the gmux would
77 * reset it to 0x00, or it would be one of 0x1, 0x4, 0x41, 0x44 if a
78 * command is currently being processed.
80 val
= ioread8(iomem_base
+ GMUX_MMIO_COMMAND_SEND
);
86 * apple_gmux_detect() - detect if gmux is built into the machine
88 * @pnp_dev: Device to probe or NULL to use the first matching device
89 * @type_ret: Returns (by reference) the apple_gmux_type of the device
91 * Detect if a supported gmux device is present by actually probing it.
92 * This avoids the false positives returned on some models by
93 * apple_gmux_present().
95 * Return: %true if a supported gmux ACPI device is detected and the kernel
96 * was configured with CONFIG_APPLE_GMUX, %false otherwise.
98 static inline bool apple_gmux_detect(struct pnp_dev
*pnp_dev
, enum apple_gmux_type
*type_ret
)
100 u8 ver_major
, ver_minor
, ver_release
;
101 struct device
*dev
= NULL
;
102 struct acpi_device
*adev
;
103 struct resource
*res
;
104 enum apple_gmux_type type
= APPLE_GMUX_TYPE_PIO
;
108 adev
= acpi_dev_get_first_match_dev(GMUX_ACPI_HID
, NULL
, -1);
112 dev
= get_device(acpi_get_first_physical_node(adev
));
117 pnp_dev
= to_pnp_dev(dev
);
120 res
= pnp_get_resource(pnp_dev
, IORESOURCE_IO
, 0);
121 if (res
&& resource_size(res
) >= GMUX_MIN_IO_LEN
) {
123 * Invalid version information may indicate either that the gmux
124 * device isn't present or that it's a new one that uses indexed io.
126 ver_major
= inb(res
->start
+ GMUX_PORT_VERSION_MAJOR
);
127 ver_minor
= inb(res
->start
+ GMUX_PORT_VERSION_MINOR
);
128 ver_release
= inb(res
->start
+ GMUX_PORT_VERSION_RELEASE
);
129 if (ver_major
== 0xff && ver_minor
== 0xff && ver_release
== 0xff) {
130 if (apple_gmux_is_indexed(res
->start
))
131 type
= APPLE_GMUX_TYPE_INDEXED
;
136 res
= pnp_get_resource(pnp_dev
, IORESOURCE_MEM
, 0);
137 if (res
&& apple_gmux_is_mmio(res
->start
))
138 type
= APPLE_GMUX_TYPE_MMIO
;
153 * apple_gmux_present() - check if gmux ACPI device is present
155 * Drivers may use this to activate quirks specific to dual GPU MacBook Pros
156 * and Mac Pros, e.g. for deferred probing, runtime pm and backlight.
158 * Return: %true if gmux ACPI device is present and the kernel was configured
159 * with CONFIG_APPLE_GMUX, %false otherwise.
161 static inline bool apple_gmux_present(void)
163 return acpi_dev_found(GMUX_ACPI_HID
);
166 #else /* !CONFIG_APPLE_GMUX */
168 static inline bool apple_gmux_present(void)
173 static inline bool apple_gmux_detect(struct pnp_dev
*pnp_dev
, bool *indexed_ret
)
178 #endif /* !CONFIG_APPLE_GMUX */
180 #endif /* LINUX_APPLE_GMUX_H */