brintos

brintos / linux-shallow public Read only

0
0
Text · 4.6 KiB · 206d97f Raw
181 lines · c
1/* SPDX-License-Identifier: GPL-2.0-only */2/*3 * apple-gmux.h - microcontroller built into dual GPU MacBook Pro & Mac Pro4 * Copyright (C) 2015 Lukas Wunner <lukas@wunner.de>5 */6 7#ifndef LINUX_APPLE_GMUX_H8#define LINUX_APPLE_GMUX_H9 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 the18 * future, and it's useful to have them documented here anyhow.19 */20#define GMUX_PORT_VERSION_MAJOR		0x0421#define GMUX_PORT_VERSION_MINOR		0x0522#define GMUX_PORT_VERSION_RELEASE	0x0623#define GMUX_PORT_SWITCH_DISPLAY	0x1024#define GMUX_PORT_SWITCH_GET_DISPLAY	0x1125#define GMUX_PORT_INTERRUPT_ENABLE	0x1426#define GMUX_PORT_INTERRUPT_STATUS	0x1627#define GMUX_PORT_SWITCH_DDC		0x2828#define GMUX_PORT_SWITCH_EXTERNAL	0x4029#define GMUX_PORT_SWITCH_GET_EXTERNAL	0x4130#define GMUX_PORT_DISCRETE_POWER	0x5031#define GMUX_PORT_MAX_BRIGHTNESS	0x7032#define GMUX_PORT_BRIGHTNESS		0x7433#define GMUX_PORT_VALUE			0xc234#define GMUX_PORT_READ			0xd035#define GMUX_PORT_WRITE			0xd436 37#define GMUX_MMIO_PORT_SELECT		0x0e38#define GMUX_MMIO_COMMAND_SEND		0x0f39 40#define GMUX_MMIO_READ			0x0041#define GMUX_MMIO_WRITE			0x4042 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 would77	 * reset it to 0x00, or it would be one of 0x1, 0x4, 0x41, 0x44 if a78	 * 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 machine87 *88 * @pnp_dev:     Device to probe or NULL to use the first matching device89 * @type_ret: Returns (by reference) the apple_gmux_type of the device90 *91 * Detect if a supported gmux device is present by actually probing it.92 * This avoids the false positives returned on some models by93 * apple_gmux_present().94 *95 * Return: %true if a supported gmux ACPI device is detected and the kernel96 * 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 gmux124		 * 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			else133				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		else140			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 present154 *155 * Drivers may use this to activate quirks specific to dual GPU MacBook Pros156 * 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 configured159 * 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 */181