File Index
Files and directories
Sign in
FILE

apple-gmux.h

File preview with syntax highlighting.

linux-6.19.14/include/linux/apple-gmux.h C
  1/* SPDX-License-Identifier: GPL-2.0-only */
  2/*
  3 * apple-gmux.h - microcontroller built into dual GPU MacBook Pro & Mac Pro
  4 * Copyright (C) 2015 Lukas Wunner <lukas@wunner.de>
  5 */
  6
  7#ifndef LINUX_APPLE_GMUX_H
  8#define LINUX_APPLE_GMUX_H
  9
 10#include <linux/acpi.h>
 11#include <linux/io.h>
 12#include <linux/pnp.h>
 13
 14#define GMUX_ACPI_HID "APP000B"
 15
 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
 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
 43#define GMUX_MIN_IO_LEN			(GMUX_PORT_BRIGHTNESS + 4)
 44
 45enum apple_gmux_type {
 46	APPLE_GMUX_TYPE_PIO,
 47	APPLE_GMUX_TYPE_INDEXED,
 48	APPLE_GMUX_TYPE_MMIO,
 49};
 50
 51#if IS_ENABLED(CONFIG_APPLE_GMUX)
 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}
 66
 67static inline bool apple_gmux_is_mmio(unsigned long iostart)
 68{
 69	u8 __iomem *iomem_base = ioremap(iostart, 16);
 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
 85/**
 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
 89 * @type_ret: Returns (by reference) the apple_gmux_type of the device
 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 */
 98static inline bool apple_gmux_detect(struct pnp_dev *pnp_dev, enum apple_gmux_type *type_ret)
 99{
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;
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);
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;
139		else
140			goto out;
141	}
142
143	if (type_ret)
144		*type_ret = type;
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
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 *
158 * Return: %true if gmux ACPI device is present and the kernel was configured
159 * with CONFIG_APPLE_GMUX, %false otherwise.
160 */
161static inline bool apple_gmux_present(void)
162{
163	return acpi_dev_found(GMUX_ACPI_HID);
164}
165
166#else  /* !CONFIG_APPLE_GMUX */
167
168static inline bool apple_gmux_present(void)
169{
170	return false;
171}
172
173static inline bool apple_gmux_detect(struct pnp_dev *pnp_dev, bool *indexed_ret)
174{
175	return false;
176}
177
178#endif /* !CONFIG_APPLE_GMUX */
179
180#endif /* LINUX_APPLE_GMUX_H */
~/ Read-only file preview.