From patchwork Sun Feb 18 22:20:34 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Christian A. Ehrhardt" X-Patchwork-Id: 13562079 Received: from cae.in-ulm.de (cae.in-ulm.de [217.10.14.231]) by smtp.subspace.kernel.org (Postfix) with ESMTP id F27F6745D7; Sun, 18 Feb 2024 22:21:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.10.14.231 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708294873; cv=none; b=PCiofYbiDor9OXtRd2tN122CdPy0e25VO/w48CAT6u1xPA68wP43X2TxYjbkC8Pcy9H0cpQfxgeGGvJ0T5DzBXX2yjFkIOYcXtHdzkzsaCg8bzxYXNzxDA4NxkYwXHJOEGW0pEJgu19MyWSHUCOermL/DRTiZ6q6uLkMCZQMZnM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708294873; c=relaxed/simple; bh=+oUmu5Lwbn9zC+hXil5i/V1qhWii7H7GOEZRyRLVGsk=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=Saj8JFilm4DfvwJffk3vsjEcDaTgUttyFEliUthI05bqPl6bBWFuNOcP9RqZci3VeAdHh9kzLvjHsqMucmUYinIvTXW4TzcxB0e9uf4QjJS76AgBEb9BDpYfxVCMTMLUfhBziQ3wGCDWM7szUbZuNt/B69IZqUsojCOLBcdoHnk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=c--e.de; spf=pass smtp.mailfrom=c--e.de; arc=none smtp.client-ip=217.10.14.231 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=c--e.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=c--e.de Received: by cae.in-ulm.de (Postfix, from userid 1000) id E687C14028D; Sun, 18 Feb 2024 23:21:04 +0100 (CET) From: "Christian A. Ehrhardt" To: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org Cc: "Christian A. Ehrhardt" , Heikki Krogerus , Greg Kroah-Hartman , Maxime Coquelin , Alexandre Torgue , =?utf-8?q?Uwe_Kleine-K?= =?utf-8?q?=C3=B6nig?= , =?utf-8?q?Samuel_?= =?utf-8?q?=C4=8Cavoj?= , Hans de Goede , Neil Armstrong , Prashanth K , Dmitry Baryshkov , Saranya Gopal , Haotien Hsu , Andy Shevchenko , Utkarsh Patel , Bjorn Andersson , Luca Weiss , Min-Hua Chen , Rob Herring , Rajaram Regupathy , linux-stm32@st-md-mailman.stormreply.com, linux-arm-kernel@lists.infradead.org, Abhishek Pandit-Subedi Subject: [RFC PATCH 1/6] usb: ucsi_glink: Fix endianness issues Date: Sun, 18 Feb 2024 23:20:34 +0100 Message-Id: <20240218222039.822040-2-lk@c--e.de> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20240218222039.822040-1-lk@c--e.de> References: <20240218222039.822040-1-lk@c--e.de> Precedence: bulk X-Mailing-List: linux-usb@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Sparse complains that some little endian header fields are assigned from plain integer values. Add the proper cpu_to_le32() calls. Signed-off-by: Christian A. Ehrhardt --- drivers/usb/typec/ucsi/ucsi_glink.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/usb/typec/ucsi/ucsi_glink.c b/drivers/usb/typec/ucsi/ucsi_glink.c index 0bd3f6dee678..0a0d08467c56 100644 --- a/drivers/usb/typec/ucsi/ucsi_glink.c +++ b/drivers/usb/typec/ucsi/ucsi_glink.c @@ -85,9 +85,9 @@ static int pmic_glink_ucsi_read(struct ucsi *__ucsi, unsigned int offset, unsigned long left; int ret; - req.hdr.owner = PMIC_GLINK_OWNER_USBC; - req.hdr.type = MSG_TYPE_REQ_RESP; - req.hdr.opcode = UC_UCSI_READ_BUF_REQ; + req.hdr.owner = cpu_to_le32(PMIC_GLINK_OWNER_USBC); + req.hdr.type = cpu_to_le32(MSG_TYPE_REQ_RESP); + req.hdr.opcode = cpu_to_le32(UC_UCSI_READ_BUF_REQ); mutex_lock(&ucsi->lock); memset(ucsi->read_buf, 0, sizeof(ucsi->read_buf)); @@ -122,9 +122,9 @@ static int pmic_glink_ucsi_locked_write(struct pmic_glink_ucsi *ucsi, unsigned i unsigned long left; int ret; - req.hdr.owner = PMIC_GLINK_OWNER_USBC; - req.hdr.type = MSG_TYPE_REQ_RESP; - req.hdr.opcode = UC_UCSI_WRITE_BUF_REQ; + req.hdr.owner = cpu_to_le32(PMIC_GLINK_OWNER_USBC); + req.hdr.type = cpu_to_le32(MSG_TYPE_REQ_RESP); + req.hdr.opcode = cpu_to_le32(UC_UCSI_WRITE_BUF_REQ); memcpy(&req.buf[offset], val, val_len); reinit_completion(&ucsi->write_ack); From patchwork Sun Feb 18 22:20:35 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Christian A. Ehrhardt" X-Patchwork-Id: 13562080 Received: from cae.in-ulm.de (cae.in-ulm.de [217.10.14.231]) by smtp.subspace.kernel.org (Postfix) with ESMTP id A542C745F8; Sun, 18 Feb 2024 22:21:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.10.14.231 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708294874; cv=none; b=h/dpz4qza7HxsTjMYNNmBg/jkdsOPXTPz4HcdZaJZrHRk7eA9J+QwvtCiP0ijmLPlxfSnnLwu5DB3JPW84z8JWZIcH7ogOh/HpnBb7MC2XUycn/NLuj1vz/2UJmu7cUQTxOI4oEZNGI4CBH6+5qbfk84/WeWEY61f5BHSdwgf28= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708294874; c=relaxed/simple; bh=+stEjvwEshPruJnaSd7743lZYwerj31wMavbwUiF8lQ=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=jMdcFGeziHoCeiPlLnOew0XGSLB1ChGph5ISBwi5k9uPwcw/p0doFrtG3jB7Xff9q5pqP1FAoC9A145Jw35QUcJH+TTnDTHPrdREsy0a5QUNH3WONGTT+iCUseUpX4j/5Tff2/1h+djy9Tgr20Ij6cCWrEbp/CWcmJ32S25YIBo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=c--e.de; spf=pass smtp.mailfrom=c--e.de; arc=none smtp.client-ip=217.10.14.231 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=c--e.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=c--e.de Received: by cae.in-ulm.de (Postfix, from userid 1000) id CE2C414033C; Sun, 18 Feb 2024 23:21:05 +0100 (CET) From: "Christian A. Ehrhardt" To: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org Cc: "Christian A. Ehrhardt" , Heikki Krogerus , Greg Kroah-Hartman , Maxime Coquelin , Alexandre Torgue , =?utf-8?q?Uwe_Kleine-K?= =?utf-8?q?=C3=B6nig?= , =?utf-8?q?Samuel_?= =?utf-8?q?=C4=8Cavoj?= , Hans de Goede , Neil Armstrong , Prashanth K , Dmitry Baryshkov , Saranya Gopal , Haotien Hsu , Andy Shevchenko , Utkarsh Patel , Bjorn Andersson , Luca Weiss , Min-Hua Chen , Rob Herring , Rajaram Regupathy , linux-stm32@st-md-mailman.stormreply.com, linux-arm-kernel@lists.infradead.org, Abhishek Pandit-Subedi Subject: [RFC PATCH 2/6] ucsi_ccg: Cleanup endianness confusion Date: Sun, 18 Feb 2024 23:20:35 +0100 Message-Id: <20240218222039.822040-3-lk@c--e.de> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20240218222039.822040-1-lk@c--e.de> References: <20240218222039.822040-1-lk@c--e.de> Precedence: bulk X-Mailing-List: linux-usb@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 When storing the cci value in the op_region struct it is converted from host to little endian. However, the value is read from hardware that is little endian according to the spec and it is never converted to host byte order. However, the value is used as if it where in host byte order. Additionally, the message_in buffer is a byte array. Any endian interpretation depends on the current command and must be done in the ocntext of that command. While all the UCSI world seems to be little endian and there are many other endian issues if this is not true, this particular value is treated with endian awareness, so it should at least be done correctly. Add the missing conversion from little endian to host byte order when reading the CCI value from hardware. Additionally, make the message_in buffer an u8 array and adjust the size macro accordingly. Signed-off-by: Christian A. Ehrhardt --- drivers/usb/typec/ucsi/ucsi_ccg.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c index dda7c7c94e08..709295948c65 100644 --- a/drivers/usb/typec/ucsi/ucsi_ccg.c +++ b/drivers/usb/typec/ucsi/ucsi_ccg.c @@ -192,10 +192,10 @@ struct ucsi_ccg_altmode { bool checked; } __packed; -#define CCGX_MESSAGE_IN_MAX 4 +#define CCGX_MESSAGE_IN_MAX 16 struct op_region { __le32 cci; - __le32 message_in[CCGX_MESSAGE_IN_MAX]; + u8 message_in[CCGX_MESSAGE_IN_MAX]; }; struct ucsi_ccg { @@ -678,6 +678,7 @@ static irqreturn_t ccg_irq_handler(int irq, void *data) u16 reg = CCGX_RAB_UCSI_DATA_BLOCK(UCSI_CCI); struct ucsi_ccg *uc = data; u8 intr_reg; + __le32 __cci; u32 cci = 0; int ret = 0; @@ -690,9 +691,10 @@ static irqreturn_t ccg_irq_handler(int irq, void *data) else if (!(intr_reg & UCSI_READ_INT)) goto err_clear_irq; - ret = ccg_read(uc, reg, (void *)&cci, sizeof(cci)); + ret = ccg_read(uc, reg, (void *)&__cci, sizeof(__cci)); if (ret) goto err_clear_irq; + cci = le32_to_cpu(__cci); if (UCSI_CCI_CONNECTOR(cci)) ucsi_connector_change(uc->ucsi, UCSI_CCI_CONNECTOR(cci)); From patchwork Sun Feb 18 22:20:36 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Christian A. Ehrhardt" X-Patchwork-Id: 13562081 Received: from cae.in-ulm.de (cae.in-ulm.de [217.10.14.231]) by smtp.subspace.kernel.org (Postfix) with ESMTP id A539B745F5; Sun, 18 Feb 2024 22:21:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.10.14.231 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708294874; cv=none; b=NCqWZPkEcPcXAp6Yefim8zg5fGEoks+/ms0f7lPXM8c1PSgJW29/UMGgaD/phXf20MlfyKS82fZdFTOEOdJ2c99uPe5+HFcQB6Gg1MgioqQTdbv43ZpELcCskDsq/XVnLUspmCfJFYUQKwAQH6SB+pqYlWTpieuZtWBQnb28Y1w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708294874; c=relaxed/simple; bh=90d1Gk641CL4PH6COhYb2mytDzl7/+xBe25WQoQ3r3k=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=TTiHBgPNnkX4pLCZAaRlVyX5fsvJ5Vf7JUMXTG0qSyw9zm1nQD3l3sWbDxI5OKYbxKW7CutUZ6nownSo2g8mYfG1bdu1h5Pjlx/C+BabbGCzH2CSgXqjbYmgaKsgNKzhOwtu3VHwxzfk+t/K0k4GAWHMHbe2B+NPvIfkQKiplhk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=c--e.de; spf=pass smtp.mailfrom=c--e.de; arc=none smtp.client-ip=217.10.14.231 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=c--e.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=c--e.de Received: by cae.in-ulm.de (Postfix, from userid 1000) id 92A2E140406; Sun, 18 Feb 2024 23:21:06 +0100 (CET) From: "Christian A. Ehrhardt" To: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org Cc: "Christian A. Ehrhardt" , Heikki Krogerus , Greg Kroah-Hartman , Maxime Coquelin , Alexandre Torgue , =?utf-8?q?Uwe_Kleine-K?= =?utf-8?q?=C3=B6nig?= , =?utf-8?q?Samuel_?= =?utf-8?q?=C4=8Cavoj?= , Hans de Goede , Neil Armstrong , Prashanth K , Dmitry Baryshkov , Saranya Gopal , Haotien Hsu , Andy Shevchenko , Utkarsh Patel , Bjorn Andersson , Luca Weiss , Min-Hua Chen , Rob Herring , Rajaram Regupathy , linux-stm32@st-md-mailman.stormreply.com, linux-arm-kernel@lists.infradead.org, Abhishek Pandit-Subedi Subject: [RFC PATCH 3/6] usb: typec: ucsi: Make Version a parameter to ucsi_register Date: Sun, 18 Feb 2024 23:20:36 +0100 Message-Id: <20240218222039.822040-4-lk@c--e.de> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20240218222039.822040-1-lk@c--e.de> References: <20240218222039.822040-1-lk@c--e.de> Precedence: bulk X-Mailing-List: linux-usb@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Reading UCSI_VERSION is a special case as there is no notification that syncs the data into host memory. Read UCSI_VERSION only once during initialization and provide it as a parameter to ucsi_register(). Signed-off-by: Christian A. Ehrhardt --- drivers/usb/typec/ucsi/ucsi.c | 13 ++++--------- drivers/usb/typec/ucsi/ucsi.h | 2 +- drivers/usb/typec/ucsi/ucsi_acpi.c | 8 +++++++- drivers/usb/typec/ucsi/ucsi_ccg.c | 12 ++++++++++-- drivers/usb/typec/ucsi/ucsi_glink.c | 11 ++++++++++- drivers/usb/typec/ucsi/ucsi_stm32g0.c | 26 ++++++++++++++++++++++---- 6 files changed, 54 insertions(+), 18 deletions(-) diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index ae105383e69e..eb630447ba80 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -1581,18 +1581,13 @@ EXPORT_SYMBOL_GPL(ucsi_destroy); /** * ucsi_register - Register UCSI interface * @ucsi: UCSI instance + * @version: The revision of the UCSI spec */ -int ucsi_register(struct ucsi *ucsi) +int ucsi_register(struct ucsi *ucsi, u16 version) { - int ret; - - ret = ucsi->ops->read(ucsi, UCSI_VERSION, &ucsi->version, - sizeof(ucsi->version)); - if (ret) - return ret; - - if (!ucsi->version) + if (!version) return -ENODEV; + ucsi->version = version; /* * Version format is JJ.M.N (JJ = Major version, M = Minor version, diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h index 7e35ffbe0a6f..100e16b49814 100644 --- a/drivers/usb/typec/ucsi/ucsi.h +++ b/drivers/usb/typec/ucsi/ucsi.h @@ -77,7 +77,7 @@ struct ucsi_operations { struct ucsi *ucsi_create(struct device *dev, const struct ucsi_operations *ops); void ucsi_destroy(struct ucsi *ucsi); -int ucsi_register(struct ucsi *ucsi); +int ucsi_register(struct ucsi *ucsi, u16 version); void ucsi_unregister(struct ucsi *ucsi); void *ucsi_get_drvdata(struct ucsi *ucsi); void ucsi_set_drvdata(struct ucsi *ucsi, void *data); diff --git a/drivers/usb/typec/ucsi/ucsi_acpi.c b/drivers/usb/typec/ucsi/ucsi_acpi.c index 928eacbeb21a..710ddfc03ed0 100644 --- a/drivers/usb/typec/ucsi/ucsi_acpi.c +++ b/drivers/usb/typec/ucsi/ucsi_acpi.c @@ -226,6 +226,7 @@ static int ucsi_acpi_probe(struct platform_device *pdev) const struct dmi_system_id *id; struct ucsi_acpi *ua; struct resource *res; + u16 version; acpi_status status; int ret; @@ -272,7 +273,12 @@ static int ucsi_acpi_probe(struct platform_device *pdev) return -ENODEV; } - ret = ucsi_register(ua->ucsi); + ret = ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_READ); + if (ret) + return ret; + version = le16_to_cpu(*(__le16 *)(ua->base + UCSI_VERSION)); + + ret = ucsi_register(ua->ucsi, version); if (ret) { acpi_remove_notify_handler(ACPI_HANDLE(&pdev->dev), ACPI_DEVICE_NOTIFY, diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c index 709295948c65..d47f5e31c98a 100644 --- a/drivers/usb/typec/ucsi/ucsi_ccg.c +++ b/drivers/usb/typec/ucsi/ucsi_ccg.c @@ -1356,7 +1356,7 @@ static int ccg_restart(struct ucsi_ccg *uc) return status; } - status = ucsi_register(uc->ucsi); + status = ucsi_register(uc->ucsi, uc->ucsi->version); if (status) { dev_err(uc->dev, "failed to register the interface\n"); return status; @@ -1422,6 +1422,7 @@ static int ucsi_ccg_probe(struct i2c_client *client) struct ucsi_ccg *uc; const char *fw_name; int status; + __le16 version; uc = devm_kzalloc(dev, sizeof(*uc), GFP_KERNEL); if (!uc) @@ -1477,7 +1478,14 @@ static int ucsi_ccg_probe(struct i2c_client *client) goto out_ucsi_destroy; } - status = ucsi_register(uc->ucsi); + status = ccg_read(uc, CCGX_RAB_UCSI_DATA_BLOCK(UCSI_VERSION), + (u8 *)&version, sizeof(version)); + if (status < 0) { + dev_err(uc->dev, "cannot read UCSI version - %d\n", status); + return status; + } + + status = ucsi_register(uc->ucsi, le16_to_cpu(version)); if (status) goto out_free_irq; diff --git a/drivers/usb/typec/ucsi/ucsi_glink.c b/drivers/usb/typec/ucsi/ucsi_glink.c index 0a0d08467c56..7a0b28536abd 100644 --- a/drivers/usb/typec/ucsi/ucsi_glink.c +++ b/drivers/usb/typec/ucsi/ucsi_glink.c @@ -255,8 +255,17 @@ static void pmic_glink_ucsi_notify(struct work_struct *work) static void pmic_glink_ucsi_register(struct work_struct *work) { struct pmic_glink_ucsi *ucsi = container_of(work, struct pmic_glink_ucsi, register_work); + __le16 version; + int ret; + + ret = pmic_glink_ucsi_read(ucsi->ucsi, UCSI_VERSION, &version, + sizeof(version)); + if (ret < 0) { + dev_err(ucsi->dev, "cannot read version: %d\n", ret); + return; + } - ucsi_register(ucsi->ucsi); + ucsi_register(ucsi->ucsi, le16_to_cpu(version)); } static void pmic_glink_ucsi_callback(const void *data, size_t len, void *priv) diff --git a/drivers/usb/typec/ucsi/ucsi_stm32g0.c b/drivers/usb/typec/ucsi/ucsi_stm32g0.c index 93d7806681cf..112692c7a158 100644 --- a/drivers/usb/typec/ucsi/ucsi_stm32g0.c +++ b/drivers/usb/typec/ucsi/ucsi_stm32g0.c @@ -325,10 +325,10 @@ static int ucsi_stm32g0_fw_rcv(struct ucsi *ucsi, void *data, size_t len) return ucsi_stm32g0_bl_rcv_woack(ucsi, data, len); } -/* UCSI ops */ -static int ucsi_stm32g0_read(struct ucsi *ucsi, unsigned int offset, void *val, size_t len) +static int ucsi_stm32g0_read_from_hw(struct ucsi_stm32g0 *g0, + unsigned int offset, + void *val, size_t len) { - struct ucsi_stm32g0 *g0 = ucsi_get_drvdata(ucsi); struct i2c_client *client = g0->client; u8 reg = offset; struct i2c_msg msg[] = { @@ -357,6 +357,15 @@ static int ucsi_stm32g0_read(struct ucsi *ucsi, unsigned int offset, void *val, return 0; } +/* UCSI ops */ +static int ucsi_stm32g0_read(struct ucsi *ucsi, unsigned int offset, + void *val, size_t len) +{ + struct ucsi_stm32g0 *g0 = ucsi_get_drvdata(ucsi); + + return ucsi_stm32g0_read_from_hw(g0, offset, val, len); +} + static int ucsi_stm32g0_async_write(struct ucsi *ucsi, unsigned int offset, const void *val, size_t len) { @@ -445,6 +454,7 @@ static int ucsi_stm32g0_register(struct ucsi *ucsi) { struct ucsi_stm32g0 *g0 = ucsi_get_drvdata(ucsi); struct i2c_client *client = g0->client; + __le16 version; int ret; /* Request alert interrupt */ @@ -455,7 +465,15 @@ static int ucsi_stm32g0_register(struct ucsi *ucsi) return ret; } - ret = ucsi_register(ucsi); + ret = ucsi_stm32g0_read_from_hw(g0, UCSI_VERSION, &version, + sizeof(version)); + if (ret) { + dev_err(g0->dev, "failed to read version number: %d\n", ret); + free_irq(client->irq, g0); + return ret; + } + + ret = ucsi_register(ucsi, le16_to_cpu(version)); if (ret) { dev_err_probe(g0->dev, ret, "ucsi_register failed\n"); free_irq(client->irq, g0); From patchwork Sun Feb 18 22:20:37 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Christian A. Ehrhardt" X-Patchwork-Id: 13562078 Received: from cae.in-ulm.de (cae.in-ulm.de [217.10.14.231]) by smtp.subspace.kernel.org (Postfix) with ESMTP id BF1F3EAD7; Sun, 18 Feb 2024 22:21:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.10.14.231 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708294872; cv=none; b=EtfzXCeL4Nr/eU3talRc3Rea1KqB63mvzNXgeH14jIN03TfT9Wq22WxUp0W73gC18F6Bxojj7xniYpctrN9X8gmNX1nWFQznlx0Olr6y6qTgIxxfVA+2Qpg1yXBmcHkvW3oD9UerxayIufKW1w9xuGOru4S5WgRTIZ47pFkjPH8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708294872; c=relaxed/simple; bh=Wo3mJx+7+d555EOF/dD4YGtyScjPacLMcmEkGZC9OFQ=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=SiZie+MtSwm47Gvh5SMcCqrzKst0a0fM7T9G1KBpCn5wg7t02iNcpcG6UwBTImpVORSTjD7VRd3UGCDSf5IBOyVhgZ24fTeqbSk/8qxNGwTWeQ4bY9ebMBh5LR5jOuHn1hd7+uASF3W+y/10i6P8DvQI5IhCNy0QhOozXinsOJo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=c--e.de; spf=pass smtp.mailfrom=c--e.de; arc=none smtp.client-ip=217.10.14.231 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=c--e.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=c--e.de Received: by cae.in-ulm.de (Postfix, from userid 1000) id 4BB4E140929; Sun, 18 Feb 2024 23:21:07 +0100 (CET) From: "Christian A. Ehrhardt" To: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org Cc: "Christian A. Ehrhardt" , Heikki Krogerus , Greg Kroah-Hartman , Maxime Coquelin , Alexandre Torgue , =?utf-8?q?Uwe_Kleine-K?= =?utf-8?q?=C3=B6nig?= , =?utf-8?q?Samuel_?= =?utf-8?q?=C4=8Cavoj?= , Hans de Goede , Neil Armstrong , Prashanth K , Dmitry Baryshkov , Saranya Gopal , Haotien Hsu , Andy Shevchenko , Utkarsh Patel , Bjorn Andersson , Luca Weiss , Min-Hua Chen , Rob Herring , Rajaram Regupathy , linux-stm32@st-md-mailman.stormreply.com, linux-arm-kernel@lists.infradead.org, Abhishek Pandit-Subedi Subject: [RFC PATCH 4/6] usb: typec: ucsi: Cache current CCI value in struct ucsi Date: Sun, 18 Feb 2024 23:20:37 +0100 Message-Id: <20240218222039.822040-5-lk@c--e.de> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20240218222039.822040-1-lk@c--e.de> References: <20240218222039.822040-1-lk@c--e.de> Precedence: bulk X-Mailing-List: linux-usb@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 All notification handlers already read the CCI value. Reading it again from hardware in ucsi_execute_command() opens races and it is not clear that this really works. The zenbook quirk in ucsi_acpi.c is one case where a re-read causes problems. In the ACPI case it is not even necessary to sync the mailbox memory. According to the intel whitepaper the ACPI handler does this before it notifies the OS. Thus simply read the CCI value in the notification handler without any ACPI method calls. During reset of the PPM, it may be necessary to poll UCSI_CCI from hardware as the reset completion may not send a notification. Provide a new ->poll_cci API function that actively updates the CCI value from hardware for this case. While there take into account that the raw CCI value read from hardware is little endian and convert it to host byte order explicitly. Signed-off-by: Christian A. Ehrhardt --- drivers/usb/typec/ucsi/ucsi.c | 11 +++--- drivers/usb/typec/ucsi/ucsi.h | 5 +++ drivers/usb/typec/ucsi/ucsi_acpi.c | 53 ++++++++------------------- drivers/usb/typec/ucsi/ucsi_ccg.c | 38 +++++++------------ drivers/usb/typec/ucsi/ucsi_glink.c | 48 +++++++++++++++++++++--- drivers/usb/typec/ucsi/ucsi_stm32g0.c | 22 ++++++++++- 6 files changed, 101 insertions(+), 76 deletions(-) diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index eb630447ba80..a4ae3d5966a0 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -140,10 +140,7 @@ static int ucsi_exec_command(struct ucsi *ucsi, u64 cmd) ret = ucsi->ops->sync_write(ucsi, UCSI_CONTROL, &cmd, sizeof(cmd)); if (ret) return ret; - - ret = ucsi->ops->read(ucsi, UCSI_CCI, &cci, sizeof(cci)); - if (ret) - return ret; + cci = READ_ONCE(ucsi->cci); if (cmd != UCSI_CANCEL && cci & UCSI_CCI_BUSY) return ucsi_exec_command(ucsi, UCSI_CANCEL); @@ -1037,9 +1034,10 @@ static int ucsi_reset_ppm(struct ucsi *ucsi) goto out; } - ret = ucsi->ops->read(ucsi, UCSI_CCI, &cci, sizeof(cci)); + ret = ucsi->ops->poll_cci(ucsi); if (ret) goto out; + cci = READ_ONCE(ucsi->cci); /* If the PPM is still doing something else, reset it again. */ if (cci & ~UCSI_CCI_RESET_COMPLETE) { @@ -1550,7 +1548,8 @@ struct ucsi *ucsi_create(struct device *dev, const struct ucsi_operations *ops) { struct ucsi *ucsi; - if (!ops || !ops->read || !ops->sync_write || !ops->async_write) + if (!ops || !ops->poll_cci || !ops->read || !ops->sync_write || + !ops->async_write) return ERR_PTR(-EINVAL); ucsi = kzalloc(sizeof(*ucsi), GFP_KERNEL); diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h index 100e16b49814..55e5c5a09b32 100644 --- a/drivers/usb/typec/ucsi/ucsi.h +++ b/drivers/usb/typec/ucsi/ucsi.h @@ -55,6 +55,7 @@ struct dentry; /** * struct ucsi_operations - UCSI I/O operations + * @poll_cci: Update the cached CCI value from hardware. Required for reset. * @read: Read operation * @sync_write: Blocking write operation * @async_write: Non-blocking write operation @@ -65,6 +66,7 @@ struct dentry; * return immediately after sending the data to the PPM. */ struct ucsi_operations { + int (*poll_cci)(struct ucsi *ucsi); int (*read)(struct ucsi *ucsi, unsigned int offset, void *val, size_t val_len); int (*sync_write)(struct ucsi *ucsi, unsigned int offset, @@ -371,6 +373,9 @@ struct ucsi { /* The latest "Notification Enable" bits (SET_NOTIFICATION_ENABLE) */ u64 ntfy; + /* The current value of the CCI field. Synced by notifications. */ + u32 cci; + /* PPM communication flags */ unsigned long flags; #define EVENT_PENDING 0 diff --git a/drivers/usb/typec/ucsi/ucsi_acpi.c b/drivers/usb/typec/ucsi/ucsi_acpi.c index 710ddfc03ed0..3aedfe78fb65 100644 --- a/drivers/usb/typec/ucsi/ucsi_acpi.c +++ b/drivers/usb/typec/ucsi/ucsi_acpi.c @@ -24,7 +24,6 @@ struct ucsi_acpi { struct completion complete; unsigned long flags; guid_t guid; - u64 cmd; bool dell_quirk_probed; bool dell_quirk_active; }; @@ -45,8 +44,7 @@ static int ucsi_acpi_dsm(struct ucsi_acpi *ua, int func) return 0; } -static int ucsi_acpi_read(struct ucsi *ucsi, unsigned int offset, - void *val, size_t val_len) +static int ucsi_acpi_poll_cci(struct ucsi *ucsi) { struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); int ret; @@ -55,6 +53,16 @@ static int ucsi_acpi_read(struct ucsi *ucsi, unsigned int offset, if (ret) return ret; + WRITE_ONCE(ucsi->cci, le32_to_cpu(*(__le32 *)(ua->base + UCSI_CCI))); + + return 0; +} + +static int ucsi_acpi_read(struct ucsi *ucsi, unsigned int offset, + void *val, size_t val_len) +{ + struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); + memcpy(val, ua->base + offset, val_len); return 0; @@ -66,7 +74,6 @@ static int ucsi_acpi_async_write(struct ucsi *ucsi, unsigned int offset, struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); memcpy(ua->base + offset, val, val_len); - ua->cmd = *(u64 *)val; return ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_WRITE); } @@ -100,34 +107,12 @@ static int ucsi_acpi_sync_write(struct ucsi *ucsi, unsigned int offset, } static const struct ucsi_operations ucsi_acpi_ops = { + .poll_cci = ucsi_acpi_poll_cci, .read = ucsi_acpi_read, .sync_write = ucsi_acpi_sync_write, .async_write = ucsi_acpi_async_write }; -static int -ucsi_zenbook_read(struct ucsi *ucsi, unsigned int offset, void *val, size_t val_len) -{ - struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); - int ret; - - if (offset == UCSI_VERSION || UCSI_COMMAND(ua->cmd) == UCSI_PPM_RESET) { - ret = ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_READ); - if (ret) - return ret; - } - - memcpy(val, ua->base + offset, val_len); - - return 0; -} - -static const struct ucsi_operations ucsi_zenbook_ops = { - .read = ucsi_zenbook_read, - .sync_write = ucsi_acpi_sync_write, - .async_write = ucsi_acpi_async_write -}; - /* * Some Dell laptops expect that an ACK command with the * UCSI_ACK_CONNECTOR_CHANGE bit set is followed by a (separate) @@ -177,19 +162,13 @@ ucsi_dell_sync_write(struct ucsi *ucsi, unsigned int offset, } static const struct ucsi_operations ucsi_dell_ops = { + .poll_cci = ucsi_acpi_poll_cci, .read = ucsi_acpi_read, .sync_write = ucsi_dell_sync_write, .async_write = ucsi_acpi_async_write }; static const struct dmi_system_id ucsi_acpi_quirks[] = { - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "ZenBook UX325UA_UM325UA"), - }, - .driver_data = (void *)&ucsi_zenbook_ops, - }, { .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), @@ -203,11 +182,9 @@ static void ucsi_acpi_notify(acpi_handle handle, u32 event, void *data) { struct ucsi_acpi *ua = data; u32 cci; - int ret; - ret = ua->ucsi->ops->read(ua->ucsi, UCSI_CCI, &cci, sizeof(cci)); - if (ret) - return; + cci = le32_to_cpu(*(__le32 *)(ua->base + UCSI_CCI)); + WRITE_ONCE(ua->ucsi->cci, cci); if (UCSI_CCI_CONNECTOR(cci)) ucsi_connector_change(ua->ucsi, UCSI_CCI_CONNECTOR(cci)); diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c index d47f5e31c98a..55d0fe5324f4 100644 --- a/drivers/usb/typec/ucsi/ucsi_ccg.c +++ b/drivers/usb/typec/ucsi/ucsi_ccg.c @@ -194,7 +194,6 @@ struct ucsi_ccg_altmode { #define CCGX_MESSAGE_IN_MAX 16 struct op_region { - __le32 cci; u8 message_in[CCGX_MESSAGE_IN_MAX]; }; @@ -338,7 +337,6 @@ static int ccg_op_region_update(struct ucsi_ccg *uc, u32 cci) } spin_lock(&uc->op_lock); - data->cci = cpu_to_le32(cci); if (UCSI_CCI_LENGTH(cci)) memcpy(&data->message_in, buf, size); spin_unlock(&uc->op_lock); @@ -556,32 +554,24 @@ static void ucsi_ccg_nvidia_altmode(struct ucsi_ccg *uc, } } +static int ucsi_ccg_poll_cci(struct ucsi *ucsi) +{ + return 0; +} + static int ucsi_ccg_read(struct ucsi *ucsi, unsigned int offset, void *val, size_t val_len) { struct ucsi_ccg *uc = ucsi_get_drvdata(ucsi); - u16 reg = CCGX_RAB_UCSI_DATA_BLOCK(offset); struct ucsi_capability *cap; struct ucsi_altmode *alt; - int ret = 0; - - if (offset == UCSI_CCI) { - spin_lock(&uc->op_lock); - memcpy(val, &(uc->op_data).cci, val_len); - spin_unlock(&uc->op_lock); - } else if (offset == UCSI_MESSAGE_IN) { - spin_lock(&uc->op_lock); - memcpy(val, &(uc->op_data).message_in, val_len); - spin_unlock(&uc->op_lock); - } else { - ret = ccg_read(uc, reg, val, val_len); - } - - if (ret) - return ret; if (offset != UCSI_MESSAGE_IN) - return ret; + return -EINVAL; + + spin_lock(&uc->op_lock); + memcpy(val, &uc->op_data.message_in, val_len); + spin_unlock(&uc->op_lock); switch (UCSI_COMMAND(uc->last_cmd_sent)) { case UCSI_GET_CURRENT_CAM: @@ -607,7 +597,7 @@ static int ucsi_ccg_read(struct ucsi *ucsi, unsigned int offset, } uc->last_cmd_sent = 0; - return ret; + return 0; } static int ucsi_ccg_async_write(struct ucsi *ucsi, unsigned int offset, @@ -620,9 +610,7 @@ static int ucsi_ccg_async_write(struct ucsi *ucsi, unsigned int offset, * UCSI may read CCI instantly after async_write, * clear CCI to avoid caller getting wrong data before we get CCI from ISR */ - spin_lock(&uc->op_lock); - uc->op_data.cci = 0; - spin_unlock(&uc->op_lock); + WRITE_ONCE(ucsi->cci, 0); return ccg_write(uc, reg, val, val_len); } @@ -667,6 +655,7 @@ static int ucsi_ccg_sync_write(struct ucsi *ucsi, unsigned int offset, } static const struct ucsi_operations ucsi_ccg_ops = { + .poll_cci = ucsi_ccg_poll_cci, .read = ucsi_ccg_read, .sync_write = ucsi_ccg_sync_write, .async_write = ucsi_ccg_async_write, @@ -695,6 +684,7 @@ static irqreturn_t ccg_irq_handler(int irq, void *data) if (ret) goto err_clear_irq; cci = le32_to_cpu(__cci); + WRITE_ONCE(uc->ucsi->cci, cci); if (UCSI_CCI_CONNECTOR(cci)) ucsi_connector_change(uc->ucsi, UCSI_CCI_CONNECTOR(cci)); diff --git a/drivers/usb/typec/ucsi/ucsi_glink.c b/drivers/usb/typec/ucsi/ucsi_glink.c index 7a0b28536abd..d65ab81b4ed6 100644 --- a/drivers/usb/typec/ucsi/ucsi_glink.c +++ b/drivers/usb/typec/ucsi/ucsi_glink.c @@ -77,10 +77,8 @@ struct pmic_glink_ucsi { u8 read_buf[UCSI_BUF_SIZE]; }; -static int pmic_glink_ucsi_read(struct ucsi *__ucsi, unsigned int offset, - void *val, size_t val_len) +static int pmic_glink_sync_read_buf(struct pmic_glink_ucsi *ucsi) { - struct pmic_glink_ucsi *ucsi = ucsi_get_drvdata(__ucsi); struct ucsi_read_buf_req_msg req = {}; unsigned long left; int ret; @@ -106,7 +104,6 @@ static int pmic_glink_ucsi_read(struct ucsi *__ucsi, unsigned int offset, goto out_unlock; } - memcpy(val, &ucsi->read_buf[offset], val_len); ret = 0; out_unlock: @@ -115,6 +112,35 @@ static int pmic_glink_ucsi_read(struct ucsi *__ucsi, unsigned int offset, return ret; } +static int pmic_glink_ucsi_poll_cci(struct ucsi *__ucsi) +{ + struct pmic_glink_ucsi *ucsi = ucsi_get_drvdata(__ucsi); + int ret; + + ret = pmic_glink_sync_read_buf(ucsi); + if (ret) + return ret; + + mutex_lock(&ucsi->lock); + WRITE_ONCE(__ucsi->cci, + le32_to_cpu(*(__le32 *)&ucsi->read_buf[UCSI_CCI])); + mutex_unlock(&ucsi->lock); + + return 0; +} + +static int pmic_glink_ucsi_read(struct ucsi *__ucsi, unsigned int offset, + void *val, size_t val_len) +{ + struct pmic_glink_ucsi *ucsi = ucsi_get_drvdata(__ucsi); + + mutex_lock(&ucsi->lock); + memcpy(val, &ucsi->read_buf[offset], val_len); + mutex_unlock(&ucsi->lock); + + return 0; +} + static int pmic_glink_ucsi_locked_write(struct pmic_glink_ucsi *ucsi, unsigned int offset, const void *val, size_t val_len) { @@ -187,6 +213,7 @@ static int pmic_glink_ucsi_sync_write(struct ucsi *__ucsi, unsigned int offset, } static const struct ucsi_operations pmic_glink_ucsi_ops = { + .poll_cci = pmic_glink_ucsi_poll_cci, .read = pmic_glink_ucsi_read, .sync_write = pmic_glink_ucsi_sync_write, .async_write = pmic_glink_ucsi_async_write @@ -221,11 +248,15 @@ static void pmic_glink_ucsi_notify(struct work_struct *work) u32 cci; int ret; - ret = pmic_glink_ucsi_read(ucsi->ucsi, UCSI_CCI, &cci, sizeof(cci)); + ret = pmic_glink_sync_read_buf(ucsi); if (ret) { - dev_err(ucsi->dev, "failed to read CCI on notification\n"); + dev_err(ucsi->dev, "failed to sync read buf\n"); return; } + mutex_lock(&ucsi->lock); + cci = le32_to_cpu(*(__le32 *)&ucsi->read_buf[UCSI_CCI]); + mutex_unlock(&ucsi->lock); + WRITE_ONCE(ucsi->ucsi->cci, cci); con_num = UCSI_CCI_CONNECTOR(cci); if (con_num) { @@ -258,6 +289,11 @@ static void pmic_glink_ucsi_register(struct work_struct *work) __le16 version; int ret; + ret = pmic_glink_sync_read_buf(ucsi); + if (ret < 0) { + dev_err(ucsi->dev, "cannot sync read buf: %d\n", ret); + return; + } ret = pmic_glink_ucsi_read(ucsi->ucsi, UCSI_VERSION, &version, sizeof(version)); if (ret < 0) { diff --git a/drivers/usb/typec/ucsi/ucsi_stm32g0.c b/drivers/usb/typec/ucsi/ucsi_stm32g0.c index 112692c7a158..bab2363b73f4 100644 --- a/drivers/usb/typec/ucsi/ucsi_stm32g0.c +++ b/drivers/usb/typec/ucsi/ucsi_stm32g0.c @@ -358,6 +358,20 @@ static int ucsi_stm32g0_read_from_hw(struct ucsi_stm32g0 *g0, } /* UCSI ops */ +static int ucsi_stm32g0_poll_cci(struct ucsi *ucsi) +{ + struct ucsi_stm32g0 *g0 = ucsi_get_drvdata(ucsi); + __le32 cci; + int ret; + + ret = ucsi_stm32g0_read_from_hw(g0, UCSI_CCI, &cci, sizeof(cci)); + if (ret) + return ret; + WRITE_ONCE(ucsi->cci, le32_to_cpu(cci)); + + return 0; +} + static int ucsi_stm32g0_read(struct ucsi *ucsi, unsigned int offset, void *val, size_t len) { @@ -424,15 +438,18 @@ static int ucsi_stm32g0_sync_write(struct ucsi *ucsi, unsigned int offset, const static irqreturn_t ucsi_stm32g0_irq_handler(int irq, void *data) { struct ucsi_stm32g0 *g0 = data; + __le32 __cci; u32 cci; int ret; if (g0->suspended) g0->wakeup_event = true; - ret = ucsi_stm32g0_read(g0->ucsi, UCSI_CCI, &cci, sizeof(cci)); + ret = ucsi_stm32g0_read_from_hw(g0, UCSI_CCI, &__cci, sizeof(__cci)); if (ret) return IRQ_NONE; + cci = le32_to_cpu(__cci); + WRITE_ONCE(g0->ucsi->cci, cci); if (UCSI_CCI_CONNECTOR(cci)) ucsi_connector_change(g0->ucsi, UCSI_CCI_CONNECTOR(cci)); @@ -445,6 +462,7 @@ static irqreturn_t ucsi_stm32g0_irq_handler(int irq, void *data) } static const struct ucsi_operations ucsi_stm32g0_ops = { + .poll_cci = ucsi_stm32g0_poll_cci, .read = ucsi_stm32g0_read, .sync_write = ucsi_stm32g0_sync_write, .async_write = ucsi_stm32g0_async_write, @@ -626,7 +644,7 @@ static int ucsi_stm32g0_probe_bootloader(struct ucsi *ucsi) * Try to guess if the STM32G0 is running a UCSI firmware. First probe the UCSI FW at its * i2c address. Fallback to bootloader i2c address only if firmware-name is specified. */ - ret = ucsi_stm32g0_read(ucsi, UCSI_VERSION, &ucsi_version, sizeof(ucsi_version)); + ret = ucsi_stm32g0_read_from_hw(g0, UCSI_VERSION, &ucsi_version, sizeof(ucsi_version)); if (!ret || !g0->fw_name) return ret; From patchwork Sun Feb 18 22:20:38 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Christian A. Ehrhardt" X-Patchwork-Id: 13562082 Received: from cae.in-ulm.de (cae.in-ulm.de [217.10.14.231]) by smtp.subspace.kernel.org (Postfix) with ESMTP id A53E8745F7; Sun, 18 Feb 2024 22:21:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.10.14.231 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708294874; cv=none; b=S+HiwLZmMW3YM+yuSGka40XjkAGUzYWdu7b7Xb1hYksNINaUKBO4NiMxjodZGeDpmE49HyNPPieRxnuqgQqhyAcJTRRVSjkggGht45ru/H1Jnrv3p96h+TC2x8IwotvGuPe+nfFU/9mklMcEMrC2JeH9L99fmvj2epwxtFX1Ysg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708294874; c=relaxed/simple; bh=oBIAbCrIJVBjDvCpY+ciTU3Tk2iXKsY0b6d7anvoIAY=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=UFeMDpJ2M7E3SMiMZsd7QZoYgd7KSIXnPjY6xtDkYNLPYFjrXwBiI5TTc5mDlzRDPzf2mtOVv6/Sh2lBef2/sCxRmmuDeASVXjY2H/+d6l+o2wli4En42hbO5UQzFqQpi75KEM+R3OS1ZCaLp/wPYoEdD887/aUSloXTmioi8+0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=c--e.de; spf=pass smtp.mailfrom=c--e.de; arc=none smtp.client-ip=217.10.14.231 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=c--e.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=c--e.de Received: by cae.in-ulm.de (Postfix, from userid 1000) id 0456414092E; Sun, 18 Feb 2024 23:21:07 +0100 (CET) From: "Christian A. Ehrhardt" To: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org Cc: "Christian A. Ehrhardt" , Heikki Krogerus , Greg Kroah-Hartman , Maxime Coquelin , Alexandre Torgue , =?utf-8?q?Uwe_Kleine-K?= =?utf-8?q?=C3=B6nig?= , =?utf-8?q?Samuel_?= =?utf-8?q?=C4=8Cavoj?= , Hans de Goede , Neil Armstrong , Prashanth K , Dmitry Baryshkov , Saranya Gopal , Haotien Hsu , Andy Shevchenko , Utkarsh Patel , Bjorn Andersson , Luca Weiss , Min-Hua Chen , Rob Herring , Rajaram Regupathy , linux-stm32@st-md-mailman.stormreply.com, linux-arm-kernel@lists.infradead.org, Abhishek Pandit-Subedi Subject: [RFC PATCH 5/6] usb: typec: ucsi: Introdcue ->read_data and ->write_data Date: Sun, 18 Feb 2024 23:20:38 +0100 Message-Id: <20240218222039.822040-6-lk@c--e.de> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20240218222039.822040-1-lk@c--e.de> References: <20240218222039.822040-1-lk@c--e.de> Precedence: bulk X-Mailing-List: linux-usb@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 With the previous refactoring ->read() is only used to read from UCSI_MESSAGE_IN. So rename ->read() to ->read_data(). Before this change there is (at least for some backends) no way to write to UCSI_MESSAGE_OUT without starting a command. As a result it is not possible to send a command with additional data on these backends. Currently, the UCSI core does not send such commands but they are defined in the spec and presumably will be required. Introduce ->write_data() to write to UCSI_MESSAGE_OUT without starting a command. This is symmetrical to ->read_data(). Signed-off-by: Christian A. Ehrhardt --- drivers/usb/typec/ucsi/ucsi.c | 6 ++--- drivers/usb/typec/ucsi/ucsi.h | 7 ++--- drivers/usb/typec/ucsi/ucsi_acpi.c | 21 +++++++++++---- drivers/usb/typec/ucsi/ucsi_ccg.c | 18 ++++++++----- drivers/usb/typec/ucsi/ucsi_glink.c | 37 +++++++++++++++++---------- drivers/usb/typec/ucsi/ucsi_stm32g0.c | 30 +++++++++++++++++----- 6 files changed, 82 insertions(+), 37 deletions(-) diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index a4ae3d5966a0..df3fe04cb9cd 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -46,7 +46,7 @@ static int ucsi_read_message_in(struct ucsi *ucsi, void *buf, if (ucsi->version <= UCSI_VERSION_1_2) buf_size = clamp(buf_size, 0, 16); - return ucsi->ops->read(ucsi, UCSI_MESSAGE_IN, buf, buf_size); + return ucsi->ops->read_data(ucsi, buf, buf_size); } static int ucsi_acknowledge_command(struct ucsi *ucsi) @@ -1548,8 +1548,8 @@ struct ucsi *ucsi_create(struct device *dev, const struct ucsi_operations *ops) { struct ucsi *ucsi; - if (!ops || !ops->poll_cci || !ops->read || !ops->sync_write || - !ops->async_write) + if (!ops || !ops->poll_cci || !ops->read_data || !ops->write_data || + !ops->sync_write || !ops->async_write) return ERR_PTR(-EINVAL); ucsi = kzalloc(sizeof(*ucsi), GFP_KERNEL); diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h index 55e5c5a09b32..2ad68124511b 100644 --- a/drivers/usb/typec/ucsi/ucsi.h +++ b/drivers/usb/typec/ucsi/ucsi.h @@ -56,7 +56,8 @@ struct dentry; /** * struct ucsi_operations - UCSI I/O operations * @poll_cci: Update the cached CCI value from hardware. Required for reset. - * @read: Read operation + * @read_data: Read MESSAGE_IN data + * @write_data: Write MESSAGE_OUT data * @sync_write: Blocking write operation * @async_write: Non-blocking write operation * @update_altmodes: Squashes duplicate DP altmodes @@ -67,8 +68,8 @@ struct dentry; */ struct ucsi_operations { int (*poll_cci)(struct ucsi *ucsi); - int (*read)(struct ucsi *ucsi, unsigned int offset, - void *val, size_t val_len); + int (*read_data)(struct ucsi *ucsi, void *val, size_t val_len); + int (*write_data)(struct ucsi *ucsi, const void *val, size_t val_len); int (*sync_write)(struct ucsi *ucsi, unsigned int offset, const void *val, size_t val_len); int (*async_write)(struct ucsi *ucsi, unsigned int offset, diff --git a/drivers/usb/typec/ucsi/ucsi_acpi.c b/drivers/usb/typec/ucsi/ucsi_acpi.c index 3aedfe78fb65..79b47b433e35 100644 --- a/drivers/usb/typec/ucsi/ucsi_acpi.c +++ b/drivers/usb/typec/ucsi/ucsi_acpi.c @@ -58,12 +58,21 @@ static int ucsi_acpi_poll_cci(struct ucsi *ucsi) return 0; } -static int ucsi_acpi_read(struct ucsi *ucsi, unsigned int offset, - void *val, size_t val_len) +static int ucsi_acpi_read_data(struct ucsi *ucsi, void *val, size_t val_len) { struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); - memcpy(val, ua->base + offset, val_len); + memcpy(val, ua->base + UCSI_MESSAGE_IN, val_len); + + return 0; +} + +static int ucsi_acpi_write_data(struct ucsi *ucsi, const void *val, + size_t val_len) +{ + struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); + + memcpy(ua->base + UCSI_MESSAGE_OUT, val, val_len); return 0; } @@ -108,7 +117,8 @@ static int ucsi_acpi_sync_write(struct ucsi *ucsi, unsigned int offset, static const struct ucsi_operations ucsi_acpi_ops = { .poll_cci = ucsi_acpi_poll_cci, - .read = ucsi_acpi_read, + .read_data = ucsi_acpi_read_data, + .write_data = ucsi_acpi_write_data, .sync_write = ucsi_acpi_sync_write, .async_write = ucsi_acpi_async_write }; @@ -163,7 +173,8 @@ ucsi_dell_sync_write(struct ucsi *ucsi, unsigned int offset, static const struct ucsi_operations ucsi_dell_ops = { .poll_cci = ucsi_acpi_poll_cci, - .read = ucsi_acpi_read, + .read_data = ucsi_acpi_read_data, + .write_data = ucsi_acpi_write_data, .sync_write = ucsi_dell_sync_write, .async_write = ucsi_acpi_async_write }; diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c index 55d0fe5324f4..d6026f61a0ed 100644 --- a/drivers/usb/typec/ucsi/ucsi_ccg.c +++ b/drivers/usb/typec/ucsi/ucsi_ccg.c @@ -559,16 +559,12 @@ static int ucsi_ccg_poll_cci(struct ucsi *ucsi) return 0; } -static int ucsi_ccg_read(struct ucsi *ucsi, unsigned int offset, - void *val, size_t val_len) +static int ucsi_ccg_read_data(struct ucsi *ucsi, void *val, size_t val_len) { struct ucsi_ccg *uc = ucsi_get_drvdata(ucsi); struct ucsi_capability *cap; struct ucsi_altmode *alt; - if (offset != UCSI_MESSAGE_IN) - return -EINVAL; - spin_lock(&uc->op_lock); memcpy(val, &uc->op_data.message_in, val_len); spin_unlock(&uc->op_lock); @@ -600,6 +596,15 @@ static int ucsi_ccg_read(struct ucsi *ucsi, unsigned int offset, return 0; } +static int ucsi_ccg_write_data(struct ucsi *ucsi, const void *val, + size_t val_len) +{ + struct ucsi_ccg *uc = ucsi_get_drvdata(ucsi); + u16 reg = CCGX_RAB_UCSI_DATA_BLOCK(UCSI_MESSAGE_OUT); + + return ccg_write(uc, reg, val, val_len); +} + static int ucsi_ccg_async_write(struct ucsi *ucsi, unsigned int offset, const void *val, size_t val_len) { @@ -656,7 +661,8 @@ static int ucsi_ccg_sync_write(struct ucsi *ucsi, unsigned int offset, static const struct ucsi_operations ucsi_ccg_ops = { .poll_cci = ucsi_ccg_poll_cci, - .read = ucsi_ccg_read, + .read_data = ucsi_ccg_read_data, + .write_data = ucsi_ccg_write_data, .sync_write = ucsi_ccg_sync_write, .async_write = ucsi_ccg_async_write, .update_altmodes = ucsi_ccg_update_altmodes diff --git a/drivers/usb/typec/ucsi/ucsi_glink.c b/drivers/usb/typec/ucsi/ucsi_glink.c index d65ab81b4ed6..9dab1b428ad9 100644 --- a/drivers/usb/typec/ucsi/ucsi_glink.c +++ b/drivers/usb/typec/ucsi/ucsi_glink.c @@ -75,6 +75,7 @@ struct pmic_glink_ucsi { struct work_struct register_work; u8 read_buf[UCSI_BUF_SIZE]; + u8 write_buf[UCSI_BUF_SIZE]; }; static int pmic_glink_sync_read_buf(struct pmic_glink_ucsi *ucsi) @@ -129,18 +130,28 @@ static int pmic_glink_ucsi_poll_cci(struct ucsi *__ucsi) return 0; } -static int pmic_glink_ucsi_read(struct ucsi *__ucsi, unsigned int offset, - void *val, size_t val_len) +static int pmic_glink_ucsi_read_data(struct ucsi *__ucsi, + void *val, size_t val_len) { struct pmic_glink_ucsi *ucsi = ucsi_get_drvdata(__ucsi); mutex_lock(&ucsi->lock); - memcpy(val, &ucsi->read_buf[offset], val_len); + memcpy(val, &ucsi->read_buf[UCSI_MESSAGE_IN], val_len); mutex_unlock(&ucsi->lock); return 0; } +static int pmic_glink_ucsi_write_data(struct ucsi *__ucsi, + const void *val, size_t val_len) +{ + struct pmic_glink_ucsi *ucsi = ucsi_get_drvdata(__ucsi); + + memcpy(&ucsi->write_buf[UCSI_MESSAGE_OUT], val, val_len); + + return 0; +} + static int pmic_glink_ucsi_locked_write(struct pmic_glink_ucsi *ucsi, unsigned int offset, const void *val, size_t val_len) { @@ -148,10 +159,15 @@ static int pmic_glink_ucsi_locked_write(struct pmic_glink_ucsi *ucsi, unsigned i unsigned long left; int ret; + if (offset != UCSI_CONTROL || val_len != sizeof(u64)) + return -EINVAL; + memcpy(ucsi->write_buf + UCSI_CONTROL, val, val_len); + req.hdr.owner = cpu_to_le32(PMIC_GLINK_OWNER_USBC); req.hdr.type = cpu_to_le32(MSG_TYPE_REQ_RESP); req.hdr.opcode = cpu_to_le32(UC_UCSI_WRITE_BUF_REQ); - memcpy(&req.buf[offset], val, val_len); + memcpy(req.buf, ucsi->write_buf, UCSI_BUF_SIZE); + memset(ucsi->write_buf, 0, sizeof(ucsi->write_buf)); reinit_completion(&ucsi->write_ack); @@ -214,7 +230,8 @@ static int pmic_glink_ucsi_sync_write(struct ucsi *__ucsi, unsigned int offset, static const struct ucsi_operations pmic_glink_ucsi_ops = { .poll_cci = pmic_glink_ucsi_poll_cci, - .read = pmic_glink_ucsi_read, + .read_data = pmic_glink_ucsi_read_data, + .write_data = pmic_glink_ucsi_write_data, .sync_write = pmic_glink_ucsi_sync_write, .async_write = pmic_glink_ucsi_async_write }; @@ -286,7 +303,6 @@ static void pmic_glink_ucsi_notify(struct work_struct *work) static void pmic_glink_ucsi_register(struct work_struct *work) { struct pmic_glink_ucsi *ucsi = container_of(work, struct pmic_glink_ucsi, register_work); - __le16 version; int ret; ret = pmic_glink_sync_read_buf(ucsi); @@ -294,14 +310,9 @@ static void pmic_glink_ucsi_register(struct work_struct *work) dev_err(ucsi->dev, "cannot sync read buf: %d\n", ret); return; } - ret = pmic_glink_ucsi_read(ucsi->ucsi, UCSI_VERSION, &version, - sizeof(version)); - if (ret < 0) { - dev_err(ucsi->dev, "cannot read version: %d\n", ret); - return; - } - ucsi_register(ucsi->ucsi, le16_to_cpu(version)); + ucsi_register(ucsi->ucsi, + le16_to_cpu(*(__le16 *)(ucsi->read_buf + UCSI_VERSION))); } static void pmic_glink_ucsi_callback(const void *data, size_t len, void *priv) diff --git a/drivers/usb/typec/ucsi/ucsi_stm32g0.c b/drivers/usb/typec/ucsi/ucsi_stm32g0.c index bab2363b73f4..d68aca118e41 100644 --- a/drivers/usb/typec/ucsi/ucsi_stm32g0.c +++ b/drivers/usb/typec/ucsi/ucsi_stm32g0.c @@ -372,18 +372,17 @@ static int ucsi_stm32g0_poll_cci(struct ucsi *ucsi) return 0; } -static int ucsi_stm32g0_read(struct ucsi *ucsi, unsigned int offset, - void *val, size_t len) +static int ucsi_stm32g0_read_data(struct ucsi *ucsi, void *val, size_t len) { struct ucsi_stm32g0 *g0 = ucsi_get_drvdata(ucsi); - return ucsi_stm32g0_read_from_hw(g0, offset, val, len); + return ucsi_stm32g0_read_from_hw(g0, UCSI_MESSAGE_IN, val, len); } -static int ucsi_stm32g0_async_write(struct ucsi *ucsi, unsigned int offset, const void *val, - size_t len) +static int ucsi_stm32g0_write_to_hw(struct ucsi_stm32g0 *g0, + unsigned int offset, + const void *val, size_t len) { - struct ucsi_stm32g0 *g0 = ucsi_get_drvdata(ucsi); struct i2c_client *client = g0->client; struct i2c_msg msg[] = { { @@ -414,6 +413,22 @@ static int ucsi_stm32g0_async_write(struct ucsi *ucsi, unsigned int offset, cons return 0; } +static int ucsi_stm32g0_write_data(struct ucsi *ucsi, + const void *val, size_t len) +{ + struct ucsi_stm32g0 *g0 = ucsi_get_drvdata(ucsi); + + return ucsi_stm32g0_write_to_hw(g0, UCSI_MESSAGE_OUT, val, len); +} + +static int ucsi_stm32g0_async_write(struct ucsi *ucsi, unsigned int offset, + const void *val, size_t len) +{ + struct ucsi_stm32g0 *g0 = ucsi_get_drvdata(ucsi); + + return ucsi_stm32g0_write_to_hw(g0, offset, val, len); +} + static int ucsi_stm32g0_sync_write(struct ucsi *ucsi, unsigned int offset, const void *val, size_t len) { @@ -463,7 +478,8 @@ static irqreturn_t ucsi_stm32g0_irq_handler(int irq, void *data) static const struct ucsi_operations ucsi_stm32g0_ops = { .poll_cci = ucsi_stm32g0_poll_cci, - .read = ucsi_stm32g0_read, + .read_data = ucsi_stm32g0_read_data, + .write_data = ucsi_stm32g0_write_data, .sync_write = ucsi_stm32g0_sync_write, .async_write = ucsi_stm32g0_async_write, }; From patchwork Sun Feb 18 22:20:39 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Christian A. Ehrhardt" X-Patchwork-Id: 13562083 Received: from cae.in-ulm.de (cae.in-ulm.de [217.10.14.231]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 8667B745EB; Sun, 18 Feb 2024 22:21:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.10.14.231 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708294874; cv=none; b=rKrzwyjaJRt1PDm8tTfsjCN5CnDohEgGgS/stmqDKMucD6D6XG3PgoALot2a5YaidIEJ39EqHHRdT72DT2GFo6OwjrptfHtKPl6pbTAIB24wJ/w3YNUZFbaZJSHInPViOXq/7axMi9c7MFWYDfpeXr+RuDcNZPjrev0sJ5IZ7vQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708294874; c=relaxed/simple; bh=CKhmIXx5mHmzqsOaPWv1xp25HBv8ABXQGCOtwj7iCO8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=kHAcvsJIHW59Suyc625x7lDWGbhvwr7NQsobZi1h0nuebi564KI99OqC5PTDyehqLDA5j3SYaHhJL7wPVkfRSrXXIsOfLlnrPRifet+mXWavKiFK+1bVex5I3ghRB+A//vjwg92J24CYnyUBCW6ebDlngTh5DTPp2RTabNt+sg8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=c--e.de; spf=pass smtp.mailfrom=c--e.de; arc=none smtp.client-ip=217.10.14.231 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=c--e.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=c--e.de Received: by cae.in-ulm.de (Postfix, from userid 1000) id B2FCA140938; Sun, 18 Feb 2024 23:21:09 +0100 (CET) From: "Christian A. Ehrhardt" To: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org Cc: "Christian A. Ehrhardt" , Heikki Krogerus , Greg Kroah-Hartman , Maxime Coquelin , Alexandre Torgue , =?utf-8?q?Uwe_Kleine-K?= =?utf-8?q?=C3=B6nig?= , =?utf-8?q?Samuel_?= =?utf-8?q?=C4=8Cavoj?= , Hans de Goede , Neil Armstrong , Prashanth K , Dmitry Baryshkov , Saranya Gopal , Haotien Hsu , Andy Shevchenko , Utkarsh Patel , Bjorn Andersson , Luca Weiss , Min-Hua Chen , Rob Herring , Rajaram Regupathy , linux-stm32@st-md-mailman.stormreply.com, linux-arm-kernel@lists.infradead.org, Abhishek Pandit-Subedi Subject: [RFC PATCH 6/6] usb: typec: ucsi: Convert a?sync_write to a?sync_cmd Date: Sun, 18 Feb 2024 23:20:39 +0100 Message-Id: <20240218222039.822040-7-lk@c--e.de> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20240218222039.822040-1-lk@c--e.de> References: <20240218222039.822040-1-lk@c--e.de> Precedence: bulk X-Mailing-List: linux-usb@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The ->sync_write an ->async_write callbacks are only used to write to the UCSI_CONTROL field and start a command, now. Rename them accordingly and remove parameters and code that are no longer used. While there note that the command passed in from the UCSI core is in host byte order but the command sent to UCSI must be in little endian byte order. Signed-off-by: Christian A. Ehrhardt --- drivers/usb/typec/ucsi/ucsi.c | 29 ++++++------------- drivers/usb/typec/ucsi/ucsi.h | 14 ++++----- drivers/usb/typec/ucsi/ucsi_acpi.c | 41 ++++++++++++--------------- drivers/usb/typec/ucsi/ucsi_ccg.c | 35 +++++++++++------------ drivers/usb/typec/ucsi/ucsi_glink.c | 18 ++++++------ drivers/usb/typec/ucsi/ucsi_stm32g0.c | 16 +++++------ 6 files changed, 67 insertions(+), 86 deletions(-) diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index df3fe04cb9cd..5bec98381be6 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -51,22 +51,16 @@ static int ucsi_read_message_in(struct ucsi *ucsi, void *buf, static int ucsi_acknowledge_command(struct ucsi *ucsi) { - u64 ctrl; + u64 cmd = UCSI_ACK_CC_CI | UCSI_ACK_COMMAND_COMPLETE; - ctrl = UCSI_ACK_CC_CI; - ctrl |= UCSI_ACK_COMMAND_COMPLETE; - - return ucsi->ops->sync_write(ucsi, UCSI_CONTROL, &ctrl, sizeof(ctrl)); + return ucsi->ops->sync_cmd(ucsi, cmd); } static int ucsi_acknowledge_connector_change(struct ucsi *ucsi) { - u64 ctrl; - - ctrl = UCSI_ACK_CC_CI; - ctrl |= UCSI_ACK_CONNECTOR_CHANGE; + u64 cmd = UCSI_ACK_CC_CI | UCSI_ACK_CONNECTOR_CHANGE; - return ucsi->ops->sync_write(ucsi, UCSI_CONTROL, &ctrl, sizeof(ctrl)); + return ucsi->ops->sync_cmd(ucsi, cmd); } static int ucsi_exec_command(struct ucsi *ucsi, u64 command); @@ -137,7 +131,7 @@ static int ucsi_exec_command(struct ucsi *ucsi, u64 cmd) u32 cci; int ret; - ret = ucsi->ops->sync_write(ucsi, UCSI_CONTROL, &cmd, sizeof(cmd)); + ret = ucsi->ops->sync_cmd(ucsi, cmd); if (ret) return ret; cci = READ_ONCE(ucsi->cci); @@ -1014,15 +1008,13 @@ static int ucsi_reset_connector(struct ucsi_connector *con, bool hard) static int ucsi_reset_ppm(struct ucsi *ucsi) { - u64 command = UCSI_PPM_RESET; unsigned long tmo; u32 cci; int ret; mutex_lock(&ucsi->ppm_lock); - ret = ucsi->ops->async_write(ucsi, UCSI_CONTROL, &command, - sizeof(command)); + ret = ucsi->ops->async_cmd(ucsi, UCSI_PPM_RESET); if (ret < 0) goto out; @@ -1041,9 +1033,7 @@ static int ucsi_reset_ppm(struct ucsi *ucsi) /* If the PPM is still doing something else, reset it again. */ if (cci & ~UCSI_CCI_RESET_COMPLETE) { - ret = ucsi->ops->async_write(ucsi, UCSI_CONTROL, - &command, - sizeof(command)); + ret = ucsi->ops->async_cmd(ucsi, UCSI_PPM_RESET); if (ret < 0) goto out; } @@ -1549,7 +1539,7 @@ struct ucsi *ucsi_create(struct device *dev, const struct ucsi_operations *ops) struct ucsi *ucsi; if (!ops || !ops->poll_cci || !ops->read_data || !ops->write_data || - !ops->sync_write || !ops->async_write) + !ops->sync_cmd || !ops->async_cmd) return ERR_PTR(-EINVAL); ucsi = kzalloc(sizeof(*ucsi), GFP_KERNEL); @@ -1612,7 +1602,6 @@ EXPORT_SYMBOL_GPL(ucsi_register); */ void ucsi_unregister(struct ucsi *ucsi) { - u64 cmd = UCSI_SET_NOTIFICATION_ENABLE; int i; /* Make sure that we are not in the middle of driver initialization */ @@ -1620,7 +1609,7 @@ void ucsi_unregister(struct ucsi *ucsi) cancel_work_sync(&ucsi->resume_work); /* Disable notifications */ - ucsi->ops->async_write(ucsi, UCSI_CONTROL, &cmd, sizeof(cmd)); + ucsi->ops->async_cmd(ucsi, UCSI_SET_NOTIFICATION_ENABLE); if (!ucsi->connector) return; diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h index 2ad68124511b..3cce83d1e70c 100644 --- a/drivers/usb/typec/ucsi/ucsi.h +++ b/drivers/usb/typec/ucsi/ucsi.h @@ -58,22 +58,20 @@ struct dentry; * @poll_cci: Update the cached CCI value from hardware. Required for reset. * @read_data: Read MESSAGE_IN data * @write_data: Write MESSAGE_OUT data - * @sync_write: Blocking write operation - * @async_write: Non-blocking write operation + * @sync_cmd: Blocking command execution + * @async_cmd: Non-blocking command execution * @update_altmodes: Squashes duplicate DP altmodes * - * Read and write routines for UCSI interface. @sync_write must wait for the - * Command Completion Event from the PPM before returning, and @async_write must + * Read and write routines for UCSI interface. @sync_cmd must wait for the + * Command Completion Event from the PPM before returning, and @async_cmd must * return immediately after sending the data to the PPM. */ struct ucsi_operations { int (*poll_cci)(struct ucsi *ucsi); int (*read_data)(struct ucsi *ucsi, void *val, size_t val_len); int (*write_data)(struct ucsi *ucsi, const void *val, size_t val_len); - int (*sync_write)(struct ucsi *ucsi, unsigned int offset, - const void *val, size_t val_len); - int (*async_write)(struct ucsi *ucsi, unsigned int offset, - const void *val, size_t val_len); + int (*sync_cmd)(struct ucsi *ucsi, u64 cmd); + int (*async_cmd)(struct ucsi *ucsi, u64 cmd); bool (*update_altmodes)(struct ucsi *ucsi, struct ucsi_altmode *orig, struct ucsi_altmode *updated); }; diff --git a/drivers/usb/typec/ucsi/ucsi_acpi.c b/drivers/usb/typec/ucsi/ucsi_acpi.c index 79b47b433e35..e6f67aa102d2 100644 --- a/drivers/usb/typec/ucsi/ucsi_acpi.c +++ b/drivers/usb/typec/ucsi/ucsi_acpi.c @@ -77,21 +77,20 @@ static int ucsi_acpi_write_data(struct ucsi *ucsi, const void *val, return 0; } -static int ucsi_acpi_async_write(struct ucsi *ucsi, unsigned int offset, - const void *val, size_t val_len) +static int ucsi_acpi_async_cmd(struct ucsi *ucsi, u64 cmd) { struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); + __le64 __cmd = cpu_to_le64(cmd); - memcpy(ua->base + offset, val, val_len); + memcpy(ua->base + UCSI_CONTROL, &__cmd, sizeof(__cmd)); return ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_WRITE); } -static int ucsi_acpi_sync_write(struct ucsi *ucsi, unsigned int offset, - const void *val, size_t val_len) +static int ucsi_acpi_sync_cmd(struct ucsi *ucsi, u64 cmd) { struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); - bool ack = UCSI_COMMAND(*(u64 *)val) == UCSI_ACK_CC_CI; + bool ack = UCSI_COMMAND(cmd) == UCSI_ACK_CC_CI; int ret; if (ack) @@ -99,7 +98,7 @@ static int ucsi_acpi_sync_write(struct ucsi *ucsi, unsigned int offset, else set_bit(COMMAND_PENDING, &ua->flags); - ret = ucsi_acpi_async_write(ucsi, offset, val, val_len); + ret = ucsi_acpi_async_cmd(ucsi, cmd); if (ret) goto out_clear_bit; @@ -119,8 +118,8 @@ static const struct ucsi_operations ucsi_acpi_ops = { .poll_cci = ucsi_acpi_poll_cci, .read_data = ucsi_acpi_read_data, .write_data = ucsi_acpi_write_data, - .sync_write = ucsi_acpi_sync_write, - .async_write = ucsi_acpi_async_write + .sync_cmd = ucsi_acpi_sync_cmd, + .async_cmd = ucsi_acpi_async_cmd }; /* @@ -131,32 +130,28 @@ static const struct ucsi_operations ucsi_acpi_ops = { * subsequent commands will timeout. */ static int -ucsi_dell_sync_write(struct ucsi *ucsi, unsigned int offset, - const void *val, size_t val_len) +ucsi_dell_sync_cmd(struct ucsi *ucsi, u64 cmd) { struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); - u64 cmd = *(u64 *)val, ack = 0; + u64 ack = 0; int ret; if (UCSI_COMMAND(cmd) == UCSI_ACK_CC_CI && cmd & UCSI_ACK_CONNECTOR_CHANGE) ack = UCSI_ACK_CC_CI | UCSI_ACK_COMMAND_COMPLETE; - ret = ucsi_acpi_sync_write(ucsi, offset, val, val_len); + ret = ucsi_acpi_sync_cmd(ucsi, cmd); if (ret != 0) return ret; if (ack == 0) - return ret; + return 0; if (!ua->dell_quirk_probed) { ua->dell_quirk_probed = true; - cmd = UCSI_GET_CAPABILITY; - ret = ucsi_acpi_sync_write(ucsi, UCSI_CONTROL, &cmd, - sizeof(cmd)); + ret = ucsi_acpi_sync_cmd(ucsi, UCSI_GET_CAPABILITY); if (ret == 0) - return ucsi_acpi_sync_write(ucsi, UCSI_CONTROL, - &ack, sizeof(ack)); + return ucsi_acpi_sync_cmd(ucsi, ack); if (ret != -ETIMEDOUT) return ret; @@ -166,17 +161,17 @@ ucsi_dell_sync_write(struct ucsi *ucsi, unsigned int offset, } if (!ua->dell_quirk_active) - return ret; + return 0; - return ucsi_acpi_sync_write(ucsi, UCSI_CONTROL, &ack, sizeof(ack)); + return ucsi_acpi_sync_cmd(ucsi, ack); } static const struct ucsi_operations ucsi_dell_ops = { .poll_cci = ucsi_acpi_poll_cci, .read_data = ucsi_acpi_read_data, .write_data = ucsi_acpi_write_data, - .sync_write = ucsi_dell_sync_write, - .async_write = ucsi_acpi_async_write + .sync_cmd = ucsi_dell_sync_cmd, + .async_cmd = ucsi_acpi_async_cmd }; static const struct dmi_system_id ucsi_acpi_quirks[] = { diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c index d6026f61a0ed..5c60816e608f 100644 --- a/drivers/usb/typec/ucsi/ucsi_ccg.c +++ b/drivers/usb/typec/ucsi/ucsi_ccg.c @@ -605,23 +605,22 @@ static int ucsi_ccg_write_data(struct ucsi *ucsi, const void *val, return ccg_write(uc, reg, val, val_len); } -static int ucsi_ccg_async_write(struct ucsi *ucsi, unsigned int offset, - const void *val, size_t val_len) +static int ucsi_ccg_async_cmd(struct ucsi *ucsi, u64 cmd) { struct ucsi_ccg *uc = ucsi_get_drvdata(ucsi); - u16 reg = CCGX_RAB_UCSI_DATA_BLOCK(offset); + u16 reg = CCGX_RAB_UCSI_DATA_BLOCK(UCSI_CONTROL); + __le64 __cmd = cpu_to_le64(cmd); /* - * UCSI may read CCI instantly after async_write, + * UCSI may read CCI instantly after async_cmd, * clear CCI to avoid caller getting wrong data before we get CCI from ISR */ WRITE_ONCE(ucsi->cci, 0); - return ccg_write(uc, reg, val, val_len); + return ccg_write(uc, reg, (u8 *)&__cmd, sizeof(__cmd)); } -static int ucsi_ccg_sync_write(struct ucsi *ucsi, unsigned int offset, - const void *val, size_t val_len) +static int ucsi_ccg_sync_cmd(struct ucsi *ucsi, u64 cmd) { struct ucsi_ccg *uc = ucsi_get_drvdata(ucsi); struct ucsi_connector *con; @@ -632,19 +631,17 @@ static int ucsi_ccg_sync_write(struct ucsi *ucsi, unsigned int offset, pm_runtime_get_sync(uc->dev); set_bit(DEV_CMD_PENDING, &uc->flags); - if (offset == UCSI_CONTROL && val_len == sizeof(uc->last_cmd_sent)) { - uc->last_cmd_sent = *(u64 *)val; + uc->last_cmd_sent = cmd; - if (UCSI_COMMAND(uc->last_cmd_sent) == UCSI_SET_NEW_CAM && - uc->has_multiple_dp) { - con_index = (uc->last_cmd_sent >> 16) & - UCSI_CMD_CONNECTOR_MASK; - con = &uc->ucsi->connector[con_index - 1]; - ucsi_ccg_update_set_new_cam_cmd(uc, con, (u64 *)val); - } + if (UCSI_COMMAND(uc->last_cmd_sent) == UCSI_SET_NEW_CAM && + uc->has_multiple_dp) { + con_index = (uc->last_cmd_sent >> 16) & + UCSI_CMD_CONNECTOR_MASK; + con = &uc->ucsi->connector[con_index - 1]; + ucsi_ccg_update_set_new_cam_cmd(uc, con, &cmd); } - ret = ucsi_ccg_async_write(ucsi, offset, val, val_len); + ret = ucsi_ccg_async_cmd(ucsi, cmd); if (ret) goto err_clear_bit; @@ -663,8 +660,8 @@ static const struct ucsi_operations ucsi_ccg_ops = { .poll_cci = ucsi_ccg_poll_cci, .read_data = ucsi_ccg_read_data, .write_data = ucsi_ccg_write_data, - .sync_write = ucsi_ccg_sync_write, - .async_write = ucsi_ccg_async_write, + .sync_cmd = ucsi_ccg_sync_cmd, + .async_cmd = ucsi_ccg_async_cmd, .update_altmodes = ucsi_ccg_update_altmodes }; diff --git a/drivers/usb/typec/ucsi/ucsi_glink.c b/drivers/usb/typec/ucsi/ucsi_glink.c index 9dab1b428ad9..1535877a9a41 100644 --- a/drivers/usb/typec/ucsi/ucsi_glink.c +++ b/drivers/usb/typec/ucsi/ucsi_glink.c @@ -186,23 +186,24 @@ static int pmic_glink_ucsi_locked_write(struct pmic_glink_ucsi *ucsi, unsigned i return 0; } -static int pmic_glink_ucsi_async_write(struct ucsi *__ucsi, unsigned int offset, - const void *val, size_t val_len) +static int pmic_glink_ucsi_async_cmd(struct ucsi *__ucsi, u64 cmd) { struct pmic_glink_ucsi *ucsi = ucsi_get_drvdata(__ucsi); + __le64 __cmd = cpu_to_le64(cmd); int ret; mutex_lock(&ucsi->lock); - ret = pmic_glink_ucsi_locked_write(ucsi, offset, val, val_len); + ret = pmic_glink_ucsi_locked_write(ucsi, UCSI_CONTROL, + &__cmd, sizeof(__cmd)); mutex_unlock(&ucsi->lock); return ret; } -static int pmic_glink_ucsi_sync_write(struct ucsi *__ucsi, unsigned int offset, - const void *val, size_t val_len) +static int pmic_glink_ucsi_sync_cmd(struct ucsi *__ucsi, u64 cmd) { struct pmic_glink_ucsi *ucsi = ucsi_get_drvdata(__ucsi); + __le64 __cmd = cpu_to_le64(cmd); unsigned long left; int ret; @@ -212,7 +213,8 @@ static int pmic_glink_ucsi_sync_write(struct ucsi *__ucsi, unsigned int offset, ucsi->sync_val = 0; reinit_completion(&ucsi->sync_ack); ucsi->sync_pending = true; - ret = pmic_glink_ucsi_locked_write(ucsi, offset, val, val_len); + ret = pmic_glink_ucsi_locked_write(ucsi, UCSI_CONTROL, + &__cmd, sizeof(__cmd)); mutex_unlock(&ucsi->lock); left = wait_for_completion_timeout(&ucsi->sync_ack, 5 * HZ); @@ -232,8 +234,8 @@ static const struct ucsi_operations pmic_glink_ucsi_ops = { .poll_cci = pmic_glink_ucsi_poll_cci, .read_data = pmic_glink_ucsi_read_data, .write_data = pmic_glink_ucsi_write_data, - .sync_write = pmic_glink_ucsi_sync_write, - .async_write = pmic_glink_ucsi_async_write + .sync_cmd = pmic_glink_ucsi_sync_cmd, + .async_cmd = pmic_glink_ucsi_async_cmd }; static void pmic_glink_ucsi_read_ack(struct pmic_glink_ucsi *ucsi, const void *data, int len) diff --git a/drivers/usb/typec/ucsi/ucsi_stm32g0.c b/drivers/usb/typec/ucsi/ucsi_stm32g0.c index d68aca118e41..0847e00163e8 100644 --- a/drivers/usb/typec/ucsi/ucsi_stm32g0.c +++ b/drivers/usb/typec/ucsi/ucsi_stm32g0.c @@ -421,23 +421,23 @@ static int ucsi_stm32g0_write_data(struct ucsi *ucsi, return ucsi_stm32g0_write_to_hw(g0, UCSI_MESSAGE_OUT, val, len); } -static int ucsi_stm32g0_async_write(struct ucsi *ucsi, unsigned int offset, - const void *val, size_t len) +static int ucsi_stm32g0_async_cmd(struct ucsi *ucsi, u64 cmd) { struct ucsi_stm32g0 *g0 = ucsi_get_drvdata(ucsi); + __le64 __cmd = cpu_to_le64(cmd); - return ucsi_stm32g0_write_to_hw(g0, offset, val, len); + return ucsi_stm32g0_write_to_hw(g0, UCSI_CONTROL, + &__cmd, sizeof(__cmd)); } -static int ucsi_stm32g0_sync_write(struct ucsi *ucsi, unsigned int offset, const void *val, - size_t len) +static int ucsi_stm32g0_sync_cmd(struct ucsi *ucsi, u64 cmd) { struct ucsi_stm32g0 *g0 = ucsi_get_drvdata(ucsi); int ret; set_bit(COMMAND_PENDING, &g0->flags); - ret = ucsi_stm32g0_async_write(ucsi, offset, val, len); + ret = ucsi_stm32g0_async_cmd(ucsi, cmd); if (ret) goto out_clear_bit; @@ -480,8 +480,8 @@ static const struct ucsi_operations ucsi_stm32g0_ops = { .poll_cci = ucsi_stm32g0_poll_cci, .read_data = ucsi_stm32g0_read_data, .write_data = ucsi_stm32g0_write_data, - .sync_write = ucsi_stm32g0_sync_write, - .async_write = ucsi_stm32g0_async_write, + .sync_cmd = ucsi_stm32g0_sync_cmd, + .async_cmd = ucsi_stm32g0_async_cmd, }; static int ucsi_stm32g0_register(struct ucsi *ucsi)