From patchwork Sat Aug 22 04:05:06 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Mani, Rajmohan" X-Patchwork-Id: 11730889 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 4333215E4 for ; Sat, 22 Aug 2020 04:42:26 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2FCAB20FC3 for ; Sat, 22 Aug 2020 04:42:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726838AbgHVEmQ (ORCPT ); Sat, 22 Aug 2020 00:42:16 -0400 Received: from mga11.intel.com ([192.55.52.93]:62111 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726414AbgHVEmK (ORCPT ); Sat, 22 Aug 2020 00:42:10 -0400 IronPort-SDR: Bd5xfcJjOo1huN9NdWgzi+ipkyMgC1M45J5A4BHXPbFVukWJBWBcK1cB78kxjkz+Xv911SdWn4 SGopv4DxGj1g== X-IronPort-AV: E=McAfee;i="6000,8403,9720"; a="153275283" X-IronPort-AV: E=Sophos;i="5.76,339,1592895600"; d="scan'208";a="153275283" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga008.jf.intel.com ([10.7.209.65]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Aug 2020 21:42:01 -0700 IronPort-SDR: 8i4hGeGeesJiGDSiCZhdtYrmz2gqvJ4jJAcmw6zUUM2qkDD8wA/cLpsxbnaCvXVmpeFryGgsYM ySOF44knnNHg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.76,339,1592895600"; d="scan'208";a="327943118" Received: from glacier.sc.intel.com ([10.3.62.63]) by orsmga008.jf.intel.com with ESMTP; 21 Aug 2020 21:42:00 -0700 From: Rajmohan Mani To: Darren Hart , Andy Shevchenko , Mika Westerberg , Dmitry Torokhov , Lee Jones , Ayman Bagabas , Masahiro Yamada , Jithu Joseph , =?utf-8?q?Bla=C5=BE_Hrastnik?= , Srinivas Pandruvada , linux-kernel@vger.kernel.org, platform-driver-x86@vger.kernel.org, Heikki Krogerus , Greg Kroah-Hartman , linux-usb@vger.kernel.org Cc: pmalani@chromium.org, bleung@chromium.org, Rajmohan Mani Subject: [PATCH v2 1/3] platform/x86: Add Intel Input Output Manager (IOM) driver Date: Fri, 21 Aug 2020 21:05:06 -0700 Message-Id: <20200822040508.23510-2-rajmohan.mani@intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200822040508.23510-1-rajmohan.mani@intel.com> References: <20200822040508.23510-1-rajmohan.mani@intel.com> MIME-Version: 1.0 Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org Input Output Manager (IOM) is part of the Tiger Lake SoC that configures the Type-C Sub System (TCSS). IOM is a micro controller that handles Type-C topology, configuration and PM functions of various Type-C devices connected on the platform. This driver helps read relevant information such as Type-C port status (whether a device is connected to a Type-C port or not) and the activity type on the Type-C ports (such as USB, Display Port, Thunderbolt), for consumption by other drivers. Currently intel_iom_port_status() API is exported by this driver, that has information about the Type-C port status and port activity type. Signed-off-by: Rajmohan Mani --- drivers/platform/x86/Kconfig | 16 ++++ drivers/platform/x86/Makefile | 1 + drivers/platform/x86/intel_iom.c | 95 +++++++++++++++++++++ include/linux/platform_data/x86/intel_iom.h | 49 +++++++++++ 4 files changed, 161 insertions(+) create mode 100644 drivers/platform/x86/intel_iom.c create mode 100644 include/linux/platform_data/x86/intel_iom.h diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 40219bba6801..f09b4b525ea5 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -837,6 +837,22 @@ config INTEL_INT0002_VGPIO To compile this driver as a module, choose M here: the module will be called intel_int0002_vgpio. +config INTEL_IOM + tristate "Intel Input Output Manager (IOM) driver" + depends on ACPI && PCI + help + This driver helps read relevant information such as Type-C port + status (whether a device is connected to a Type-C port or not) + and the activity type on the Type-C ports (such as USB, Display + Port, Thunderbolt), for consumption by other drivers. + + Currently intel_iom_port_status() API is exported by this driver, + that has information about the Type-C port status and port activity + type. + + To compile this driver as a module, choose M here: the module will + be called intel_iom. + config INTEL_MENLOW tristate "Thermal Management driver for Intel menlow platform" depends on ACPI_THERMAL diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 5f823f7eff45..b44f706074c3 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -77,6 +77,7 @@ intel_cht_int33fe-objs := intel_cht_int33fe_common.o \ intel_cht_int33fe_microb.o obj-$(CONFIG_INTEL_HID_EVENT) += intel-hid.o obj-$(CONFIG_INTEL_INT0002_VGPIO) += intel_int0002_vgpio.o +obj-$(CONFIG_INTEL_IOM) += intel_iom.o obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o obj-$(CONFIG_INTEL_OAKTRAIL) += intel_oaktrail.o obj-$(CONFIG_INTEL_VBTN) += intel-vbtn.o diff --git a/drivers/platform/x86/intel_iom.c b/drivers/platform/x86/intel_iom.c new file mode 100644 index 000000000000..cda7716410c6 --- /dev/null +++ b/drivers/platform/x86/intel_iom.c @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Intel Core SoC Input Output Manager (IOM) driver. + * + * This driver provides access to the Input Output Manager (IOM) (that + * is part of Tiger Lake SoC) registers that can be used to know about + * Type-C Sub System related information (such as Type-C port status, + * activity type on Type-C ports). + * + * Copyright (C) 2020, Intel Corporation + * Author: Rajmohan Mani + */ + +#include +#include +#include +#include +#include +#include + +#define IOM_PORT_STATUS_OFFSET 0x560 + +struct intel_iom { + struct device *dev; + void __iomem *regbar; +}; + +static struct intel_iom *iom; + +/** + * intel_iom_port_status() - Get status bits for the Type-C port + * @port: Type-C port number + * @status: pointer to receive the status bits + * + * Returns 0 on success, error otherwise. + */ +int intel_iom_port_status(u8 port, u32 *status) +{ + void __iomem *reg; + + if (!iom || !iom->dev || !iom->regbar) + return -ENODEV; + + if (!status || (port > IOM_MAX_PORTS - 1)) + return -EINVAL; + + reg = iom->regbar + IOM_PORT_STATUS_OFFSET + IOM_REG_LEN * port; + + *status = ioread32(reg); + + return 0; +} +EXPORT_SYMBOL_GPL(intel_iom_port_status); + +static int intel_iom_probe(struct platform_device *pdev) +{ + void __iomem *addr; + + /* only one IOM device is supported */ + if (iom) + return -EBUSY; + + iom = devm_kzalloc(&pdev->dev, sizeof(*iom), GFP_KERNEL); + if (!iom) + return -ENOMEM; + + addr = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(addr)) + return PTR_ERR(addr); + + iom->regbar = addr; + iom->dev = &pdev->dev; + + return 0; +} + +static const struct acpi_device_id intel_iom_acpi_ids[] = { + { "INTC1072" }, + {} +}; +MODULE_DEVICE_TABLE(acpi, intel_iom_acpi_ids); + +static struct platform_driver intel_iom_driver = { + .probe = intel_iom_probe, + .driver = { + .name = "intel_iom", + .acpi_match_table = intel_iom_acpi_ids, + }, +}; + +module_platform_driver_probe(intel_iom_driver, intel_iom_probe); + +MODULE_AUTHOR("Rajmohan Mani "); +MODULE_DESCRIPTION("Intel IOM driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/platform_data/x86/intel_iom.h b/include/linux/platform_data/x86/intel_iom.h new file mode 100644 index 000000000000..e4c9a305e7a9 --- /dev/null +++ b/include/linux/platform_data/x86/intel_iom.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _PLATFORM_DATA_X86_INTEL_IOM_H_ +#define _PLATFORM_DATA_X86_INTEL_IOM_H_ + +#include +#include + +/* Input Output Manager (IOM) PORT STATUS */ +#define IOM_PORT_STATUS_ACTIVITY_TYPE_MASK GENMASK(9, 6) +#define IOM_PORT_STATUS_ACTIVITY_TYPE_SHIFT 0x06 +#define IOM_PORT_STATUS_ACTIVITY_TYPE_USB 0x03 +/* activity type: Safe Mode */ +#define IOM_PORT_STATUS_ACTIVITY_TYPE_SAFE_MODE 0x04 +/* activity type: Display Port */ +#define IOM_PORT_STATUS_ACTIVITY_TYPE_DP 0x05 +/* activity type: Display Port Multi Function Device */ +#define IOM_PORT_STATUS_ACTIVITY_TYPE_DP_MFD 0x06 +/* activity type: Thunderbolt */ +#define IOM_PORT_STATUS_ACTIVITY_TYPE_TBT 0x07 +#define IOM_PORT_STATUS_ACTIVITY_TYPE_ALT_MODE_USB 0x0c +#define IOM_PORT_STATUS_ACTIVITY_TYPE_ALT_MODE_TBT_USB 0x0d +/* Upstream Facing Port Information */ +#define IOM_PORT_STATUS_UFP BIT(10) +/* Display Port Hot Plug Detect status */ +#define IOM_PORT_STATUS_DHPD_HPD_STATUS_MASK GENMASK(13, 12) +#define IOM_PORT_STATUS_DHPD_HPD_STATUS_SHIFT 0x0c +#define IOM_PORT_STATUS_DHPD_HPD_STATUS_ASSERT 0x01 +#define IOM_PORT_STATUS_DHPD_HPD_SOURCE_TBT BIT(14) +#define IOM_PORT_STATUS_CONNECTED BIT(31) + +#define IOM_MAX_PORTS 4 +/* Register length in bytes */ +#define IOM_REG_LEN 4 + +#ifdef CONFIG_ACPI + +int intel_iom_port_status(u8 port, u32 *status); + +#else + +int intel_iom_port_status(struct intel_iom *iom, u8 port, u32 *status) +{ + return 0; +} + +#endif + +#endif /* _PLATFORM_DATA_X86_INTEL_IOM_H_ */ From patchwork Sat Aug 22 04:05:07 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Mani, Rajmohan" X-Patchwork-Id: 11730881 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 2BDD214F6 for ; Sat, 22 Aug 2020 04:42:13 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 19DED214F1 for ; Sat, 22 Aug 2020 04:42:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726700AbgHVEmL (ORCPT ); Sat, 22 Aug 2020 00:42:11 -0400 Received: from mga11.intel.com ([192.55.52.93]:62114 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726440AbgHVEmG (ORCPT ); Sat, 22 Aug 2020 00:42:06 -0400 IronPort-SDR: m0YiysR4BRqaqgZ8iTdUiYD+jPBVCEKC5EGzFynwNXroUC0itJEenYH4Nln3ixx49QFy1ff2YV +YjWdYUe6wqw== X-IronPort-AV: E=McAfee;i="6000,8403,9720"; a="153275284" X-IronPort-AV: E=Sophos;i="5.76,339,1592895600"; d="scan'208";a="153275284" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga008.jf.intel.com ([10.7.209.65]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Aug 2020 21:42:01 -0700 IronPort-SDR: hdHQfmYhOHgQuIYIV7dgpV6D1n4IYm7T/hjpsffdmlvZbvSi4iqU16V/rAJy5PKtd912puGLP1 VOzZoK9Ct2cg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.76,339,1592895600"; d="scan'208";a="327943124" Received: from glacier.sc.intel.com ([10.3.62.63]) by orsmga008.jf.intel.com with ESMTP; 21 Aug 2020 21:42:01 -0700 From: Rajmohan Mani To: Darren Hart , Andy Shevchenko , Mika Westerberg , Dmitry Torokhov , Lee Jones , Ayman Bagabas , Masahiro Yamada , Jithu Joseph , =?utf-8?q?Bla=C5=BE_Hrastnik?= , Srinivas Pandruvada , linux-kernel@vger.kernel.org, platform-driver-x86@vger.kernel.org, Heikki Krogerus , Greg Kroah-Hartman , linux-usb@vger.kernel.org Cc: pmalani@chromium.org, bleung@chromium.org, Rajmohan Mani Subject: [PATCH v2 2/3] usb: typec: intel_pmc_mux: Check the port status before connect Date: Fri, 21 Aug 2020 21:05:07 -0700 Message-Id: <20200822040508.23510-3-rajmohan.mani@intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200822040508.23510-1-rajmohan.mani@intel.com> References: <20200822040508.23510-1-rajmohan.mani@intel.com> MIME-Version: 1.0 Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org From: Heikki Krogerus The PMC microcontroller that we use for configuration, does not supply any status information back. For port status we need to talk to another controller on the board called IOM (I/O manager). By checking the port status before configuring the muxes, we can make sure that we do not reconfigure the port after bootup when the system firmware (for example BIOS) has already configured it. Using the status information also to check if DisplayPort HPD is still asserted when the cable plug is disconnected, and clearing it if it is. Signed-off-by: Heikki Krogerus Signed-off-by: Rajmohan Mani --- drivers/usb/typec/mux/Kconfig | 1 + drivers/usb/typec/mux/intel_pmc_mux.c | 75 +++++++++++++++++++++++---- 2 files changed, 65 insertions(+), 11 deletions(-) diff --git a/drivers/usb/typec/mux/Kconfig b/drivers/usb/typec/mux/Kconfig index a4dbd11f8ee2..46f5512de63d 100644 --- a/drivers/usb/typec/mux/Kconfig +++ b/drivers/usb/typec/mux/Kconfig @@ -12,6 +12,7 @@ config TYPEC_MUX_PI3USB30532 config TYPEC_MUX_INTEL_PMC tristate "Intel PMC mux control" depends on INTEL_SCU_IPC + depends on INTEL_IOM select USB_ROLE_SWITCH help Driver for USB muxes controlled by Intel PMC FW. Intel PMC FW can diff --git a/drivers/usb/typec/mux/intel_pmc_mux.c b/drivers/usb/typec/mux/intel_pmc_mux.c index e4021e13af40..c758d6113c41 100644 --- a/drivers/usb/typec/mux/intel_pmc_mux.c +++ b/drivers/usb/typec/mux/intel_pmc_mux.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -83,10 +84,22 @@ enum { #define PMC_USB_DP_HPD_LVL BIT(4) #define PMC_USB_DP_HPD_IRQ BIT(5) +/* IOM Port Status */ +#define IOM_PORT_ACTIVITY_IS(_status_, _type_) \ + ((((_status_) & IOM_PORT_STATUS_ACTIVITY_TYPE_MASK) >> \ + IOM_PORT_STATUS_ACTIVITY_TYPE_SHIFT) == \ + (IOM_PORT_STATUS_ACTIVITY_TYPE_##_type_)) + +#define IOM_PORT_HPD_ASSERTED(_status_) \ + ((((_status_) & IOM_PORT_STATUS_DHPD_HPD_STATUS_MASK) >> \ + IOM_PORT_STATUS_DHPD_HPD_STATUS_SHIFT) & \ + IOM_PORT_STATUS_DHPD_HPD_STATUS_ASSERT) + struct pmc_usb; struct pmc_usb_port { int num; + u32 iom_status; struct pmc_usb *pmc; struct typec_mux *typec_mux; struct typec_switch *typec_sw; @@ -145,18 +158,17 @@ static int pmc_usb_command(struct pmc_usb_port *port, u8 *msg, u32 len) } static int -pmc_usb_mux_dp_hpd(struct pmc_usb_port *port, struct typec_mux_state *state) +pmc_usb_mux_dp_hpd(struct pmc_usb_port *port, struct typec_displayport_data *dp) { - struct typec_displayport_data *data = state->data; u8 msg[2] = { }; msg[0] = PMC_USB_DP_HPD; msg[0] |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT; - if (data->status & DP_STATUS_IRQ_HPD) + if (dp->status & DP_STATUS_IRQ_HPD) msg[1] = PMC_USB_DP_HPD_IRQ; - if (data->status & DP_STATUS_HPD_STATE) + if (dp->status & DP_STATUS_HPD_STATE) msg[1] |= PMC_USB_DP_HPD_LVL; return pmc_usb_command(port, msg, sizeof(msg)); @@ -169,8 +181,18 @@ pmc_usb_mux_dp(struct pmc_usb_port *port, struct typec_mux_state *state) struct altmode_req req = { }; int ret; + if (IOM_PORT_ACTIVITY_IS(port->iom_status, DP) || + IOM_PORT_ACTIVITY_IS(port->iom_status, DP_MFD)) { + if (IOM_PORT_HPD_ASSERTED(port->iom_status) && + (!(data->status & DP_STATUS_IRQ_HPD) && + data->status & DP_STATUS_HPD_STATE)) + return 0; + + return pmc_usb_mux_dp_hpd(port, state->data); + } + if (data->status & DP_STATUS_IRQ_HPD) - return pmc_usb_mux_dp_hpd(port, state); + return pmc_usb_mux_dp_hpd(port, state->data); req.usage = PMC_USB_ALT_MODE; req.usage |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT; @@ -192,8 +214,8 @@ pmc_usb_mux_dp(struct pmc_usb_port *port, struct typec_mux_state *state) if (ret) return ret; - if (data->status & DP_STATUS_HPD_STATE) - return pmc_usb_mux_dp_hpd(port, state); + if (data->status & (DP_STATUS_IRQ_HPD | DP_STATUS_HPD_STATE)) + return pmc_usb_mux_dp_hpd(port, state->data); return 0; } @@ -205,6 +227,10 @@ pmc_usb_mux_tbt(struct pmc_usb_port *port, struct typec_mux_state *state) u8 cable_speed = TBT_CABLE_SPEED(data->cable_mode); struct altmode_req req = { }; + if (IOM_PORT_ACTIVITY_IS(port->iom_status, TBT) || + IOM_PORT_ACTIVITY_IS(port->iom_status, ALT_MODE_TBT_USB)) + return 0; + req.usage = PMC_USB_ALT_MODE; req.usage |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT; req.mode_type = PMC_USB_MODE_TYPE_TBT << PMC_USB_MODE_TYPE_SHIFT; @@ -239,6 +265,10 @@ pmc_usb_mux_usb4(struct pmc_usb_port *port, struct typec_mux_state *state) struct altmode_req req = { }; u8 cable_speed; + if (IOM_PORT_ACTIVITY_IS(port->iom_status, TBT) || + IOM_PORT_ACTIVITY_IS(port->iom_status, ALT_MODE_TBT_USB)) + return 0; + req.usage = PMC_USB_ALT_MODE; req.usage |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT; req.mode_type = PMC_USB_MODE_TYPE_TBT << PMC_USB_MODE_TYPE_SHIFT; @@ -273,6 +303,9 @@ static int pmc_usb_mux_safe_state(struct pmc_usb_port *port) { u8 msg; + if (IOM_PORT_ACTIVITY_IS(port->iom_status, SAFE_MODE)) + return 0; + msg = PMC_USB_SAFE_MODE; msg |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT; @@ -283,6 +316,9 @@ static int pmc_usb_connect(struct pmc_usb_port *port) { u8 msg[2]; + if (port->iom_status & IOM_PORT_STATUS_CONNECTED) + return 0; + msg[0] = PMC_USB_CONNECT; msg[0] |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT; @@ -295,8 +331,16 @@ static int pmc_usb_connect(struct pmc_usb_port *port) static int pmc_usb_disconnect(struct pmc_usb_port *port) { + struct typec_displayport_data data = { }; u8 msg[2]; + if (!(port->iom_status & IOM_PORT_STATUS_CONNECTED)) + return 0; + + /* Clear DisplayPort HPD if it's still asserted. */ + if (IOM_PORT_HPD_ASSERTED(port->iom_status)) + pmc_usb_mux_dp_hpd(port, &data); + msg[0] = PMC_USB_DISCONNECT; msg[0] |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT; @@ -309,6 +353,11 @@ static int pmc_usb_mux_set(struct typec_mux *mux, struct typec_mux_state *state) { struct pmc_usb_port *port = typec_mux_get_drvdata(mux); + int ret; + + ret = intel_iom_port_status(port->num, &port->iom_status); + if (ret) + return ret; if (port->orientation == TYPEC_ORIENTATION_NONE || port->role == USB_ROLE_NONE) return 0; @@ -344,9 +393,11 @@ static int pmc_usb_set_orientation(struct typec_switch *sw, enum typec_orientation orientation) { struct pmc_usb_port *port = typec_switch_get_drvdata(sw); + int ret; - if (port->orientation == orientation) - return 0; + ret = intel_iom_port_status(port->num, &port->iom_status); + if (ret) + return ret; port->orientation = orientation; @@ -363,9 +414,11 @@ static int pmc_usb_set_orientation(struct typec_switch *sw, static int pmc_usb_set_role(struct usb_role_switch *sw, enum usb_role role) { struct pmc_usb_port *port = usb_role_switch_get_drvdata(sw); + int ret; - if (port->role == role) - return 0; + ret = intel_iom_port_status(port->num, &port->iom_status); + if (ret) + return ret; port->role = role; From patchwork Sat Aug 22 04:05:08 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Mani, Rajmohan" X-Patchwork-Id: 11730885 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 4C47F14F6 for ; Sat, 22 Aug 2020 04:42:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 371AA20720 for ; Sat, 22 Aug 2020 04:42:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726885AbgHVEmQ (ORCPT ); Sat, 22 Aug 2020 00:42:16 -0400 Received: from mga11.intel.com ([192.55.52.93]:62114 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725840AbgHVEmK (ORCPT ); Sat, 22 Aug 2020 00:42:10 -0400 IronPort-SDR: fVSt6qW7t56PouEtv0eYWPHnAIHkYgoi42c4uz+g8J4wtYOC1Y2/BRIGDC+IvUTPTk+aFVuajK 0vJg05kgX3Qg== X-IronPort-AV: E=McAfee;i="6000,8403,9720"; a="153275287" X-IronPort-AV: E=Sophos;i="5.76,339,1592895600"; d="scan'208";a="153275287" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga008.jf.intel.com ([10.7.209.65]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Aug 2020 21:42:01 -0700 IronPort-SDR: griWtDcJu82w9E+SGCJUbsLhzP1NJ6oVRQ6OMPvx3UflMk7vkzDwFSCtrgD8EdkjVUk+48o7Qq b0xXQG4a6W9w== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.76,339,1592895600"; d="scan'208";a="327943130" Received: from glacier.sc.intel.com ([10.3.62.63]) by orsmga008.jf.intel.com with ESMTP; 21 Aug 2020 21:42:01 -0700 From: Rajmohan Mani To: Darren Hart , Andy Shevchenko , Mika Westerberg , Dmitry Torokhov , Lee Jones , Ayman Bagabas , Masahiro Yamada , Jithu Joseph , =?utf-8?q?Bla=C5=BE_Hrastnik?= , Srinivas Pandruvada , linux-kernel@vger.kernel.org, platform-driver-x86@vger.kernel.org, Heikki Krogerus , Greg Kroah-Hartman , linux-usb@vger.kernel.org Cc: pmalani@chromium.org, bleung@chromium.org, Rajmohan Mani Subject: [PATCH v2 3/3] usb: typec: intel_pmc_mux: Support for device role (UFP) Date: Fri, 21 Aug 2020 21:05:08 -0700 Message-Id: <20200822040508.23510-4-rajmohan.mani@intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200822040508.23510-1-rajmohan.mani@intel.com> References: <20200822040508.23510-1-rajmohan.mani@intel.com> MIME-Version: 1.0 Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org From: Heikki Krogerus This adds support for device data role, and data role swapping. The driver no longer relies on the cached role, as it may not be valid (for example after bootup). Instead, the role is always checked by readding the port status from IOM. Note. After this, the orientation is always only cached, so the driver does not support scenario where the role is set before orientation. It means the typec drivers must always set the orientation first before role. Signed-off-by: Heikki Krogerus Signed-off-by: Rajmohan Mani --- drivers/usb/typec/mux/intel_pmc_mux.c | 67 ++++++++++++++------------- 1 file changed, 34 insertions(+), 33 deletions(-) diff --git a/drivers/usb/typec/mux/intel_pmc_mux.c b/drivers/usb/typec/mux/intel_pmc_mux.c index c758d6113c41..d4ee7132227b 100644 --- a/drivers/usb/typec/mux/intel_pmc_mux.c +++ b/drivers/usb/typec/mux/intel_pmc_mux.c @@ -191,9 +191,6 @@ pmc_usb_mux_dp(struct pmc_usb_port *port, struct typec_mux_state *state) return pmc_usb_mux_dp_hpd(port, state->data); } - if (data->status & DP_STATUS_IRQ_HPD) - return pmc_usb_mux_dp_hpd(port, state->data); - req.usage = PMC_USB_ALT_MODE; req.usage |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT; req.mode_type = PMC_USB_MODE_TYPE_DP << PMC_USB_MODE_TYPE_SHIFT; @@ -312,39 +309,52 @@ static int pmc_usb_mux_safe_state(struct pmc_usb_port *port) return pmc_usb_command(port, &msg, sizeof(msg)); } -static int pmc_usb_connect(struct pmc_usb_port *port) +static int pmc_usb_disconnect(struct pmc_usb_port *port) { + struct typec_displayport_data data = { }; u8 msg[2]; - if (port->iom_status & IOM_PORT_STATUS_CONNECTED) + if (!(port->iom_status & IOM_PORT_STATUS_CONNECTED)) return 0; - msg[0] = PMC_USB_CONNECT; + /* Clear DisplayPort HPD if it's still asserted. */ + if (IOM_PORT_HPD_ASSERTED(port->iom_status)) + pmc_usb_mux_dp_hpd(port, &data); + + msg[0] = PMC_USB_DISCONNECT; msg[0] |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT; msg[1] = port->usb2_port << PMC_USB_MSG_USB2_PORT_SHIFT; - msg[1] |= hsl_orientation(port) << PMC_USB_MSG_ORI_HSL_SHIFT; - msg[1] |= sbu_orientation(port) << PMC_USB_MSG_ORI_AUX_SHIFT; return pmc_usb_command(port, msg, sizeof(msg)); } -static int pmc_usb_disconnect(struct pmc_usb_port *port) +static int pmc_usb_connect(struct pmc_usb_port *port, enum usb_role role) { - struct typec_displayport_data data = { }; + u8 ufp = role == USB_ROLE_DEVICE ? 1 : 0; u8 msg[2]; + int ret; - if (!(port->iom_status & IOM_PORT_STATUS_CONNECTED)) - return 0; + if (port->orientation == TYPEC_ORIENTATION_NONE) + return -EINVAL; - /* Clear DisplayPort HPD if it's still asserted. */ - if (IOM_PORT_HPD_ASSERTED(port->iom_status)) - pmc_usb_mux_dp_hpd(port, &data); + if (port->iom_status & IOM_PORT_STATUS_CONNECTED) { + if (port->role == role || port->role == USB_ROLE_NONE) + return 0; - msg[0] = PMC_USB_DISCONNECT; + /* Role swap */ + ret = pmc_usb_disconnect(port); + if (ret) + return ret; + } + + msg[0] = PMC_USB_CONNECT; msg[0] |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT; msg[1] = port->usb2_port << PMC_USB_MSG_USB2_PORT_SHIFT; + msg[1] |= ufp << PMC_USB_MSG_UFP_SHIFT; + msg[1] |= hsl_orientation(port) << PMC_USB_MSG_ORI_HSL_SHIFT; + msg[1] |= sbu_orientation(port) << PMC_USB_MSG_ORI_AUX_SHIFT; return pmc_usb_command(port, msg, sizeof(msg)); } @@ -365,7 +375,7 @@ pmc_usb_mux_set(struct typec_mux *mux, struct typec_mux_state *state) if (state->mode == TYPEC_STATE_SAFE) return pmc_usb_mux_safe_state(port); if (state->mode == TYPEC_STATE_USB) - return pmc_usb_connect(port); + return pmc_usb_connect(port, port->role); if (state->alt) { switch (state->alt->svid) { @@ -380,7 +390,7 @@ pmc_usb_mux_set(struct typec_mux *mux, struct typec_mux_state *state) /* REVISIT: Try with usb3_port set to 0? */ break; case TYPEC_MODE_USB3: - return pmc_usb_connect(port); + return pmc_usb_connect(port, port->role); case TYPEC_MODE_USB4: return pmc_usb_mux_usb4(port, state); } @@ -401,13 +411,6 @@ static int pmc_usb_set_orientation(struct typec_switch *sw, port->orientation = orientation; - if (port->role) { - if (orientation == TYPEC_ORIENTATION_NONE) - return pmc_usb_disconnect(port); - else - return pmc_usb_connect(port); - } - return 0; } @@ -420,16 +423,14 @@ static int pmc_usb_set_role(struct usb_role_switch *sw, enum usb_role role) if (ret) return ret; - port->role = role; + if (role == USB_ROLE_NONE) + ret = pmc_usb_disconnect(port); + else + ret = pmc_usb_connect(port, role); - if (port->orientation) { - if (role == USB_ROLE_NONE) - return pmc_usb_disconnect(port); - else - return pmc_usb_connect(port); - } + port->role = role; - return 0; + return ret; } static int pmc_usb_register_port(struct pmc_usb *pmc, int index,