Merge tag 'xfs-6.4-rc1-fixes' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
[linux-block.git] / include / linux / apple-gmux.h
CommitLineData
caab277b 1/* SPDX-License-Identifier: GPL-2.0-only */
2413306c
LW
2/*
3 * apple-gmux.h - microcontroller built into dual GPU MacBook Pro & Mac Pro
4 * Copyright (C) 2015 Lukas Wunner <lukas@wunner.de>
2413306c
LW
5 */
6
7#ifndef LINUX_APPLE_GMUX_H
8#define LINUX_APPLE_GMUX_H
9
10#include <linux/acpi.h>
d143908f
HG
11#include <linux/io.h>
12#include <linux/pnp.h>
2413306c
LW
13
14#define GMUX_ACPI_HID "APP000B"
15
39f5a81f
HG
16/*
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.
19 */
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
36
0c18184d
OC
37#define GMUX_MMIO_PORT_SELECT 0x0e
38#define GMUX_MMIO_COMMAND_SEND 0x0f
39
40#define GMUX_MMIO_READ 0x00
41#define GMUX_MMIO_WRITE 0x40
42
39f5a81f
HG
43#define GMUX_MIN_IO_LEN (GMUX_PORT_BRIGHTNESS + 4)
44
96ec2d98
OC
45enum apple_gmux_type {
46 APPLE_GMUX_TYPE_PIO,
47 APPLE_GMUX_TYPE_INDEXED,
0c18184d 48 APPLE_GMUX_TYPE_MMIO,
96ec2d98
OC
49};
50
b7172119 51#if IS_ENABLED(CONFIG_APPLE_GMUX)
d143908f
HG
52static inline bool apple_gmux_is_indexed(unsigned long iostart)
53{
54 u16 val;
55
56 outb(0xaa, iostart + 0xcc);
57 outb(0x55, iostart + 0xcd);
58 outb(0x00, iostart + 0xce);
59
60 val = inb(iostart + 0xcc) | (inb(iostart + 0xcd) << 8);
61 if (val == 0x55aa)
62 return true;
63
64 return false;
65}
b7172119 66
0c18184d
OC
67static inline bool apple_gmux_is_mmio(unsigned long iostart)
68{
fb131c47 69 u8 __iomem *iomem_base = ioremap(iostart, 16);
0c18184d
OC
70 u8 val;
71
72 if (!iomem_base)
73 return false;
74
75 /*
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.
79 */
80 val = ioread8(iomem_base + GMUX_MMIO_COMMAND_SEND);
81 iounmap(iomem_base);
82 return (val != 0xff);
83}
84
2413306c 85/**
d143908f
HG
86 * apple_gmux_detect() - detect if gmux is built into the machine
87 *
88 * @pnp_dev: Device to probe or NULL to use the first matching device
ad3d0ee8 89 * @type_ret: Returns (by reference) the apple_gmux_type of the device
d143908f
HG
90 *
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().
94 *
95 * Return: %true if a supported gmux ACPI device is detected and the kernel
96 * was configured with CONFIG_APPLE_GMUX, %false otherwise.
97 */
96ec2d98 98static inline bool apple_gmux_detect(struct pnp_dev *pnp_dev, enum apple_gmux_type *type_ret)
d143908f
HG
99{
100 u8 ver_major, ver_minor, ver_release;
101 struct device *dev = NULL;
102 struct acpi_device *adev;
103 struct resource *res;
96ec2d98 104 enum apple_gmux_type type = APPLE_GMUX_TYPE_PIO;
d143908f
HG
105 bool ret = false;
106
107 if (!pnp_dev) {
108 adev = acpi_dev_get_first_match_dev(GMUX_ACPI_HID, NULL, -1);
109 if (!adev)
110 return false;
111
112 dev = get_device(acpi_get_first_physical_node(adev));
113 acpi_dev_put(adev);
114 if (!dev)
115 return false;
116
117 pnp_dev = to_pnp_dev(dev);
118 }
119
120 res = pnp_get_resource(pnp_dev, IORESOURCE_IO, 0);
0c18184d
OC
121 if (res && resource_size(res) >= GMUX_MIN_IO_LEN) {
122 /*
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.
125 */
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;
132 else
133 goto out;
134 }
135 } else {
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;
96ec2d98 139 else
d143908f
HG
140 goto out;
141 }
142
96ec2d98
OC
143 if (type_ret)
144 *type_ret = type;
d143908f
HG
145
146 ret = true;
147out:
148 put_device(dev);
149 return ret;
150}
151
152/**
153 * apple_gmux_present() - check if gmux ACPI device is present
2413306c
LW
154 *
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.
157 *
d143908f 158 * Return: %true if gmux ACPI device is present and the kernel was configured
2413306c
LW
159 * with CONFIG_APPLE_GMUX, %false otherwise.
160 */
161static inline bool apple_gmux_present(void)
162{
c68ae33e 163 return acpi_dev_found(GMUX_ACPI_HID);
2413306c
LW
164}
165
b7172119
LW
166#else /* !CONFIG_APPLE_GMUX */
167
168static inline bool apple_gmux_present(void)
169{
170 return false;
171}
172
d143908f
HG
173static inline bool apple_gmux_detect(struct pnp_dev *pnp_dev, bool *indexed_ret)
174{
175 return false;
176}
177
b7172119
LW
178#endif /* !CONFIG_APPLE_GMUX */
179
2413306c 180#endif /* LINUX_APPLE_GMUX_H */