From patchwork Mon Aug 20 10:31:25 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Haojian Zhuang X-Patchwork-Id: 144563 Delivered-To: patch@linaro.org Received: by 2002:a2e:9754:0:0:0:0:0 with SMTP id f20-v6csp3796903ljj; Mon, 20 Aug 2018 03:31:48 -0700 (PDT) X-Google-Smtp-Source: ANB0VdYaJrO9rl4dwZ8KYEKhjBzUf1v7+xc/kqNgfgx6JeZ2zsfWsK/T0C+H0uDbAqlaA8Lv7yk+ X-Received: by 2002:a0c:b217:: with SMTP id x23-v6mr9391659qvd.220.1534761108291; Mon, 20 Aug 2018 03:31:48 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1534761108; cv=none; d=google.com; s=arc-20160816; b=dh6v4QHctcu0DiSi20YXuxGMhD+DLj/oWMoDqhdQnxMsyjEhxPVQQb8EmygR/FeJ1J GQFR1MdkehNwt2SrhIZgM2k+UbkL7P9zNvRXJVPkNmvtBaTPha++11fV4r2ZCAeKtIlX U7d34rRbiW1cTnPfUoZYSadzyMdphgvGw2g6nzT9SCqtzq6/DzVU3IWbzJEbZJ22STMz saOZx5IlziJl6eHpeZdebkmPJu1NuQ1EP+sP4Ikn9WGo62pDt6UxctpwxOKEIKyr2bEI 7Qc3WPfoKcAgaRiDosc029GIP4kQFhU3BMdhezfLpB7huT6mUooqDaUJTbiPNZ5zOjRC m8mQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:references:in-reply-to:message-id:date :to:from:dkim-signature:delivered-to:arc-authentication-results; bh=IdqrCINfubpN5F0v8ndFCA14XhMFOelt2L6XnMxcsNw=; b=Vd3ChrYBUnzZDW3LY/HX65Yt0fwKsGE4/xe+A29d6gTa3BjEdERdL8MQBYOQmeu0mT ti+Ogy75k2S+igKzY8Ge0bdgxfelhQFRvUvOvyB0nANmA9LFQN9/3qAicQAaddiY1NlL Iei/+Op4S8mmja53AfmDCWFos79UVjsTaNRdAR93NtKo5S5iq6z1T2ofVHmDT0Py5eHb GbH97rTZYiDR43KuHCoqyesZbDulOn7vBRVJBDIUQdo/fWDN3t8P+2RuifAFYLnMPiWw 9SlMUnYJVaFZCpKdteZicxtgakjFxsEVhtaY6qLZC4aN8QlM5/nnF6c2QytP3ey31ge8 CRlA== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=JVbk98Ds; spf=pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 2001:19d0:306:5::1 as permitted sender) smtp.mailfrom=edk2-devel-bounces@lists.01.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from ml01.01.org (ml01.01.org. [2001:19d0:306:5::1]) by mx.google.com with ESMTPS id q34-v6si992736qkq.244.2018.08.20.03.31.47 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 20 Aug 2018 03:31:48 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 2001:19d0:306:5::1 as permitted sender) client-ip=2001:19d0:306:5::1; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=JVbk98Ds; spf=pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 2001:19d0:306:5::1 as permitted sender) smtp.mailfrom=edk2-devel-bounces@lists.01.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 3C6B5210F624A; Mon, 20 Aug 2018 03:31:47 -0700 (PDT) X-Original-To: edk2-devel@lists.01.org Delivered-To: edk2-devel@lists.01.org Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=2607:f8b0:400e:c01::22a; helo=mail-pl0-x22a.google.com; envelope-from=haojian.zhuang@linaro.org; receiver=edk2-devel@lists.01.org Received: from mail-pl0-x22a.google.com (mail-pl0-x22a.google.com [IPv6:2607:f8b0:400e:c01::22a]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 7C064210F6249 for ; Mon, 20 Aug 2018 03:31:45 -0700 (PDT) Received: by mail-pl0-x22a.google.com with SMTP id j8-v6so6886070pll.12 for ; Mon, 20 Aug 2018 03:31:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=AIB+O69hzVTsrBxOp8I/lqPnpq8YqsGMFAy2VZFpiwo=; b=JVbk98Ds7HnO7FwHlN3skfie7nt0rkhDFkJO4BLZuxdxePfNB6MR/1XcTKpna0+JP6 Rhg2Lj/sKObWxZNAS469o5ikaCLenUBucGNTfRwroU3y/gOhBVmHPBxiDx9ayXKt5A1L Kbr6P6SvvtoM5JeUIPmLZiWqcwP0kMz2X6bsE= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=AIB+O69hzVTsrBxOp8I/lqPnpq8YqsGMFAy2VZFpiwo=; b=KybDvZw+5PiPqE5pQAPFtNFiil5Yn4XCKrJqR9+7Xgs2PoDoFjKzyXNrc6B5HxztpG jDQ5GfotICUi9Dxa9srrvz+zbuxZPr7it3p9h2iF1ZcMqlT36hJlZMcNP4W4QlROa7EQ KDRznCm5MibTCQo9NM9BzssWf4sdqqeRQa3cQz2c/GnoDhXBjOEIbo0p3XiVF2sf2hvR BepZzPGIoGeL6QVgLpU9vq904zJpOQqntBUxBVpr+9BoPTYh103dU0fjuZ7Me+M0VD6A gCMP0eKMflxudMfvzNgCtHx2+xTQ0XN+HM1Q4OfUWKbZROT17e5KDCyxwqUb+kRHnMM1 +19A== X-Gm-Message-State: AOUpUlFvk6yC+RD0sqMNnDNJ9RHJ7rWxRTcGXryPPwIStlLO0boCScdL URVUbavXvQu5xaRSwZ/X7vtctlIBIJpnvQ== X-Received: by 2002:a17:902:14e:: with SMTP id 72-v6mr44476568plb.299.1534761103430; Mon, 20 Aug 2018 03:31:43 -0700 (PDT) Received: from localhost.localdomain ([64.64.108.180]) by smtp.gmail.com with ESMTPSA id e73-v6sm17581027pfb.153.2018.08.20.03.31.40 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 20 Aug 2018 03:31:42 -0700 (PDT) From: Haojian Zhuang To: edk2-devel@lists.01.org Date: Mon, 20 Aug 2018 18:31:25 +0800 Message-Id: <1534761085-26972-3-git-send-email-haojian.zhuang@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1534761085-26972-1-git-send-email-haojian.zhuang@linaro.org> References: <1534761085-26972-1-git-send-email-haojian.zhuang@linaro.org> Subject: [edk2] [PATCH v1 2/2] EmbeddedPkg/Drivers: add DwUsb3Dxe driver X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" Add Designware USB 3.0 device driver. It's focus on USB device functionality, not USB Host functionality. The USB driver is mainly used for Android Fastboot application. Cc: Leif Lindholm Cc: Ard Biesheuvel Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Haojian Zhuang --- EmbeddedPkg/Drivers/DwUsb3Dxe/DwUsb3Dxe.dec | 44 + EmbeddedPkg/Drivers/DwUsb3Dxe/DwUsb3Dxe.inf | 52 + EmbeddedPkg/Drivers/DwUsb3Dxe/DwUsb3Dxe.h | 632 +++++ EmbeddedPkg/Drivers/DwUsb3Dxe/DwUsb3Dxe.c | 2434 ++++++++++++++++++++ 4 files changed, 3162 insertions(+) -- 2.7.4 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel diff --git a/EmbeddedPkg/Drivers/DwUsb3Dxe/DwUsb3Dxe.dec b/EmbeddedPkg/Drivers/DwUsb3Dxe/DwUsb3Dxe.dec new file mode 100644 index 000000000000..038e4881a948 --- /dev/null +++ b/EmbeddedPkg/Drivers/DwUsb3Dxe/DwUsb3Dxe.dec @@ -0,0 +1,44 @@ +#/** @file +# Framework Module Development Environment Industry Standards +# +# This Package provides headers and libraries that conform to EFI/PI Industry standards. +# Copyright (c) 2007, Intel Corporation. All rights reserved.
+# Copyright (c) 2012-2014, ARM Ltd. All rights reserved.
+# Copyright (c) 2018, Linaro. All rights reserved.
+# +# This program and the accompanying materials are licensed and made available under +# the terms and conditions of the BSD License which accompanies this distribution. +# The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + DEC_SPECIFICATION = 0x00010019 + PACKAGE_NAME = DwUsb3DxePkg + PACKAGE_GUID = 9b7aa6fe-405b-4955-af1f-5faf183aedec + PACKAGE_VERSION = 0.1 + + +################################################################################ +# +# Include Section - list of Include Paths that are provided by this package. +# Comments are used for Keywords and Module Types. +# +# Supported Module Types: +# BASE SEC PEI_CORE PEIM DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER DXE_SAL_DRIVER UEFI_DRIVER UEFI_APPLICATION +# +################################################################################ + +[Guids.common] + gDwUsb3DxeTokenSpaceGuid = { 0x098a50d3, 0x92e2, 0x461a, { 0xb6, 0xba, 0xf8, 0x5d, 0x9d, 0x89, 0x49, 0xf5 }} + +[Protocols.common] + gDwUsbProtocolGuid = { 0x109fa264, 0x7811, 0x4862, { 0xa9, 0x73, 0x4a, 0xb2, 0xef, 0x2e, 0xe2, 0xff }} + +[PcdsFixedAtBuild.common] + # DwUsb Driver PCDs + gDwUsb3DxeTokenSpaceGuid.PcdDwUsb3DxeBaseAddress|0x0|UINT32|0x00000001 diff --git a/EmbeddedPkg/Drivers/DwUsb3Dxe/DwUsb3Dxe.inf b/EmbeddedPkg/Drivers/DwUsb3Dxe/DwUsb3Dxe.inf new file mode 100644 index 000000000000..510b51a34de7 --- /dev/null +++ b/EmbeddedPkg/Drivers/DwUsb3Dxe/DwUsb3Dxe.inf @@ -0,0 +1,52 @@ +#/** @file +# +# Copyright (c) 2018, Linaro Limited. All rights reserved. +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = DwUsb3Dxe + FILE_GUID = 0879cd34-c399-4315-9891-56024072e711 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = DwUsb3EntryPoint + +[Sources.common] + DwUsb3Dxe.c + +[LibraryClasses] + CacheMaintenanceLib + DebugLib + DmaLib + IoLib + MemoryAllocationLib + TimerLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UsbSerialNumberLib + +[Protocols] + gEfiDriverBindingProtocolGuid + gUsbDeviceProtocolGuid + +[Packages] + ArmPkg/ArmPkg.dec + EmbeddedPkg/Drivers/DwUsb3Dxe/DwUsb3Dxe.dec + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[Pcd] + gDwUsb3DxeTokenSpaceGuid.PcdDwUsb3DxeBaseAddress + +[Depex] + TRUE diff --git a/EmbeddedPkg/Drivers/DwUsb3Dxe/DwUsb3Dxe.h b/EmbeddedPkg/Drivers/DwUsb3Dxe/DwUsb3Dxe.h new file mode 100644 index 000000000000..92b610553169 --- /dev/null +++ b/EmbeddedPkg/Drivers/DwUsb3Dxe/DwUsb3Dxe.h @@ -0,0 +1,632 @@ +/** @file + + Copyright (c) 2017, Linaro Limited. All rights reserved. + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __DW_USB3_DXE_H__ +#define __DW_USB3_DXE_H__ + +#define DW_USB3_BASE FixedPcdGet32 (PcdDwUsb3DxeBaseAddress) + +#define GSBUCFG0 (DW_USB3_BASE + 0xC100) +#define GCTL (DW_USB3_BASE + 0xC110) + +#define GCTL_PWRDNSCALE_MASK (0x1FFF << 19) +#define GCTL_PWRDNSCALE(x) (((x) & 0x1FFF) << 19) +#define GCTL_U2RSTECN BIT16 +#define GCTL_PRTCAPDIR_MASK (BIT13 | BIT12) +#define GCTL_PRTCAPDIR_HOST BIT12 +#define GCTL_PRTCAPDIR_DEVICE BIT13 +#define GCTL_PRTCAPDIR_OTG (BIT13 | BIT12) +#define GCTL_U2EXIT_LFPS BIT2 + +#define GUSB2PHYCFG(x) (DW_USB3_BASE + 0xC200 + (((x) & 0xF) << 2)) + +#define GUSB2PHYCFG_USBTRDTIM_MASK (0xF << 10) +#define GUSB2PHYCFG_USBTRDTIM(x) (((x) & 0xF) << 10) +#define GUSB2PHYCFG_SUSPHY BIT6 + +#define GUSB3PIPECTL(x) (DW_USB3_BASE + 0xC2C0 + (((x) & 0x3) << 2)) + +#define PIPECTL_DELAYP1TRANS BIT18 +#define PIPECTL_SUSPEND_EN BIT17 +#define PIPECTL_LFPS_FILTER BIT9 +#define PIPECTL_TX_DEMPH_MASK (0x3 << 1) +#define PIPECTL_TX_DEMPH(x) (((x) & 0x3) << 1) + +#define GTXFIFOSIZ(x) (DW_USB3_BASE + 0xC300 + (((x) & 0x1F) << 2)) +#define GRXFIFOSIZ(x) (DW_USB3_BASE + 0xC380 + (((x) & 0x1F) << 2)) + +#define FIFOSIZ_ADDR(x) (((x) & 0xFFFF) << 16) +#define FIFOSIZ_DEP(x) ((x) & 0xFFFF) + +#define GEVNTADRL(x) (DW_USB3_BASE + 0xC400 + (((x) & 0x1F) << 2)) +#define GEVNTADRH(x) (DW_USB3_BASE + 0xC404 + (((x) & 0x1F) << 2)) +#define GEVNTSIZ(x) (DW_USB3_BASE + 0xC408 + (((x) & 0x1F) << 2)) + +#define GEVNTSIZ_EVNTINTMASK BIT31 +#define GEVNTSIZ_EVNTSIZ_MASK (0xFFFF) +#define GEVNTSIZ_EVNTSIZ(x) ((x) & 0xFFFF) + +#define GEVNTCOUNT(x) (DW_USB3_BASE + 0xC40C + (((x) & 0x1F) << 2)) +#define GEVNTCOUNT_EVNTCOUNT_MASK (0xFFFF) +#define GEVNTCOUNT_EVNTCOUNT(x) ((x) & 0xFFFF) + +// Non-Endpoint specific event flag +#define GEVNT_INTTYPE_MASK (0x7F << 1) +#define GEVNT_INTTYPE(x) (((x) & 0x7F) << 1) +#define EVENT_I2C_INT 4 +#define EVENT_CARKIT_INT 3 +#define EVENT_OTG_INT 1 +#define EVENT_DEV_INT 0 + +#define GEVNT_NON_EP BIT0 +// Endpoint specific event flag +#define GEVNT_DEPEVT_INTTYPE_MASK (0xF << 6) +#define GEVNT_DEPEVT_INTTYPE(x) (((x) & 0xF) << 6) +#define GEVNT_DEPEVT_INTTYPE_EPCMD_CMPL (7 << 6) +#define GEVNT_DEPEVT_INTTYPE_STRM_EVT (6 << 6) +#define GEVNT_DEPEVT_INTTYPE_FIFOXRUN (4 << 6) +#define GEVNT_DEPEVT_INTTYPE_XFER_NRDY (3 << 6) +#define GEVNT_DEPEVT_INTTYPE_XFER_IN_PROG (2 << 6) +#define GEVNT_DEPEVT_INTTYPE_XFER_CMPL (1 << 6) +#define GEVNT_DEPEVT_EPNUM_MASK (0x1F << 1) +#define GEVNT_DEPEVT_EPNUM_SHIFT 1 +#define GEVNT_DEPEVT_EPNUM(x) (((x) & 0x1F) << 1) +// Devices specific event flag +#define GEVNT_DEVT_MASK (0xF << 8) +#define GEVNT_DEVT_SHIFT 8 +#define GEVNT_DEVT(x) (((x) & 0xF) << 8) +#define GEVNT_DEVT_INACT_TIMEOUT_RCVD (0x15 << 8) +#define GEVNT_DEVT_VNDR_DEV_TST_RCVD (0x14 << 8) +#define GEVNT_DEVT_OVERFLOW (0x13 << 8) +#define GEVNT_DEVT_CMD_CMPL (0x12 << 8) +#define GEVNT_DEVT_ERRATICERR (0x11 << 8) +#define GEVNT_DEVT_SOF (0x7 << 8) +#define GEVNT_DEVT_EOPF (0x6 << 8) +#define GEVNT_DEVT_HIBER_REQ (0x5 << 8) +#define GEVNT_DEVT_WKUP (0x4 << 8) +#define GEVNT_DEVT_ULST_CHNG (0x3 << 8) +#define GEVNT_DEVT_CONNDONE (0x2 << 8) +#define GEVNT_DEVT_USBRESET (0x1 << 8) +#define GEVNT_DEVT_DISCONN (0x0 << 8) + +#define DCFG (DW_USB3_BASE + 0xC700) + +#define DCFG_NUMP_MASK (0x1F << 17) +#define DCFG_NUMP(x) (((x) & 0x1F) << 17) +#define DCFG_DEVADDR_MASK (0x7F << 3) +#define DCFG_DEVADDR(x) (((x) & 0x7F) << 3) +#define DCFG_DEVSPD_MASK (0x7) +#define DCFG_DEVSPD(x) ((x) & 0x7) +#define DEVSPD_HS_PHY_30MHZ_OR_60MHZ 0 +#define DEVSPD_FS_PHY_30MHZ_OR_60MHZ 1 +#define DEVSPD_LS_PHY_6MHZ 2 +#define DEVSPD_FS_PHY_48MHZ 3 +#define DEVSPD_SS_PHY_125MHZ_OR_250MHZ 4 + +#define DCTL (DW_USB3_BASE + 0xC704) + +#define DCTL_RUN_STOP BIT31 +#define DCTL_CSFTRST BIT30 +#define DCTL_INIT_U2_EN BIT12 +#define DCTL_ACCEPT_U2_EN BIT11 +#define DCTL_INIT_U1_EN BIT10 +#define DCTL_ACCEPT_U1_EN BIT9 + +#define DEVTEN (DW_USB3_BASE + 0xC708) +#define DEVTEN_CONNECTDONEEN BIT2 +#define DEVTEN_USBRSTEN BIT1 +#define DEVTEN_DISCONNEN BIT0 + +#define DSTS (DW_USB3_BASE + 0xC70C) +#define DSTS_GET_DEVSPD(x) ((x) & 0x7) + +#define DALEPENA (DW_USB3_BASE + 0xC720) + +#define DEPCMDPAR2(x) (DW_USB3_BASE + 0xC800 + ((x) & 0x1F) * 0x10) +#define DEPCMDPAR1(x) (DW_USB3_BASE + 0xC804 + ((x) & 0x1F) * 0x10) +#define DEPCMDPAR0(x) (DW_USB3_BASE + 0xC808 + ((x) & 0x1F) * 0x10) +#define DEPCMD(x) (DW_USB3_BASE + 0xc80C + ((x) & 0x1F) * 0x10) + +#define DEPCMD_COMMANDPARAM_MASK (0xFFFF << 16) +#define DEPCMD_COMMANDPARAM(x) (((x) & 0xFFFF) << 16) +/* Stream Number or uFrame (input) */ +#define DEPCMD_STR_NUM_OR_UF_MASK (0xFFFF << 16) +#define DEPCMD_STR_NUM_OR_UF(x) (((x) & 0xFFFF) << 16) +/* Transfer Resource Index (output) */ +#define DEPCMD_XFER_RSRC_IDX_SHIFT 16 +#define DEPCMD_XFER_RSRC_IDX_MASK (0x7F << 16) +#define DEPCMD_XFER_RSRC_IDX(x) (((x) & 0x7F) << 16) +#define GET_DEPCMD_XFER_RSRC_IDX(x) (((x) >> 16) & 0x7F) +#define DEPCMD_CMDACT BIT10 +#define DEPCMD_CMDTYPE_MASK 0xFF +#define DEPCMD_CMDTYPE(x) ((x) & 0xFF) + +/* EP registers range as: OUT0, IN0, OUT1, IN1, ... */ +#define EP_OUT_IDX(x) ((x) * 2) +#define EP_IN_IDX(x) (((x) * 2) + 1) + +#define CMDTYPE_SET_EP_CFG 1 +#define CMDTYPE_SET_XFER_CFG 2 +#define CMDTYPE_GET_EP_STATE 3 +#define CMDTYPE_SET_STALL 4 +#define CMDTYPE_CLR_STALL 5 +#define CMDTYPE_START_XFER 6 +#define CMDTYPE_UPDATE_XFER 7 +#define CMDTYPE_END_XFER 8 +#define CMDTYPE_START_NEW_CFG 9 + +#define EPTYPE_CONTROL 0 +#define EPTYPE_ISOC 1 +#define EPTYPE_BULK 2 +#define EPTYPE_INTR 3 + +#define CFG_ACTION_INIT 0 +#define CFG_ACTION_RESTORE 1 +#define CFG_ACTION_MODIFY 2 + +#define EPCFG0_CFG_ACTION_MASK (0x3 << 30) +#define EPCFG0_CFG_ACTION(x) (((x) & 0x3) << 30) +#define EPCFG0_BRSTSIZ_MASK (0xF << 22) +#define EPCFG0_BRSTSIZ(x) (((x) & 0xF) << 22) +#define EPCFG0_TXFNUM_MASK (0x1F << 17) +#define EPCFG0_TXFNUM(x) (((x) & 0x1F) << 17) +#define EPCFG0_MPS_MASK (0x7FF << 3) +#define EPCFG0_MPS(x) (((x) & 0x7FF) << 3) +#define EPCFG0_EPTYPE_MASK (0x3 << 1) +#define EPCFG0_EPTYPE_SHIFT 1 +#define EPCFG0_EPTYPE(x) (((x) & 0x3) << 1) + +/* Endpoint Number */ +#define EPCFG1_EP_NUM_MASK (0xF << 26) +#define EPCFG1_EP_NUM(x) (((x) & 0xF) << 26) +/* Endpoint Direction */ +#define EPCFG1_EP_DIR_IN BIT25 +/* Stream Not Ready */ +#define EPCFG1_XFER_NRDY BIT10 +/* XferInProgress Enable */ +#define EPCFG1_XFER_IN_PROG BIT9 +/* Stream Completed */ +#define EPCFG1_XFER_CMPL BIT8 + +#define USB_SPEED_UNKNOWN 0 +#define USB_SPEED_LOW 1 +#define USB_SPEED_FULL 2 +#define USB_SPEED_HIGH 3 +#define USB_SPEED_VARIABLE 4 +#define USB_SPEED_SUPER 5 + +// DMA registers +#define DSCSTS_TRBRSP_MASK (0xF << 28) +#define DSCSTS_TRBRSP(x) (((x) & 0xF) << 28) +#define GET_DSCSTS_TRBRSP(x) (((x) >> 28) & 0xF) +#define TRBRSP_MISSED_ISOC_IN 1 +#define TRBRSP_SETUP_PEND 2 +#define TRBRSP_XFER_IN_PROG 4 +#define DSCSTS_PCM1_MASK (0x3 << 24) +#define DSCSTS_PCM1(x) (((x) & 0x3) << 24) +#define DSCSTS_XFERCNT_MASK 0xFFFFFF +#define DSCSTS_XFERCNT(x) ((x) & 0xFFFFFF) +#define GET_DSCSTS_XFERCNT(x) ((x) & 0xFFFFFF) + +#define DSCCTL_STRMID_SOFN(x) (((x) & 0xFFFF) << 14) +#define DSCCTL_IOC BIT11 +#define DSCCTL_ISP BIT10 +#define DSCCTL_TRBCTL_MASK (0x3F << 4) +#define DSCCTL_TRBCTL(x) (((x) & 0x3F) << 4) +#define DSCCTL_LST BIT1 +#define DSCCTL_HWO BIT0 +#define TRBCTL_NORMAL 1 +#define TRBCTL_SETUP 2 +#define TRBCTL_STATUS_2 3 +#define TRBCTL_STATUS_3 4 +#define TRBCTL_CTLDATA_1ST 5 +#define TRBCTL_ISOC_1ST 6 +#define TRBCTL_ISOC 7 +#define TRBCTL_LINK 8 +#define TRBCTL_NORMAL_ZLP 9 + + +#define UE_DIR_IN 0x80 +#define UE_DIR_OUT 0 +#define UE_SET_DIR(a, d) ((a) | (((d) & 1) << 7)) +#define UE_GET_DIR(a) ((a) & 0x80) +#define UE_ADDR 0x0F +#define UE_GET_ADDR(a) ((a) & UE_ADDR) + +#define UT_GET_DIR(a) ((a) & 0x80) +#define UT_WRITE 0x00 +#define UT_READ 0x80 + +#define UT_GET_TYPE(a) ((a) & 0x60) +#define UT_STANDARD 0x00 +#define UT_CLASS 0x20 +#define UT_VENDOR 0x40 + +#define UT_GET_RECIPIENT(a) ((a) & 0x1f) +#define UT_DEVICE 0x00 +#define UT_INTERFACE 0x01 +#define UT_ENDPOINT 0x02 +#define UT_OTHER 0x03 + +#define UR_GET_STATUS 0x00 +#define UR_CLEAR_FEATURE 0x01 +#define UR_SET_FEATURE 0x03 +#define UR_SET_ADDRESS 0x05 +#define UR_GET_DESCRIPTOR 0x06 +#define UR_SET_DESCRIPTOR 0x07 +#define UR_GET_CONFIG 0x08 +#define UR_SET_CONFIG 0x09 +#define UR_GET_INTERFACE 0x0A +#define UR_SET_INTERFACE 0x0B +#define UR_SYNCH_FRAME 0x0C +#define UR_SET_SEL 0x30 +#define UR_SET_ISOC_DELAY 0x31 + +/* Feature numbers */ +#define UF_ENDPOINT_HALT 0 +#define UF_DEVICE_REMOTE_WAKEUP 1 +#define UF_TEST_MODE 2 +#define UF_DEVICE_B_HNP_ENABLE 3 +#define UF_DEVICE_A_HNP_SUPPORT 4 +#define UF_DEVICE_A_ALT_HNP_SUPPORT 5 +#define UF_FUNCTION_SUSPEND 0 +#define UF_U1_ENABLE 48 +#define UF_U2_ENABLE 49 +#define UF_LTM_ENABLE 50 + +#define UDESC_DEVICE 0x01 +#define UDESC_CONFIG 0x02 +#define UDESC_STRING 0x03 +#define UDESC_INTERFACE 0x04 +#define UDESC_ENDPOINT 0x05 +#define UDESC_SS_USB_COMPANION 0x30 +#define UDESC_DEVICE_QUALIFIER 0x06 +#define UDESC_BOS 0x0f +#define UDESC_DEVICE_CAPABILITY 0x10 + +#define STRING_LANGUAGE 0 +#define STRING_MANUFACTURER 1 +#define STRING_PRODUCT 2 +#define STRING_SERIAL 3 + +#define CONFIG_VALUE 1 + +#define USB3_BULK_IN_EP 1 +#define USB3_BULK_OUT_EP 1 + +#define USB_ENUM_ADB_PORT_VID 0x18D1 +#define USB_ENUM_ADB_PORT_PID 0xD00D +#define USB_ENUM_INTERFACE_ADB_SUBCLASS 0x42 +#define USB_ENUM_INTERFACE_ADB_PROTOCOL 0x03 + +struct usb3_pcd; + +typedef enum pcd_state { + USB3_STATE_UNCONNECTED, /* no host */ + USB3_STATE_DEFAULT, + USB3_STATE_ADDRESSED, + USB3_STATE_CONFIGURED, +} pcdstate_e; + +typedef enum ep0_state { + EP0_IDLE, + EP0_IN_DATA_PHASE, + EP0_OUT_DATA_PHASE, + EP0_IN_WAIT_NRDY, + EP0_OUT_WAIT_NRDY, + EP0_IN_STATUS_PHASE, + EP0_OUT_STATUS_PHASE, + EP0_STALL, +} ep0state_e; + +typedef struct usb3_dma_desc { + /** Buffer Pointer - Low address quadlet */ + UINT32 bptl; + + /** Buffer Pointer - High address quadlet */ + UINT32 bpth; + + /** Status quadlet. Fields defined in enum @ref desc_sts_data. */ + UINT32 status; + + /** Control quadlet. Fields defined in enum @ref desc_ctl_data. */ + UINT32 control; +} usb3_dma_desc_t; + +typedef struct usb3_pcd_req { + usb3_dma_desc_t *trb; + UINT64 trbdma; + + UINT32 length; + UINT32 actual; + + UINT64 *bufdma; + int (*complete)(unsigned actual, int status); +} usb3_pcd_req_t; + +typedef struct usb_device_request { + UINT8 bmRequestType; + UINT8 bRequest; + UINT16 wValue; + UINT16 wIndex; + UINT16 wLength; +} usb_device_request_t; + +#pragma pack(1) +/** USB_DT_DEVICE: Device descriptor */ +typedef struct usb_device_descriptor { + UINT8 bLength; + UINT8 bDescriptorType; + + UINT16 bcdUSB; +#define USB_CLASS_COMM 0x02 +#define USB_CLASS_VENDOR_SPEC 0xFF +#define USB_SC_VENDOR_SPEC 0xFF +#define USB_PR_VENDOR_SPEC 0xFF + UINT8 bDeviceClass; + UINT8 bDeviceSubClass; + UINT8 bDeviceProtocol; + UINT8 bMaxPacketSize0; + UINT16 idVendor; + UINT16 idProduct; + UINT16 bcdDevice; + UINT8 iManufacturer; + UINT8 iProduct; + UINT8 iSerialNumber; + UINT8 bNumConfigurations; +} usb_device_descriptor_t; + +/* USB_DT_CONFIG: Config descriptor */ +typedef struct usb_config_descriptor { + UINT8 bLength; + UINT8 bDescriptorType; + + UINT16 wTotalLength; + UINT8 bNumInterfaces; +#define CONFIG_VALUE 1 + UINT8 bConfigurationValue; + UINT8 iConfiguration; +#define USB_CONFIG_ATT_ONE (1 << 7) + UINT8 bmAttributes; +#define USB_CONFIG_VBUS_DRAW (0xFA) + UINT8 bMaxPower; +} usb_config_descriptor_t; + +/* USB_DT_DEVICE_QUALIFIER: Device Qualifier descriptor */ +typedef struct usb_qualifier_descriptor { + UINT8 bLength; + UINT8 bDescriptorType; + + UINT16 bcdUSB; + UINT8 bDeviceClass; + UINT8 bDeviceSubClass; + UINT8 bDeviceProtocol; + UINT8 bMaxPacketSize0; + UINT8 bNumConfigurations; + UINT8 bRESERVED; +} usb_qualifier_descriptor_t; + +/* USB_DT_INTERFACE: Interface descriptor */ +typedef struct usb_interface_descriptor { + UINT8 bLength; + UINT8 bDescriptorType; + + UINT8 bInterfaceNumber; + UINT8 bAlternateSetting; + UINT8 bNumEndpoints; + UINT8 bInterfaceClass; + UINT8 bInterfaceSubClass; + UINT8 bInterfaceProtocol; + UINT8 iInterface; +} usb_interface_descriptor_t; + +/* USB_DT_ENDPOINT: Endpoint descriptor */ +typedef struct usb_endpoint_descriptor { + UINT8 bLength; + UINT8 bDescriptorType; + + UINT8 bEndpointAddress; + UINT8 bmAttributes; +#define USB_ENDPOINT_XFER_CONTROL 0x00 +#define USB_ENDPOINT_XFER_ISOC 0x01 +#define USB_ENDPOINT_XFER_BULK 0x02 +#define USB_ENDPOINT_XFER_INT 0x03 + UINT16 wMaxPacketSize; + UINT8 bInterval; +} usb_endpoint_descriptor_t; + +/* USB_DT_SS_ENDPOINT_COMP: SuperSpeed Endpoint Companion descriptor */ +typedef struct usb_ss_ep_comp_descriptor { + UINT8 bLength; + UINT8 bDescriptorType; + + UINT8 bMaxBurst; + UINT8 bmAttributes; + UINT16 wBytesPerInterval; +} usb_ss_ep_comp_descriptor_t; + +/* WUSB BOS Descriptor (Binary device Object Store) */ +typedef struct wusb_bos_desc { + UINT8 bLength; + UINT8 bDescriptorType; + UINT16 wTotalLength; + UINT8 bNumDeviceCaps; +} wusb_bos_desc_t; + +#define USB_DEVICE_CAPABILITY_20_EXTENSION 0x02 +typedef struct usb_dev_cap_20_ext_desc { + UINT8 bLength; + UINT8 bDescriptorType; + UINT8 bDevCapabilityType; +#define USB_20_EXT_LPM 0x02 + UINT32 bmAttributes; +} usb_dev_cap_20_ext_desc_t; + +#define USB_DEVICE_CAPABILITY_SS_USB 0x03 +typedef struct usb_dev_cap_ss_usb { + UINT8 bLength; + UINT8 bDescriptorType; + UINT8 bDevCapabilityType; +#define USB_DC_SS_USB_LTM_CAPABLE 0x02 + UINT8 bmAttributes; +#define USB_DC_SS_USB_SPEED_SUPPORT_LOW 0x01 +#define USB_DC_SS_USB_SPEED_SUPPORT_FULL 0x02 +#define USB_DC_SS_USB_SPEED_SUPPORT_HIGH 0x04 +#define USB_DC_SS_USB_SPEED_SUPPORT_SS 0x08 + UINT32 wSpeedsSupported; + UINT8 bFunctionalitySupport; + UINT8 bU1DevExitLat; + UINT32 wU2DevExitLat; +} usb_dev_cap_ss_usb_t; + +#define USB_DEVICE_CAPABILITY_CONTAINER_ID 0x04 +typedef struct usb_dev_cap_container_id { + UINT8 bLength; + UINT8 bDescriptorType; + UINT8 bDevCapabilityType; + UINT8 bReserved; + UINT8 containerID[16]; +} usb_dev_cap_container_id_t; +#pragma pack() + +typedef union usb_setup_pkt { + usb_device_request_t req; + UINT32 d32[2]; + UINT8 d8[8]; +} usb_setup_pkt_t; + +typedef struct usb3_pcd_ep { + struct usb3_pcd *pcd; + + UINT8 EpInIdx; + UINT8 EpOutIdx; + UINT8 phys; + + //UINT8 phys; + UINT8 num; + UINT8 type; + UINT8 maxburst; + UINT16 maxpacket; + /* Tx FIFO # for IN EPs */ + UINT8 tx_fifo_num; + + /* The Transfer Resource Index from the Start Transfer command */ + UINT8 tri_out; + UINT8 tri_in; + + UINT8 stopped; + /* Send ZLP */ + UINT8 send_zlp; + /* True if 3-stage control transfer */ + UINT8 three_stage; + /* True if transfer has been started on EP */ + UINT8 xfer_started; + /* EP direction 0 = OUT */ + UINT8 is_in; + /* True if endpoint is active */ + UINT8 active; + /* Initial data pid of bulk endpoint */ + UINT8 data_pid_start; + + /* ep_desc (excluding ep0) */ + usb3_dma_desc_t *ep_desc; + +#if 0 + /* TRB descriptor must be aligned to 16 bytes */ + UINT8 epx_desc[32]; +#endif + + /* request (excluding ep0) */ + usb3_pcd_req_t req; +} usb3_pcd_ep_t; + +typedef struct usb3_pcd { + //struct usb3_device *usb3_dev; + + INT32 link_state; + pcdstate_e state; + UINT8 new_config; + ep0state_e ep0state; + + UINT32 eps_enabled; + UINT32 ltm_enable; + + usb3_pcd_ep_t ep0; + usb3_pcd_ep_t out_ep; + usb3_pcd_ep_t in_ep; + + /* + usb3_dev_global_regs_t *dev_global_regs; + usb3_dev_ep_regs_t *out_ep_regs; + usb3_dev_ep_regs_t *in_ep_regs; + */ + + usb3_pcd_req_t ep0_req; + + UINT8 speed; + + usb3_dma_desc_t *ep0_setup_desc; + usb3_dma_desc_t *ep0_in_desc; + usb3_dma_desc_t *ep0_out_desc; + + /* TRB descriptor must be aligned to 16 bytes */ +#if 0 + UINT8 ep0_setup[32]; + UINT8 ep0_in[32]; + UINT8 ep0_out[32]; + + usb_setup_pkt_t ep0_setup_pkt[5]; + +#define USB3_STATUS_BUF_SIZE 512 + UINT8 ep0_status_buf[USB3_STATUS_BUF_SIZE]; + +#define USB3_BULK_BUF_SIZE 2048 + UINT8 ss_bulk_buf[USB3_BULK_BUF_SIZE]; +#endif + + UINT32 file_type; + UINT32 file_address; + UINT32 file_capacity; + UINT32 file_total_frame; + UINT32 file_curr_frame; + UINT32 file_next_frame; + UINT32 file_received; + UINT32 file_complete; + + UINT16 test_mode_nr; + UINT16 test_mode; +} usb3_pcd_t; + +struct usb_enum_port_param { + UINT16 idVendor; + UINT16 idProduct; + UINT8 bInterfaceSubClass; + UINT8 bInterfaceProtocol; +}; + +#if 0 +typedef struct usb3_pcd_req { + usb3_dma_desc_t *trb; + UINT64 trbdma; + + UINT32 length; + UINT32 actual; + + UINT64 *bufdma; + int (*complete)(unsigned actual, int status); +} usb3_pcd_req_t; + +#endif + +#endif /* __DW_USB3_DXE_H__ */ diff --git a/EmbeddedPkg/Drivers/DwUsb3Dxe/DwUsb3Dxe.c b/EmbeddedPkg/Drivers/DwUsb3Dxe/DwUsb3Dxe.c new file mode 100644 index 000000000000..83d5e4736de0 --- /dev/null +++ b/EmbeddedPkg/Drivers/DwUsb3Dxe/DwUsb3Dxe.c @@ -0,0 +1,2434 @@ +/** @file + + Copyright (c) 2018, Linaro Limited. All rights reserved. + + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License which accompanies this + distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "DwUsb3Dxe.h" + +#define FIFO_DIR_TX 0 +#define FIFO_DIR_RX 1 + +#define TX_FIFO_ADDR 0 +#define RX_FIFO_ADDR 0 + +#define RAM_WIDTH 8 +#define RAM_TX0_DEPTH 2048 +#define RAM_TX1_DEPTH 4096 +#define RAM_RX_DEPTH 8192 + +#define USB_TYPE_LENGTH 16 +#define USB_BLOCK_HIGH_SPEED_SIZE 512 +#define DATA_SIZE 131072 +#define CMD_SIZE 512 +#define MATCH_CMD_LITERAL(Cmd, Buf) !AsciiStrnCmp (Cmd, Buf, sizeof (Cmd) - 1) + +#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1)) + +// +// The time between interrupt polls, in units of 100 nanoseconds +// 10 Microseconds +// +#define DW_INTERRUPT_POLL_PERIOD 100 + +#define DWUSB3_EVENT_BUF_SIZE 256 + +// +// Maxpacket size for EP0, defined by USB3 spec +// +#define USB3_MAX_EP0_SIZE 512 + +// +// Maxpacket size for any EP, defined by USB3 spec +// +#define USB3_MAX_PACKET_SIZE 1024 +#define USB2_HS_MAX_PACKET_SIZE 512 +#define USB2_FS_MAX_PACKET_SIZE 64 + +#define USB3_STATE_UNCONNECTED 0 +#define USB3_STATE_DEFAULT 1 +#define USB3_STATE_ADDRESSED 2 +#define USB3_STATE_CONFIGURED 3 + +#define USB3_STATUS_BUF_SIZE 512 + +#define GET_EVENTBUF_COUNT() \ + (GEVNTCOUNT_EVNTCOUNT (MmioRead32 (GEVNTCOUNT (0)))) +#define UPDATE_EVENTBUF_COUNT(x) \ + (MmioWrite32 (GEVNTCOUNT (0), GEVNTCOUNT_EVNTCOUNT (x))) + +#define SET_DEVADDR(x) \ + (MmioAndThenOr32 (DCFG, ~DCFG_DEVADDR_MASK, DCFG_DEVADDR (x))) + +EFI_GUID gDwUsbProtocolGuid = DW_USB_PROTOCOL_GUID; + +STATIC DW_USB_PROTOCOL *DwUsb; + +STATIC usb3_pcd_t gPcd; +STATIC UINT32 *gEventBuf, *gEventPtr; +STATIC struct usb_device_descriptor gDwUsb3DevDesc; +STATIC VOID *gRxBuf; + +STATIC usb_setup_pkt_t *gEndPoint0SetupPacket; +STATIC UINT8 *gEndPoint0StatusBuf; +STATIC USB_DEVICE_RX_CALLBACK mDataReceivedCallback; +STATIC UINTN mDataBufferSize; + +struct usb_interface_descriptor intf = { + sizeof (struct usb_interface_descriptor), + UDESC_INTERFACE, + 0, + 0, + 2, + USB_CLASS_VENDOR_SPEC, + 0x42, + 0x03, + 0 +}; + +const struct usb_ss_ep_comp_descriptor ep_comp = { + sizeof (struct usb_ss_ep_comp_descriptor), + UDESC_SS_USB_COMPANION, + 0, + 0, + 0 +}; + +const struct usb_endpoint_descriptor hs_bulk_in = { + sizeof (struct usb_endpoint_descriptor), + UDESC_ENDPOINT, + UE_DIR_IN | USB3_BULK_IN_EP, + USB_ENDPOINT_XFER_BULK, + 0x200, + 0 +}; + +const struct usb_endpoint_descriptor +hs_bulk_out = { + sizeof(struct usb_endpoint_descriptor), /* bLength */ + UDESC_ENDPOINT, /* bDescriptorType */ + + UE_DIR_OUT | USB3_BULK_OUT_EP, /* bEndpointAddress */ + USB_ENDPOINT_XFER_BULK, /* bmAttributes */ + 0x200, /* wMaxPacketSize: 512 of high-speed */ + 1, /* bInterval */ +}; + +const struct usb_endpoint_descriptor ss_bulk_in = { + sizeof(struct usb_endpoint_descriptor), /* bLength */ + UDESC_ENDPOINT, /* bDescriptorType */ + + UE_DIR_IN | USB3_BULK_IN_EP, /* bEndpointAddress */ + USB_ENDPOINT_XFER_BULK, /* bmAttributes */ + 0x400, /* wMaxPacketSize: 1024 of super-speed */ + 0, /* bInterval */ +}; + +const struct usb_endpoint_descriptor ss_bulk_out = { + sizeof(struct usb_endpoint_descriptor), /* bLength */ + UDESC_ENDPOINT, /* bDescriptorType */ + + UE_DIR_OUT | USB3_BULK_OUT_EP, /* bEndpointAddress */ + USB_ENDPOINT_XFER_BULK, /* bmAttributes */ + 0x400, /* wMaxPacketSize: 1024 of super-speed */ + 0, /* bInterval */ +}; + +/** The BOS Descriptor */ + +const struct usb_dev_cap_20_ext_desc cap1 = { + sizeof(struct usb_dev_cap_20_ext_desc), /* bLength */ + UDESC_DEVICE_CAPABILITY, /* bDescriptorType */ + USB_DEVICE_CAPABILITY_20_EXTENSION, /* bDevCapabilityType */ + 0x2, /* bmAttributes */ +}; + +const struct usb_dev_cap_ss_usb +cap2 = { + sizeof(struct usb_dev_cap_ss_usb), /* bLength */ + UDESC_DEVICE_CAPABILITY, /* bDescriptorType */ + USB_DEVICE_CAPABILITY_SS_USB, /* bDevCapabilityType */ + 0x0, /* bmAttributes */ + (USB_DC_SS_USB_SPEED_SUPPORT_SS | + USB_DC_SS_USB_SPEED_SUPPORT_HIGH), /* wSpeedsSupported */ + 0x2, /* bFunctionalitySupport */ + 0xa, /* bU1DevExitLat */ + 0x100, /* wU2DevExitLat */ +}; + +const struct usb_dev_cap_container_id +cap3 = { + sizeof(struct usb_dev_cap_container_id),/* bLength */ + UDESC_DEVICE_CAPABILITY, /* bDescriptorType */ + USB_DEVICE_CAPABILITY_CONTAINER_ID, /* bDevCapabilityType */ + 0, /* bReserved */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* containerID */ +}; + +const struct wusb_bos_desc +bos = { + sizeof(struct wusb_bos_desc), /* bLength */ + UDESC_BOS, /* bDescriptorType */ + (sizeof(struct wusb_bos_desc) + \ + sizeof(cap1) + sizeof(cap2) + \ + sizeof(cap3)), /* wTotalLength */ + 3, /* bNumDeviceCaps */ +}; + +STATIC struct usb_enum_port_param usb_port_activity_config = { + .idVendor = USB_ENUM_ADB_PORT_VID, + .idProduct = USB_ENUM_ADB_PORT_PID, + .bInterfaceSubClass = USB_ENUM_INTERFACE_ADB_SUBCLASS, + .bInterfaceProtocol = USB_ENUM_INTERFACE_ADB_PROTOCOL +}; + +STATIC +UINT32 +DwUsb3GetEventBufEvent ( + IN UINTN Size + ) +{ + UINT32 Event; + + Event = *gEventPtr++; + if ((UINT32)(UINTN)gEventPtr >= (UINT32)(UINTN)gEventBuf + Size) { + gEventPtr = gEventBuf; + } + return Event; +} + +STATIC +VOID +DwUsb3SetFifoSize ( + IN UINT32 Addr, + IN UINT32 Depth, + IN UINT32 Dir, + IN UINT32 FifoNum + ) +{ + UINT32 Reg = 0; + + if (Dir == FIFO_DIR_TX) { + Reg = GTXFIFOSIZ (FifoNum); + } else if (Dir == FIFO_DIR_RX) { + Reg = GRXFIFOSIZ (FifoNum); + } else { + ASSERT (0); + } + MmioWrite32 (Reg, FIFOSIZ_DEP (Depth) | FIFOSIZ_ADDR (Addr)); +} + +STATIC +UINT32 +Handshake ( + IN UINT32 Reg, + IN UINT32 Mask, + IN UINT32 Done + ) +{ + UINT32 Timeout = 100000; + + do { + if ((MmioRead32 (Reg) & Mask) == Done) { + return 1; + } + MicroSecondDelay (1); + } while (Timeout-- > 0); + return 0; +} + +STATIC +VOID +DwUsb3FillDesc ( + IN usb3_dma_desc_t *desc, + IN UINT64 dma_addr, + IN UINT32 dma_len, + IN UINT32 stream, + IN UINT32 type, + IN UINT32 ctrlbits, + IN UINT32 own + ) +{ + desc->bptl = (UINT32)(dma_addr & 0xFFFFFFFF); + desc->bpth = (UINT32)(dma_addr >> 32); + desc->status = DSCSTS_XFERCNT (dma_len); + if (type) { + desc->control = DSCCTL_TRBCTL (type); + } + desc->control |= DSCCTL_STRMID_SOFN (stream) | ctrlbits; + ArmDataSynchronizationBarrier (); + /* must execute this operation at last */ + if (own) { + desc->control |= DSCCTL_HWO; + } + ArmDataSynchronizationBarrier (); +} + +STATIC +VOID +DwUsb3DepStartNewCfg ( + IN UINT32 EpIdx, + IN UINT32 RsrcIdx + ) +{ + /* start the command */ + MmioWrite32 ( + DEPCMD (EpIdx), + DEPCMD_XFER_RSRC_IDX (RsrcIdx) | DEPCMD_CMDTYPE (CMDTYPE_START_NEW_CFG) | \ + DEPCMD_CMDACT + ); + Handshake (DEPCMD (EpIdx), DEPCMD_CMDACT, 0); +} + +STATIC +VOID +DwUsb3DepCfg ( + IN UINT32 EpIdx, + IN UINT32 DepCfg0, + IN UINT32 DepCfg1, + IN UINT32 DepCfg2 + ) +{ + MmioWrite32 (DEPCMDPAR2 (EpIdx), DepCfg2); + MmioWrite32 (DEPCMDPAR1 (EpIdx), DepCfg1); + MmioWrite32 (DEPCMDPAR0 (EpIdx), DepCfg0); + MmioWrite32 ( + DEPCMD (EpIdx), + DEPCMD_CMDTYPE (CMDTYPE_SET_EP_CFG) | DEPCMD_CMDACT + ); + Handshake (DEPCMD (EpIdx), DEPCMD_CMDACT, 0); +} + +STATIC +VOID +DwUsb3DepXferCfg ( + IN UINT32 EpIdx, + IN UINT32 DepStrmCfg + ) +{ + MmioWrite32 (DEPCMDPAR0 (EpIdx), DepStrmCfg); + MmioWrite32 ( + DEPCMD (EpIdx), + DEPCMD_CMDTYPE (CMDTYPE_SET_XFER_CFG) | DEPCMD_CMDACT + ); + Handshake (DEPCMD (EpIdx), DEPCMD_CMDACT, 0); +} + +STATIC +UINT8 +DwUsb3DepStartXfer ( + IN UINT32 EpIdx, + IN UINT64 DmaAddr, + IN UINT32 StreamOrUf + ) +{ + UINT32 Data; + + MmioWrite32 (DEPCMDPAR1 (EpIdx), (UINT32)DmaAddr); + MmioWrite32 (DEPCMDPAR0 (EpIdx), (UINT32)(DmaAddr >> 32)); + MmioWrite32 ( + DEPCMD (EpIdx), + DEPCMD_STR_NUM_OR_UF (StreamOrUf) | DEPCMD_CMDTYPE (CMDTYPE_START_XFER) | \ + DEPCMD_CMDACT + ); + Handshake (DEPCMD (EpIdx), DEPCMD_CMDACT, 0); + Data = MmioRead32 (DEPCMD (EpIdx)); + return GET_DEPCMD_XFER_RSRC_IDX(Data); +} + +STATIC +VOID +DwUsb3DepStopXfer ( + IN UINT32 EpIdx, + IN UINT32 Tri + ) +{ + MmioWrite32 (DEPCMDPAR2 (EpIdx), 0); + MmioWrite32 (DEPCMDPAR1 (EpIdx), 0); + MmioWrite32 (DEPCMDPAR0 (EpIdx), 0); + MmioWrite32 ( + DEPCMD (EpIdx), + DEPCMD_XFER_RSRC_IDX (Tri) | DEPCMD_CMDTYPE (CMDTYPE_END_XFER) | \ + DEPCMD_CMDACT + ); + Handshake (DEPCMD (EpIdx), DEPCMD_CMDACT, 0); +} + +VOID +DwUsb3DepUpdateXfer ( + IN UINT32 EpIdx, + IN UINT32 Tri + ) +{ + MmioWrite32 ( + DEPCMD (EpIdx), + DEPCMD_XFER_RSRC_IDX (Tri) | DEPCMD_CMDTYPE (CMDTYPE_UPDATE_XFER) | \ + DEPCMD_CMDACT + ); + Handshake (DEPCMD (EpIdx), DEPCMD_CMDACT, 0); +} + +STATIC +VOID +DwUsb3DepClearStall ( + IN UINTN EpIdx + ) +{ + MmioWrite32 ( + DEPCMD (EpIdx), + DEPCMD_CMDTYPE (CMDTYPE_CLR_STALL) | DEPCMD_CMDACT + ); + Handshake (DEPCMD (EpIdx), DEPCMD_CMDACT, 0); +} + + +STATIC +VOID +DwUsb3DepSetStall ( + IN UINTN EpIdx + ) +{ + MmioWrite32 ( + DEPCMD (EpIdx), + DEPCMD_CMDTYPE (CMDTYPE_SET_STALL) | DEPCMD_CMDACT + ); + Handshake (DEPCMD (EpIdx), DEPCMD_CMDACT, 0); +} + +STATIC +VOID +DwUsb3EnableEp ( + IN UINT32 EpIdx, + IN usb3_pcd_ep_t *ep + ) +{ + UINT32 Dalepena; + + Dalepena = MmioRead32 (DALEPENA); + /* If the EP is already enabled, skip to set it again. */ + if (Dalepena & (1 << EpIdx)) { + return; + } + Dalepena |= 1 << EpIdx; + MmioWrite32 (DALEPENA, Dalepena); +} + +STATIC +VOID +DwUsb3Ep0Activate ( + IN OUT usb3_pcd_t *pcd + ) +{ + /* issue DEPCFG command to EP0 OUT */ + DwUsb3DepStartNewCfg (EP_OUT_IDX (0), 0); + DwUsb3DepCfg ( + EP_OUT_IDX (0), + EPCFG0_EPTYPE (EPTYPE_CONTROL) | EPCFG0_MPS (512), + EPCFG1_XFER_CMPL | EPCFG1_XFER_NRDY, + 0 + ); + /* issue DEPSTRMCFG command to EP0 OUT */ + DwUsb3DepXferCfg (EP_OUT_IDX (0), 1); // one stream + /* issue DEPCFG command to EP0 IN */ + DwUsb3DepCfg ( + EP_IN_IDX (0), + EPCFG0_EPTYPE (EPTYPE_CONTROL) | EPCFG0_MPS (512) | \ + EPCFG0_TXFNUM (pcd->ep0.tx_fifo_num), + EPCFG1_XFER_NRDY | EPCFG1_XFER_CMPL | EPCFG1_EP_DIR_IN, + 0 + ); + /* issue DEPSTRMCFG command to EP0 IN */ + DwUsb3DepXferCfg (EP_IN_IDX (0), 1); // one stream + pcd->ep0.active = 1; +} + +STATIC +VOID +DwUsb3EpActivate ( + IN OUT usb3_pcd_t *pcd, + IN OUT usb3_pcd_ep_t *ep + ) +{ + UINT32 EpIdx, DepCfg0, DepCfg1; + if (ep->is_in) { + EpIdx = EP_IN_IDX (ep->num); + } else { + EpIdx = EP_OUT_IDX (ep->num); + } + + /* Start a new configurate when enable the first EP. */ + if (!pcd->eps_enabled) { + pcd->eps_enabled = 1; + /* Issue DEPCFG command to physical EP1 (logical EP0 IN) first. + * It resets the core's Tx FIFO mapping table. + */ + DepCfg0 = EPCFG0_EPTYPE (EPTYPE_CONTROL); + DepCfg0 |= EPCFG0_CFG_ACTION (CFG_ACTION_MODIFY); + DepCfg1 = EPCFG1_XFER_CMPL | EPCFG1_XFER_NRDY | EPCFG1_EP_DIR_IN; + + switch (pcd->speed) { + case USB_SPEED_SUPER: + DepCfg0 |= EPCFG0_MPS (512); + break; + case USB_SPEED_HIGH: + case USB_SPEED_FULL: + DepCfg0 |= EPCFG0_MPS (64); + break; + case USB_SPEED_LOW: + DepCfg0 |= EPCFG0_MPS (8); + break; + default: + ASSERT (0); + break; + } + DwUsb3DepCfg (EP_IN_IDX (0), DepCfg0, DepCfg1, 0); + DwUsb3DepStartNewCfg (EP_OUT_IDX (0), 2); + } + /* issue DEPCFG command to EP */ + DepCfg0 = EPCFG0_EPTYPE (ep->type); + DepCfg0 |= EPCFG0_MPS (ep->maxpacket); + if (ep->is_in) { + DepCfg0 |= EPCFG0_TXFNUM (ep->tx_fifo_num); + } + DepCfg0 |= EPCFG0_BRSTSIZ (ep->maxburst); + DepCfg1 = EPCFG1_EP_NUM (ep->num); + if (ep->is_in) { + DepCfg1 |= EPCFG1_EP_DIR_IN; + } else { + DepCfg1 |= EPCFG1_XFER_CMPL; + } + DwUsb3DepCfg (EpIdx, DepCfg0, DepCfg1, 0); + /* issue DEPSTRMCFG command to EP */ + DwUsb3DepXferCfg (EpIdx, 1); + DwUsb3EnableEp (EpIdx, ep); + ep->active = 1; +} + +STATIC +VOID +DwUsb3Ep0OutStart ( + IN usb3_pcd_t *pcd + ) +{ + usb3_dma_desc_t *desc; + + /* Get the SETUP packet DMA Descriptor (TRB) */ + desc = pcd->ep0_setup_desc; + + /* DMA Descriptor setup */ + DwUsb3FillDesc ( + desc, + (UINT64)gEndPoint0SetupPacket, + pcd->ep0.maxpacket, + 0, + TRBCTL_SETUP, + DSCCTL_IOC | DSCCTL_ISP | DSCCTL_LST, + 1 + ); + + /* issue DEPSTRTXFER command to EP0 OUT */ + pcd->ep0.tri_out = DwUsb3DepStartXfer (EP_OUT_IDX (0), (UINT64)desc, 0); +} + +STATIC +VOID +DwUsb3Init ( + VOID + ) +{ + UINT32 Data, Addr; + usb3_pcd_t *pcd = &gPcd; + + /* soft reset the usb core */ + do { + MmioAndThenOr32 (DCTL, ~DCTL_RUN_STOP, DCTL_CSFTRST); + + do { + MicroSecondDelay (1000); + Data = MmioRead32 (DCTL); + } while (Data & DCTL_CSFTRST); + // + // wait for at least 3 PHY clocks + // + MicroSecondDelay (1000); + } while (0); + + pcd->link_state = 0; + + /* TI PHY: Set Turnaround Time = 9 (8-bit UTMI+ / ULPI) */ + MmioAndThenOr32 ( + GUSB2PHYCFG (0), + ~GUSB2PHYCFG_USBTRDTIM_MASK, + GUSB2PHYCFG_USBTRDTIM (9) + ); + + /* set TX FIFO size */ + Addr = TX_FIFO_ADDR; + DwUsb3SetFifoSize (Addr, RAM_TX0_DEPTH / RAM_WIDTH, FIFO_DIR_TX, 0); + Addr += RAM_TX0_DEPTH / RAM_WIDTH; + DwUsb3SetFifoSize (Addr, RAM_TX1_DEPTH / RAM_WIDTH, FIFO_DIR_TX, 1); + /* set RX FIFO size */ + DwUsb3SetFifoSize (RX_FIFO_ADDR, RAM_RX_DEPTH / RAM_WIDTH, FIFO_DIR_RX, 0); + + /* set LFPS filter delay1trans */ + MmioAndThenOr32 ( + GUSB3PIPECTL (0), + ~PIPECTL_DELAYP1TRANS, + PIPECTL_LFPS_FILTER | PIPECTL_TX_DEMPH (1) + ); + + /* set GCTL */ + Data = GCTL_U2EXIT_LFPS | GCTL_PRTCAPDIR_DEVICE | GCTL_U2RSTECN | + GCTL_PWRDNSCALE(2); + MmioWrite32 (GCTL, Data); + + /* init event buf */ + MmioWrite32 (GEVNTADRL(0), (UINT32)(UINTN)gEventBuf); + MmioWrite32 (GEVNTADRH(0), (UINTN)gEventBuf >> 32); + MmioWrite32 (GEVNTSIZ(0), DWUSB3_EVENT_BUF_SIZE << 2); + MmioWrite32 (GEVNTCOUNT(0), 0); + + /* set max speed to super speed */ + MmioAndThenOr32 ( + DCFG, + ~DCFG_DEVSPD_MASK, + DCFG_DEVSPD (DEVSPD_SS_PHY_125MHZ_OR_250MHZ) + ); + + /* set nump */ + MmioAndThenOr32 (DCFG, ~DCFG_NUMP_MASK, DCFG_NUMP (16)); + + /* init address */ + SET_DEVADDR (0); + + /* disable phy suspend */ + MmioAnd32 (GUSB3PIPECTL (0), ~PIPECTL_SUSPEND_EN); + MmioAnd32 (GUSB2PHYCFG (0), ~GUSB2PHYCFG_SUSPHY); + + /* clear any pending interrupts */ + Data = MmioRead32 (GEVNTCOUNT (0)); + MmioWrite32 (GEVNTCOUNT (0), Data); + /* enable device interrupts */ + MmioWrite32 (DEVTEN, DEVTEN_CONNECTDONEEN | DEVTEN_USBRSTEN); + /* activate EP0 */ + DwUsb3Ep0Activate (pcd); + /* start EP0 to receive SETUP packets */ + DwUsb3Ep0OutStart (pcd); + + /* enable EP0 OUT/IN in DALEPENA */ + MmioWrite32 (DALEPENA, (1 << EP_OUT_IDX (0)) | (1 << EP_IN_IDX (0))); + + /* set RUN/STOP bit */ + MmioOr32 (DCTL, DCTL_RUN_STOP); +} + +STATIC +VOID +DriverInit ( + VOID + ) +{ + usb3_pcd_t *pcd = &gPcd; + usb3_pcd_ep_t *ep; + EFI_STATUS Status; + + pcd->speed = USB_SPEED_UNKNOWN; + + // + // init EP0 + // + ep = &pcd->ep0; + ep->pcd = pcd; + ep->stopped = 1; + ep->is_in = 0; + ep->active = 0; + ep->phys = 0; + ep->num = 0; + ep->tx_fifo_num = 0; + ep->type = EPTYPE_CONTROL; + ep->maxburst = 0; + ep->maxpacket = USB3_MAX_EP0_SIZE; + ep->send_zlp = 0; + ep->req.length = 0; + ep->req.actual = 0; + pcd->ep0_req.length = 0; + pcd->ep0_req.actual = 0; + + // + // init EP1 OUT + // + ep = &pcd->out_ep; + ep->pcd = pcd; + ep->stopped = 1; + ep->is_in = 0; + ep->active = 0; + ep->phys = USB3_BULK_OUT_EP << 1; + ep->num = 1; + ep->tx_fifo_num = 0; + // + // bulk ep is activated + // + ep->type = EPTYPE_BULK; + ep->maxburst = 0; + ep->maxpacket = USB3_MAX_PACKET_SIZE; + ep->send_zlp = 0; + ep->req.length = 0; + ep->req.actual = 0; + + // + // init EP1 IN + // + ep = &pcd->in_ep; + ep->stopped = 1; + ep->is_in = 1; + ep->active = 0; + ep->phys = (USB3_BULK_IN_EP << 1) | 1; + ep->num = 1; + ep->tx_fifo_num = USB3_BULK_IN_EP; + // + // bulk ep is activated + // + ep->type = EPTYPE_BULK; + ep->maxburst = 0; + ep->maxpacket = USB3_MAX_PACKET_SIZE; + ep->send_zlp = 0; + ep->req.length = 0; + ep->req.actual = 0; + + pcd->ep0state = EP0_IDLE; + pcd->ep0.maxpacket = USB3_MAX_EP0_SIZE; + pcd->ep0.type = EPTYPE_CONTROL; + + Status = DmaAllocateBuffer ( + EfiBootServicesData, + EFI_SIZE_TO_PAGES (sizeof (usb3_dma_desc_t) * 5), + (VOID *)&pcd->ep0_setup_desc + ); + if (EFI_ERROR (Status)) { + return; + } + pcd->ep0_in_desc = pcd->ep0_setup_desc++; + pcd->ep0_out_desc = pcd->ep0_in_desc++; + pcd->in_ep.ep_desc = pcd->ep0_out_desc++; + pcd->out_ep.ep_desc = pcd->in_ep.ep_desc++; +} + +STATIC +VOID +DwUsb3HandleUsbResetInterrupt ( + IN usb3_pcd_t *pcd + ) +{ + usb3_pcd_ep_t *ep; + + // + // clear stall on each EP + // + ep = &pcd->in_ep; + if (ep->xfer_started) { + if (ep->is_in) { + DwUsb3DepStopXfer (EP_IN_IDX (ep->num), ep->tri_in); + } else { + DwUsb3DepStopXfer (EP_OUT_IDX (ep->num), ep->tri_out); + } + } + if (ep->stopped) { + if (ep->is_in) { + DwUsb3DepClearStall (EP_IN_IDX (ep->num)); + } else { + DwUsb3DepClearStall (EP_OUT_IDX (ep->num)); + } + } + + ep = &pcd->out_ep; + if (ep->xfer_started) { + if (ep->is_in) { + DwUsb3DepStopXfer (EP_IN_IDX (ep->num), ep->tri_in); + } else { + DwUsb3DepStopXfer (EP_OUT_IDX (ep->num), ep->tri_out); + } + } + if (ep->stopped) { + if (ep->is_in) { + DwUsb3DepClearStall (EP_IN_IDX (ep->num)); + } else { + DwUsb3DepClearStall (EP_OUT_IDX (ep->num)); + } + } + + // + // set device address to 0 + // + SET_DEVADDR (0); + + pcd->ltm_enable = 0; + DEBUG ((DEBUG_INFO, "usb reset\n")); +} + +STATIC +UINT32 +DwUsb3GetDeviceSpeed ( + IN usb3_pcd_t *pcd + ) +{ + UINT32 Data, Speed; + + Data = MmioRead32 (DSTS); + switch (DSTS_GET_DEVSPD (Data)) { + case DEVSPD_HS_PHY_30MHZ_OR_60MHZ: + Speed = USB_SPEED_HIGH; + break; + case DEVSPD_FS_PHY_30MHZ_OR_60MHZ: + case DEVSPD_FS_PHY_48MHZ: + Speed = USB_SPEED_FULL; + break; + case DEVSPD_LS_PHY_6MHZ: + Speed = USB_SPEED_LOW; + break; + case DEVSPD_SS_PHY_125MHZ_OR_250MHZ: + Speed = USB_SPEED_SUPER; + break; + default: + DEBUG ((DEBUG_ERROR, "DwUsb3GetDeviceSpeed: invalid DSTS:0x%x\n", Data)); + Speed = USB_SPEED_UNKNOWN; + break; + } + return Speed; +} + +STATIC +VOID +DwUsb3PcdSetSpeed ( + IN usb3_pcd_t *pcd, + IN UINTN speed + ) +{ + // + // set the MPS of EP0 based on the connection speed + // + switch (speed) { + case USB_SPEED_SUPER: + pcd->ep0.maxpacket = 512; + pcd->in_ep.maxpacket = USB3_MAX_PACKET_SIZE; + pcd->out_ep.maxpacket = USB3_MAX_PACKET_SIZE; + break; + case USB_SPEED_HIGH: + pcd->ep0.maxpacket = 64; + pcd->in_ep.maxpacket = USB2_HS_MAX_PACKET_SIZE; + pcd->out_ep.maxpacket = USB2_HS_MAX_PACKET_SIZE; + break; + case USB_SPEED_FULL: + pcd->ep0.maxpacket = 64; + pcd->in_ep.maxpacket = USB2_FS_MAX_PACKET_SIZE; + pcd->out_ep.maxpacket = USB2_FS_MAX_PACKET_SIZE; + break; + default: + DEBUG ((DEBUG_ERROR, "invalid speed: %d\n", speed)); + break; + } +} + +STATIC +VOID +DwUsb3HandleConnectDoneInterrupt ( + IN usb3_pcd_t *pcd + ) +{ + usb3_pcd_ep_t *ep0 = &pcd->ep0; + UINT32 DiepCfg0, DoepCfg0, DiepCfg1, DoepCfg1; + UINT32 Speed; + + ep0->stopped = 0; + Speed = (UINT32)DwUsb3GetDeviceSpeed (pcd); + pcd->speed = (UINT8)Speed; + + DwUsb3PcdSetSpeed (pcd, Speed); + // + // set the MPS of EP0 based on the connection speed + // + DiepCfg0 = EPCFG0_EPTYPE (EPTYPE_CONTROL) | \ + EPCFG0_CFG_ACTION (CFG_ACTION_MODIFY); + DiepCfg1 = EPCFG1_XFER_CMPL | EPCFG1_XFER_NRDY | \ + EPCFG1_EP_DIR_IN; + DoepCfg0 = EPCFG0_EPTYPE (EPTYPE_CONTROL) | \ + EPCFG0_CFG_ACTION (CFG_ACTION_MODIFY); + DoepCfg1 = EPCFG1_XFER_CMPL | EPCFG1_XFER_NRDY; + + switch (Speed) { + case USB_SPEED_SUPER: + DiepCfg0 |= EPCFG0_MPS (512); + DoepCfg0 |= EPCFG0_MPS (512); + break; + case USB_SPEED_HIGH: + case USB_SPEED_FULL: + DiepCfg0 |= EPCFG0_MPS (64); + DoepCfg0 |= EPCFG0_MPS (64); + break; + case USB_SPEED_LOW: + DiepCfg0 |= EPCFG0_MPS (8); + DoepCfg0 |= EPCFG0_MPS (8); + break; + default: + DEBUG (( + DEBUG_ERROR, + "DwUsb3HandleConnectDoneInterrupt: invalid speed %d\n", + Speed + )); + break; + } + DiepCfg0 |= EPCFG0_TXFNUM (ep0->tx_fifo_num); + // + // issue DEPCFG command to EP0 OUT + // + DwUsb3DepCfg (EP_OUT_IDX (0), DoepCfg0, DoepCfg1, 0); + // + // issue DEPCFG command to EP0 IN + // + DwUsb3DepCfg (EP_IN_IDX (0), DiepCfg0, DiepCfg1, 0); + pcd->state = USB3_STATE_DEFAULT; +} + +STATIC +VOID +DwUsb3HandleDeviceInterrupt ( + IN usb3_pcd_t *pcd, + IN UINT32 Event + ) +{ + switch (Event & GEVNT_DEVT_MASK) { + case GEVNT_DEVT_USBRESET: + DwUsb3HandleUsbResetInterrupt (pcd); + break; + case GEVNT_DEVT_CONNDONE: + DwUsb3HandleConnectDoneInterrupt (pcd); + break; + default: + DEBUG ((DEBUG_ERROR, "DwUsb3HandleDeviceInterrupt: invalid event\n")); + break; + } +} + +STATIC +usb3_pcd_ep_t * +DwUsb3GetOutEndPoint ( + IN usb3_pcd_t *pcd, + IN UINT32 EndPointNum + ) +{ + if (EndPointNum == 0) { + return &pcd->ep0; + } + return &pcd->out_ep; +} + +STATIC +usb3_pcd_ep_t * +DwUsb3GetInEndPoint ( + IN usb3_pcd_t *pcd, + IN UINT32 EndPointNum + ) +{ + if (EndPointNum == 0) { + return &pcd->ep0; + } + return &pcd->in_ep; +} + +STATIC +VOID +EndPoint0DoStall ( + IN usb3_pcd_t *pcd + ) +{ + usb3_pcd_ep_t *ep0 = &pcd->ep0; + + // + // stall EP0 IN & OUT simultanelusly + // + ep0->is_in = 1; + DwUsb3DepSetStall (EP_IN_IDX (0)); + ep0->is_in = 0; + DwUsb3DepSetStall (EP_OUT_IDX (0)); + // + // prepare for the next setup transfer + // + ep0->stopped = 1; + pcd->ep0state = EP0_IDLE; + DwUsb3Ep0OutStart (pcd); +} + +STATIC +VOID +EndPoint0ContinueTransfer ( + IN usb3_pcd_t *pcd, + IN usb3_pcd_req_t *req + ) +{ + usb3_pcd_ep_t *ep0 = &pcd->ep0; + usb3_dma_desc_t *desc; + UINT64 desc_dma; + UINT8 tri; + + // + // send a 0-byte length packet after the end of transfer + // + if (ep0->is_in) { + desc = pcd->ep0_in_desc; + desc_dma = (UINT64)pcd->ep0_in_desc; + // + // DMA descriptor setup + // + DwUsb3FillDesc ( + desc, + (UINT64)req->bufdma, + 0, + 0, + TRBCTL_NORMAL, + DSCCTL_IOC | DSCCTL_ISP | DSCCTL_LST, + 1 + ); + tri = DwUsb3DepStartXfer (EP_IN_IDX (0), desc_dma, 0); + ep0->tri_in = tri; + } +} + +STATIC +VOID +EndPoint0CompleteRequest ( + IN usb3_pcd_t *pcd, + IN usb3_pcd_req_t *req, + IN usb3_dma_desc_t *desc + ) +{ + usb3_pcd_ep_t *ep = &pcd->ep0; + + if (req == NULL) { + return; + } + + if ((pcd->ep0state == EP0_OUT_DATA_PHASE) || + (pcd->ep0state == EP0_IN_DATA_PHASE)) { + if (ep->is_in) { + if (GET_DSCSTS_XFERCNT (desc->status) == 0) { + pcd->ep0.is_in = 0; + pcd->ep0state = EP0_OUT_WAIT_NRDY; + } + } else { + pcd->ep0.is_in = 1; + pcd->ep0state = EP0_IN_WAIT_NRDY; + } + } +} + +STATIC +VOID +DwUsb3OsGetTrb ( + IN usb3_pcd_t *pcd, + IN usb3_pcd_ep_t *ep, + IN usb3_pcd_req_t *req + ) +{ + // + // If EP0, fill request with EP0 IN/OUT data TRB + // + if (ep == &pcd->ep0) { + if (ep->is_in) { + req->trb = pcd->ep0_in_desc; + req->trbdma = (UINT64)pcd->ep0_in_desc; + } else { + req->trb = pcd->ep0_out_desc; + req->trbdma = (UINT64)pcd->ep0_out_desc; + } + } else { + // + // fill request with TRB from the non-EP0 allocation + // + req->trb = ep->ep_desc; + req->trbdma = (UINT64)ep->ep_desc; + } +} + +STATIC +VOID +DwUsb3EndPoint0StartTransfer ( + IN usb3_pcd_t *pcd, + IN usb3_pcd_req_t *req + ) +{ + usb3_pcd_ep_t *ep0 = &pcd->ep0; + usb3_dma_desc_t *desc; + UINT64 desc_dma; + UINT32 desc_type, len; + + // + // get the DMA descriptor (TRB) for this request + // + DwUsb3OsGetTrb (pcd, ep0, req); + desc = req->trb; + desc_dma = req->trbdma; + + if (ep0->is_in) { + // + // start DMA on EP0 IN + // DMA Descriptor (TRB) setup + // + len = req->length; + if (pcd->ep0state == EP0_IN_STATUS_PHASE) { + if (ep0->three_stage) { + desc_type = TRBCTL_STATUS_3; + } else { + desc_type = TRBCTL_STATUS_2; + } + } else { + desc_type = TRBCTL_CTLDATA_1ST; + } + DwUsb3FillDesc ( + desc, + (UINT64)req->bufdma, + len, + 0, + desc_type, + DSCCTL_IOC | DSCCTL_ISP | DSCCTL_LST, + 1 + ); + // + // issue DEPSTRTXFER command to EP0 IN + // + ep0->tri_in = DwUsb3DepStartXfer (EP_IN_IDX (0), desc_dma, 0); + } else { + // + // start DMA on EP0 OUT + // DMA Descriptor (TRB) setup + // + len = ALIGN (req->length, ep0->maxpacket); + if (pcd->ep0state == EP0_OUT_STATUS_PHASE) { + if (ep0->three_stage) { + desc_type = TRBCTL_STATUS_3; + } else { + desc_type = TRBCTL_STATUS_2; + } + } else { + desc_type = TRBCTL_CTLDATA_1ST; + } + DwUsb3FillDesc ( + desc, + (UINT64)req->bufdma, + len, + 0, + desc_type, + DSCCTL_IOC | DSCCTL_ISP | DSCCTL_LST, + 1 + ); + // + // issue DEPSTRTXFER command to EP0 OUT + // + ep0->tri_out = DwUsb3DepStartXfer (EP_OUT_IDX (0), desc_dma, 0); + } +} + +STATIC +INTN +DwUsb3EndPointXStartTransfer ( + IN usb3_pcd_t *pcd, + IN usb3_pcd_ep_t *ep + ) +{ + usb3_pcd_req_t *req = &ep->req; + usb3_dma_desc_t *desc; + UINT64 desc_dma; + UINT32 len; + + // + // get the TRB for this request + // + DwUsb3OsGetTrb (pcd, ep, req); + desc = req->trb; + desc_dma = req->trbdma; + + if (ep->is_in) { + // + // For IN, TRB length is just xfer length + // + len = req->length; + if (ep->xfer_started && !(desc->control & DSCCTL_HWO)) { + DEBUG ((DEBUG_INFO, "[%a] last tx succ, but not in 10s!\n", __func__)); + ep->xfer_started = 0; + } + } else { + // + // For OUT, TRB length must be multiple of maxpacket + // must be power of 2, use cheap AND + // + len = (req->length + ep->maxpacket - 1) & ~(ep->maxpacket - 1); + req->length = len; + } + // + // DMA descriptor setup + // + DwUsb3FillDesc ( + desc, + (UINT64)req->bufdma, + len, + 0, + TRBCTL_NORMAL, + DSCCTL_IOC | DSCCTL_ISP | DSCCTL_LST, + 1 + ); + if (ep->is_in) { + // + // start DMA on EPn IN + // + if (ep->xfer_started) { + // + // issue DEPUPDTXFER command to EP + // + DwUsb3DepUpdateXfer (EP_IN_IDX (ep->num), ep->tri_in); + } else { + ep->tri_in = DwUsb3DepStartXfer (EP_IN_IDX (ep->num), desc_dma, 0); + ep->xfer_started = 1; + } + } else { + // + // start DMA on EPn OUT + // + if (ep->xfer_started) { + // + // issue DEPUPDTXFER command to EP + // + DwUsb3DepUpdateXfer (EP_OUT_IDX (ep->num), ep->tri_out); + } else { + ep->tri_out = DwUsb3DepStartXfer (EP_OUT_IDX (ep->num), desc_dma, 0); + ep->xfer_started = 1; + } + } + if (ep->is_in) { + UINT32 count = 0; + // + // wait until send complete + // + while ((desc->control & DSCCTL_HWO) && (count < 1000000)) { + MicroSecondDelay (10); + count++; + } + if (count >= 1000000) { + DEBUG ((DEBUG_INFO, "[%a]: ep%d transfer timeout!\n", __func__, ep->num)); + DEBUG (( + DEBUG_INFO, + "please disconnect then connect USB cable again to recovery!\n" + )); + return -1; + } + ep->xfer_started = 0; + } + return 0; +} + +STATIC +VOID +SetupInStatusPhase ( + IN usb3_pcd_t *pcd, + IN VOID *buf + ) +{ + usb3_pcd_ep_t *ep0 = &pcd->ep0; + + if (pcd->ep0state == EP0_STALL) + return; + + ep0->is_in = 1; + pcd->ep0state = EP0_IN_STATUS_PHASE; + pcd->ep0_req.bufdma = buf; + pcd->ep0_req.length = 0; + pcd->ep0_req.actual = 0; + DwUsb3EndPoint0StartTransfer (pcd, &pcd->ep0_req); +} + +STATIC +VOID +SetupOutStatusPhase ( + IN usb3_pcd_t *pcd, + IN VOID *buf + ) +{ + usb3_pcd_ep_t *ep0 = &pcd->ep0; + + if (pcd->ep0state == EP0_STALL) + return; + + ep0->is_in = 0; + pcd->ep0state = EP0_OUT_STATUS_PHASE; + pcd->ep0_req.bufdma = buf; + pcd->ep0_req.length = 0; + pcd->ep0_req.actual = 0; + DwUsb3EndPoint0StartTransfer (pcd, &pcd->ep0_req); +} + +STATIC +VOID +DwUsb3HandleEndPoint0 ( + IN usb3_pcd_t *pcd, + IN usb3_pcd_req_t *req, + IN UINT32 event + ) +{ + usb3_pcd_ep_t *ep0 = &pcd->ep0; + usb3_dma_desc_t *desc = NULL; + UINT32 byte_count, len; + + switch (pcd->ep0state) { + case EP0_IN_DATA_PHASE: + if (req == NULL) { + req = &pcd->ep0_req; + } + desc = pcd->ep0_in_desc; + + if (desc->control & DSCCTL_HWO) { + goto out; + } + + if (GET_DSCSTS_TRBRSP (desc->status) == TRBRSP_SETUP_PEND) { + // + // start of a new control transfer + // + desc->status = 0; + } + byte_count = req->length - GET_DSCSTS_XFERCNT (desc->status); + req->actual += byte_count; + req->bufdma += byte_count; + + if (req->actual < req->length) { + // + // IN CONTINUE, stall EP0 + // + EndPoint0DoStall (pcd); + } else if (ep0->send_zlp) { + // + // CONTINUE TRANSFER IN ZLP + // + EndPoint0ContinueTransfer (pcd, req); + ep0->send_zlp = 0; + } else { + // + // COMPLETE IN TRANSFER + // + EndPoint0CompleteRequest (pcd, req, desc); + } + break; + case EP0_OUT_DATA_PHASE: + if (req == NULL) { + req = &pcd->ep0_req; + } + desc = pcd->ep0_out_desc; + + if (desc->control & DSCCTL_HWO) { + goto out; + } + + if (GET_DSCSTS_TRBRSP (desc->status) == TRBRSP_SETUP_PEND) { + // + // start of a new control transfer + // + desc->status = 0; + } + len = (req->length + ep0->maxpacket - 1) & ~(ep0->maxpacket - 1); + byte_count = len - GET_DSCSTS_XFERCNT (desc->status); + req->actual += byte_count; + req->bufdma += byte_count; + + if (req->actual < req->length) { + // + // IN CONTINUE, stall EP0 + // + EndPoint0DoStall (pcd); + } else if (ep0->send_zlp) { + // + // CONTINUE TRANSFER IN ZLP + // + EndPoint0ContinueTransfer (pcd, req); + ep0->send_zlp = 0; + } else { + // + // COMPLETE IN TRANSFER + // + EndPoint0CompleteRequest (pcd, req, desc); + } + break; + case EP0_IN_WAIT_NRDY: + if (ep0->is_in) { + SetupInStatusPhase (pcd, gEndPoint0SetupPacket); + } else { + ASSERT (0); + } + break; + case EP0_OUT_WAIT_NRDY: + if (!ep0->is_in) { + SetupOutStatusPhase (pcd, gEndPoint0SetupPacket); + } else { + ASSERT (0); + } + break; + case EP0_IN_STATUS_PHASE: + if (ep0->is_in) { + desc = pcd->ep0_in_desc; + } else { + ASSERT (0); + } + EndPoint0CompleteRequest (pcd, req, desc); + pcd->ep0state = EP0_IDLE; + ep0->stopped = 1; + ep0->is_in = 0; // OUT for next SETUP + // + // prepare for more SETUP packets + // + DwUsb3Ep0OutStart (pcd); + break; + case EP0_OUT_STATUS_PHASE: + if (!ep0->is_in) { + desc = pcd->ep0_out_desc; + } else { + ASSERT (0); + } + EndPoint0CompleteRequest (pcd, req, desc); + pcd->ep0state = EP0_IDLE; + ep0->stopped = 1; + ep0->is_in = 0; // OUT for next SETUP + // + // prepare for more SETUP packets + // + DwUsb3Ep0OutStart (pcd); + break; + case EP0_STALL: + break; + case EP0_IDLE: + break; + default: + DEBUG ((DEBUG_ERROR, "%a: invalid state %d\n", __func__, pcd->ep0state)); + break; + } +out: + return; +} + +STATIC +usb3_pcd_ep_t * +Addr2EndPoint ( + IN usb3_pcd_t *pcd, + IN UINT16 index + ) +{ + UINT32 ep_num; + + ep_num = UE_GET_ADDR (index); + if (ep_num == 0) { + return &pcd->ep0; + } else { + if (UE_GET_DIR (index) == UE_DIR_IN) { + return &pcd->in_ep; + } + return &pcd->out_ep; + } +} + +STATIC +VOID +DwUsb3DoGetStatus ( + IN usb3_pcd_t *pcd + ) +{ + usb_device_request_t *ctrl = &gEndPoint0SetupPacket->req; + UINT8 *status = gEndPoint0StatusBuf; + usb3_pcd_ep_t *ep; + + if (ctrl->wLength != 2) { + EndPoint0DoStall (pcd); + return; + } + + switch (UT_GET_RECIPIENT (ctrl->bmRequestType)) { + case UT_DEVICE: + *status = 0; // bus powered + if (pcd->speed == USB_SPEED_SUPER) { + if (pcd->state == USB3_STATE_CONFIGURED) { + if (MmioRead32 (DCTL) & DCTL_INIT_U1_EN) { + *status |= 1 << 2; + } + if (MmioRead32 (DCTL) & DCTL_INIT_U2_EN) { + *status |= 1 << 3; + } + *status |= (UINT8)(pcd->ltm_enable << 4); + } + } + *(status + 1) = 0; + break; + case UT_INTERFACE: + *status = 0; + *(status + 1) = 0; + break; + case UT_ENDPOINT: + ep = Addr2EndPoint (pcd, ctrl->wIndex); + *status = ep->stopped; + *(status + 1) = 0; + break; + default: + EndPoint0DoStall (pcd); + return; + } + pcd->ep0_req.bufdma = (UINT64 *)status; + pcd->ep0_req.length = 2; + pcd->ep0_req.actual = 0; + DwUsb3EndPoint0StartTransfer (pcd, &pcd->ep0_req); +} + +STATIC +VOID +DoClearHalt ( + IN usb3_pcd_t *pcd, + IN usb3_pcd_ep_t *ep + ) +{ + if (ep->is_in) { + DwUsb3DepClearStall (EP_IN_IDX (ep->num)); + } else { + DwUsb3DepClearStall (EP_OUT_IDX (ep->num)); + } + if (ep->stopped) { + ep->stopped = 0; + } +} + +STATIC +VOID +Usb3PcdEpEnable ( + IN usb3_pcd_t *pcd, + IN usb3_pcd_ep_t *ep + ) +{ + // + // activate the EP + // + ep->stopped = 0; + ep->xfer_started = 0; + ep->ep_desc->control = 0; + ep->ep_desc->status = 0; + // + // set initial data pid. + // + if (ep->type == EPTYPE_BULK) { + ep->data_pid_start = 0; + } + DwUsb3EpActivate (pcd, ep); +} + +STATIC +VOID +DwUsb3DoClearFeature ( + IN usb3_pcd_t *pcd + ) +{ + usb_device_request_t *ctrl = &gEndPoint0SetupPacket->req; + usb3_pcd_ep_t *ep; + + switch (UT_GET_RECIPIENT (ctrl->bmRequestType)) { + case UT_DEVICE: + switch (ctrl->wValue) { + case UF_U1_ENABLE: + if ((pcd->speed != USB_SPEED_SUPER) || + (pcd->state != USB3_STATE_CONFIGURED)) { + EndPoint0DoStall (pcd); + return; + } + MmioAnd32 (DCTL, ~DCTL_INIT_U1_EN); + break; + case UF_U2_ENABLE: + if ((pcd->speed != USB_SPEED_SUPER) || + (pcd->state != USB3_STATE_CONFIGURED)) { + EndPoint0DoStall (pcd); + return; + } + MmioAnd32 (DCTL, ~DCTL_INIT_U2_EN); + break; + case UF_LTM_ENABLE: + if ((pcd->speed != USB_SPEED_SUPER) || + (pcd->state != USB3_STATE_CONFIGURED) || + (ctrl->wIndex != 0)) { + EndPoint0DoStall (pcd); + return; + } + pcd->ltm_enable = 0; + break; + default: + EndPoint0DoStall (pcd); + return; + } + break; + case UT_INTERFACE: + if (ctrl->wValue) { + EndPoint0DoStall (pcd); + return; + } + break; + case UT_ENDPOINT: + ep = Addr2EndPoint (pcd, ctrl->wIndex); + if (ctrl->wValue != UF_ENDPOINT_HALT) { + EndPoint0DoStall (pcd); + return; + } + DoClearHalt (pcd, ep); + break; + default: + DEBUG ((DEBUG_ERROR, "invalid bmRequestType :%d\n", UT_GET_RECIPIENT (ctrl->bmRequestType))); + break; + } + pcd->ep0.is_in = 1; + pcd->ep0state = EP0_IN_WAIT_NRDY; +} + +STATIC +VOID +DwUsb3DoSetFeature ( + IN usb3_pcd_t *pcd + ) +{ + usb_device_request_t *ctrl = &gEndPoint0SetupPacket->req; + usb3_pcd_ep_t *ep; + + switch (UT_GET_RECIPIENT (ctrl->bmRequestType)) { + case UT_DEVICE: + switch (ctrl->wValue) { + case UF_DEVICE_REMOTE_WAKEUP: + break; + case UF_TEST_MODE: + pcd->test_mode_nr = ctrl->wIndex >> 8; + pcd->test_mode = 1; + break; + case UF_U1_ENABLE: + if ((pcd->speed != USB_SPEED_SUPER) || + (pcd->state != USB3_STATE_CONFIGURED)) { + EndPoint0DoStall (pcd); + return; + } + MmioOr32 (DCTL, DCTL_INIT_U1_EN); + break; + case UF_U2_ENABLE: + if ((pcd->speed != USB_SPEED_SUPER) || + (pcd->state != USB3_STATE_CONFIGURED)) { + EndPoint0DoStall (pcd); + return; + } + MmioOr32 (DCTL, DCTL_INIT_U2_EN); + break; + case UF_LTM_ENABLE: + if ((pcd->speed != USB_SPEED_SUPER) || + (pcd->state != USB3_STATE_CONFIGURED) || + (ctrl->wIndex != 0)) { + EndPoint0DoStall (pcd); + return; + } + pcd->ltm_enable = 1; + break; + default: + EndPoint0DoStall (pcd); + return; + } + break; + case UT_INTERFACE: + if (ctrl->wValue) { + EndPoint0DoStall (pcd); + return; + } + break; + case UT_ENDPOINT: + ep = Addr2EndPoint (pcd, ctrl->wIndex); + if (ctrl->wValue != UF_ENDPOINT_HALT) { + EndPoint0DoStall (pcd); + return; + } + ep->stopped = 1; + if (ep->is_in) { + DwUsb3DepClearStall (EP_IN_IDX (ep->num)); + } else { + DwUsb3DepClearStall (EP_OUT_IDX (ep->num)); + } + break; + default: + DEBUG ((DEBUG_ERROR, "invalid bmRequestType %d\n", UT_GET_RECIPIENT (ctrl->bmRequestType))); + break; + } + pcd->ep0.is_in = 1; + pcd->ep0state = EP0_IN_WAIT_NRDY; +} + +STATIC +VOID +DwUsb3DoSetAddress ( + IN usb3_pcd_t *pcd + ) +{ + usb_device_request_t *ctrl = &gEndPoint0SetupPacket->req; + + if (ctrl->bmRequestType == UT_DEVICE) { + SET_DEVADDR (ctrl->wValue); + pcd->ep0.is_in = 1; + pcd->ep0state = EP0_IN_WAIT_NRDY; + if (ctrl->wValue) { + pcd->state = USB3_STATE_ADDRESSED; + } else { + pcd->state = USB3_STATE_DEFAULT; + } + } +} + +STATIC +VOID +DwUsb3DoGetConfig ( + IN usb3_pcd_t *pcd + ) +{ + usb_device_request_t *ctrl = &gEndPoint0SetupPacket->req; + UINT8 *status = gEndPoint0StatusBuf; + + if (ctrl->bmRequestType != (UT_READ | UT_STANDARD | UT_DEVICE)) { + EndPoint0DoStall (pcd); + return; + } + // + // Notify host the current config value + // + *status = pcd->new_config; + pcd->ep0_req.bufdma = (UINT64 *)status; + pcd->ep0_req.length = 1; + pcd->ep0_req.actual = 0; + DwUsb3EndPoint0StartTransfer (pcd, &pcd->ep0_req); +} + +STATIC +VOID +DwUsb3DoSetConfig ( + IN usb3_pcd_t *pcd + ) +{ + usb_device_request_t *ctrl = &gEndPoint0SetupPacket->req; + UINT16 wvalue = ctrl->wValue; + usb3_pcd_ep_t *ep; + + if (ctrl->bmRequestType != (UT_WRITE | UT_STANDARD | UT_DEVICE)) { + EndPoint0DoStall (pcd); + return; + } + + if (!wvalue || (wvalue == CONFIG_VALUE)) { + pcd->new_config = (UINT8)wvalue; + // + // set new configuration + // + if (wvalue) { + // + // activate bulk in endpoint + // + ep = &pcd->in_ep; + Usb3PcdEpEnable (pcd, ep); + // + // activate bulk out endpoint + // + ep = &pcd->out_ep; + Usb3PcdEpEnable (pcd, ep); + pcd->state = USB3_STATE_CONFIGURED; + { + // + // prepare for EP1 OUT + // + usb3_pcd_ep_t *ep = &pcd->out_ep; + usb3_pcd_req_t *req = &ep->req; + + // + // AndroidFast App will free the rx buffer. + // + gRxBuf = AllocatePool (DATA_SIZE); + ASSERT (gRxBuf != NULL); + WriteBackDataCacheRange (gRxBuf, DATA_SIZE); + req->bufdma = (UINT64 *)gRxBuf; + if (mDataBufferSize == 0) { + req->length = CMD_SIZE; + } else if (mDataBufferSize > DATA_SIZE) { + req->length = DATA_SIZE; + mDataBufferSize = mDataBufferSize - DATA_SIZE; + } else if (mDataBufferSize > CMD_SIZE) { + req->length = CMD_SIZE; + mDataBufferSize = mDataBufferSize - CMD_SIZE; + } else { + req->length = mDataBufferSize; + mDataBufferSize = 0; + } + DwUsb3EndPointXStartTransfer (pcd, ep); + } + } else { + pcd->state = USB3_STATE_ADDRESSED; + } + pcd->ep0.is_in = 1; + pcd->ep0state = EP0_IN_WAIT_NRDY; + } else { + EndPoint0DoStall (pcd); + } +} + +STATIC +VOID +DwUsb3DoGetDescriptor ( + IN usb3_pcd_t *pcd + ) +{ + usb_device_request_t *ctrl = &gEndPoint0SetupPacket->req; + UINT8 dt = ctrl->wValue >> 8; + UINT8 index = (UINT8)ctrl->wValue; + UINT16 len = ctrl->wLength; + UINT8 *buf = gEndPoint0StatusBuf; + UINT16 value = 0; + EFI_USB_STRING_DESCRIPTOR *Descriptor = NULL; + + if (ctrl->bmRequestType != (UT_READ | UT_STANDARD | UT_DEVICE)) { + EndPoint0DoStall (pcd); + return; + } + + switch (dt) { + case UDESC_DEVICE: + { + struct usb_device_descriptor *dev = &gDwUsb3DevDesc; + dev->bLength = sizeof (struct usb_device_descriptor); + dev->bDescriptorType = UDESC_DEVICE; + dev->bDeviceClass = 0; + dev->bDeviceSubClass = 0; + dev->bDeviceProtocol = 0; + if (pcd->speed == USB_SPEED_SUPER) { + dev->bcdUSB = 0x300; + // + // 2^9 = 512 + // + dev->bMaxPacketSize0 = 9; + } else { + dev->bcdUSB = 0x0200; + dev->bMaxPacketSize0 = 0x40; + } + dev->idVendor = usb_port_activity_config.idVendor; + dev->idProduct = usb_port_activity_config.idProduct; + dev->bcdDevice = 0x0100; + dev->iManufacturer = STRING_MANUFACTURER; + dev->iProduct = STRING_PRODUCT; + dev->iSerialNumber = STRING_SERIAL; + dev->bNumConfigurations = 1; + value = sizeof (struct usb_device_descriptor); + CopyMem ((void *)buf, (void *)dev, value); + } + break; + case UDESC_DEVICE_QUALIFIER: + { + struct usb_qualifier_descriptor *qual = (struct usb_qualifier_descriptor *)buf; + struct usb_device_descriptor *dev = &gDwUsb3DevDesc; + + qual->bLength = sizeof (*qual); + qual->bDescriptorType = UDESC_DEVICE_QUALIFIER; + qual->bcdUSB = dev->bcdUSB; + qual->bDeviceClass = dev->bDeviceClass; + qual->bDeviceSubClass = dev->bDeviceSubClass; + qual->bDeviceProtocol = dev->bDeviceProtocol; + qual->bMaxPacketSize0 = dev->bMaxPacketSize0; + qual->bNumConfigurations = 1; + qual->bRESERVED = 0; + value = sizeof (struct usb_qualifier_descriptor); + } + break; + + case UDESC_CONFIG: + { + struct usb_config_descriptor *config = (struct usb_config_descriptor *)buf; + + config->bLength = sizeof (*config); + config->bDescriptorType = UDESC_CONFIG; + config->bNumInterfaces = 1; + config->bConfigurationValue = 1; + config->iConfiguration = 0; + config->bmAttributes = USB_CONFIG_ATT_ONE; + + if (pcd->speed == USB_SPEED_SUPER) { + config->bMaxPower = 0x50; + } else { + config->bMaxPower = 0x80; + } + buf += sizeof (*config); + + intf.bInterfaceSubClass = usb_port_activity_config.bInterfaceSubClass; + intf.bInterfaceProtocol = usb_port_activity_config.bInterfaceProtocol; + CopyMem ((void *)buf, (void *)&intf, sizeof (intf)); + buf += sizeof (intf); + + switch (pcd->speed) { + case USB_SPEED_SUPER: + CopyMem (buf, &ss_bulk_in, sizeof (ss_bulk_in)); + buf += sizeof (ss_bulk_in); + CopyMem (buf, &ep_comp, sizeof (ep_comp)); + buf += sizeof (ep_comp); + CopyMem (buf, &ss_bulk_out, sizeof (ss_bulk_out)); + buf += sizeof (ss_bulk_out); + CopyMem (buf, &ep_comp, sizeof (ep_comp)); + + config->wTotalLength = sizeof (*config) + sizeof (intf) + sizeof (ss_bulk_in) + + sizeof (ep_comp) + sizeof (ss_bulk_out) + sizeof (ep_comp); + break; + + default: // HS/FS + { + struct usb_endpoint_descriptor *endp = (struct usb_endpoint_descriptor *)buf; + + CopyMem (buf, &hs_bulk_in, sizeof (hs_bulk_in)); + (endp++)->wMaxPacketSize = pcd->in_ep.maxpacket; + buf += sizeof (hs_bulk_in); + CopyMem (buf, &hs_bulk_out, sizeof (hs_bulk_out)); + endp->wMaxPacketSize = pcd->out_ep.maxpacket; + config->wTotalLength = sizeof (*config) + sizeof (intf) + sizeof (hs_bulk_in) + + sizeof (hs_bulk_out); + break; + } + } + value = config->wTotalLength; + } + break; + + case UDESC_STRING: + { + switch (index) { + case STRING_LANGUAGE: + Descriptor = (EFI_USB_STRING_DESCRIPTOR *)(UINTN)gEndPoint0StatusBuf; + ASSERT (Descriptor != NULL); + Descriptor->Length = LANG_LENGTH * sizeof (CHAR16); + Descriptor->DescriptorType = USB_DESC_TYPE_STRING; + DwUsb->GetLang (Descriptor->String, &Descriptor->Length); + value = Descriptor->Length; + break; + case STRING_MANUFACTURER: + Descriptor = (EFI_USB_STRING_DESCRIPTOR *)(UINTN)gEndPoint0StatusBuf; + ASSERT (Descriptor != NULL); + Descriptor->Length = MANU_FACTURER_STRING_LENGTH * sizeof (CHAR16); + Descriptor->DescriptorType = USB_DESC_TYPE_STRING; + DwUsb->GetManuFacturer (Descriptor->String, &Descriptor->Length); + value = Descriptor->Length; + break; + case STRING_PRODUCT: + Descriptor = (EFI_USB_STRING_DESCRIPTOR *)(UINTN)gEndPoint0StatusBuf; + ASSERT (Descriptor != NULL); + Descriptor->Length = PRODUCT_STRING_LENGTH * sizeof (CHAR16); + Descriptor->DescriptorType = USB_DESC_TYPE_STRING; + DwUsb->GetProduct (Descriptor->String, &Descriptor->Length); + value = Descriptor->Length; + break; + case STRING_SERIAL: + Descriptor = (EFI_USB_STRING_DESCRIPTOR *)(UINTN)gEndPoint0StatusBuf; + ASSERT (Descriptor != NULL); + Descriptor->Length = SERIAL_STRING_LENGTH * sizeof (CHAR16); + Descriptor->DescriptorType = USB_DESC_TYPE_STRING; + DwUsb->GetSerialNo (Descriptor->String, &Descriptor->Length); + value = Descriptor->Length; + break; + default: + EndPoint0DoStall (pcd); + break; + } + } + break; + + case UDESC_BOS: + if (pcd->speed != USB_SPEED_SUPER) { + EndPoint0DoStall (pcd); + return; + } + value = bos.wTotalLength; + CopyMem (buf, &bos, sizeof (bos)); + buf += sizeof (bos); + CopyMem (buf, &cap1, sizeof (cap1)); + buf += sizeof (cap1); + CopyMem (buf, &cap2, sizeof (cap2)); + buf += sizeof (cap2); + CopyMem (buf, &cap3, sizeof (cap3)); + break; + default: + EndPoint0DoStall (pcd); + return; + } + pcd->ep0_req.bufdma = (UINT64 *)gEndPoint0StatusBuf; + pcd->ep0_req.length = value < len ? value : len; + pcd->ep0_req.actual = 0; + DwUsb3EndPoint0StartTransfer (pcd, &pcd->ep0_req); +} + +STATIC +VOID +DwUsb3DoSetup ( + IN usb3_pcd_t *pcd + ) +{ + usb_device_request_t *ctrl = &gEndPoint0SetupPacket->req; + usb3_pcd_ep_t *ep0 = &pcd->ep0; + UINT16 wLength; + + wLength = ctrl->wLength; + ep0->stopped = 0; + ep0->three_stage = 1; + if (ctrl->bmRequestType & UE_DIR_IN) { + ep0->is_in = 1; + pcd->ep0state = EP0_IN_DATA_PHASE; + } else { + ep0->is_in = 0; + pcd->ep0state = EP0_OUT_DATA_PHASE; + } + + if (wLength == 0) { + ep0->is_in = 1; + pcd->ep0state = EP0_IN_WAIT_NRDY; + ep0->three_stage = 0; + } + if (UT_GET_TYPE (ctrl->bmRequestType) != UT_STANDARD) { + EndPoint0DoStall (pcd); + return; + } + + switch (ctrl->bRequest) { + case UR_GET_STATUS: + DwUsb3DoGetStatus (pcd); + break; + case UR_CLEAR_FEATURE: + DwUsb3DoClearFeature (pcd); + break; + case UR_SET_FEATURE: + DwUsb3DoSetFeature (pcd); + break; + case UR_SET_ADDRESS: + DwUsb3DoSetAddress (pcd); + break; + case UR_SET_CONFIG: + DwUsb3DoSetConfig (pcd); + MmioOr32 (DCTL, DCTL_ACCEPT_U1_EN); + MmioOr32 (DCTL, DCTL_ACCEPT_U2_EN); + DEBUG ((DEBUG_INFO, "enum done")); + pcd->ltm_enable = 0; + break; + case UR_GET_CONFIG: + DwUsb3DoGetConfig (pcd); + break; + case UR_GET_DESCRIPTOR: + DwUsb3DoGetDescriptor (pcd); + break; + case UR_SET_SEL: + // + // for now this is a no-op + // + pcd->ep0_req.bufdma = (UINT64 *)gEndPoint0StatusBuf; + pcd->ep0_req.length = USB3_STATUS_BUF_SIZE; + pcd->ep0_req.actual = 0; + ep0->send_zlp = 0; + DwUsb3EndPoint0StartTransfer (pcd, &pcd->ep0_req); + break; + default: + EndPoint0DoStall (pcd); + break; + } +} + +STATIC +VOID +DwUsb3OsHandleEndPoint0 ( + IN usb3_pcd_t *pcd, + IN UINT32 event + ) +{ + if (pcd->ep0state == EP0_IDLE) { + DwUsb3DoSetup (pcd); + } else { + DwUsb3HandleEndPoint0 (pcd, NULL, event); + } +} + +STATIC +VOID +DwUsb3RequestDone ( + IN usb3_pcd_t *pcd, + IN usb3_pcd_ep_t *ep, + IN usb3_pcd_req_t *req, + IN UINTN status + ) +{ + if (ep != &pcd->ep0) { + req->trb = NULL; + } + if (req->complete) { + req->complete (req->actual, status); + } else { + if (!ep->is_in) { + ASSERT (req->actual <= req->length); + InvalidateDataCacheRange (gRxBuf, req->actual); + mDataReceivedCallback (req->actual, gRxBuf); + } + } + req->actual = 0; +} + +STATIC +VOID +DwUsb3EndPointcompleteRequest ( + IN usb3_pcd_t *pcd, + IN usb3_pcd_ep_t *ep, + IN UINT32 event + ) +{ + usb3_pcd_req_t *req = &ep->req; + usb3_dma_desc_t *desc = req->trb; + UINT32 byte_count; + + ep->send_zlp = 0; + if (!desc) { + return; + } + + if (desc->control & DSCCTL_HWO) { + return; + } + + if (ep->is_in) { + // + // IN ep + // + if (GET_DSCSTS_XFERCNT (desc->status) == 0) { + req->actual += req->length; + } + // + // reset IN tri + // + ep->tri_in = 0; + // + // complete the IN request + // + DwUsb3RequestDone (pcd, ep, req, 0); + } else { + // + // OUT ep + // + byte_count = req->length - GET_DSCSTS_XFERCNT (desc->status); + req->actual += byte_count; + // + //req->bufdma += byte_count; + // reset OUT tri + // + ep->tri_out = 0; + // + // OUT transfer complete or not + // complete the OUT request + // + DwUsb3RequestDone (pcd, ep, req, 0); + { + // + // prepare for EP1 OUT + // + usb3_pcd_ep_t *ep = &pcd->out_ep; + usb3_pcd_req_t *req = &ep->req; + + ZeroMem (req, sizeof (usb3_pcd_req_t)); + gRxBuf = AllocatePool (DATA_SIZE); + ASSERT (gRxBuf != NULL); + WriteBackDataCacheRange (gRxBuf, DATA_SIZE); + req->bufdma = (UINT64 *)gRxBuf; + if (mDataBufferSize == 0) { + req->length = CMD_SIZE; + } else if (mDataBufferSize > DATA_SIZE) { + req->length = DATA_SIZE; + mDataBufferSize = mDataBufferSize - DATA_SIZE; + } else if (mDataBufferSize > CMD_SIZE) { + req->length = CMD_SIZE; + mDataBufferSize = mDataBufferSize - CMD_SIZE; + } else { + req->length = mDataBufferSize; + mDataBufferSize = 0; + } + DwUsb3EndPointXStartTransfer (pcd, ep); + } + } +} + +STATIC +VOID +DwUsb3HandleEndPointInterrupt ( + IN usb3_pcd_t *pcd, + IN UINTN PhySep, + IN UINT32 event + ) +{ + usb3_pcd_ep_t *ep; + UINT32 epnum, is_in; + + // + // Physical Out EPs are even, physical In EPs are odd + // + is_in = (UINT32)PhySep & 1; + epnum = ((UINT32)PhySep >> 1) & 0xF; + + // + // Get the EP pointer + // + if (is_in) { + ep = DwUsb3GetInEndPoint (pcd, epnum); + } else { + ep = DwUsb3GetOutEndPoint (pcd, epnum); + } + + switch (event & GEVNT_DEPEVT_INTTYPE_MASK) { + case GEVNT_DEPEVT_INTTYPE_XFER_CMPL: + ep->xfer_started = 0; + // + // complete the transfer + // + if (epnum == 0) { + DwUsb3OsHandleEndPoint0 (pcd, event); + } else { + DwUsb3EndPointcompleteRequest (pcd, ep, event); + } + break; + case GEVNT_DEPEVT_INTTYPE_XFER_IN_PROG: + break; + case GEVNT_DEPEVT_INTTYPE_XFER_NRDY: + if (epnum == 0) { + switch (pcd->ep0state) { + case EP0_IN_WAIT_NRDY: + if (is_in) { + DwUsb3OsHandleEndPoint0 (pcd, event); + } else { + } + break; + case EP0_OUT_WAIT_NRDY: + if (!is_in) { + DwUsb3OsHandleEndPoint0 (pcd, event); + } else { + } + break; + default: + break; + } + } else { + } + break; + default: + DEBUG (( + DEBUG_ERROR, + "invalid event %d\n", + event & GEVNT_DEPEVT_INTTYPE_MASK + )); + break; + } +} + +STATIC +UINTN +DwUsb3HandleEvent ( + VOID + ) +{ + usb3_pcd_t *pcd = &gPcd; + UINT32 Count, Index, Event, Intr; + UINT32 PhySep; + + Count = GET_EVENTBUF_COUNT (); + // + // reset event buffer when it's full + // + if ((GEVNTCOUNT_EVNTCOUNT (Count) == GEVNTCOUNT_EVNTCOUNT_MASK) || + (Count >= DWUSB3_EVENT_BUF_SIZE * sizeof (UINT32))) { + UPDATE_EVENTBUF_COUNT (Count); + Count = 0; + } + + for (Index = 0; Index < Count; Index += sizeof (UINT32)) { + Event = DwUsb3GetEventBufEvent (DWUSB3_EVENT_BUF_SIZE << 2); + UPDATE_EVENTBUF_COUNT (sizeof (UINT32)); + if (Event == 0) { + // + // ignore null events + // + continue; + } + if (Event & GEVNT_NON_EP) { + Intr = Event & GEVNT_INTTYPE_MASK; + if (Intr == GEVNT_INTTYPE (EVENT_DEV_INT)) { + DwUsb3HandleDeviceInterrupt (pcd, Event); + } + } else { + PhySep = (Event & GEVNT_DEPEVT_EPNUM_MASK) >> GEVNT_DEPEVT_EPNUM_SHIFT; + DwUsb3HandleEndPointInterrupt (pcd, PhySep, Event); + } + } + return 0; +} + +STATIC +VOID +DwUsb3Poll ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + if (DwUsb3HandleEvent ()) { + DEBUG ((DEBUG_ERROR, "error: exit from usb_poll\n")); + return; + } +} + +EFI_STATUS +EFIAPI +DwUsb3Start ( + IN USB_DEVICE_DESCRIPTOR *DeviceDescriptor, + IN VOID **Descriptors, + IN USB_DEVICE_RX_CALLBACK RxCallback, + IN USB_DEVICE_TX_CALLBACK TxCallback + ) +{ + EFI_STATUS Status; + EFI_EVENT TimerEvent; + + Status = DmaAllocateBuffer ( + EfiBootServicesData, + EFI_SIZE_TO_PAGES (DWUSB3_EVENT_BUF_SIZE << 2), + (VOID *)&gEventBuf + ); + if (EFI_ERROR (Status)) { + return Status; + } + if (gEventBuf == NULL) { + return EFI_OUT_OF_RESOURCES; + } + ZeroMem (gEventBuf, EFI_SIZE_TO_PAGES (DWUSB3_EVENT_BUF_SIZE << 2)); + gEventPtr = gEventBuf; + DriverInit (); + DwUsb3Init (); + Status = gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + DwUsb3Poll, + NULL, + &TimerEvent + ); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->SetTimer ( + TimerEvent, + TimerPeriodic, + DW_INTERRUPT_POLL_PERIOD + ); + ASSERT_EFI_ERROR (Status); + mDataReceivedCallback = RxCallback; + return Status; +} + +EFI_STATUS +DwUsb3Send ( + IN UINT8 EndpointIndex, + IN UINTN Size, + IN CONST VOID *Buffer + ) +{ + usb3_pcd_t *pcd = &gPcd; + usb3_pcd_ep_t *ep = &pcd->in_ep; + usb3_pcd_req_t *req = &ep->req; + + WriteBackDataCacheRange ((VOID *)Buffer, Size); + req->bufdma = (UINT64 *)Buffer; + req->length = Size; + DwUsb3EndPointXStartTransfer (pcd, ep); + return EFI_SUCCESS; +} + +USB_DEVICE_PROTOCOL mUsbDevice = { + DwUsb3Start, + DwUsb3Send +}; + +EFI_STATUS +EFIAPI +DwUsb3EntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status = DmaAllocateBuffer ( + EfiBootServicesData, + EFI_SIZE_TO_PAGES (sizeof (usb_setup_pkt_t) * 5), + (VOID *)&gEndPoint0SetupPacket + ); + if (EFI_ERROR (Status)) { + return Status; + } + Status = DmaAllocateBuffer ( + EfiBootServicesData, + EFI_SIZE_TO_PAGES (USB3_STATUS_BUF_SIZE * sizeof (UINT8)), + (VOID *)&gEndPoint0StatusBuf + ); + if (EFI_ERROR (Status)) { + goto Out; + } + Status = gBS->LocateProtocol (&gDwUsbProtocolGuid, NULL, (VOID **) &DwUsb); + if (EFI_ERROR (Status)) { + goto OutProtocol; + } + + Status = DwUsb->PhyInit(USB_DEVICE_MODE); + if (EFI_ERROR (Status)) { + goto OutProtocol; + } + + Status = gBS->InstallProtocolInterface ( + &ImageHandle, + &gUsbDeviceProtocolGuid, + EFI_NATIVE_INTERFACE, + &mUsbDevice + ); + if (EFI_ERROR (Status)) { + goto OutProtocol; + } + return Status; + +OutProtocol: + DmaFreeBuffer ( + EFI_SIZE_TO_PAGES (USB3_STATUS_BUF_SIZE * sizeof (UINT8)), + (VOID *)gEndPoint0StatusBuf + ); +Out: + DmaFreeBuffer ( + EFI_SIZE_TO_PAGES (sizeof (usb_setup_pkt_t) * 5), + (VOID *)gEndPoint0SetupPacket + ); + return Status; +}