From patchwork Wed Jul 29 21:05:57 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Daniel Dadap X-Patchwork-Id: 11707095 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 25577722 for ; Mon, 10 Aug 2020 07:36:52 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 02DB82073A for ; Mon, 10 Aug 2020 07:36:52 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=nvidia.com header.i=@nvidia.com header.b="aAGM3/E+" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 02DB82073A Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=nvidia.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 416666E379; Mon, 10 Aug 2020 07:36:12 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from bmailout1.hostsharing.net (bmailout1.hostsharing.net [83.223.95.100]) by gabe.freedesktop.org (Postfix) with ESMTPS id 0A8D389CA8 for ; Sun, 9 Aug 2020 15:00:57 +0000 (UTC) Received: from h08.hostsharing.net (h08.hostsharing.net [IPv6:2a01:37:1000::53df:5f1c:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client CN "*.hostsharing.net", Issuer "COMODO RSA Domain Validation Secure Server CA" (not verified)) by bmailout1.hostsharing.net (Postfix) with ESMTPS id 51A80300002AA for ; Sun, 9 Aug 2020 17:00:55 +0200 (CEST) Received: by h08.hostsharing.net (Postfix, from userid 100393) id 2686210630; Sun, 9 Aug 2020 17:00:55 +0200 (CEST) Resent-From: Lukas Wunner Resent-Date: Sun, 9 Aug 2020 17:00:55 +0200 Resent-Message-ID: <20200809150055.vukqxbmt33uysnes@wunner.de> Resent-To: dri-devel@lists.freedesktop.org X-Original-To: lukas@wunner.de Received: from mailin3.hostsharing.net (mailin3.hostsharing.net [176.9.242.53]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client CN "*.hostsharing.net", Issuer "COMODO RSA Domain Validation Secure Server CA" (not verified)) by h08.hostsharing.net (Postfix) with ESMTPS id 1DCE24AAE8 for ; Wed, 29 Jul 2020 23:04:50 +0200 (CEST) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mailin3.hostsharing.net (Postfix) with ESMTP id 645C518809A for ; Wed, 29 Jul 2020 23:04:49 +0200 (CEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726718AbgG2VEq (ORCPT ); Wed, 29 Jul 2020 17:04:46 -0400 Received: from hqnvemgate25.nvidia.com ([216.228.121.64]:9392 "EHLO hqnvemgate25.nvidia.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726476AbgG2VEq (ORCPT ); Wed, 29 Jul 2020 17:04:46 -0400 Received: from hqpgpgate101.nvidia.com (Not Verified[216.228.121.13]) by hqnvemgate25.nvidia.com (using TLS: TLSv1.2, DES-CBC3-SHA) id ; Wed, 29 Jul 2020 14:04:00 -0700 Received: from hqmail.nvidia.com ([172.20.161.6]) by hqpgpgate101.nvidia.com (PGP Universal service); Wed, 29 Jul 2020 14:04:46 -0700 X-PGP-Universal: processed; by hqpgpgate101.nvidia.com on Wed, 29 Jul 2020 14:04:46 -0700 Received: from lenny.nvidia.com (10.124.1.5) by HQMAIL107.nvidia.com (172.20.187.13) with Microsoft SMTP Server (TLS) id 15.0.1473.3; Wed, 29 Jul 2020 21:04:45 +0000 From: Daniel Dadap To: Subject: [PATCH v3] platform/x86: Add new vga-switcheroo gmux driver for ACPI-driven muxes Date: Wed, 29 Jul 2020 16:05:57 -0500 Message-ID: <20200729210557.9195-1-ddadap@nvidia.com> X-Mailer: git-send-email 2.18.4 In-Reply-To: <0850ac9a-3d60-053d-1d70-5f20ce621b24@nvidia.com> References: <0850ac9a-3d60-053d-1d70-5f20ce621b24@nvidia.com> MIME-Version: 1.0 X-NVConfidentiality: public X-Originating-IP: [10.124.1.5] X-ClientProxiedBy: HQMAIL111.nvidia.com (172.20.187.18) To HQMAIL107.nvidia.com (172.20.187.13) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nvidia.com; s=n1; t=1596056640; bh=S0GXf4hrswAPtEz73pzPQjh2puUuWae0LpOWNSRYCdE=; h=X-PGP-Universal:From:To:CC:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:MIME-Version:X-NVConfidentiality: X-Originating-IP:X-ClientProxiedBy:Content-Type: Content-Transfer-Encoding; b=aAGM3/E+YngRs9I/jOLDTHNpdNLGvLzdeMSsE2eqoI0vP6rOZMQ2w1L8O8nAYKXGG wm45lEMMvhB6ojVFrHU+V/Uq9n1WZsTSdNN1ZwaRWtfdeRM+45iq8EF7+j+eXicorH 78gKLjZd7mrytFKLV/DcW28fncx2DC2JkxszDRTZdZEfFWTyeiLL+y3LS48Tl30MFq smRygvv3uDug2Z7+TStQTpBpZ9tCFclYyQjyh5HFitiHIvGCucfkzdG5VXwr+CnqBJ 7pqTB5dXq/+NeZID1OTONCNAtcYbYSbSv871BaM0oEDhPb80C5El7eGIa+sxFAOb7y ecP8YIjJiblkA== Precedence: bulk X-Mailing-List: platform-driver-x86@vger.kernel.org X-Mailman-Approved-At: Mon, 10 Aug 2020 07:35:59 +0000 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: pobrn@protonmail.com, Daniel Dadap , andy@infradead.org, dvhart@infradead.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Some upcoming notebook designs utilize display muxes driven by a pair of ACPI methods, MXDM to query and configure the operational mode of the mux (integrated only, discrete only, hybrid non-muxed, hybrid with dynamic mux switching), and MXDS to query and set the mux state when running in dynamic switch mode. Add a vga-switcheroo driver to support switching the mux on systems with the ACPI MXDM/MXDS interface. The mux mode cannot be changed dynamically (calling MXDM to change the mode won't have effect until the next boot, and calling MXDM to read the mux mode returns the active mode, not the mode that will be enabled on next boot), and MXDS only works when the mux mode is set to dynamic switch, so this driver will fail to load when MXDM reports any non-dynamic mode. This driver currently only supports systems with Intel integrated graphics and NVIDIA discrete graphics. It will need to be updated if designs are developed using the same interfaces which utilize GPUs from other vendors. v2,v3: misc. fixes suggested by Barnabás Pőcze Signed-off-by: Daniel Dadap --- MAINTAINERS | 6 + drivers/platform/x86/Kconfig | 9 ++ drivers/platform/x86/Makefile | 2 + drivers/platform/x86/mxds-gmux.c | 267 +++++++++++++++++++++++++++++++ 4 files changed, 284 insertions(+) create mode 100644 drivers/platform/x86/mxds-gmux.c diff --git a/MAINTAINERS b/MAINTAINERS index eeff55560759..636c9259b345 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11510,6 +11510,12 @@ L: linux-usb@vger.kernel.org S: Maintained F: drivers/usb/musb/ +MXDS GMUX DRIVER +M: Daniel Dadap +L: platform-driver-x86@vger.kernel.org +S: Supported +F: drivers/platform/x86/mxds-gmux.c + MXL301RF MEDIA DRIVER M: Akihiro Tsukada L: linux-media@vger.kernel.org diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 0ad7ad8cf8e1..5d00ad1ffc0e 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1368,6 +1368,15 @@ config INTEL_TELEMETRY directly via debugfs files. Various tools may use this interface for SoC state monitoring. +config MXDS_GMUX + tristate "ACPI MXDS Gmux Driver" + depends on ACPI_WMI + depends on ACPI + depends on VGA_SWITCHEROO + help + This driver provides support for ACPI-driven gmux devices which are + present on some notebook designs with hybrid graphics. + endif # X86_PLATFORM_DEVICES config PMC_ATOM diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 53408d965874..b79000733fae 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -146,3 +146,5 @@ obj-$(CONFIG_INTEL_TELEMETRY) += intel_telemetry_core.o \ intel_telemetry_pltdrv.o \ intel_telemetry_debugfs.o obj-$(CONFIG_PMC_ATOM) += pmc_atom.o + +obj-$(CONFIG_MXDS_GMUX) += mxds-gmux.o diff --git a/drivers/platform/x86/mxds-gmux.c b/drivers/platform/x86/mxds-gmux.c new file mode 100644 index 000000000000..070a64fc1b25 --- /dev/null +++ b/drivers/platform/x86/mxds-gmux.c @@ -0,0 +1,267 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * mxds-gmux: vga_switcheroo mux handler for ACPI MXDS muxes + * + * Copyright (C) 2020 NVIDIA Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("vga_switcheroo mux handler for ACPI MXDS muxes"); +MODULE_AUTHOR("Daniel Dadap "); + +/* + * The mux doesn't have its own ACPI HID/CID, or WMI wrapper, so key off of + * the WMI wrapper for the related WMAA method for backlight control. + */ +MODULE_ALIAS("wmi:603E9613-EF25-4338-A3D0-C46177516DB7"); + +static struct pci_dev *ig_dev, *dg_dev; +static acpi_handle internal_mux_handle; +static acpi_handle external_mux_handle; + +static int mxds_gmux_switchto(enum vga_switcheroo_client_id); +static enum vga_switcheroo_client_id mxds_gmux_get_client_id(struct pci_dev *); + +static const struct vga_switcheroo_handler handler = { + .switchto = mxds_gmux_switchto, + .get_client_id = mxds_gmux_get_client_id, +}; + +enum acpi_method { + MXDM = 0, + MXDS, + NUM_ACPI_METHODS +}; + +static char *acpi_methods[NUM_ACPI_METHODS] = { + [MXDM] = "MXDM", + [MXDS] = "MXDS", +}; + +enum mux_mode_command { + MUX_MODE_GET = 0, +}; + +enum mux_mode { + MUX_MODE_DGPU_ONLY = 1, + MUX_MODE_IGPU_ONLY = 2, + MUX_MODE_MSHYBRID = 3, /* Dual GPU, mux switched to iGPU */ + MUX_MODE_DYNAMIC = 4, /* Dual GPU, dynamic mux switching */ +}; + +/* + * Call MXDS with argument value 0 to read the current state. + * When reading, a return value of 1 means iGPU and 2 means dGPU. + * Call MXDS with bit 0 set to change the current state. + * When changing state, clear bit 4 for iGPU and set bit 4 for dGPU. + */ + +enum mux_state { + MUX_STATE_IGPU = 1, + MUX_STATE_DGPU = 2, +}; + +enum mux_state_command { + MUX_STATE_GET = 0, + MUX_STATE_SET_IGPU = 0x01, + MUX_STATE_SET_DGPU = 0x11, +}; + +static acpi_integer acpi_helper(acpi_handle handle, enum acpi_method method, + acpi_integer action) +{ + union acpi_object arg; + struct acpi_object_list in = {.count = 1, .pointer = &arg}; + acpi_integer ret; + acpi_status status; + + arg.integer.type = ACPI_TYPE_INTEGER; + arg.integer.value = action; + + status = acpi_evaluate_integer(handle, acpi_methods[method], &in, &ret); + + if (ACPI_FAILURE(status)) { + pr_err("ACPI %s failed: %s\n", acpi_methods[method], + acpi_format_exception(status)); + return 0; + } + + return ret; +} + +static acpi_integer get_mux_mode(acpi_handle handle) +{ + return acpi_helper(handle, MXDM, MUX_MODE_GET); +} + +static acpi_integer get_mux_state(acpi_handle handle) +{ + return acpi_helper(handle, MXDS, MUX_STATE_GET); +} + +static void set_mux_state(acpi_handle handle, enum mux_state state) +{ + enum mux_state_command command; + + switch (state) { + case MUX_STATE_IGPU: + command = MUX_STATE_SET_IGPU; + break; + case MUX_STATE_DGPU: + command = MUX_STATE_SET_DGPU; + break; + default: + return; + } + + acpi_helper(handle, MXDS, command); +} + +static int mxds_gmux_switchto(enum vga_switcheroo_client_id id) +{ + enum mux_state state; + + switch (id) { + case VGA_SWITCHEROO_IGD: + state = MUX_STATE_IGPU; + break; + case VGA_SWITCHEROO_DIS: + state = MUX_STATE_DGPU; + break; + default: + return -EINVAL; + } + + if (internal_mux_handle) { + set_mux_state(internal_mux_handle, state); + if (get_mux_state(internal_mux_handle) != state) + return -EAGAIN; + } + + if (external_mux_handle) { + set_mux_state(external_mux_handle, state); + if (get_mux_state(external_mux_handle) != state) + return -EAGAIN; + } + + /* DP AUX can take up to 100ms to settle after mux switch */ + mdelay(100); + + return 0; +} + +static enum vga_switcheroo_client_id mxds_gmux_get_client_id( + struct pci_dev *dev) +{ + if (dev) { + if (ig_dev && dev->vendor == ig_dev->vendor) + return VGA_SWITCHEROO_IGD; + if (dg_dev && dev->vendor == dg_dev->vendor) + return VGA_SWITCHEROO_DIS; + } + + return VGA_SWITCHEROO_UNKNOWN_ID; +} + +static acpi_status find_acpi_methods( + acpi_handle object, u32 nesting_level, void *context, + void **return_value) +{ + acpi_handle search; + + /* If either MXDM or MXDS is missing, we can't use this object */ + if (acpi_get_handle(object, "MXDM", &search)) + return 0; + if (acpi_get_handle(object, "MXDS", &search)) + return 0; + + /* MXDS only works when MXDM indicates dynamic mode */ + if (get_mux_mode(object) != MUX_MODE_DYNAMIC) + return 0; + + /* Internal display has _BCL; external does not */ + if (acpi_get_handle(object, "_BCL", &search)) + external_mux_handle = object; + else + internal_mux_handle = object; + + return 0; +} + +static int __init mxds_gmux_init(void) +{ + int ret = 0; + struct pci_dev *dev = NULL; + + /* Currently only supports Intel integrated and NVIDIA discrete GPUs */ + while ((dev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, dev))) { + switch (dev->vendor) { + case PCI_VENDOR_ID_INTEL: + pci_dev_put(ig_dev); + ig_dev = pci_dev_get(dev); + break; + case PCI_VENDOR_ID_NVIDIA: + pci_dev_put(dg_dev); + dg_dev = pci_dev_get(dev); + break; + default: + break; + } + } + + /* Require both integrated and discrete GPUs */ + if (!ig_dev || !dg_dev) { + ret = -ENODEV; + goto done; + } + + acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, + find_acpi_methods, NULL, NULL, NULL); + + /* Require at least one mux */ + if (!internal_mux_handle && !external_mux_handle) { + ret = -ENODEV; + goto done; + } + + ret = vga_switcheroo_register_handler(&handler, 0); + +done: + + if (ret) { + pci_dev_put(ig_dev); + pci_dev_put(dg_dev); + } + + return ret; +} +module_init(mxds_gmux_init); + +static void __exit mxds_gmux_exit(void) +{ + vga_switcheroo_unregister_handler(); + pci_dev_put(ig_dev); + pci_dev_put(dg_dev); +} +module_exit(mxds_gmux_exit);