From nobody Tue Jun 16 07:38:50 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F27B930EF95; Mon, 20 Apr 2026 10:09:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776679756; cv=none; b=P4YlabGZ4JO9AM2K7efJoz8+WIlHYArAzSX2ZJOJvu9YnahGJYlTiMEmUgiG/1ErJ2N2zTwn1M50FWEK/vvCtbaswWlrbk/AlDGYXJnZK+IfbEU5gIW8LtqmxBgt+Ux3Ww58VTPcVjTYlBAIhphJYeLlH6B7rbgbgMk9yUDgL9k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776679756; c=relaxed/simple; bh=Ndid9a7WggsDxQpOO5S0aMO0PPvq17hsq3KUVPs1w10=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To:Cc; b=oDj18gCCho7hLL6ICmJs/RLtT1lyKJtm51n80/ESgO52cZ6NiIK3OkIHFBN05LwBiXfnV17O4JXlTz+f8QRJrb15C9KL6Pxe0ESZ85q8R5hS9lERYvM8GuPk2U92KALYpQOX9IL2E/wiC6FdhMjsQqR0KXWorc08cHraHZxN5fY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=TdweIhB1; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="TdweIhB1" Received: by smtp.kernel.org (Postfix) with ESMTPS id 90277C19425; Mon, 20 Apr 2026 10:09:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1776679755; bh=Ndid9a7WggsDxQpOO5S0aMO0PPvq17hsq3KUVPs1w10=; h=From:Date:Subject:To:Cc:Reply-To:From; b=TdweIhB1/WmDnv/eOky/3kKTN9zf/0Q2k/ySNbBS8NSdrcXfoV2fWCNxKfVAjktuY Y10mDlS5wErzphlC9aCYaO4jTFYFB3IlmtqZ0/eqINkkLt/pquaJYQs3DkOehY3JPD FSBWPGUgPz/eKPdKNuoPJfbmrMj0irICiDMNjk0cNCdYqaKcClKmfTFB5TgNIg1IyR EU7Nf6ELU8+XOOptUnYi9+92j3LiWna1lm97LZ0ggYUxKp4taS2PJ27F8d9NN9VH1A MbBP7zmqahlv+SV2nvNy1tDEUZg12t46hoX1wupMUggtFhwTz4vDMAcDLZYvGyV+vV ER9dK/YMVTtPw== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 81D66F557EF; Mon, 20 Apr 2026 10:09:15 +0000 (UTC) From: Pawel Laszczak via B4 Relay Date: Mon, 20 Apr 2026 12:23:57 +0200 Subject: [PATCH v2] usb: cdnsp: add support for eUSB2v2 port Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260420-eusb2v2_upstream-v2-1-9883645e2ede@cadence.com> X-B4-Tracking: v=1; b=H4sIALz+5WkC/32Nyw6CMBBFf4XM2pq2oIgr/8MQ08cgNYGSDm00h H+34N7lSc49dwHC4JDgWiwQMDlyfswgDwWYXo1PZM5mBsnlmVeiZhhJyyQfcaI5oBrYhZuTlo2 qtVaQZ1PAzr335L39MUX9QjNvnc3oHc0+fPbPJDbvTz4JJlhZVtw2ttEdx5tRFkeDR+MHaNd1/ QKQvXkmxAAAAA== X-Change-ID: 20260417-eusb2v2_upstream-80c5b29a7bba To: Greg Kroah-Hartman Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, peter.chen@kernel.org, Pawel Laszczak X-Mailer: b4 0.15.1 X-Developer-Signature: v=1; a=ed25519-sha256; t=1776680652; l=10753; i=pawell@cadence.com; h=from:subject:message-id; bh=1S2xw8eKEGUe+bnE03nIXmCBqk4ynYOJ3VbC74u7qJ0=; b=EOaOmceN0jXVtNJSPBaLEpPZl8pfC6bnazbbz+5n95jeeo169ydpW4V5uuKYwSNwogwSJDrzR CS2cysffA8vCpcIvSD6M1HrIQYaa/e2nuXxMrOyOMP/T1CFIKOdG7Bz X-Developer-Key: i=pawell@cadence.com; a=ed25519; pk=EUPBvLO9CDg7j6defeDl2iqi+z5Ivqu4Z46aiqe7dYc= X-Endpoint-Received: by B4 Relay for pawell@cadence.com/default with auth_id=707 X-Original-From: Pawel Laszczak Reply-To: pawell@cadence.com From: Pawel Laszczak The Cadence CDNSP controller optionally supports eUSB2 (embedded USB2) port. While this port type operates logically like high-speed USB 2.0, it utilizes a different physical layer signaling. This patch: - Extends the port detection logic to recognize the eUSB2 protocol. - Tracks the eUSB2 port offset in the cdnsp_device structure. - Ensures that eUSB2 ports are correctly handled during Link State transitions, specifically forcing L0 when LPM is capable, similar to standard USB 2.0 ports. Signed-off-by: Pawel Laszczak Acked-by: Peter Chen --- Changes in v2: - Removed unnecessary space. - Added Acked-by: Peter Chen. --- drivers/usb/cdns3/cdnsp-gadget.c | 49 ++++++++++++++++++--------- drivers/usb/cdns3/cdnsp-gadget.h | 1 + drivers/usb/cdns3/cdnsp-mem.c | 73 +++++++++++++++++++++++++++---------= ---- drivers/usb/cdns3/cdnsp-ring.c | 9 +++-- 4 files changed, 90 insertions(+), 42 deletions(-) diff --git a/drivers/usb/cdns3/cdnsp-gadget.c b/drivers/usb/cdns3/cdnsp-gad= get.c index 6b3815f8a6e5..2c71c77e6ec3 100644 --- a/drivers/usb/cdns3/cdnsp-gadget.c +++ b/drivers/usb/cdns3/cdnsp-gadget.c @@ -124,20 +124,28 @@ void cdnsp_set_link_state(struct cdnsp_device *pdev, } =20 static void cdnsp_disable_port(struct cdnsp_device *pdev, - __le32 __iomem *port_regs) + struct cdnsp_port *port) { - u32 temp =3D cdnsp_port_state_to_neutral(readl(port_regs)); + u32 temp; + + if (!port->exist) + return; =20 - writel(temp | PORT_PED, port_regs); + temp =3D cdnsp_port_state_to_neutral(readl(&port->regs->portsc)); + writel(temp | PORT_PED, &port->regs->portsc); } =20 static void cdnsp_clear_port_change_bit(struct cdnsp_device *pdev, - __le32 __iomem *port_regs) + struct cdnsp_port *port) { - u32 portsc =3D readl(port_regs); + u32 portsc; + + if (!port->exist) + return; =20 + portsc =3D readl(&port->regs->portsc); writel(cdnsp_port_state_to_neutral(portsc) | - (portsc & PORT_CHANGE_BITS), port_regs); + (portsc & PORT_CHANGE_BITS), &port->regs->portsc); } =20 static void cdnsp_set_apb_timeout_value(struct cdnsp_device *pdev) @@ -944,7 +952,7 @@ void cdnsp_set_usb2_hardware_lpm(struct cdnsp_device *p= dev, struct usb_request *req, int enable) { - if (pdev->active_port !=3D &pdev->usb2_port || !pdev->gadget.lpm_capable) + if (pdev->active_port =3D=3D &pdev->usb3_port || !pdev->gadget.lpm_capabl= e) return; =20 trace_cdnsp_lpm(enable); @@ -1310,20 +1318,26 @@ static int cdnsp_run(struct cdnsp_device *pdev, break; } =20 - if (speed >=3D USB_SPEED_SUPER) { + if (pdev->usb3_port.exist && speed >=3D USB_SPEED_SUPER) { writel(temp, &pdev->port3x_regs->mode_addr); cdnsp_set_link_state(pdev, &pdev->usb3_port.regs->portsc, XDEV_RXDETECT); } else { - cdnsp_disable_port(pdev, &pdev->usb3_port.regs->portsc); + cdnsp_disable_port(pdev, &pdev->usb3_port); } =20 - cdnsp_set_link_state(pdev, &pdev->usb2_port.regs->portsc, - XDEV_RXDETECT); + if (pdev->usb2_port.exist) { + cdnsp_set_link_state(pdev, &pdev->usb2_port.regs->portsc, + XDEV_RXDETECT); + writel(PORT_REG6_L1_L0_HW_EN | fs_speed, &pdev->port20_regs->port_reg6); + } + + if (pdev->eusb_port.exist) + cdnsp_set_link_state(pdev, &pdev->eusb_port.regs->portsc, + XDEV_RXDETECT); =20 cdnsp_gadget_ep0_desc.wMaxPacketSize =3D cpu_to_le16(512); =20 - writel(PORT_REG6_L1_L0_HW_EN | fs_speed, &pdev->port20_regs->port_reg6); =20 ret =3D cdnsp_start(pdev); if (ret) { @@ -1469,8 +1483,10 @@ static void cdnsp_stop(struct cdnsp_device *pdev) cdnsp_ep_dequeue(&pdev->eps[0], req); } =20 - cdnsp_disable_port(pdev, &pdev->usb2_port.regs->portsc); - cdnsp_disable_port(pdev, &pdev->usb3_port.regs->portsc); + cdnsp_disable_port(pdev, &pdev->usb2_port); + cdnsp_disable_port(pdev, &pdev->usb3_port); + cdnsp_disable_port(pdev, &pdev->eusb_port); + cdnsp_disable_slot(pdev); cdnsp_halt(pdev); =20 @@ -1479,8 +1495,9 @@ static void cdnsp_stop(struct cdnsp_device *pdev) temp =3D readl(&pdev->ir_set->irq_pending); writel(IMAN_IE_CLEAR(temp), &pdev->ir_set->irq_pending); =20 - cdnsp_clear_port_change_bit(pdev, &pdev->usb2_port.regs->portsc); - cdnsp_clear_port_change_bit(pdev, &pdev->usb3_port.regs->portsc); + cdnsp_clear_port_change_bit(pdev, &pdev->usb2_port); + cdnsp_clear_port_change_bit(pdev, &pdev->eusb_port); + cdnsp_clear_port_change_bit(pdev, &pdev->usb3_port); =20 /* Clear interrupt line */ temp =3D readl(&pdev->ir_set->irq_pending); diff --git a/drivers/usb/cdns3/cdnsp-gadget.h b/drivers/usb/cdns3/cdnsp-gad= get.h index a91cca509db0..c44bca348a41 100644 --- a/drivers/usb/cdns3/cdnsp-gadget.h +++ b/drivers/usb/cdns3/cdnsp-gadget.h @@ -1474,6 +1474,7 @@ struct cdnsp_device { unsigned int link_state; =20 struct cdnsp_port usb2_port; + struct cdnsp_port eusb_port; struct cdnsp_port usb3_port; struct cdnsp_port *active_port; u16 test_mode; diff --git a/drivers/usb/cdns3/cdnsp-mem.c b/drivers/usb/cdns3/cdnsp-mem.c index a2a1b21f2ef8..5d8cdc91927d 100644 --- a/drivers/usb/cdns3/cdnsp-mem.c +++ b/drivers/usb/cdns3/cdnsp-mem.c @@ -1088,11 +1088,9 @@ void cdnsp_mem_cleanup(struct cdnsp_device *pdev) pdev->dcbaa, pdev->dcbaa->dma); =20 pdev->dcbaa =3D NULL; - - pdev->usb2_port.exist =3D 0; - pdev->usb3_port.exist =3D 0; - pdev->usb2_port.port_num =3D 0; - pdev->usb3_port.port_num =3D 0; + memset(&pdev->usb2_port, 0, sizeof(struct cdnsp_port)); + memset(&pdev->eusb_port, 0, sizeof(struct cdnsp_port)); + memset(&pdev->usb3_port, 0, sizeof(struct cdnsp_port)); pdev->active_port =3D NULL; } =20 @@ -1133,6 +1131,18 @@ static void cdnsp_add_in_port(struct cdnsp_device *p= dev, port_offset =3D CDNSP_EXT_PORT_OFF(temp); port_count =3D CDNSP_EXT_PORT_COUNT(temp); =20 + if (port =3D=3D &pdev->eusb_port) { + /* + * If controller has usb2 + eusb port then eusb is as + * second port + */ + if (port_count =3D=3D 2) + port_offset++; + + if (port_count =3D=3D 1 && pdev->usb2_port.exist) + return; + } + trace_cdnsp_port_info(addr, port_offset, port_count, port->maj_rev); =20 port->port_num =3D port_offset; @@ -1152,13 +1162,10 @@ static int cdnsp_setup_port_arrays(struct cdnsp_dev= ice *pdev) base =3D &pdev->cap_regs->hc_capbase; offset =3D cdnsp_find_next_ext_cap(base, 0, EXT_CAP_CFG_DEV_20PORT_CAP_ID); - pdev->port20_regs =3D base + offset; - - offset =3D cdnsp_find_next_ext_cap(base, 0, D_XEC_CFG_3XPORT_CAP); - pdev->port3x_regs =3D base + offset; + if (offset) + pdev->port20_regs =3D base + offset; =20 offset =3D 0; - base =3D &pdev->cap_regs->hc_capbase; =20 /* Driver expects max 2 extended protocol capability. */ for (i =3D 0; i < 2; i++) { @@ -1173,26 +1180,46 @@ static int cdnsp_setup_port_arrays(struct cdnsp_dev= ice *pdev) cdnsp_add_in_port(pdev, &pdev->usb3_port, base + offset); =20 - if (CDNSP_EXT_PORT_MAJOR(temp) =3D=3D 0x02 && - !pdev->usb2_port.port_num) - cdnsp_add_in_port(pdev, &pdev->usb2_port, - base + offset); + if (CDNSP_EXT_PORT_MAJOR(temp) =3D=3D 0x02) { + if (!pdev->usb2_port.port_num && pdev->port20_regs) + cdnsp_add_in_port(pdev, &pdev->usb2_port, + base + offset); + + if (!pdev->eusb_port.port_num) + cdnsp_add_in_port(pdev, &pdev->eusb_port, + base + offset); + } } =20 - if (!pdev->usb2_port.exist || !pdev->usb3_port.exist) { - dev_err(pdev->dev, "Error: Only one port detected\n"); + if (!pdev->usb2_port.exist && !pdev->eusb_port.exist && + !pdev->usb3_port.exist) { + dev_err(pdev->dev, "Error: No port detected\n"); return -ENODEV; } =20 - trace_cdnsp_init("Found USB 2.0 ports and USB 3.0 ports."); + if (pdev->usb2_port.exist) { + pdev->usb2_port.regs =3D (struct cdnsp_port_regs __iomem *) + (&pdev->op_regs->port_reg_base + NUM_PORT_REGS * + (pdev->usb2_port.port_num - 1)); + trace_cdnsp_init("Found USB 2.0 port."); + } =20 - pdev->usb2_port.regs =3D (struct cdnsp_port_regs __iomem *) - (&pdev->op_regs->port_reg_base + NUM_PORT_REGS * - (pdev->usb2_port.port_num - 1)); + if (pdev->eusb_port.exist) { + pdev->eusb_port.regs =3D (struct cdnsp_port_regs __iomem *) + (&pdev->op_regs->port_reg_base + NUM_PORT_REGS * + (pdev->eusb_port.port_num - 1)); + trace_cdnsp_init("Found eUSB 2.0 port."); + } + + if (pdev->usb3_port.exist) { + offset =3D cdnsp_find_next_ext_cap(base, 0, D_XEC_CFG_3XPORT_CAP); + pdev->port3x_regs =3D base + offset; =20 - pdev->usb3_port.regs =3D (struct cdnsp_port_regs __iomem *) - (&pdev->op_regs->port_reg_base + NUM_PORT_REGS * - (pdev->usb3_port.port_num - 1)); + pdev->usb3_port.regs =3D (struct cdnsp_port_regs __iomem *) + (&pdev->op_regs->port_reg_base + NUM_PORT_REGS * + (pdev->usb3_port.port_num - 1)); + trace_cdnsp_init("Found USB 3.x port."); + } =20 return 0; } diff --git a/drivers/usb/cdns3/cdnsp-ring.c b/drivers/usb/cdns3/cdnsp-ring.c index 0758f171f73e..715658c981ff 100644 --- a/drivers/usb/cdns3/cdnsp-ring.c +++ b/drivers/usb/cdns3/cdnsp-ring.c @@ -259,7 +259,7 @@ static bool cdnsp_room_on_ring(struct cdnsp_device *pde= v, */ static void cdnsp_force_l0_go(struct cdnsp_device *pdev) { - if (pdev->active_port =3D=3D &pdev->usb2_port && pdev->gadget.lpm_capable) + if (pdev->active_port !=3D &pdev->usb3_port && pdev->gadget.lpm_capable) cdnsp_set_link_state(pdev, &pdev->active_port->regs->portsc, XDEV_U0); } =20 @@ -763,6 +763,8 @@ static int cdnsp_update_port_id(struct cdnsp_device *pd= ev, u32 port_id) =20 if (port_id =3D=3D pdev->usb2_port.port_num) { port =3D &pdev->usb2_port; + } else if (port_id =3D=3D pdev->eusb_port.port_num) { + port =3D &pdev->eusb_port; } else if (port_id =3D=3D pdev->usb3_port.port_num) { port =3D &pdev->usb3_port; } else { @@ -779,7 +781,8 @@ static int cdnsp_update_port_id(struct cdnsp_device *pd= ev, u32 port_id) cdnsp_enable_slot(pdev); } =20 - if (port_id =3D=3D pdev->usb2_port.port_num) + if ((pdev->usb2_port.exist && port_id =3D=3D pdev->usb2_port.port_num) || + (pdev->eusb_port.exist && port_id =3D=3D pdev->eusb_port.port_num)) cdnsp_set_usb2_hardware_lpm(pdev, NULL, 1); else writel(PORT_U1_TIMEOUT(1) | PORT_U2_TIMEOUT(1), @@ -808,7 +811,7 @@ static void cdnsp_handle_port_status(struct cdnsp_devic= e *pdev, =20 port_regs =3D pdev->active_port->regs; =20 - if (port_id =3D=3D pdev->usb2_port.port_num) + if (port_id =3D=3D pdev->usb2_port.port_num || port_id =3D=3D pdev->eusb_= port.port_num) port2 =3D true; =20 new_event: --- base-commit: 1c7cc4904160c6fc6377564140062d68a3dc93a0 change-id: 20260417-eusb2v2_upstream-80c5b29a7bba Best regards, -- =20 Pawel Laszczak