From patchwork Mon Nov 20 10:25:44 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: kalyan-nagabhirava X-Patchwork-Id: 119266 Delivered-To: patch@linaro.org Received: by 10.140.22.164 with SMTP id 33csp3663182qgn; Mon, 20 Nov 2017 02:28:14 -0800 (PST) X-Google-Smtp-Source: AGs4zMZdjX1Gx/pqjhI+dGzb+5io9KwDmuvrCKFEsuZXCvvvllo3tnnqP8/K04YpiUn4OfYlQMRD X-Received: by 10.98.220.79 with SMTP id t76mr10774701pfg.165.1511173693935; Mon, 20 Nov 2017 02:28:13 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1511173693; cv=none; d=google.com; s=arc-20160816; b=uAnRuQlCo/u/juwy9SMmOUw2dj0lkQiAvkv2Ok5rRl7npWBmW9T2g9ii8eFvRAjNko oLUaaF4BQtUTqQ5hk6t2YcjiKxyIcKYZhCAh8KxjIzibdhWVSIkWMgI8fyISSKnN7KzH f+oRYFfaTLFg08zWHeseh8IsOveM2/jDDxk7/l7YyLXKY+1TxJwG0Ea/ipvZasszzKeo ePEfuYE2zjbW7jb+sMB0+lJH4eZrKEnSdBIflbupKL/FnzYxCqpgWHojPwJr8BrKYHfA DgEE2Sr+/4PMSpilGiJULiF03eyloAYS8yAR7CWGd6O052nu3JsOkdHjTxqVW9YuMMfv pvsw== 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:cc :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:message-id:date:to:from:dkim-signature :delivered-to:arc-authentication-results; bh=kNDZHdr4OtrIqi3RwmVEp9koLPILCZntqO4MjOVvv9E=; b=gNuN/FlP62BJQ+zwSMgu5RC5pHTJtbcbDjXvkJdBPwX39upXYsqcy0AJZOHC9ZFT6L OohXdhrXcxrMdJVakYf9QzU0VBzOJnfxa2zXdY5bTx1YKc1XhIa/4fF0358ciEBDNAYG Ghp8fmzqxNlizFRKc62kyu2dZMezVplG62sXcMMlRKlOB4IC+yQzRzd2RMUNBS/+UBe3 mt0/F3rEklF1dea01I4/5d6PyHn28vAcWTXOzI83++/6NX+LizyQItQg1VwqFCFasJk4 6o8ufv8xt6nAezGv4pqQHQBM1Jlk4CF51Jduv2hr6FbgMq6BBykbcZkevxBQ8LfhnKVS deLw== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=YK1vP/5C; spf=pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 198.145.21.10 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. [198.145.21.10]) by mx.google.com with ESMTPS id t202si7731247pgb.548.2017.11.20.02.28.13 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 20 Nov 2017 02:28:13 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 198.145.21.10 as permitted sender) client-ip=198.145.21.10; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=YK1vP/5C; spf=pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 198.145.21.10 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 910AC2034712D; Mon, 20 Nov 2017 02:23:58 -0800 (PST) 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:c00::243; helo=mail-pf0-x243.google.com; envelope-from=kalyankumar.nagabhirava@linaro.org; receiver=edk2-devel@lists.01.org Received: from mail-pf0-x243.google.com (mail-pf0-x243.google.com [IPv6:2607:f8b0:400e:c00::243]) (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 913A020347121 for ; Mon, 20 Nov 2017 02:23:56 -0800 (PST) Received: by mail-pf0-x243.google.com with SMTP id 17so6971620pfn.12 for ; Mon, 20 Nov 2017 02:28:10 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id; bh=JN8q5IkE/LFeovOqaOwwiu8fGjrKZDglpCnGXNu6X/4=; b=YK1vP/5C86FPRafhjSyr6eetWLtJ1Swt+BHqobIzkTaFx1E7S+b1ccBI82HCe7I7ff S4tpM1vjIOSsHe3ucClQG7diKxc6x/pn7r/0jXboFKIV4Tf+NWR0lJNLulRLJ1NLM44h shjmhFCamtosmR8UclKNnVA/y4IO/A9eGZDWw= 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; bh=JN8q5IkE/LFeovOqaOwwiu8fGjrKZDglpCnGXNu6X/4=; b=l6plSlnNrAM+3vgF/ZhirRZyPvzelUO1HPGLLsIk5axP/0SsdFLMVl1XRMPZ26k6gR r23vqk/TuAL8l6YZWfq6xKrBUKrB8wFG50rsrwusiU+cErplbK/qXX/e0QevvqGs+Z6A dr28KxE/gxCIAfu1nXJdKvPn5Z9JgV7kObY/h6NrfCczQUa3vxGslyhRbyM2NFKw5Ts9 KohlxCtqIlK+yjd3f729lE0Fu9e7yWslNLms07kNCn6eNGUggMFWxwgmk/G4wkQHIuye 0ip/k4yOpqRY9Hhx6W4cYL/dBudVfYkXtXFzwipCrzlOldo1eH8ovhv87vnmGk1PVoHJ ggKw== X-Gm-Message-State: AJaThX5rJUl8KskBIgcCOcvbsepoghQTV2k00+6x57beDi4NxUwdWVB4 s3ZXWSBhaRhl9cq7jFUFXRwWWMDbetM= X-Received: by 10.84.215.207 with SMTP id g15mr13194588plj.369.1511173686358; Mon, 20 Nov 2017 02:28:06 -0800 (PST) Received: from localhost.localdomain ([220.225.120.129]) by smtp.gmail.com with ESMTPSA id m87sm5136203pfi.88.2017.11.20.02.28.01 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 20 Nov 2017 02:28:05 -0800 (PST) From: kalyan-nagabhirava To: edk2-devel@lists.01.org, ard.biesheuvel@linaro.org, leif.lindholm@linaro.org Date: Mon, 20 Nov 2017 15:55:44 +0530 Message-Id: <20171120102544.21532-1-kalyankumar.nagabhirava@linaro.org> X-Mailer: git-send-email 2.15.0 Subject: [edk2] [PATCH] [edk2-platforms]: Adding usb Host driver support from OpenPlatformPkg hikey-wip branch X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: peter.griffin@linaro.org, mark.gregotski@linaro.org MIME-Version: 1.0 Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: kalyan-nagabhirava --- Platform/Hisilicon/HiKey/HiKey.dec | 4 + Platform/Hisilicon/HiKey/HiKey.dsc | 11 + Platform/Hisilicon/HiKey/HiKey.fdf | 3 + .../Include/Library/UncachedMemoryAllocationLib.h | 665 ++++++ .../Hisilicon/HiKey/Library/ArmDmaLib/ArmDmaLib.c | 342 +++ .../HiKey/Library/ArmDmaLib/ArmDmaLib.inf | 50 + .../UncachedMemoryAllocationLib.c | 692 ++++++ .../UncachedMemoryAllocationLib.inf | 45 + Silicon/Synopsys/Usb/DwNonPci/DwNonPciUsbDxe.inf | 47 + Silicon/Synopsys/Usb/DwNonPci/InitController.c | 37 + Silicon/Synopsys/Usb/DwUsbDxe/ComponentName.c | 244 ++ Silicon/Synopsys/Usb/DwUsbDxe/ComponentName.h | 148 ++ Silicon/Synopsys/Usb/DwUsbDxe/DwUsbDxe.c | 2324 ++++++++++++++++++++ Silicon/Synopsys/Usb/DwUsbDxe/DwUsbDxe.dec | 42 + Silicon/Synopsys/Usb/DwUsbDxe/DwUsbDxe.h | 534 +++++ Silicon/Synopsys/Usb/DwUsbDxe/DwUsbDxe.inf | 60 + Silicon/Synopsys/Usb/DwUsbHostDxe/ComponentName.c | 243 ++ Silicon/Synopsys/Usb/DwUsbHostDxe/ComponentName.h | 148 ++ Silicon/Synopsys/Usb/DwUsbHostDxe/DwUsbHostDxe.c | 2043 +++++++++++++++++ Silicon/Synopsys/Usb/DwUsbHostDxe/DwUsbHostDxe.h | 121 + Silicon/Synopsys/Usb/DwUsbHostDxe/DwUsbHostDxe.inf | 61 + Silicon/Synopsys/Usb/DwUsbHostDxe/DwcHw.h | 792 +++++++ 22 files changed, 8656 insertions(+) create mode 100644 Platform/Hisilicon/HiKey/Include/Library/UncachedMemoryAllocationLib.h create mode 100644 Platform/Hisilicon/HiKey/Library/ArmDmaLib/ArmDmaLib.c create mode 100644 Platform/Hisilicon/HiKey/Library/ArmDmaLib/ArmDmaLib.inf create mode 100644 Platform/Hisilicon/HiKey/Library/UncachedMemoryAllocationLib/UncachedMemoryAllocationLib.c create mode 100644 Platform/Hisilicon/HiKey/Library/UncachedMemoryAllocationLib/UncachedMemoryAllocationLib.inf create mode 100644 Silicon/Synopsys/Usb/DwNonPci/DwNonPciUsbDxe.inf create mode 100644 Silicon/Synopsys/Usb/DwNonPci/InitController.c create mode 100644 Silicon/Synopsys/Usb/DwUsbDxe/ComponentName.c create mode 100644 Silicon/Synopsys/Usb/DwUsbDxe/ComponentName.h create mode 100644 Silicon/Synopsys/Usb/DwUsbDxe/DwUsbDxe.c create mode 100644 Silicon/Synopsys/Usb/DwUsbDxe/DwUsbDxe.dec create mode 100644 Silicon/Synopsys/Usb/DwUsbDxe/DwUsbDxe.h create mode 100644 Silicon/Synopsys/Usb/DwUsbDxe/DwUsbDxe.inf create mode 100644 Silicon/Synopsys/Usb/DwUsbHostDxe/ComponentName.c create mode 100644 Silicon/Synopsys/Usb/DwUsbHostDxe/ComponentName.h create mode 100644 Silicon/Synopsys/Usb/DwUsbHostDxe/DwUsbHostDxe.c create mode 100644 Silicon/Synopsys/Usb/DwUsbHostDxe/DwUsbHostDxe.h create mode 100644 Silicon/Synopsys/Usb/DwUsbHostDxe/DwUsbHostDxe.inf create mode 100644 Silicon/Synopsys/Usb/DwUsbHostDxe/DwcHw.h -- 2.15.0 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel diff --git a/Platform/Hisilicon/HiKey/HiKey.dec b/Platform/Hisilicon/HiKey/HiKey.dec index 537138eb4..a1f610bf0 100644 --- a/Platform/Hisilicon/HiKey/HiKey.dec +++ b/Platform/Hisilicon/HiKey/HiKey.dec @@ -34,3 +34,7 @@ [PcdsFixedAtBuild.common] gHiKeyTokenSpaceGuid.PcdAndroidFastbootNvmDevicePath|L""|VOID*|0x00000001 gHiKeyTokenSpaceGuid.PcdArmFastbootFlashLimit|L""|VOID*|0x00000002 + + # This PCD will free the unallocated buffers if their size reach this threshold. + # We set the default value to 512MB. + gArmTokenSpaceGuid.PcdArmFreeUncachedMemorySizeThreshold|0x20000000|UINT64|0x00000003 diff --git a/Platform/Hisilicon/HiKey/HiKey.dsc b/Platform/Hisilicon/HiKey/HiKey.dsc index 2e3b1c879..497361454 100644 --- a/Platform/Hisilicon/HiKey/HiKey.dsc +++ b/Platform/Hisilicon/HiKey/HiKey.dsc @@ -109,6 +109,10 @@ # USB Requirements UefiUsbLib|MdePkg/Library/UefiUsbLib/UefiUsbLib.inf + DmaLib|Platform/Hisilicon/HiKey/Library/ArmDmaLib/ArmDmaLib.inf + + UncachedMemoryAllocationLib|Platform/Hisilicon/HiKey/Library/UncachedMemoryAllocationLib/UncachedMemoryAllocationLib.inf + NonDiscoverableDeviceRegistrationLib|MdeModulePkg/Library/NonDiscoverableDeviceRegistrationLib/NonDiscoverableDeviceRegistrationLib.inf # Network Libraries UefiScsiLib|MdePkg/Library/UefiScsiLib/UefiScsiLib.inf @@ -330,7 +334,11 @@ gEmbeddedTokenSpaceGuid.PcdDwEmmcDxeBaseAddress|0xF723D000 gEmbeddedTokenSpaceGuid.PcdDwEmmcDxeClockFrequencyInHz|100000000 + # DW USB controller # + gDwUsbDxeTokenSpaceGuid.PcdDwUsbBaseAddress|0xF72c0000 + gDwUsbDxeTokenSpaceGuid.PcdDwUsbSysCtrlBaseAddress|0xF7030000 + # # Fastboot # @@ -399,6 +407,9 @@ # USB Host Support # MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf + Silicon/Synopsys/Usb/DwUsbHostDxe/DwUsbHostDxe.inf + Silicon/Synopsys/Usb/DwNonPci/DwNonPciUsbDxe.inf + MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.inf # # USB Mass Storage Support diff --git a/Platform/Hisilicon/HiKey/HiKey.fdf b/Platform/Hisilicon/HiKey/HiKey.fdf index d277bd6ce..78ba85399 100644 --- a/Platform/Hisilicon/HiKey/HiKey.fdf +++ b/Platform/Hisilicon/HiKey/HiKey.fdf @@ -129,6 +129,9 @@ READ_LOCK_STATUS = TRUE # USB Host Support # INF MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf + INF Silicon/Synopsys/Usb/DwUsbHostDxe/DwUsbHostDxe.inf + INF Silicon/Synopsys/Usb/DwNonPci/DwNonPciUsbDxe.inf + INF MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.inf # # USB Mass Storage Support diff --git a/Platform/Hisilicon/HiKey/Include/Library/UncachedMemoryAllocationLib.h b/Platform/Hisilicon/HiKey/Include/Library/UncachedMemoryAllocationLib.h new file mode 100644 index 000000000..a49d8d3ac --- /dev/null +++ b/Platform/Hisilicon/HiKey/Include/Library/UncachedMemoryAllocationLib.h @@ -0,0 +1,665 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. 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 __UNCACHED_MEMORY_ALLOCATION_LIB_H__ +#define __UNCACHED_MEMORY_ALLOCATION_LIB_H__ + +/** + Converts a cached or uncached address to a physical address suitable for use in SoC registers. + + @param VirtualAddress The pointer to convert. + + @return The physical address of the supplied virtual pointer. + +**/ +EFI_PHYSICAL_ADDRESS +ConvertToPhysicalAddress ( + IN VOID *VirtualAddress + ); + +/** + Converts a cached or uncached address to a cached address. + + @param Address The pointer to convert. + + @return The address of the cached memory location corresponding to the input address. + +**/ +VOID * +ConvertToCachedAddress ( + IN VOID *Address + ); + +/** + Converts a cached or uncached address to an uncached address. + + @param Address The pointer to convert. + + @return The address of the uncached memory location corresponding to the input address. + +**/ +VOID * +ConvertToUncachedAddress ( + IN VOID *Address + ); + +/** + Allocates one or more 4KB pages of type EfiBootServicesData. + + Allocates the number of 4KB pages of type EfiBootServicesData and returns a pointer to the + allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL + is returned. If there is not enough memory remaining to satisfy the request, then NULL is + returned. + + @param Pages The number of 4 KB pages to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +UncachedAllocatePages ( + IN UINTN Pages + ); + +/** + Allocates one or more 4KB pages of type EfiRuntimeServicesData. + + Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a pointer to the + allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL + is returned. If there is not enough memory remaining to satisfy the request, then NULL is + returned. + + @param Pages The number of 4 KB pages to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +UncachedAllocateRuntimePages ( + IN UINTN Pages + ); + +/** + Allocates one or more 4KB pages of type EfiReservedMemoryType. + + Allocates the number of 4KB pages of type EfiReservedMemoryType and returns a pointer to the + allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL + is returned. If there is not enough memory remaining to satisfy the request, then NULL is + returned. + + @param Pages The number of 4 KB pages to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +UncachedAllocateReservedPages ( + IN UINTN Pages + ); + +/** + Frees one or more 4KB pages that were previously allocated with one of the page allocation + functions in the Memory Allocation Library. + + Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer + must have been allocated on a previous call to the page allocation services of the Memory + Allocation Library. + If Buffer was not allocated with a page allocation function in the Memory Allocation Library, + then ASSERT(). + If Pages is zero, then ASSERT(). + + @param Buffer Pointer to the buffer of pages to free. + @param Pages The number of 4 KB pages to free. + +**/ +VOID +EFIAPI +UncachedFreePages ( + IN VOID *Buffer, + IN UINTN Pages + ); + +/** + Allocates one or more 4KB pages of type EfiBootServicesData at a specified alignment. + + Allocates the number of 4KB pages specified by Pages of type EfiBootServicesData with an + alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is + returned. If there is not enough memory at the specified alignment remaining to satisfy the + request, then NULL is returned. + If Alignment is not a power of two and Alignment is not zero, then ASSERT(). + + @param Pages The number of 4 KB pages to allocate. + @param Alignment The requested alignment of the allocation. Must be a power of two. + If Alignment is zero, then byte alignment is used. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +UncachedAllocateAlignedPages ( + IN UINTN Pages, + IN UINTN Alignment + ); + +/** + Allocates one or more 4KB pages of type EfiRuntimeServicesData at a specified alignment. + + Allocates the number of 4KB pages specified by Pages of type EfiRuntimeServicesData with an + alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is + returned. If there is not enough memory at the specified alignment remaining to satisfy the + request, then NULL is returned. + If Alignment is not a power of two and Alignment is not zero, then ASSERT(). + + @param Pages The number of 4 KB pages to allocate. + @param Alignment The requested alignment of the allocation. Must be a power of two. + If Alignment is zero, then byte alignment is used. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +UncachedAllocateAlignedRuntimePages ( + IN UINTN Pages, + IN UINTN Alignment + ); + +/** + Allocates one or more 4KB pages of type EfiReservedMemoryType at a specified alignment. + + Allocates the number of 4KB pages specified by Pages of type EfiReservedMemoryType with an + alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is + returned. If there is not enough memory at the specified alignment remaining to satisfy the + request, then NULL is returned. + If Alignment is not a power of two and Alignment is not zero, then ASSERT(). + + @param Pages The number of 4 KB pages to allocate. + @param Alignment The requested alignment of the allocation. Must be a power of two. + If Alignment is zero, then byte alignment is used. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +UncachedAllocateAlignedReservedPages ( + IN UINTN Pages, + IN UINTN Alignment + ); + +/** + Frees one or more 4KB pages that were previously allocated with one of the aligned page + allocation functions in the Memory Allocation Library. + + Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer + must have been allocated on a previous call to the aligned page allocation services of the Memory + Allocation Library. + If Buffer was not allocated with an aligned page allocation function in the Memory Allocation + Library, then ASSERT(). + If Pages is zero, then ASSERT(). + + @param Buffer Pointer to the buffer of pages to free. + @param Pages The number of 4 KB pages to free. + +**/ +VOID +EFIAPI +UncachedFreeAlignedPages ( + IN VOID *Buffer, + IN UINTN Pages + ); + +/** + Allocates a buffer of type EfiBootServicesData. + + Allocates the number bytes specified by AllocationSize of type EfiBootServicesData and returns a + pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is + returned. If there is not enough memory remaining to satisfy the request, then NULL is returned. + + @param AllocationSize The number of bytes to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +UncachedAllocatePool ( + IN UINTN AllocationSize + ); + +/** + Allocates a buffer of type EfiRuntimeServicesData. + + Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData and returns + a pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is + returned. If there is not enough memory remaining to satisfy the request, then NULL is returned. + + @param AllocationSize The number of bytes to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +UncachedAllocateRuntimePool ( + IN UINTN AllocationSize + ); + +/** + Allocates a buffer of type EfieservedMemoryType. + + Allocates the number bytes specified by AllocationSize of type EfieservedMemoryType and returns + a pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is + returned. If there is not enough memory remaining to satisfy the request, then NULL is returned. + + @param AllocationSize The number of bytes to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +UncachedAllocateReservedPool ( + IN UINTN AllocationSize + ); + +/** + Allocates and zeros a buffer of type EfiBootServicesData. + + Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, clears the + buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a + valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the + request, then NULL is returned. + + @param AllocationSize The number of bytes to allocate and zero. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +UncachedAllocateZeroPool ( + IN UINTN AllocationSize + ); + +/** + Allocates and zeros a buffer of type EfiRuntimeServicesData. + + Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData, clears the + buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a + valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the + request, then NULL is returned. + + @param AllocationSize The number of bytes to allocate and zero. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +UncachedAllocateRuntimeZeroPool ( + IN UINTN AllocationSize + ); + +/** + Allocates and zeros a buffer of type EfiReservedMemoryType. + + Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType, clears the + buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a + valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the + request, then NULL is returned. + + @param AllocationSize The number of bytes to allocate and zero. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +UncachedAllocateReservedZeroPool ( + IN UINTN AllocationSize + ); + +/** + Copies a buffer to an allocated buffer of type EfiBootServicesData. + + Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, copies + AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the + allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there + is not enough memory remaining to satisfy the request, then NULL is returned. + If Buffer is NULL, then ASSERT(). + If AllocationSize is greater than (MAX_ADDRESS ? Buffer + 1), then ASSERT(). + + @param AllocationSize The number of bytes to allocate and zero. + @param Buffer The buffer to copy to the allocated buffer. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +UncachedAllocateCopyPool ( + IN UINTN AllocationSize, + IN CONST VOID *Buffer + ); + +/** + Copies a buffer to an allocated buffer of type EfiRuntimeServicesData. + + Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData, copies + AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the + allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there + is not enough memory remaining to satisfy the request, then NULL is returned. + If Buffer is NULL, then ASSERT(). + If AllocationSize is greater than (MAX_ADDRESS ? Buffer + 1), then ASSERT(). + + @param AllocationSize The number of bytes to allocate and zero. + @param Buffer The buffer to copy to the allocated buffer. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +UncachedAllocateRuntimeCopyPool ( + IN UINTN AllocationSize, + IN CONST VOID *Buffer + ); + +/** + Copies a buffer to an allocated buffer of type EfiReservedMemoryType. + + Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType, copies + AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the + allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there + is not enough memory remaining to satisfy the request, then NULL is returned. + If Buffer is NULL, then ASSERT(). + If AllocationSize is greater than (MAX_ADDRESS ? Buffer + 1), then ASSERT(). + + @param AllocationSize The number of bytes to allocate and zero. + @param Buffer The buffer to copy to the allocated buffer. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +UncachedAllocateReservedCopyPool ( + IN UINTN AllocationSize, + IN CONST VOID *Buffer + ); + +/** + Frees a buffer that was previously allocated with one of the pool allocation functions in the + Memory Allocation Library. + + Frees the buffer specified by Buffer. Buffer must have been allocated on a previous call to the + pool allocation services of the Memory Allocation Library. + If Buffer was not allocated with a pool allocation function in the Memory Allocation Library, + then ASSERT(). + + @param Buffer Pointer to the buffer to free. + +**/ +VOID +EFIAPI +UncachedFreePool ( + IN VOID *Buffer + ); + +/** + Allocates a buffer of type EfiBootServicesData at a specified alignment. + + Allocates the number bytes specified by AllocationSize of type EfiBootServicesData with an + alignment specified by Alignment. The allocated buffer is returned. If AllocationSize is 0, + then a valid buffer of 0 size is returned. If there is not enough memory at the specified + alignment remaining to satisfy the request, then NULL is returned. + If Alignment is not a power of two and Alignment is not zero, then ASSERT(). + + @param AllocationSize The number of bytes to allocate. + @param Alignment The requested alignment of the allocation. Must be a power of two. + If Alignment is zero, then byte alignment is used. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +UncachedAllocateAlignedPool ( + IN UINTN AllocationSize, + IN UINTN Alignment + ); + +/** + Allocates a buffer of type EfiRuntimeServicesData at a specified alignment. + + Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData with an + alignment specified by Alignment. The allocated buffer is returned. If AllocationSize is 0, + then a valid buffer of 0 size is returned. If there is not enough memory at the specified + alignment remaining to satisfy the request, then NULL is returned. + If Alignment is not a power of two and Alignment is not zero, then ASSERT(). + + @param AllocationSize The number of bytes to allocate. + @param Alignment The requested alignment of the allocation. Must be a power of two. + If Alignment is zero, then byte alignment is used. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +UncachedAllocateAlignedRuntimePool ( + IN UINTN AllocationSize, + IN UINTN Alignment + ); + +/** + Allocates a buffer of type EfieservedMemoryType at a specified alignment. + + Allocates the number bytes specified by AllocationSize of type EfieservedMemoryType with an + alignment specified by Alignment. The allocated buffer is returned. If AllocationSize is 0, + then a valid buffer of 0 size is returned. If there is not enough memory at the specified + alignment remaining to satisfy the request, then NULL is returned. + If Alignment is not a power of two and Alignment is not zero, then ASSERT(). + + @param AllocationSize The number of bytes to allocate. + @param Alignment The requested alignment of the allocation. Must be a power of two. + If Alignment is zero, then byte alignment is used. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +UncachedAllocateAlignedReservedPool ( + IN UINTN AllocationSize, + IN UINTN Alignment + ); + +/** + Allocates and zeros a buffer of type EfiBootServicesData at a specified alignment. + + Allocates the number bytes specified by AllocationSize of type EfiBootServicesData with an + alignment specified by Alignment, clears the buffer with zeros, and returns a pointer to the + allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there + is not enough memory at the specified alignment remaining to satisfy the request, then NULL is + returned. + If Alignment is not a power of two and Alignment is not zero, then ASSERT(). + + @param AllocationSize The number of bytes to allocate. + @param Alignment The requested alignment of the allocation. Must be a power of two. + If Alignment is zero, then byte alignment is used. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +UncachedAllocateAlignedZeroPool ( + IN UINTN AllocationSize, + IN UINTN Alignment + ); + +/** + Allocates and zeros a buffer of type EfiRuntimeServicesData at a specified alignment. + + Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData with an + alignment specified by Alignment, clears the buffer with zeros, and returns a pointer to the + allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there + is not enough memory at the specified alignment remaining to satisfy the request, then NULL is + returned. + If Alignment is not a power of two and Alignment is not zero, then ASSERT(). + + @param AllocationSize The number of bytes to allocate. + @param Alignment The requested alignment of the allocation. Must be a power of two. + If Alignment is zero, then byte alignment is used. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +UncachedAllocateAlignedRuntimeZeroPool ( + IN UINTN AllocationSize, + IN UINTN Alignment + ); + +/** + Allocates and zeros a buffer of type EfieservedMemoryType at a specified alignment. + + Allocates the number bytes specified by AllocationSize of type EfieservedMemoryType with an + alignment specified by Alignment, clears the buffer with zeros, and returns a pointer to the + allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there + is not enough memory at the specified alignment remaining to satisfy the request, then NULL is + returned. + If Alignment is not a power of two and Alignment is not zero, then ASSERT(). + + @param AllocationSize The number of bytes to allocate. + @param Alignment The requested alignment of the allocation. Must be a power of two. + If Alignment is zero, then byte alignment is used. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +UncachedAllocateAlignedReservedZeroPool ( + IN UINTN AllocationSize, + IN UINTN Alignment + ); + +/** + Copies a buffer to an allocated buffer of type EfiBootServicesData at a specified alignment. + + Allocates the number bytes specified by AllocationSize of type EfiBootServicesData type with an + alignment specified by Alignment. The allocated buffer is returned. If AllocationSize is 0, + then a valid buffer of 0 size is returned. If there is not enough memory at the specified + alignment remaining to satisfy the request, then NULL is returned. + If Alignment is not a power of two and Alignment is not zero, then ASSERT(). + + @param AllocationSize The number of bytes to allocate. + @param Buffer The buffer to copy to the allocated buffer. + @param Alignment The requested alignment of the allocation. Must be a power of two. + If Alignment is zero, then byte alignment is used. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +UncachedAllocateAlignedCopyPool ( + IN UINTN AllocationSize, + IN CONST VOID *Buffer, + IN UINTN Alignment + ); + +/** + Copies a buffer to an allocated buffer of type EfiRuntimeServicesData at a specified alignment. + + Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData type with an + alignment specified by Alignment. The allocated buffer is returned. If AllocationSize is 0, + then a valid buffer of 0 size is returned. If there is not enough memory at the specified + alignment remaining to satisfy the request, then NULL is returned. + If Alignment is not a power of two and Alignment is not zero, then ASSERT(). + + @param AllocationSize The number of bytes to allocate. + @param Buffer The buffer to copy to the allocated buffer. + @param Alignment The requested alignment of the allocation. Must be a power of two. + If Alignment is zero, then byte alignment is used. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +UncachedAllocateAlignedRuntimeCopyPool ( + IN UINTN AllocationSize, + IN CONST VOID *Buffer, + IN UINTN Alignment + ); + +/** + Copies a buffer to an allocated buffer of type EfiReservedMemoryType at a specified alignment. + + Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType type with an + alignment specified by Alignment. The allocated buffer is returned. If AllocationSize is 0, + then a valid buffer of 0 size is returned. If there is not enough memory at the specified + alignment remaining to satisfy the request, then NULL is returned. + If Alignment is not a power of two and Alignment is not zero, then ASSERT(). + + @param AllocationSize The number of bytes to allocate. + @param Buffer The buffer to copy to the allocated buffer. + @param Alignment The requested alignment of the allocation. Must be a power of two. + If Alignment is zero, then byte alignment is used. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +UncachedAllocateAlignedReservedCopyPool ( + IN UINTN AllocationSize, + IN CONST VOID *Buffer, + IN UINTN Alignment + ); + +/** + Frees a buffer that was previously allocated with one of the aligned pool allocation functions + in the Memory Allocation Library. + + Frees the buffer specified by Buffer. Buffer must have been allocated on a previous call to the + aligned pool allocation services of the Memory Allocation Library. + If Buffer was not allocated with an aligned pool allocation function in the Memory Allocation + Library, then ASSERT(). + + @param Buffer Pointer to the buffer to free. + +**/ +VOID +EFIAPI +UncachedFreeAlignedPool ( + IN VOID *Buffer + ); + +VOID +EFIAPI +UncachedSafeFreePool ( + IN VOID *Buffer + ); + +#endif // __UNCACHED_MEMORY_ALLOCATION_LIB_H__ diff --git a/Platform/Hisilicon/HiKey/Library/ArmDmaLib/ArmDmaLib.c b/Platform/Hisilicon/HiKey/Library/ArmDmaLib/ArmDmaLib.c new file mode 100644 index 000000000..f4ee9e4c5 --- /dev/null +++ b/Platform/Hisilicon/HiKey/Library/ArmDmaLib/ArmDmaLib.c @@ -0,0 +1,342 @@ +/** @file + Generic ARM implementation of DmaLib.h + + Copyright (c) 2008 - 2010, Apple Inc. 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 + +typedef struct { + EFI_PHYSICAL_ADDRESS HostAddress; + VOID *BufferAddress; + UINTN NumberOfBytes; + DMA_MAP_OPERATION Operation; + BOOLEAN DoubleBuffer; +} MAP_INFO_INSTANCE; + + + +STATIC EFI_CPU_ARCH_PROTOCOL *mCpu; + +STATIC +PHYSICAL_ADDRESS +HostToDeviceAddress ( + IN PHYSICAL_ADDRESS HostAddress + ) +{ + return HostAddress + PcdGet64 (PcdArmDmaDeviceOffset); +} + +/** + Provides the DMA controller-specific addresses needed to access system memory. + + Operation is relative to the DMA bus master. + + @param Operation Indicates if the bus master is going to read or write to system memory. + @param HostAddress The system memory address to map to the DMA controller. + @param NumberOfBytes On input the number of bytes to map. On output the number of bytes + that were mapped. + @param DeviceAddress The resulting map address for the bus master controller to use to + access the hosts HostAddress. + @param Mapping A resulting value to pass to Unmap(). + + @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes. + @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_DEVICE_ERROR The system hardware could not map the requested address. + +**/ +EFI_STATUS +EFIAPI +DmaMap ( + IN DMA_MAP_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ) +{ + EFI_STATUS Status; + MAP_INFO_INSTANCE *Map; + VOID *Buffer; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor; + + if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress == NULL || Mapping == NULL ) { + return EFI_INVALID_PARAMETER; + } + + if (Operation >= MapOperationMaximum) { + return EFI_INVALID_PARAMETER; + } + + // + // The debug implementation of UncachedMemoryAllocationLib in ArmPkg returns + // a virtual uncached alias, and unmaps the cached ID mapping of the buffer, + // in order to catch inadvertent references to the cached mapping. + // Since HostToDeviceAddress () expects ID mapped input addresses, convert + // the host address to an ID mapped address first. + // + *DeviceAddress = HostToDeviceAddress (ConvertToPhysicalAddress (HostAddress)); + + // Remember range so we can flush on the other side + Map = AllocatePool (sizeof (MAP_INFO_INSTANCE)); + if (Map == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if ((((UINTN)HostAddress & (mCpu->DmaBufferAlignment - 1)) != 0) || + ((*NumberOfBytes & (mCpu->DmaBufferAlignment - 1)) != 0)) { + + // Get the cacheability of the region + Status = gDS->GetMemorySpaceDescriptor ((UINTN)HostAddress, &GcdDescriptor); + if (EFI_ERROR(Status)) { + goto FreeMapInfo; + } + + // If the mapped buffer is not an uncached buffer + if ((GcdDescriptor.Attributes & (EFI_MEMORY_WB | EFI_MEMORY_WT)) != 0) { + // + // Operations of type MapOperationBusMasterCommonBuffer are only allowed + // on uncached buffers. + // + if (Operation == MapOperationBusMasterCommonBuffer) { + DEBUG ((EFI_D_ERROR, + "%a: Operation type 'MapOperationBusMasterCommonBuffer' is only supported\n" + "on memory regions that were allocated using DmaAllocateBuffer ()\n", + __FUNCTION__)); + Status = EFI_UNSUPPORTED; + goto FreeMapInfo; + } + + // + // If the buffer does not fill entire cache lines we must double buffer into + // uncached memory. Device (PCI) address becomes uncached page. + // + Map->DoubleBuffer = TRUE; + Status = DmaAllocateBuffer (EfiBootServicesData, EFI_SIZE_TO_PAGES (*NumberOfBytes), &Buffer); + if (EFI_ERROR (Status)) { + goto FreeMapInfo; + } + + if (Operation == MapOperationBusMasterRead) { + CopyMem (Buffer, HostAddress, *NumberOfBytes); + } + + *DeviceAddress = HostToDeviceAddress (ConvertToPhysicalAddress (Buffer)); + Map->BufferAddress = Buffer; + } else { + Map->DoubleBuffer = FALSE; + } + } else { + Map->DoubleBuffer = FALSE; + + DEBUG_CODE_BEGIN (); + + // + // The operation type check above only executes if the buffer happens to be + // misaligned with respect to CWG, but even if it is aligned, we should not + // allow arbitrary buffers to be used for creating consistent mappings. + // So duplicate the check here when running in DEBUG mode, just to assert + // that we are not trying to create a consistent mapping for cached memory. + // + Status = gDS->GetMemorySpaceDescriptor ((UINTN)HostAddress, &GcdDescriptor); + ASSERT_EFI_ERROR(Status); + + ASSERT (Operation != MapOperationBusMasterCommonBuffer || + (GcdDescriptor.Attributes & (EFI_MEMORY_WB | EFI_MEMORY_WT)) == 0); + + DEBUG_CODE_END (); + + // Flush the Data Cache (should not have any effect if the memory region is uncached) + mCpu->FlushDataCache (mCpu, (UINTN)HostAddress, *NumberOfBytes, + EfiCpuFlushTypeWriteBackInvalidate); + } + + Map->HostAddress = (UINTN)HostAddress; + Map->NumberOfBytes = *NumberOfBytes; + Map->Operation = Operation; + + *Mapping = Map; + + return EFI_SUCCESS; + +FreeMapInfo: + FreePool (Map); + + return Status; +} + + +/** + Completes the DmaMapBusMasterRead(), DmaMapBusMasterWrite(), or DmaMapBusMasterCommonBuffer() + operation and releases any corresponding resources. + + @param Mapping The mapping value returned from DmaMap*(). + + @retval EFI_SUCCESS The range was unmapped. + @retval EFI_DEVICE_ERROR The data was not committed to the target system memory. + @retval EFI_INVALID_PARAMETER An inconsistency was detected between the mapping type + and the DoubleBuffer field + +**/ +EFI_STATUS +EFIAPI +DmaUnmap ( + IN VOID *Mapping + ) +{ + MAP_INFO_INSTANCE *Map; + EFI_STATUS Status; + + if (Mapping == NULL) { + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + Map = (MAP_INFO_INSTANCE *)Mapping; + + Status = EFI_SUCCESS; + if (Map->DoubleBuffer) { + ASSERT (Map->Operation != MapOperationBusMasterCommonBuffer); + + if (Map->Operation == MapOperationBusMasterCommonBuffer) { + Status = EFI_INVALID_PARAMETER; + } else if (Map->Operation == MapOperationBusMasterWrite) { + CopyMem ((VOID *)(UINTN)Map->HostAddress, Map->BufferAddress, + Map->NumberOfBytes); + } + + DmaFreeBuffer (EFI_SIZE_TO_PAGES (Map->NumberOfBytes), Map->BufferAddress); + + } else { + if (Map->Operation == MapOperationBusMasterWrite) { + // + // Make sure we read buffer from uncached memory and not the cache + // + mCpu->FlushDataCache (mCpu, Map->HostAddress, Map->NumberOfBytes, + EfiCpuFlushTypeInvalidate); + } + } + + FreePool (Map); + + return Status; +} + +/** + Allocates pages that are suitable for an DmaMap() of type MapOperationBusMasterCommonBuffer. + mapping. + + @param MemoryType The type of memory to allocate, EfiBootServicesData or + EfiRuntimeServicesData. + @param Pages The number of pages to allocate. + @param HostAddress A pointer to store the base system memory address of the + allocated range. + + @retval EFI_SUCCESS The requested memory pages were allocated. + @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are + MEMORY_WRITE_COMBINE and MEMORY_CACHED. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. + +**/ +EFI_STATUS +EFIAPI +DmaAllocateBuffer ( + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + OUT VOID **HostAddress + ) +{ + VOID *Allocation; + + if (HostAddress == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData + // + // We used uncached memory to keep coherency + // + if (MemoryType == EfiBootServicesData) { + Allocation = UncachedAllocatePages (Pages); + } else if (MemoryType == EfiRuntimeServicesData) { + Allocation = UncachedAllocateRuntimePages (Pages); + } else { + return EFI_INVALID_PARAMETER; + } + + if (Allocation == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + *HostAddress = Allocation; + + return EFI_SUCCESS; +} + + +/** + Frees memory that was allocated with DmaAllocateBuffer(). + + @param Pages The number of pages to free. + @param HostAddress The base system memory address of the allocated range. + + @retval EFI_SUCCESS The requested memory pages were freed. + @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages + was not allocated with DmaAllocateBuffer(). + +**/ +EFI_STATUS +EFIAPI +DmaFreeBuffer ( + IN UINTN Pages, + IN VOID *HostAddress + ) +{ + if (HostAddress == NULL) { + return EFI_INVALID_PARAMETER; + } + + UncachedFreePages (HostAddress, Pages); + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +ArmDmaLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + // Get the Cpu protocol for later use + Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&mCpu); + ASSERT_EFI_ERROR(Status); + + return Status; +} + diff --git a/Platform/Hisilicon/HiKey/Library/ArmDmaLib/ArmDmaLib.inf b/Platform/Hisilicon/HiKey/Library/ArmDmaLib/ArmDmaLib.inf new file mode 100644 index 000000000..9b7dad114 --- /dev/null +++ b/Platform/Hisilicon/HiKey/Library/ArmDmaLib/ArmDmaLib.inf @@ -0,0 +1,50 @@ +#/** @file +# +# Copyright (c) 2008 - 2010, Apple Inc. 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 = 0x00010005 + BASE_NAME = ArmDmaLib + FILE_GUID = F1BD6B36-B705-43aa-8A28-33F58ED85EFB + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = DmaLib + CONSTRUCTOR = ArmDmaLibConstructor + +[Sources.common] + ArmDmaLib.c + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + ArmPkg/ArmPkg.dec + + +[LibraryClasses] + DebugLib + DxeServicesTableLib + UefiBootServicesTableLib + MemoryAllocationLib + UncachedMemoryAllocationLib + IoLib + BaseMemoryLib + +[Protocols] + gEfiCpuArchProtocolGuid + +[Guids] + +[Pcd] + gArmTokenSpaceGuid.PcdArmDmaDeviceOffset + +[Depex] + gEfiCpuArchProtocolGuid diff --git a/Platform/Hisilicon/HiKey/Library/UncachedMemoryAllocationLib/UncachedMemoryAllocationLib.c b/Platform/Hisilicon/HiKey/Library/UncachedMemoryAllocationLib/UncachedMemoryAllocationLib.c new file mode 100644 index 000000000..f6c692f9a --- /dev/null +++ b/Platform/Hisilicon/HiKey/Library/UncachedMemoryAllocationLib/UncachedMemoryAllocationLib.c @@ -0,0 +1,692 @@ +/** @file + UncachedMemoryAllocation lib that uses DXE Service to change cachability for + a buffer. + + Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
+ Copyright (c) 2014, AMR Ltd. 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 + +VOID * +UncachedInternalAllocatePages ( + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages + ); + +VOID * +UncachedInternalAllocateAlignedPages ( + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + IN UINTN Alignment + ); + + + +// +// Assume all of memory has the same cache attributes, unless we do our magic +// +UINT64 gAttributes; + +typedef struct { + EFI_PHYSICAL_ADDRESS Base; + VOID *Allocation; + UINTN Pages; + EFI_MEMORY_TYPE MemoryType; + BOOLEAN Allocated; + LIST_ENTRY Link; +} FREE_PAGE_NODE; + +STATIC LIST_ENTRY mPageList = INITIALIZE_LIST_HEAD_VARIABLE (mPageList); +// Track the size of the non-allocated buffer in the linked-list +STATIC UINTN mFreedBufferSize = 0; + +/** + * This function firstly checks if the requested allocation can fit into one + * of the previously allocated buffer. + * If the requested allocation does not fit in the existing pool then + * the function makes a new allocation. + * + * @param MemoryType Type of memory requested for the new allocation + * @param Pages Number of requested page + * @param Alignment Required alignment + * @param Allocation Address of the newly allocated buffer + * + * @return EFI_SUCCESS If the function manage to allocate a buffer + * @return !EFI_SUCCESS If the function did not manage to allocate a buffer + */ +STATIC +EFI_STATUS +AllocatePagesFromList ( + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + IN UINTN Alignment, + OUT VOID **Allocation + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + FREE_PAGE_NODE *Node; + FREE_PAGE_NODE *NewNode; + UINTN AlignmentMask; + EFI_PHYSICAL_ADDRESS Memory; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor; + + // Alignment must be a power of two or zero. + ASSERT ((Alignment & (Alignment - 1)) == 0); + + // + // Look in our list for the smallest page that could satisfy the new allocation + // + Node = NULL; + NewNode = NULL; + for (Link = mPageList.ForwardLink; Link != &mPageList; Link = Link->ForwardLink) { + Node = BASE_CR (Link, FREE_PAGE_NODE, Link); + if ((Node->Allocated == FALSE) && (Node->MemoryType == MemoryType)) { + // We have a node that fits our requirements + if (((UINTN)Node->Base & (Alignment - 1)) == 0) { + // We found a page that matches the page size + if (Node->Pages == Pages) { + Node->Allocated = TRUE; + Node->Allocation = (VOID*)(UINTN)Node->Base; + *Allocation = Node->Allocation; + + // Update the size of the freed buffer + mFreedBufferSize -= Pages * EFI_PAGE_SIZE; + return EFI_SUCCESS; + } else if (Node->Pages > Pages) { + if (NewNode == NULL) { + // It is the first node that could contain our new allocation + NewNode = Node; + } else if (NewNode->Pages > Node->Pages) { + // This node offers a smaller number of page. + NewNode = Node; + } + } + } + } + } + // Check if we have found a node that could contain our new allocation + if (NewNode != NULL) { + NewNode->Allocated = TRUE; + NewNode->Allocation = (VOID*)(UINTN)NewNode->Base; + *Allocation = NewNode->Allocation; + mFreedBufferSize -= NewNode->Pages * EFI_PAGE_SIZE; + return EFI_SUCCESS; + } + + // + // Otherwise, we need to allocate a new buffer + // + + // We do not want to over-allocate in case the alignment requirement does not + // require extra pages + if (Alignment > EFI_PAGE_SIZE) { + AlignmentMask = Alignment - 1; + Pages += EFI_SIZE_TO_PAGES (Alignment); + } else { + AlignmentMask = 0; + } + + Status = gBS->AllocatePages (AllocateAnyPages, MemoryType, Pages, &Memory); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gDS->GetMemorySpaceDescriptor (Memory, &Descriptor); + if (!EFI_ERROR (Status)) { + // We are making an assumption that all of memory has the same default attributes + gAttributes = Descriptor.Attributes; + } else { + gBS->FreePages (Memory, Pages); + return Status; + } + + Status = gDS->SetMemorySpaceAttributes (Memory, EFI_PAGES_TO_SIZE (Pages), EFI_MEMORY_WC); + if (EFI_ERROR (Status)) { + gBS->FreePages (Memory, Pages); + return Status; + } + + InvalidateDataCacheRange ((VOID *)(UINTN)Memory, EFI_PAGES_TO_SIZE (Pages)); + + NewNode = AllocatePool (sizeof (FREE_PAGE_NODE)); + if (NewNode == NULL) { + ASSERT (FALSE); + gBS->FreePages (Memory, Pages); + return EFI_OUT_OF_RESOURCES; + } + + NewNode->Base = Memory; + NewNode->Allocation = (VOID*)(((UINTN)Memory + AlignmentMask) & ~AlignmentMask); + NewNode->Pages = Pages; + NewNode->Allocated = TRUE; + NewNode->MemoryType = MemoryType; + + InsertTailList (&mPageList, &NewNode->Link); + + *Allocation = NewNode->Allocation; + return EFI_SUCCESS; +} + +/** + * Free the memory allocation + * + * This function will actually try to find the allocation in the linked list. + * And it will then mark the entry as freed. + * + * @param Allocation Base address of the buffer to free + * + * @return EFI_SUCCESS The allocation has been freed + * @return EFI_NOT_FOUND The allocation was not found in the pool. + * @return EFI_INVALID_PARAMETER If Allocation is NULL + * + */ +STATIC +EFI_STATUS +FreePagesFromList ( + IN VOID *Allocation + ) +{ + LIST_ENTRY *Link; + FREE_PAGE_NODE *Node; + + if (Allocation == NULL) { + return EFI_INVALID_PARAMETER; + } + + for (Link = mPageList.ForwardLink; Link != &mPageList; Link = Link->ForwardLink) { + Node = BASE_CR (Link, FREE_PAGE_NODE, Link); + if ((UINTN)Node->Allocation == (UINTN)Allocation) { + Node->Allocated = FALSE; + + // Update the size of the freed buffer + mFreedBufferSize += Node->Pages * EFI_PAGE_SIZE; + + // If the size of the non-allocated reaches the threshold we raise a warning. + // It might be an expected behaviour in some cases. + // We might device to free some of these buffers later on. + if (mFreedBufferSize > PcdGet64 (PcdArmFreeUncachedMemorySizeThreshold)) { + DEBUG ((EFI_D_WARN, "Warning: The list of non-allocated buffer has reach the threshold.\n")); + } + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +/** + * This function is automatically invoked when the driver exits + * It frees all the non-allocated memory buffer. + * This function is not responsible to free allocated buffer (eg: case of memory leak, + * runtime allocation). + */ +EFI_STATUS +EFIAPI +UncachedMemoryAllocationLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + LIST_ENTRY *Link; + FREE_PAGE_NODE *OldNode; + + // Test if the list is empty + Link = mPageList.ForwardLink; + if (Link == &mPageList) { + return EFI_SUCCESS; + } + + // Free all the pages and nodes + do { + OldNode = BASE_CR (Link, FREE_PAGE_NODE, Link); + // Point to the next entry + Link = Link->ForwardLink; + + // We only free the non-allocated buffer + if (OldNode->Allocated == FALSE) { + gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)OldNode->Base, OldNode->Pages); + RemoveEntryList (&OldNode->Link); + FreePool (OldNode); + } + } while (Link != &mPageList); + + return EFI_SUCCESS; +} + +/** + Converts a cached or uncached address to a physical address suitable for use in SoC registers. + + @param VirtualAddress The pointer to convert. + + @return The physical address of the supplied virtual pointer. + +**/ +EFI_PHYSICAL_ADDRESS +ConvertToPhysicalAddress ( + IN VOID *VirtualAddress + ) +{ + return (EFI_PHYSICAL_ADDRESS)(UINTN)VirtualAddress; +} + + +VOID * +UncachedInternalAllocatePages ( + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages + ) +{ + return UncachedInternalAllocateAlignedPages (MemoryType, Pages, EFI_PAGE_SIZE); +} + + +VOID * +EFIAPI +UncachedAllocatePages ( + IN UINTN Pages + ) +{ + return UncachedInternalAllocatePages (EfiBootServicesData, Pages); +} + +VOID * +EFIAPI +UncachedAllocateRuntimePages ( + IN UINTN Pages + ) +{ + return UncachedInternalAllocatePages (EfiRuntimeServicesData, Pages); +} + +VOID * +EFIAPI +UncachedAllocateReservedPages ( + IN UINTN Pages + ) +{ + return UncachedInternalAllocatePages (EfiReservedMemoryType, Pages); +} + + + +VOID +EFIAPI +UncachedFreePages ( + IN VOID *Buffer, + IN UINTN Pages + ) +{ + UncachedFreeAlignedPages (Buffer, Pages); + return; +} + + +VOID * +UncachedInternalAllocateAlignedPages ( + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + IN UINTN Alignment + ) +{ + EFI_STATUS Status; + VOID *Allocation; + + if (Pages == 0) { + return NULL; + } + + Allocation = NULL; + Status = AllocatePagesFromList (MemoryType, Pages, Alignment, &Allocation); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return NULL; + } else { + return Allocation; + } +} + + +VOID +EFIAPI +UncachedFreeAlignedPages ( + IN VOID *Buffer, + IN UINTN Pages + ) +{ + FreePagesFromList (Buffer); +} + + +VOID * +UncachedInternalAllocateAlignedPool ( + IN EFI_MEMORY_TYPE PoolType, + IN UINTN AllocationSize, + IN UINTN Alignment + ) +{ + VOID *AlignedAddress; + + // + // Alignment must be a power of two or zero. + // + ASSERT ((Alignment & (Alignment - 1)) == 0); + + if (Alignment < EFI_PAGE_SIZE) { + Alignment = EFI_PAGE_SIZE; + } + + AlignedAddress = UncachedInternalAllocateAlignedPages (PoolType, EFI_SIZE_TO_PAGES (AllocationSize), Alignment); + if (AlignedAddress == NULL) { + return NULL; + } + + return (VOID *) AlignedAddress; +} + +VOID * +EFIAPI +UncachedAllocateAlignedPool ( + IN UINTN AllocationSize, + IN UINTN Alignment + ) +{ + return UncachedInternalAllocateAlignedPool (EfiBootServicesData, AllocationSize, Alignment); +} + +VOID * +EFIAPI +UncachedAllocateAlignedRuntimePool ( + IN UINTN AllocationSize, + IN UINTN Alignment + ) +{ + return UncachedInternalAllocateAlignedPool (EfiRuntimeServicesData, AllocationSize, Alignment); +} + +VOID * +EFIAPI +UncachedAllocateAlignedReservedPool ( + IN UINTN AllocationSize, + IN UINTN Alignment + ) +{ + return UncachedInternalAllocateAlignedPool (EfiReservedMemoryType, AllocationSize, Alignment); +} + +VOID * +UncachedInternalAllocateAlignedZeroPool ( + IN EFI_MEMORY_TYPE PoolType, + IN UINTN AllocationSize, + IN UINTN Alignment + ) +{ + VOID *Memory; + Memory = UncachedInternalAllocateAlignedPool (PoolType, AllocationSize, Alignment); + if (Memory != NULL) { + Memory = ZeroMem (Memory, AllocationSize); + } + return Memory; +} + +VOID * +EFIAPI +UncachedAllocateAlignedZeroPool ( + IN UINTN AllocationSize, + IN UINTN Alignment + ) +{ + return UncachedInternalAllocateAlignedZeroPool (EfiBootServicesData, AllocationSize, Alignment); +} + +VOID * +EFIAPI +UncachedAllocateAlignedRuntimeZeroPool ( + IN UINTN AllocationSize, + IN UINTN Alignment + ) +{ + return UncachedInternalAllocateAlignedZeroPool (EfiRuntimeServicesData, AllocationSize, Alignment); +} + +VOID * +EFIAPI +UncachedAllocateAlignedReservedZeroPool ( + IN UINTN AllocationSize, + IN UINTN Alignment + ) +{ + return UncachedInternalAllocateAlignedZeroPool (EfiReservedMemoryType, AllocationSize, Alignment); +} + +VOID * +UncachedInternalAllocateAlignedCopyPool ( + IN EFI_MEMORY_TYPE PoolType, + IN UINTN AllocationSize, + IN CONST VOID *Buffer, + IN UINTN Alignment + ) +{ + VOID *Memory; + + ASSERT (Buffer != NULL); + ASSERT (AllocationSize <= (MAX_ADDRESS - (UINTN) Buffer + 1)); + + Memory = UncachedInternalAllocateAlignedPool (PoolType, AllocationSize, Alignment); + if (Memory != NULL) { + Memory = CopyMem (Memory, Buffer, AllocationSize); + } + return Memory; +} + +VOID * +EFIAPI +UncachedAllocateAlignedCopyPool ( + IN UINTN AllocationSize, + IN CONST VOID *Buffer, + IN UINTN Alignment + ) +{ + return UncachedInternalAllocateAlignedCopyPool (EfiBootServicesData, AllocationSize, Buffer, Alignment); +} + +VOID * +EFIAPI +UncachedAllocateAlignedRuntimeCopyPool ( + IN UINTN AllocationSize, + IN CONST VOID *Buffer, + IN UINTN Alignment + ) +{ + return UncachedInternalAllocateAlignedCopyPool (EfiRuntimeServicesData, AllocationSize, Buffer, Alignment); +} + +VOID * +EFIAPI +UncachedAllocateAlignedReservedCopyPool ( + IN UINTN AllocationSize, + IN CONST VOID *Buffer, + IN UINTN Alignment + ) +{ + return UncachedInternalAllocateAlignedCopyPool (EfiReservedMemoryType, AllocationSize, Buffer, Alignment); +} + +VOID +EFIAPI +UncachedFreeAlignedPool ( + IN VOID *Allocation + ) +{ + UncachedFreePages (Allocation, 0); +} + +VOID * +UncachedInternalAllocatePool ( + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN AllocationSize + ) +{ + UINTN CacheLineLength = ArmDataCacheLineLength (); + return UncachedInternalAllocateAlignedPool (MemoryType, AllocationSize, CacheLineLength); +} + +VOID * +EFIAPI +UncachedAllocatePool ( + IN UINTN AllocationSize + ) +{ + return UncachedInternalAllocatePool (EfiBootServicesData, AllocationSize); +} + +VOID * +EFIAPI +UncachedAllocateRuntimePool ( + IN UINTN AllocationSize + ) +{ + return UncachedInternalAllocatePool (EfiRuntimeServicesData, AllocationSize); +} + +VOID * +EFIAPI +UncachedAllocateReservedPool ( + IN UINTN AllocationSize + ) +{ + return UncachedInternalAllocatePool (EfiReservedMemoryType, AllocationSize); +} + +VOID * +UncachedInternalAllocateZeroPool ( + IN EFI_MEMORY_TYPE PoolType, + IN UINTN AllocationSize + ) +{ + VOID *Memory; + + Memory = UncachedInternalAllocatePool (PoolType, AllocationSize); + if (Memory != NULL) { + Memory = ZeroMem (Memory, AllocationSize); + } + return Memory; +} + +VOID * +EFIAPI +UncachedAllocateZeroPool ( + IN UINTN AllocationSize + ) +{ + return UncachedInternalAllocateZeroPool (EfiBootServicesData, AllocationSize); +} + +VOID * +EFIAPI +UncachedAllocateRuntimeZeroPool ( + IN UINTN AllocationSize + ) +{ + return UncachedInternalAllocateZeroPool (EfiRuntimeServicesData, AllocationSize); +} + +VOID * +EFIAPI +UncachedAllocateReservedZeroPool ( + IN UINTN AllocationSize + ) +{ + return UncachedInternalAllocateZeroPool (EfiReservedMemoryType, AllocationSize); +} + +VOID * +UncachedInternalAllocateCopyPool ( + IN EFI_MEMORY_TYPE PoolType, + IN UINTN AllocationSize, + IN CONST VOID *Buffer + ) +{ + VOID *Memory; + + ASSERT (Buffer != NULL); + ASSERT (AllocationSize <= (MAX_ADDRESS - (UINTN) Buffer + 1)); + + Memory = UncachedInternalAllocatePool (PoolType, AllocationSize); + if (Memory != NULL) { + Memory = CopyMem (Memory, Buffer, AllocationSize); + } + return Memory; +} + +VOID * +EFIAPI +UncachedAllocateCopyPool ( + IN UINTN AllocationSize, + IN CONST VOID *Buffer + ) +{ + return UncachedInternalAllocateCopyPool (EfiBootServicesData, AllocationSize, Buffer); +} + +VOID * +EFIAPI +UncachedAllocateRuntimeCopyPool ( + IN UINTN AllocationSize, + IN CONST VOID *Buffer + ) +{ + return UncachedInternalAllocateCopyPool (EfiRuntimeServicesData, AllocationSize, Buffer); +} + +VOID * +EFIAPI +UncachedAllocateReservedCopyPool ( + IN UINTN AllocationSize, + IN CONST VOID *Buffer + ) +{ + return UncachedInternalAllocateCopyPool (EfiReservedMemoryType, AllocationSize, Buffer); +} + +VOID +EFIAPI +UncachedFreePool ( + IN VOID *Buffer + ) +{ + UncachedFreeAlignedPool (Buffer); +} + +VOID +EFIAPI +UncachedSafeFreePool ( + IN VOID *Buffer + ) +{ + if (Buffer != NULL) { + UncachedFreePool (Buffer); + Buffer = NULL; + } +} + diff --git a/Platform/Hisilicon/HiKey/Library/UncachedMemoryAllocationLib/UncachedMemoryAllocationLib.inf b/Platform/Hisilicon/HiKey/Library/UncachedMemoryAllocationLib/UncachedMemoryAllocationLib.inf new file mode 100644 index 000000000..64edc32cf --- /dev/null +++ b/Platform/Hisilicon/HiKey/Library/UncachedMemoryAllocationLib/UncachedMemoryAllocationLib.inf @@ -0,0 +1,45 @@ +#/** @file +# +# UncachedMemoryAllocation lib that uses DXE Service to change cachability for +# a buffer. +# +# Copyright (c) 2008 - 2010, Apple Inc. 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 = 0x00010005 + BASE_NAME = UncachedMemoryAllocationLib + FILE_GUID = DC101A1A-7525-429B-84AF-EEAA630E576C + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = UncachedMemoryAllocationLib + + DESTRUCTOR = UncachedMemoryAllocationLibDestructor + +[Sources.common] + UncachedMemoryAllocationLib.c + +[Packages] + ArmPkg/ArmPkg.dec + MdePkg/MdePkg.dec + Platform/Hisilicon/HiKey/HiKey.dec + +[LibraryClasses] + BaseLib + ArmLib + MemoryAllocationLib + PcdLib + DxeServicesTableLib + CacheMaintenanceLib + +[Pcd] + gArmTokenSpaceGuid.PcdArmFreeUncachedMemorySizeThreshold diff --git a/Silicon/Synopsys/Usb/DwNonPci/DwNonPciUsbDxe.inf b/Silicon/Synopsys/Usb/DwNonPci/DwNonPciUsbDxe.inf new file mode 100644 index 000000000..0211c937f --- /dev/null +++ b/Silicon/Synopsys/Usb/DwNonPci/DwNonPciUsbDxe.inf @@ -0,0 +1,47 @@ +## @file +# +# Initialize Designware USB controller via dummy PCI device +# +# Copyright (c) 2016, Linaro, Ltd. All rights reserved.
+# Copyright (c) 2016, Jeremy Linton +# +# 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 = DwNonPcieUsbDxe + FILE_GUID = 298e1629-54bb-4763-8c66-e43f934a555d + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = DwNonPciUsbDxeEntryPoint + +[Sources] + InitController.c + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Silicon/Synopsys/Usb/DwUsbDxe/DwUsbDxe.dec + +[LibraryClasses] + BaseLib + DebugLib + IoLib + NonDiscoverableDeviceRegistrationLib + UefiBootServicesTableLib + UefiDriverEntryPoint + +[Pcd] + gDwUsbDxeTokenSpaceGuid.PcdDwUsbBaseAddress + gDwUsbDxeTokenSpaceGuid.PcdDwUsbSysCtrlBaseAddress + +[Depex] + TRUE diff --git a/Silicon/Synopsys/Usb/DwNonPci/InitController.c b/Silicon/Synopsys/Usb/DwNonPci/InitController.c new file mode 100644 index 000000000..832d9dcaf --- /dev/null +++ b/Silicon/Synopsys/Usb/DwNonPci/InitController.c @@ -0,0 +1,37 @@ +/** @file + Initialize Designware USB controller via dummy PCI device + + Copyright (c) 2016, Linaro, Ltd. All rights reserved.
+ Copyright (c) 2016, Jeremy Linton + + 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 + +EFI_STATUS +EFIAPI +DwNonPciUsbDxeEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + DEBUG ((EFI_D_ERROR, "DwUsbExportController \n")); + return RegisterNonDiscoverableMmioDevice ( + NonDiscoverableDeviceTypeEhci, + NonDiscoverableDeviceDmaTypeNonCoherent, + NULL, + NULL, + 1, + FixedPcdGet32 (PcdDwUsbBaseAddress), SIZE_256KB, + FixedPcdGet32 (PcdDwUsbSysCtrlBaseAddress), SIZE_8KB); +} diff --git a/Silicon/Synopsys/Usb/DwUsbDxe/ComponentName.c b/Silicon/Synopsys/Usb/DwUsbDxe/ComponentName.c new file mode 100644 index 000000000..53a65bb9b --- /dev/null +++ b/Silicon/Synopsys/Usb/DwUsbDxe/ComponentName.c @@ -0,0 +1,244 @@ +/** @file +UEFI Component Name and Name2 protocol for Designware USB driver. + +Copyright (c) 2013-2015 Intel Corporation. +Copyright (c) 2017 Jeremy Linton + +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 "Ohci.h" +#include "ComponentName.h" +#include "DwUsbDxe.h" + +// +// EFI Component Name Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gOhciComponentName = { + OhciComponentNameGetDriverName, + OhciComponentNameGetControllerName, + "eng" +}; + +// +// EFI Component Name 2 Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gOhciComponentName2 = { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) OhciComponentNameGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) OhciComponentNameGetControllerName, + "en" +}; + + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mOhciDriverNameTable[] = { + { "eng;en", L"Designware Usb Driver" }, + { NULL, NULL } +}; + + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +OhciComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mOhciDriverNameTable, + DriverName, + (BOOLEAN)(This == &gOhciComponentName) + ); +} + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +OhciComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +{ + EFI_STATUS Status; + USB_OHCI_HC_DEV *OhciDev; + EFI_USB_HC_PROTOCOL *UsbHc; + + // + // This is a device driver, so ChildHandle must be NULL. + // + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + // + // Make sure this driver is currently managing ControllerHandle + // +/* Status = EfiTestManagedDevice ( + ControllerHandle, + gOhciDriverBinding.DriverBindingHandle, + &gEfiPciIoProtocolGuid + ); + if (EFI_ERROR (Status)) { + return Status; +}*/ + // + // Get the device context + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUsbHcProtocolGuid, + (VOID **) &UsbHc, + gOhciDriverBinding.DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + OhciDev = USB_OHCI_HC_DEV_FROM_THIS (UsbHc); + + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + OhciDev->ControllerNameTable, + ControllerName, + (BOOLEAN)(This == &gOhciComponentName) + ); + +} diff --git a/Silicon/Synopsys/Usb/DwUsbDxe/ComponentName.h b/Silicon/Synopsys/Usb/DwUsbDxe/ComponentName.h new file mode 100644 index 000000000..cfc660334 --- /dev/null +++ b/Silicon/Synopsys/Usb/DwUsbDxe/ComponentName.h @@ -0,0 +1,148 @@ +/** @file +UEFI Component Name and Name2 protocol for Designware USB driver. + +Copyright (c) 2013-2015 Intel Corporation. +Copyright (c) 2017 Jeremy Linton + +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 _COMPONENT_NAME_H_ +#define _COMPONENT_NAME_H_ + + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +OhciComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +OhciComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +#endif + diff --git a/Silicon/Synopsys/Usb/DwUsbDxe/DwUsbDxe.c b/Silicon/Synopsys/Usb/DwUsbDxe/DwUsbDxe.c new file mode 100644 index 000000000..6903112f9 --- /dev/null +++ b/Silicon/Synopsys/Usb/DwUsbDxe/DwUsbDxe.c @@ -0,0 +1,2324 @@ +/** @file + + Copyright (c) 2015, Linaro Limited. All rights reserved. + Copyright (c) 2015, Hisilicon Limited. All rights reserved. + Copyright (c) 2017, Jeremy Linton. 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 +#include +#include + +#include "DwUsbDxe.h" +#include "Hi6220.h" + +// Blah, the existing hikey driver only works in OTG mode (aka its an endpoint device for fastboot) +// out of the box this driver configures a made up protocol which +// setups the port to act as a fastboot programming taget. This sucks! +#ifdef NOTACTIVE + +STATIC dwc_otg_dev_dma_desc_t *g_dma_desc,*g_dma_desc_ep0,*g_dma_desc_in; +STATIC USB_DEVICE_REQUEST *p_ctrlreq; +STATIC VOID *rx_buf; +STATIC UINT32 rx_desc_bytes = 0; +STATIC UINTN mNumDataBytes; + +#define USB_BLOCK_HIGH_SPEED_SIZE 512 +#define DATA_SIZE 32768 +#define CMD_SIZE 512 +#define MATCH_CMD_LITERAL(Cmd, Buf) !AsciiStrnCmp (Cmd, Buf, sizeof (Cmd) - 1) + + + +STATIC USB_DEVICE_DESCRIPTOR *mDeviceDescriptor; + +// The config descriptor, interface descriptor, and endpoint descriptors in a +// buffer (in that order) +STATIC VOID *mDescriptors; +// Convenience pointers to those descriptors inside the buffer: +STATIC USB_INTERFACE_DESCRIPTOR *mInterfaceDescriptor; +STATIC USB_CONFIG_DESCRIPTOR *mConfigDescriptor; +STATIC USB_ENDPOINT_DESCRIPTOR *mEndpointDescriptors; + +STATIC USB_DEVICE_RX_CALLBACK mDataReceivedCallback; +STATIC USB_DEVICE_TX_CALLBACK mDataSentCallback; + +STATIC EFI_USB_STRING_DESCRIPTOR mLangStringDescriptor = { + 4, + USB_DESC_TYPE_STRING, + {0x409} +}; + + +// The time between interrupt polls, in units of 100 nanoseconds +// 10 Microseconds +#define DW_INTERRUPT_POLL_PERIOD 10000 +STATIC int usb_drv_port_speed(void) /*To detect which mode was run, high speed or full speed*/ +{ + /* + * 2'b00: High speed (PHY clock is running at 30 or 60 MHz) + */ + UINT32 val = READ_REG32(DSTS) & 2; + return (!val); +} + + + +STATIC VOID reset_endpoints(void) +{ + /* EP0 IN ACTIVE NEXT=1 */ + WRITE_REG32(DIEPCTL0, 0x8800); + + /* EP0 OUT ACTIVE */ + WRITE_REG32(DOEPCTL0, 0x8000); + + /* Clear any pending OTG Interrupts */ + WRITE_REG32(GOTGINT, 0xFFFFFFFF); + + /* Clear any pending interrupts */ + WRITE_REG32(GINTSTS, 0xFFFFFFFF); + WRITE_REG32(DIEPINT0, 0xFFFFFFFF); + WRITE_REG32(DOEPINT0, 0xFFFFFFFF); + WRITE_REG32(DIEPINT1, 0xFFFFFFFF); + WRITE_REG32(DOEPINT1, 0xFFFFFFFF); + + /* IN EP interrupt mask */ + WRITE_REG32(DIEPMSK, 0x0D); + /* OUT EP interrupt mask */ + WRITE_REG32(DOEPMSK, 0x0D); + /* Enable interrupts on Ep0 */ + WRITE_REG32(DAINTMSK, 0x00010001); + + /* EP0 OUT Transfer Size:64 Bytes, 1 Packet, 3 Setup Packet, Read to receive setup packet*/ + WRITE_REG32(DOEPTSIZ0, 0x60080040); + + //notes that:the compulsive conversion is expectable. + g_dma_desc_ep0->status.b.bs = 0x3; + g_dma_desc_ep0->status.b.mtrf = 0; + g_dma_desc_ep0->status.b.sr = 0; + g_dma_desc_ep0->status.b.l = 1; + g_dma_desc_ep0->status.b.ioc = 1; + g_dma_desc_ep0->status.b.sp = 0; + g_dma_desc_ep0->status.b.bytes = 64; + g_dma_desc_ep0->buf = (UINT32)(UINTN)(p_ctrlreq); + g_dma_desc_ep0->status.b.sts = 0; + g_dma_desc_ep0->status.b.bs = 0x0; + WRITE_REG32(DOEPDMA0, (unsigned long)(g_dma_desc_ep0)); + /* EP0 OUT ENABLE CLEARNAK */ + WRITE_REG32(DOEPCTL0, (READ_REG32(DOEPCTL0) | 0x84000000)); +} + +STATIC VOID ep_tx(IN UINT8 ep, CONST VOID *ptr, UINT32 len) +{ + UINT32 blocksize; + UINT32 packets; + + /* EPx OUT ACTIVE */ + WRITE_REG32(DIEPCTL(ep), (READ_REG32(DIEPCTL(ep))) | 0x8000); + if(!ep) { + blocksize = 64; + } else { + blocksize = usb_drv_port_speed() ? USB_BLOCK_HIGH_SPEED_SIZE : 64; + } + packets = (len + blocksize - 1) / blocksize; + + if (!len) { //send a null packet + /* one empty packet */ + g_dma_desc_in->status.b.bs = 0x3; + g_dma_desc_in->status.b.l = 1; + g_dma_desc_in->status.b.ioc = 1; + g_dma_desc_in->status.b.sp = 1; + g_dma_desc_in->status.b.bytes = 0; + g_dma_desc_in->buf = 0; + g_dma_desc_in->status.b.sts = 0; + g_dma_desc_in->status.b.bs = 0x0; + + WRITE_REG32(DIEPDMA(ep), (unsigned long)(g_dma_desc_in)); // DMA Address (DMAAddr) is zero + } else { //prepare to send a packet + /*WRITE_REG32((len | (packets << 19)), DIEPTSIZ(ep));*/ // packets+transfer size + WRITE_REG32(DIEPTSIZ(ep), len | (packets << 19)); + + //flush cache + WriteBackDataCacheRange ((void*)ptr, len); + + g_dma_desc_in->status.b.bs = 0x3; + g_dma_desc_in->status.b.l = 1; + g_dma_desc_in->status.b.ioc = 1; + g_dma_desc_in->status.b.sp = 1; + g_dma_desc_in->status.b.bytes = len; + g_dma_desc_in->buf = (UINT32)((UINTN)ptr); + g_dma_desc_in->status.b.sts = 0; + g_dma_desc_in->status.b.bs = 0x0; + WRITE_REG32(DIEPDMA(ep), (unsigned long)(g_dma_desc_in)); // ptr is DMA address + } + asm("dsb sy"); + asm("isb sy"); + /* epena & cnak*/ + WRITE_REG32(DIEPCTL(ep), READ_REG32(DIEPCTL(ep)) | 0x84000800); + return; +} + +STATIC VOID ep_rx(unsigned ep, UINT32 len) +{ + /* EPx UNSTALL */ + WRITE_REG32(DOEPCTL(ep), ((READ_REG32(DOEPCTL(ep))) & (~0x00200000))); + /* EPx OUT ACTIVE */ + WRITE_REG32(DOEPCTL(ep), (READ_REG32(DOEPCTL(ep)) | 0x8000)); + + if (len >= DATA_SIZE) + rx_desc_bytes = DATA_SIZE; + else + rx_desc_bytes = len; + + rx_buf = AllocatePool (DATA_SIZE); + ASSERT (rx_buf != NULL); + + InvalidateDataCacheRange (rx_buf, len); + + g_dma_desc->status.b.bs = 0x3; + g_dma_desc->status.b.mtrf = 0; + g_dma_desc->status.b.sr = 0; + g_dma_desc->status.b.l = 1; + g_dma_desc->status.b.ioc = 1; + g_dma_desc->status.b.sp = 0; + g_dma_desc->status.b.bytes = rx_desc_bytes; + g_dma_desc->buf = (UINT32)((UINTN)rx_buf); + g_dma_desc->status.b.sts = 0; + g_dma_desc->status.b.bs = 0x0; + + asm("dsb sy"); + asm("isb sy"); + WRITE_REG32(DOEPDMA(ep), (UINT32)((UINTN)g_dma_desc)); + /* EPx OUT ENABLE CLEARNAK */ + WRITE_REG32(DOEPCTL(ep), (READ_REG32(DOEPCTL(ep)) | 0x84000000)); +} + +STATIC +EFI_STATUS +HandleGetDescriptor ( + IN USB_DEVICE_REQUEST *Request + ) +{ + UINT8 DescriptorType; + UINTN ResponseSize; + VOID *ResponseData; +// CHAR16 SerialNo[16]; +// UINTN SerialNoLen; +// EFI_STATUS Status; + + ResponseSize = 0; + ResponseData = NULL; + + // Pretty confused if bmRequestType is anything but this: + ASSERT (Request->RequestType == USB_DEV_GET_DESCRIPTOR_REQ_TYPE); + + // Choose the response + DescriptorType = Request->Value >> 8; + switch (DescriptorType) { + case USB_DESC_TYPE_DEVICE: + DEBUG ((EFI_D_ERROR, "USB: Got a request for device descriptor\n")); + ResponseSize = sizeof (USB_DEVICE_DESCRIPTOR); + ResponseData = mDeviceDescriptor; + break; + case USB_DESC_TYPE_CONFIG: + DEBUG ((EFI_D_ERROR, "USB: Got a request for config descriptor\n")); + ResponseSize = mConfigDescriptor->TotalLength; + ResponseData = mDescriptors; + break; + case USB_DESC_TYPE_STRING: + DEBUG ((EFI_D_ERROR, "USB: Got a request for String descriptor %d\n", Request->Value & 0xFF)); + switch (Request->Value & 0xff) { + case 0: + ResponseSize = mLangStringDescriptor.Length; + ResponseData = &mLangStringDescriptor; + break; + case 1: + ResponseSize = mManufacturerStringDescriptor.Hdr.Length; + ResponseData = &mManufacturerStringDescriptor; + break; + case 2: + ResponseSize = mProductStringDescriptor.Hdr.Length; + ResponseData = &mProductStringDescriptor; + break; + case 3: +/* Status = gRT->GetVariable ( + (CHAR16*)L"SerialNo", + &gArmGlobalVariableGuid, + NULL, + &SerialNoLen, + SerialNo + ); + if (EFI_ERROR (Status) == 0) { + CopyMem (mSerialStringDescriptor.String, SerialNo, SerialNoLen); + } + ResponseSize = mSerialStringDescriptor.Length; + ResponseData = &mSerialStringDescriptor;*/ + CopyMem (mSerialStringDescriptor.Hdr.String, "12345", 6); + ResponseSize = 6; + ResponseData = &mSerialStringDescriptor; + + break; + } + break; + default: + DEBUG ((EFI_D_ERROR, "USB: Didn't understand request for descriptor 0x%04x\n", Request->Value)); + break; + } + + // Send the response + if (ResponseData) { + ASSERT (ResponseSize != 0); + + if (Request->Length < ResponseSize) { + // Truncate response + ResponseSize = Request->Length; + } else if (Request->Length > ResponseSize) { + DEBUG ((EFI_D_ERROR, "USB: Info: ResponseSize < wLength\n")); + } + + ep_tx(0, ResponseData, ResponseSize); + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +HandleSetAddress ( + IN USB_DEVICE_REQUEST *Request + ) +{ + // Pretty confused if bmRequestType is anything but this: + ASSERT (Request->RequestType == USB_DEV_SET_ADDRESS_REQ_TYPE); + DEBUG ((EFI_D_ERROR, "USB: Setting address to %d\n", Request->Value)); + reset_endpoints(); + + WRITE_REG32(DCFG, (READ_REG32(DCFG) & ~0x7F0) | (Request->Value << 4)); + ep_tx(0, 0, 0); + + return EFI_SUCCESS; +} + +int usb_drv_request_endpoint(unsigned int type, int dir) +{ + unsigned int ep = 1; /*FIXME*/ + int ret; + unsigned long newbits; + + ret = (int)ep | dir; + newbits = (type << 18) | 0x10000000; + + /* + * (type << 18):Endpoint Type (EPType) + * 0x10000000:Endpoint Enable (EPEna) + * 0x000C000:Endpoint Type (EPType);Hardcoded to 00 for control. + * (ep<<22):TxFIFO Number (TxFNum) + * 0x20000:NAK Status (NAKSts);The core is transmitting NAK handshakes on this endpoint. + */ + if (dir) { // IN: to host + WRITE_REG32(DIEPCTL(ep), ((READ_REG32(DIEPCTL(ep)))& ~0x000C0000) | newbits | (ep<<22)|0x20000); + } else { // OUT: to device + WRITE_REG32(DOEPCTL(ep), ((READ_REG32(DOEPCTL(ep))) & ~0x000C0000) | newbits); + } + + return ret; +} +STATIC +EFI_STATUS +HandleSetConfiguration ( + IN USB_DEVICE_REQUEST *Request + ) +{ + ASSERT (Request->RequestType == USB_DEV_SET_CONFIGURATION_REQ_TYPE); + + // Cancel all transfers + reset_endpoints(); + + usb_drv_request_endpoint(2, 0); + usb_drv_request_endpoint(2, 0x80); + + WRITE_REG32(DIEPCTL1, (READ_REG32(DIEPCTL1)) | 0x10088800); + + /* Enable interrupts on all endpoints */ + WRITE_REG32(DAINTMSK, 0xFFFFFFFF); + + ep_rx(1, CMD_SIZE); + ep_tx(0, 0, 0); + return EFI_SUCCESS; +} + + +STATIC +EFI_STATUS +HandleDeviceRequest ( + IN USB_DEVICE_REQUEST *Request + ) +{ + EFI_STATUS Status; + + switch (Request->Request) { + case USB_DEV_GET_DESCRIPTOR: + Status = HandleGetDescriptor (Request); + break; + case USB_DEV_SET_ADDRESS: + Status = HandleSetAddress (Request); + break; + case USB_DEV_SET_CONFIGURATION: + Status = HandleSetConfiguration (Request); + break; + default: + DEBUG ((EFI_D_ERROR, + "Didn't understand RequestType 0x%x Request 0x%x\n", + Request->RequestType, Request->Request)); + Status = EFI_INVALID_PARAMETER; + break; + } + + return Status; +} + + +// Instead of actually registering interrupt handlers, we poll the controller's +// interrupt source register in this function. +STATIC +VOID +CheckInterrupts ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + UINT32 ints = READ_REG32(GINTSTS); // interrupt register + UINT32 epints; + + /* + * bus reset + * The core sets this bit to indicate that a reset is detected on the USB. + */ + if (ints & 0x1000) { + WRITE_REG32(DCFG, 0x800004); + reset_endpoints(); + } + + /* + * enumeration done, we now know the speed + * The core sets this bit to indicate that speed enumeration is complete. The + * application must read the Device Status (DSTS) register to obtain the + * enumerated speed. + */ + if (ints & 0x2000) { + /* Set up the maximum packet sizes accordingly */ + unsigned long maxpacket = usb_drv_port_speed() ? USB_BLOCK_HIGH_SPEED_SIZE : 64; + //Set Maximum In Packet Size (MPS) + WRITE_REG32(DIEPCTL1, ((READ_REG32(DIEPCTL1)) & ~0x000003FF) | maxpacket); + //Set Maximum Out Packet Size (MPS) + WRITE_REG32(DOEPCTL1, ((READ_REG32(DOEPCTL1)) & ~0x000003FF) | maxpacket); + } + + /* + * IN EP event + * The core sets this bit to indicate that an interrupt is pending on one of the IN + * endpoints of the core (in Device mode). The application must read the + * Device All Endpoints Interrupt (DAINT) register to determine the exact + * number of the IN endpoint on which the interrupt occurred, and then read + * the corresponding Device IN Endpoint-n Interrupt (DIEPINTn) register to + * determine the exact cause of the interrupt. The application must clear the + * appropriate status bit in the corresponding DIEPINTn register to clear this bit. + */ + if (ints & 0x40000) { + epints = READ_REG32(DIEPINT0); + WRITE_REG32(DIEPINT0, epints); + if (epints & 0x1) /* Transfer Completed Interrupt (XferCompl) */ + DEBUG ((EFI_D_ERROR, "INT: IN TX completed.DIEPTSIZ(0) = 0x%x.\n", READ_REG32(DIEPTSIZ0))); + + epints = READ_REG32(DIEPINT1); + WRITE_REG32(DIEPINT1, epints); + if (epints & 0x1) + DEBUG ((EFI_D_ERROR, "ep1: IN TX completed\n")); + } + + /* + * OUT EP event + * The core sets this bit to indicate that an interrupt is pending on one of the + * OUT endpoints of the core (in Device mode). The application must read the + * Device All Endpoints Interrupt (DAINT) register to determine the exact + * number of the OUT endpoint on which the interrupt occurred, and then read + * the corresponding Device OUT Endpoint-n Interrupt (DOEPINTn) register + * to determine the exact cause of the interrupt. The application must clear the + * appropriate status bit in the corresponding DOEPINTn register to clear this bit. + */ + if (ints & 0x80000) { + /* indicates the status of an endpoint + * with respect to USB- and AHB-related events. */ + epints = READ_REG32(DOEPINT0); + if(epints) { + WRITE_REG32(DOEPINT0, epints); + if (epints & 0x1) + DEBUG ((EFI_D_ERROR,"INT: EP0 RX completed. DOEPTSIZ(0) = 0x%x.\n", READ_REG32(DOEPTSIZ0))); + /* + * + IN Token Received When TxFIFO is Empty (INTknTXFEmp) + * Indicates that an IN token was received when the associated TxFIFO (periodic/nonperiodic) + * was empty. This interrupt is asserted on the endpoint for which the IN token + * was received. + */ + if (epints & 0x8) { /* SETUP phase done */ + // PRINT_DEBUG("Setup phase \n"); + WRITE_REG32(DIEPCTL0, READ_REG32(DIEPCTL0) | 0x08000000); + WRITE_REG32(DOEPCTL0, READ_REG32(DOEPCTL0) | 0x08000000); + /*clear IN EP intr*/ + WRITE_REG32(DIEPINT0, 0xffffffff); + HandleDeviceRequest((USB_DEVICE_REQUEST *)p_ctrlreq); + } + + /* Make sure EP0 OUT is set up to accept the next request */ + /* memset(p_ctrlreq, 0, NUM_ENDPOINTS*8); */ + WRITE_REG32(DOEPTSIZ0, 0x60080040); + /* + * IN Token Received When TxFIFO is Empty (INTknTXFEmp) + * Indicates that an IN token was received when the associated TxFIFO (periodic/nonperiodic) + * was empty. This interrupt is asserted on the endpoint for which the IN token + * was received. + */ + g_dma_desc_ep0->status.b.bs = 0x3; + g_dma_desc_ep0->status.b.mtrf = 0; + g_dma_desc_ep0->status.b.sr = 0; + g_dma_desc_ep0->status.b.l = 1; + g_dma_desc_ep0->status.b.ioc = 1; + g_dma_desc_ep0->status.b.sp = 0; + g_dma_desc_ep0->status.b.bytes = 64; + g_dma_desc_ep0->buf = (UINT32)(UINTN)(p_ctrlreq); + g_dma_desc_ep0->status.b.sts = 0; + g_dma_desc_ep0->status.b.bs = 0x0; + WRITE_REG32(DOEPDMA0, (unsigned long)(g_dma_desc_ep0)); + // endpoint enable; clear NAK + WRITE_REG32(DOEPCTL0, 0x84000000); + } + + epints = (READ_REG32(DOEPINT1)); + if(epints) { + WRITE_REG32(DOEPINT1, epints); + /* Transfer Completed Interrupt (XferCompl);Transfer completed */ + if (epints & 0x1) { + asm("dsb sy"); + asm("isb sy"); + + UINT32 bytes = rx_desc_bytes - g_dma_desc->status.b.bytes; + UINT32 len = 0; + + if (MATCH_CMD_LITERAL ("download", rx_buf)) { + mNumDataBytes = AsciiStrHexToUint64 (rx_buf + sizeof ("download")); + } else { + if (mNumDataBytes != 0) + mNumDataBytes -= bytes; + } + + mDataReceivedCallback (bytes, rx_buf); + + if (mNumDataBytes == 0) + len = CMD_SIZE; + else if (mNumDataBytes > DATA_SIZE) + len = DATA_SIZE; + else + len = mNumDataBytes; + + ep_rx(1, len); + } + } + } + + //WRITE_REG32 clear ints + WRITE_REG32(GINTSTS, ints); +} + +EFI_STATUS +DwUsbSend ( + IN UINT8 EndpointIndex, + IN UINTN Size, + IN CONST VOID *Buffer + ) +{ + ep_tx(EndpointIndex, Buffer, Size); + return 0; +} + + +STATIC VOID usb_init() +{ + VOID* buf; + + buf = UncachedAllocatePages (1); + g_dma_desc = buf; + g_dma_desc_ep0 = g_dma_desc + sizeof(struct dwc_otg_dev_dma_desc); + g_dma_desc_in = g_dma_desc_ep0 + sizeof(struct dwc_otg_dev_dma_desc); + p_ctrlreq = (USB_DEVICE_REQUEST *)g_dma_desc_in + sizeof(struct dwc_otg_dev_dma_desc); + + SetMem(g_dma_desc, sizeof(struct dwc_otg_dev_dma_desc), 0); + SetMem(g_dma_desc_ep0, sizeof(struct dwc_otg_dev_dma_desc), 0); + SetMem(g_dma_desc_in, sizeof(struct dwc_otg_dev_dma_desc), 0); + + /*Reset usb controller.*/ + /* Wait for AHB master idle */ + while (!((READ_REG32(GRSTCTL)) & 0x80000000)); + + /* OTG: Assert Software Reset */ + WRITE_REG32(GRSTCTL, 1); + + /* Wait for OTG to ack reset */ + while ((READ_REG32(GRSTCTL)) & 1); + + /* Wait for OTG AHB master idle */ + while (!((READ_REG32(GRSTCTL)) & 0x80000000)); + + WRITE_REG32(GDFIFOCFG, DATA_FIFO_CONFIG); + WRITE_REG32(GRXFSIZ, RX_SIZE); + WRITE_REG32(GNPTXFSIZ, ENDPOINT_TX_SIZE); + WRITE_REG32(DIEPTXF1, DATA_IN_ENDPOINT_TX_FIFO1); + + /* + * set Periodic TxFIFO Empty Level, + * Non-Periodic TxFIFO Empty Level, + * Enable DMA, Unmask Global Intr + */ + WRITE_REG32(GAHBCFG, 0x1a1); + + /*select 8bit UTMI+, ULPI Inerface*/ + WRITE_REG32(GUSBCFG, 0x2400); + + /* Detect usb work mode,host or device? */ + while ((READ_REG32(GINTSTS)) & 1); + MicroSecondDelay(1); + + /*Init global and device mode csr register.*/ + /*set Non-Zero-Length status out handshake */ + WRITE_REG32(DCFG, 0x800004); + + /* Interrupt unmask: IN event, OUT event, bus reset */ + WRITE_REG32(GINTMSK, 0xC3C08); + + while ((READ_REG32(GINTSTS)) & 0x2000); + + /* Clear any pending OTG Interrupts */ + WRITE_REG32(GOTGINT, 0xFFFFFFFF); + /* Clear any pending interrupts */ + WRITE_REG32(GINTSTS, 0xFFFFFFFF); + WRITE_REG32(GINTMSK, 0xFFFFFFFF); + WRITE_REG32(GOTGINT, READ_REG32(GOTGINT) & (~0x3000)); + /*endpoint settings cfg*/ + reset_endpoints(); + + /*init finish. and ready to transfer data*/ + + /* Soft Disconnect */ + WRITE_REG32(DCTL, 0x802); + MicroSecondDelay(1); + + /* Soft Reconnect */ + WRITE_REG32(DCTL, 0x800); +} + + + +EFI_STATUS +EFIAPI +DwUsbStart ( + IN USB_DEVICE_DESCRIPTOR *DeviceDescriptor, + IN VOID **Descriptors, + IN USB_DEVICE_RX_CALLBACK RxCallback, + IN USB_DEVICE_TX_CALLBACK TxCallback + ) +{ + UINT8 *Ptr; + EFI_STATUS Status; + EFI_EVENT TimerEvent; + + ASSERT (DeviceDescriptor != NULL); + ASSERT (Descriptors[0] != NULL); + ASSERT (RxCallback != NULL); + ASSERT (TxCallback != NULL); + + usb_init(); + + mDeviceDescriptor = DeviceDescriptor; + mDescriptors = Descriptors[0]; + + // Right now we just support one configuration + ASSERT (mDeviceDescriptor->NumConfigurations == 1); + // ... and one interface + mConfigDescriptor = (USB_CONFIG_DESCRIPTOR *)mDescriptors; + ASSERT (mConfigDescriptor->NumInterfaces == 1); + + Ptr = ((UINT8 *) mDescriptors) + sizeof (USB_CONFIG_DESCRIPTOR); + mInterfaceDescriptor = (USB_INTERFACE_DESCRIPTOR *) Ptr; + Ptr += sizeof (USB_INTERFACE_DESCRIPTOR); + + mEndpointDescriptors = (USB_ENDPOINT_DESCRIPTOR *) Ptr; + + mDataReceivedCallback = RxCallback; + mDataSentCallback = TxCallback; + + // Register a timer event so CheckInterupts gets called periodically + Status = gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + CheckInterrupts, + 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); + + return Status; +} + +USB_DEVICE_PROTOCOL mUsbDevice = { + DwUsbStart, + DwUsbSend +}; + + + + +#endif + + +STATIC VOID phy_init(USB_OHCI_HC_DEV *Ehc) +{ + UINT32 val; + + DEBUG ((EFI_D_ERROR, "phy_init() sequence\n")); + // setup direction of hub + val = GPIO_READ_REG32(GPIODIR); + DEBUG ((EFI_D_ERROR, "GPIO0_3=%X DIR=%X CTL=%X\n", GPIO_READ_REG32(GPIODATA_3),val,GPIO_READ_REG32(GPIOAFSEL))); + val |= 0x84; + GPIO_WRITE_REG32(GPIODIR,val); + + + asm("dsb sy"); + asm("isb sy"); + MicroSecondDelay (1000); + GPIO_WRITE_REG32(GPIODATA_3,1<<3); + GPIO_WRITE_REG32(GPIODATA_7,1<<7); + + asm("dsb sy"); + asm("isb sy"); + MicroSecondDelay (1000); + DEBUG ((EFI_D_ERROR, "GPIO0_3=%X DIR=%X CTL=%X\n", GPIO_READ_REG32(GPIODATA_3),val,GPIO_READ_REG32(GPIOAFSEL))); + DEBUG ((EFI_D_ERROR, "GPIO0=%X\n", GPIO_READ_REG32(0x3FC))); +// DEBUG ((EFI_D_ERROR, "GPIO0_7=%X\n", GPIO_READ_REG32(GPIODATA_7))); //turn on Hub port +/* ++STATIC ++VOID ++HiKeyDetectUsbModeInit ( ++ IN VOID ++ ) ++{ ++ EFI_STATUS Status; ++ ++ //set pullup on both GPIO2_5 & GPIO2_6. It's required for inupt. ++ MmioWrite32 (0xf8001864, 1); ++ MmioWrite32 (0xf8001868, 1); ++ ++ Status = gBS->LocateProtocol (&gEmbeddedGpioProtocolGuid, NULL, (VOID **)&mGpio); ++ ASSERT_EFI_ERROR (Status); ++ Status = mGpio->Set (mGpio, USB_SEL_GPIO0_3, GPIO_MODE_OUTPUT_0); ++ ASSERT_EFI_ERROR (Status); ++ Status = mGpio->Set (mGpio, USB_5V_HUB_EN, GPIO_MODE_OUTPUT_0); ++ ASSERT_EFI_ERROR (Status); ++ MicroSecondDelay (1000); ++ ++ Status = mGpio->Set (mGpio, USB_ID_DET_GPIO2_5, GPIO_MODE_INPUT); ++ ASSERT_EFI_ERROR (Status); ++ Status = mGpio->Set (mGpio, USB_VBUS_DET_GPIO2_6, GPIO_MODE_INPUT); ++ ASSERT_EFI_ERROR (Status); ++} */ + + //setup clock + val = PHY_READ_REG32(SC_PERIPH_CLKEN0); + val |= BIT4; + PHY_WRITE_REG32(SC_PERIPH_CLKEN0, val); + + do { + val = PHY_READ_REG32(SC_PERIPH_CLKSTAT0); + } while ((val & BIT4) == 0); + + // setup phy (this is just hi6220_phy_init() minus the "reset enable"? + // AKA looks like its just pulling the phy out of reset + val = PHY_READ_REG32(SC_PERIPH_RSTDIS0); + val |= RST0_USBOTG_BUS | RST0_POR_PICOPHY | RST0_USBOTG | RST0_USBOTG_32K; + PHY_WRITE_REG32(SC_PERIPH_RSTDIS0, val); + + // this is the "on" mode from linux hi6220_phy_setup() + val = PHY_READ_REG32(SC_PERIPH_CTRL5); + val &= ~CTRL5_PICOPHY_BC_MODE; + val |= CTRL5_USBOTG_RES_SEL | CTRL5_PICOPHY_ACAENB; //newer HIsi edk has this | CTRL5_PICOPHY_VDATDETENB | CTRL5_PICOPHY_DCDENB; ; + PHY_WRITE_REG32(SC_PERIPH_CTRL5, val); + + val = PHY_READ_REG32(SC_PERIPH_CTRL4); + val &= ~(CTRL4_PICO_SIDDQ | CTRL4_PICO_OGDISABLE); + val |= CTRL4_PICO_VBUSVLDEXT | CTRL4_PICO_VBUSVLDEXTSEL | CTRL4_OTG_PHY_SEL; + PHY_WRITE_REG32(SC_PERIPH_CTRL4, val); + + PHY_WRITE_REG32(SC_PERIPH_CTRL8, EYE_PATTERN_PARA); +} + +// Try to get the controller inited, the appropriate linux function +// is probably dwc2_core_host_init() +STATIC VOID DwHostInit(USB_OHCI_HC_DEV *Ehc) +{ + UINT32 reg; + + // rpi needs the USB controller powered? + // do we? + // play with PCGCCTL +/* status = dwc_power_on(); + if (status != USB_STATUS_SUCCESS) + { + return status; + }*/ + + DEBUG ((EFI_D_ERROR, "DwHostInit reset\n")); + /*Reset usb controller.*/ + /* Wait for AHB master idle */ + while (!((READ_REG32(GRSTCTL)) & GRSTCTL_AHBIDLE)); + /* Assert Software Reset */ + WRITE_REG32(GRSTCTL, GRSTCTL_CSFTRST); + /* Wait for ack reset */ + while ((READ_REG32(GRSTCTL)) & GRSTCTL_CSFTRST); + /* Wait for AHB master idle */ + while (!((READ_REG32(GRSTCTL)) & GRSTCTL_AHBIDLE)); + + // version + reg=READ_REG32(GSNPSID); //global rx fifo size + DEBUG ((EFI_D_ERROR, "DwHostInit version %X\n",reg)); + + DEBUG ((EFI_D_ERROR, "DwHostInit setup dma\n")); + reg=READ_REG32(GRXFSIZ); //global rx fifo size + DEBUG ((EFI_D_ERROR, "DwHostInit global rx fifo size 0x%X\n",reg)); + reg=READ_REG32(GNPTXFSIZ); //global np tx fifo size + DEBUG ((EFI_D_ERROR, "DwHostInit global np tx fifo size 0x%X\n",reg)); + reg=READ_REG32(HPTXFSIZ); //global tx fifo size + DEBUG ((EFI_D_ERROR, "DwHostInit global tx fifo size 0x%X\n",reg)); + reg=READ_REG32(GNPTXSTS); //global np tx fifo status + DEBUG ((EFI_D_ERROR, "DwHostInit global np tx fifo status 0x%X\n",reg)); + + reg=READ_REG32(GAHBCFG); + DEBUG ((EFI_D_ERROR, "DwHostInit global AHB config 0x%X\n",reg)); + reg |= GAHBCFG_DMA_EN; + WRITE_REG32(GAHBCFG, reg); + +// dwc_soft_reset(); +// dwc_setup_dma_mode(); +// dwc_setup_interrupts(); +// status = dwc_start_xfer_scheduler(); +/* if (status != USB_STATUS_SUCCESS) + { + dwc_power_off(); + }*/ +} + +// Compare with dwc2_hc_init() +// Can we get away with just using a single channel? +// after all, we only want sync request/response type +// behavior.... +STATIC EFI_STATUS DwChannelInit(USB_OHCI_HC_DEV *Ehc, int DevAddr, int EpNum, EFI_USB_DATA_DIRECTION EpDir, BOOLEAN Slow, UINT8 Type, UINT8 MaxPacket) +{ + UINT32 hcchar; + int channel = 0; + hcchar = DevAddr << HCCHAR_DEVADDR_SHIFT & HCCHAR_DEVADDR_MASK; + hcchar |= EpNum << HCCHAR_EPNUM_SHIFT & HCCHAR_EPNUM_MASK; + hcchar |= Type << HCCHAR_EPTYPE_SHIFT & HCCHAR_EPTYPE_MASK; + hcchar |= MaxPacket << HCCHAR_MPS_SHIFT & HCCHAR_MPS_MASK; + + if (EpDir == EfiUsbDataIn) { + hcchar |= HCCHAR_EPDIR; + } + if (Slow) { + hcchar |= HCCHAR_LSPDDEV; + } + hcchar |= (READ_REG32(HFNUM) +1) & 1; //set odd frame??? + hcchar |= HCCHAR_CHENA; // enable channel, disable is already cleared + + WRITE_REG32(HCINT(channel), 0); //clear existing channel status + WRITE_REG32(HCINTMSK(channel), 0xFFFFFFFF); //enable all status flags + WRITE_REG32(HCCHAR(channel), hcchar); + + return EFI_SUCCESS; +} + + + +/** + Provides software reset for the USB host controller. + + @param This This EFI_USB_HC_PROTOCOL instance. + @param Attributes A bit mask of the reset operation to perform. + + @retval EFI_SUCCESS The reset operation succeeded. + @retval EFI_INVALID_PARAMETER Attributes is not valid. + @retval EFI_UNSUPPOURTED The type of reset specified by Attributes is + not currently supported by the host controller. + @retval EFI_DEVICE_ERROR Host controller isn't halted to reset. + +**/ +EFI_STATUS +EFIAPI +OhciReset ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT16 Attributes + ) +{ + DEBUG ((EFI_D_ERROR, "USB: OhciReset\n")); + return EFI_SUCCESS; +} + +/** + Retrieve the current state of the USB host controller. + + @param This This EFI_USB_HC_PROTOCOL instance. + @param State Variable to return the current host controller + state. + + @retval EFI_SUCCESS Host controller state was returned in State. + @retval EFI_INVALID_PARAMETER State is NULL. + @retval EFI_DEVICE_ERROR An error was encountered while attempting to + retrieve the host controller's current state. + +**/ + +EFI_STATUS +EFIAPI +OhciGetState ( + IN EFI_USB_HC_PROTOCOL *This, + OUT EFI_USB_HC_STATE *State + ) +{ + DEBUG ((EFI_D_ERROR, "USB: OhciGetState\n")); + return EFI_SUCCESS; +} + +/** + Sets the USB host controller to a specific state. + + @param This This EFI_USB_HC_PROTOCOL instance. + @param State The state of the host controller that will be set. + + @retval EFI_SUCCESS The USB host controller was successfully placed + in the state specified by State. + @retval EFI_INVALID_PARAMETER State is invalid. + @retval EFI_DEVICE_ERROR Failed to set the state due to device error. + +**/ + +EFI_STATUS +EFIAPI +OhciSetState( + IN EFI_USB_HC_PROTOCOL *This, + IN EFI_USB_HC_STATE State + ) +{ + DEBUG ((EFI_D_ERROR, "USB: OhciSetState\n")); + return EFI_SUCCESS; +} + +/** + + Submits control transfer to a target USB device. + + @param This A pointer to the EFI_USB_HC_PROTOCOL instance. + @param DeviceAddress Represents the address of the target device on the USB, + which is assigned during USB enumeration. + @param IsSlowDevice Indicates whether the target device is slow device + or full-speed device. + @param MaxPaketLength Indicates the maximum packet size that the + default control transfer endpoint is capable of + sending or receiving. + @param Request A pointer to the USB device request that will be sent + to the USB device. + @param TransferDirection Specifies the data direction for the transfer. + There are three values available, DataIn, DataOut + and NoData. + @param Data A pointer to the buffer of data that will be transmitted + to USB device or received from USB device. + @param DataLength Indicates the size, in bytes, of the data buffer + specified by Data. + @param TimeOut Indicates the maximum time, in microseconds, + which the transfer is allowed to complete. + @param TransferResult A pointer to the detailed result information generated + by this control transfer. + + @retval EFI_SUCCESS The control transfer was completed successfully. + @retval EFI_OUT_OF_RESOURCES The control transfer could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER Some parameters are invalid. + @retval EFI_TIMEOUT The control transfer failed due to timeout. + @retval EFI_DEVICE_ERROR The control transfer failed due to host controller or device error. + Caller should check TranferResult for detailed error information. + +--*/ + +void DumpRequest(EFI_USB_DEVICE_REQUEST *Request) +{ + if (Request->RequestType & 0x80) { + DEBUG ((EFI_D_ERROR, "USB: RequestType %X -> Host\n",Request->RequestType)); + } + else { + DEBUG ((EFI_D_ERROR, "USB: RequestType %X -> Device\n",Request->RequestType)); + } + if (Request->RequestType & 0x60) { + DEBUG ((EFI_D_ERROR, "USB: -> CLS/VEND\n")); + } + else { + DEBUG ((EFI_D_ERROR, "USB: -> STD\n")); + } + switch (Request->RequestType & 0x03) { + case USB_TARGET_DEVICE: + DEBUG ((EFI_D_ERROR, "USB: -> DEVICE\n")); + break; + case USB_TARGET_INTERFACE: + DEBUG ((EFI_D_ERROR, "USB: -> ITERFACE\n")); + break; + case USB_TARGET_ENDPOINT: + DEBUG ((EFI_D_ERROR, "USB: -> ENDPOINT\n")); + break; + case USB_TARGET_OTHER: + DEBUG ((EFI_D_ERROR, "USB: -> OTHER\n")); + break; + } + DEBUG ((EFI_D_ERROR, "USB: RequestType 0x%X\n",Request->RequestType)); + switch (Request->Request) { + case USB_DEV_GET_STATUS: + DEBUG ((EFI_D_ERROR, "USB: GET STATUS\n")); + break; + case USB_DEV_CLEAR_FEATURE: + DEBUG ((EFI_D_ERROR, "USB: CLEAR FEATURE\n")); + break; + case USB_DEV_SET_FEATURE: + DEBUG ((EFI_D_ERROR, "USB: SET FEATURE\n")); + break; + case USB_DEV_SET_ADDRESS: + DEBUG ((EFI_D_ERROR, "USB: SET ADDRESS\n")); + break; + case USB_DEV_GET_DESCRIPTOR: + DEBUG ((EFI_D_ERROR, "USB: GET DESCRIPTOR\n")); + break; + case USB_DEV_SET_DESCRIPTOR: + DEBUG ((EFI_D_ERROR, "USB: SET DESCRIPTOR\n")); + break; + default: + break; + } + DEBUG ((EFI_D_ERROR, "USB: Request %d\n",Request->Request)); + DEBUG ((EFI_D_ERROR, "USB: Value 0x%X\n",Request->Value)); + DEBUG ((EFI_D_ERROR, "USB: Index 0x%X\n",Request->Index)); + DEBUG ((EFI_D_ERROR, "USB: Length %d\n",Request->Length)); +} + +STATIC USB_DEVICE_DESCRIPTOR RootDevDescriptor = +{ + .Length = sizeof(USB_DEVICE_DESCRIPTOR), + .DescriptorType = USB_DESC_TYPE_DEVICE, + .BcdUSB = 0x200, + .DeviceClass = 0x09, //TYPE HUB + .DeviceSubClass = 0, + .DeviceProtocol = 1, + .MaxPacketSize0 = 18, + .IdVendor = 0, + .IdProduct = 2, + .BcdDevice = 0, + .StrManufacturer = 0, + .StrProduct = 1, + .StrSerialNumber = 2, + .NumConfigurations = 1 +}; + +STATIC struct ROOT_HUB_CFG +{ + USB_CONFIG_DESCRIPTOR RootCfgDescriptor; + USB_INTERFACE_DESCRIPTOR RootIntDescriptor; + USB_ENDPOINT_DESCRIPTOR RootEndDescriptor; +} RootCfg = +{ + .RootCfgDescriptor = + { + .Length = sizeof(USB_CONFIG_DESCRIPTOR), + .DescriptorType = USB_DESC_TYPE_CONFIG, + .TotalLength = sizeof(struct ROOT_HUB_CFG), + .NumInterfaces = 1, + .ConfigurationValue = 1, + .Configuration = 0 , + .Attributes = 0xC0, + .MaxPower = 0 + }, + .RootIntDescriptor = + { + .Length = sizeof(USB_INTERFACE_DESCRIPTOR), + .DescriptorType = USB_DESC_TYPE_INTERFACE, + .InterfaceNumber = 0, + .AlternateSetting = 0, + .NumEndpoints = 1, + .InterfaceClass = 0x09, //hub + .InterfaceSubClass = 0, + .InterfaceProtocol = 0, + .Interface = 0 + }, + .RootEndDescriptor = + { + .Length = sizeof(USB_ENDPOINT_DESCRIPTOR), + .DescriptorType = USB_DESC_TYPE_ENDPOINT, + .EndpointAddress = 0x81, + .Attributes = 0x03, + .MaxPacketSize = 64, + .Interval = 0xFF + }, +}; + +typedef struct { + EFI_USB_STRING_DESCRIPTOR Hdr; + CHAR16 buf[16]; +} DEF_EFI_USB_STRING_DESCRIPTOR; + +STATIC DEF_EFI_USB_STRING_DESCRIPTOR mManufacturerStringDescriptor = { + { + 18, + USB_DESC_TYPE_STRING, + {'9'} + }, + {'6', 'B', 'o', 'a', 'r', 'd', 's'} +}; + +STATIC DEF_EFI_USB_STRING_DESCRIPTOR mProductStringDescriptor = { + { + 12, + USB_DESC_TYPE_STRING, + {'H'} + }, + {'i', 'K', 'e', 'y'} +}; + +STATIC DEF_EFI_USB_STRING_DESCRIPTOR mSerialStringDescriptor = { + { + 34, + USB_DESC_TYPE_STRING, + {'0'} + }, + {'1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'} +}; + + + + +EFI_STATUS +EFIAPI +OhciControlTransfer ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN BOOLEAN IsSlowDevice, + IN UINT8 MaxPacketLength, + IN EFI_USB_DEVICE_REQUEST *Request, + IN EFI_USB_DATA_DIRECTION TransferDirection, + IN OUT VOID *Data OPTIONAL, + IN OUT UINTN *DataLength OPTIONAL, + IN UINTN TimeOut, + OUT UINT32 *TransferResult + ) +{ + int handled = 0; + static int first = 1; +#define ENABLE_EMULATION 20 + DEBUG ((EFI_D_ERROR, "USB: OhciControlTransfer (addr:%d) (direction:%d) Len:%d\n",DeviceAddress,TransferDirection,*DataLength)); + + DumpRequest(Request); + if ((DeviceAddress == 0+ENABLE_EMULATION) && (first)) + { + // ignore first set addr + first = 0; + handled = 1; + DEBUG ((EFI_D_ERROR, "USB: OhciControlTransfer, ignore first set addr for root port\n")); + } + if (DeviceAddress == 1+ENABLE_EMULATION) { //root port fake response + if (Request->RequestType == 0x80) { //device to host + if (Request->Request == USB_DEV_GET_DESCRIPTOR) { + DEBUG ((EFI_D_ERROR, "USB: OhciControlTransfer get descriptor\n")); + if ((Request->Value & 0xFF) == 0) + { + switch (Request->Value >> 8) { + case USB_DESC_TYPE_DEVICE: + CopyMem (Data, &RootDevDescriptor, *DataLength); + handled = 1; + break; + case USB_DESC_TYPE_CONFIG: + CopyMem (Data, &RootCfg, *DataLength); + handled = 1; + break; + case USB_DESC_TYPE_STRING: + switch (Request->Index) + { + case 0: + CopyMem (Data, &mManufacturerStringDescriptor, *DataLength); + handled = 1; + break; + case 1: + CopyMem (Data, &mProductStringDescriptor, *DataLength); + handled = 1; + break; + case 2: + CopyMem (Data, &mSerialStringDescriptor, *DataLength); + handled = 1; + break; + + } + break; + } + } + } + } + if (Request->RequestType == 0) //host to device + { + if (Request->Request == USB_DEV_SET_CONFIGURATION) + { + DEBUG ((EFI_D_ERROR, "USB: OhciControlTransfer Set configuration\n")); + handled = 1; + } + } + } + + if (!handled) { + USB_OHCI_HC_DEV *Ehc; + UINT64 addr; + UINT32 transfer; + + EFI_PHYSICAL_ADDRESS BusPhysAddr; + UINTN BusLength; + VOID *Mapping; + EFI_STATUS Status; + + + DEBUG ((EFI_D_ERROR, "USB: OhciControlTransfer forward to (slow=%d) (MaxTransfer=%d) bus\n",IsSlowDevice,MaxPacketLength)); + Ehc = USB_OHCI_HC_DEV_FROM_THIS (This); + + BusLength = sizeof(EFI_USB_DEVICE_REQUEST); + Status = Ehc->PciIo->Map(Ehc->PciIo, EfiPciIoOperationBusMasterRead, Request, &BusLength, &BusPhysAddr, &Mapping); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Usb: Map DMA failed\n")); + } + + addr = BusPhysAddr; + DEBUG ((EFI_D_ERROR, "USB: OhciControlTransfer 1 DMAADDR=%X BUSADDR=%X\n",Request,addr)); + // Ek gad, really? Split each control transfer into its phases? (see dwc2_hc_init_xfer) + // SETUP->DATA->STATUS +// ASSERT(Request<32bit); + WRITE_REG32(HCDMA(0), (UINT32)addr); + transfer = TSIZ_SC_MC_PID_SETUP<PciIo->Unmap (Ehc->PciIo, Mapping); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Usb: failed to Unmap DMA\n")); + } + + + // word aligned buffer can go directly to HCDMA + // packet count = 1, send 'Request' + // wait for complete packet + if (*DataLength) + { + // do the data phase. + BusLength = *DataLength; + Mapping = NULL; + Status = Ehc->PciIo->Map(Ehc->PciIo, EfiPciIoOperationBusMasterCommonBuffer , Data, &BusLength, &BusPhysAddr, &Mapping); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Usb: Map DMA failed\n")); + } + + addr = BusPhysAddr; + +// addr=(UINT64)Data; + DEBUG ((EFI_D_ERROR, "USB: OhciControlTransfer 6 datap=%X\n",addr)); + WRITE_REG32(HCDMA(0), (UINT32)addr); + transfer = TSIZ_SC_MC_PID_DATA0<PciIo->Unmap (Ehc->PciIo, Mapping); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Usb: failed to Unmap DMA\n")); + } + + } + + // do the status phase + // status flows in the oposite direction of data + if (TransferDirection == EfiUsbDataIn) { + TransferDirection = EfiUsbDataOut; + } + else { + TransferDirection = EfiUsbDataIn; + } + + *TransferResult=0; + + BusLength = 4; + Status = Ehc->PciIo->Map(Ehc->PciIo, EfiPciIoOperationBusMasterWrite , TransferResult , &BusLength, &BusPhysAddr, &Mapping); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Usb: Map DMA failed\n")); + } + + addr = BusPhysAddr; + +// addr=(UINT64)TransferResult; + WRITE_REG32(HCDMA(0), (UINT32)addr); + transfer = TSIZ_SC_MC_PID_DATA1<PciIo->Unmap (Ehc->PciIo, Mapping); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Usb: failed to Unmap DMA\n")); + } + + DEBUG ((EFI_D_ERROR, "USB: OhciControlTransfer Status = %X pkt_remaining = %d \n",READ_REG32(HCINT(0)), READ_REG32(HCTSIZ(0)))); + DEBUG ((EFI_D_ERROR, "USB: OhciControlTransfer Status = %X tdata =%X\n",READ_REG32(HCINT(0)),*TransferResult )); + // packet count = DataLength/Maxpacket (+1) send/recv 'Data' + // wait from complete + // (other direction for status) + //DwChannelInit(Ehc, DeviceAddress, 0 , TransferDirection, IsSlowDevice, USB_ENDPOINT_XFER_CONTROL, MaxPacketLength); + } + + return EFI_SUCCESS; +} + + +/** + + Submits bulk transfer to a bulk endpoint of a USB device. + + @param This A pointer to the EFI_USB_HC_PROTOCOL instance. + @param DeviceAddress Represents the address of the target device on the USB, + which is assigned during USB enumeration. + @param EndPointAddress The combination of an endpoint number and an + endpoint direction of the target USB device. + Each endpoint address supports data transfer in + one direction except the control endpoint + (whose default endpoint address is 0). + It is the caller's responsibility to make sure that + the EndPointAddress represents a bulk endpoint. + @param MaximumPacketLength Indicates the maximum packet size the target endpoint + is capable of sending or receiving. + @param Data A pointer to the buffer of data that will be transmitted + to USB device or received from USB device. + @param DataLength When input, indicates the size, in bytes, of the data buffer + specified by Data. When output, indicates the actually + transferred data size. + @param DataToggle A pointer to the data toggle value. On input, it indicates + the initial data toggle value the bulk transfer should adopt; + on output, it is updated to indicate the data toggle value + of the subsequent bulk transfer. + @param TimeOut Indicates the maximum time, in microseconds, which the + transfer is allowed to complete. + TransferResult A pointer to the detailed result information of the + bulk transfer. + + @retval EFI_SUCCESS The bulk transfer was completed successfully. + @retval EFI_OUT_OF_RESOURCES The bulk transfer could not be submitted due to lack of resource. + @retval EFI_INVALID_PARAMETER Some parameters are invalid. + @retval EFI_TIMEOUT The bulk transfer failed due to timeout. + @retval EFI_DEVICE_ERROR The bulk transfer failed due to host controller or device error. + Caller should check TranferResult for detailed error information. + +**/ + + +EFI_STATUS +EFIAPI +OhciBulkTransfer( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN UINT8 MaxPacketLength, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN OUT UINT8 *DataToggle, + IN UINTN TimeOut, + OUT UINT32 *TransferResult + ) +{ + DEBUG ((EFI_D_ERROR, "USB: OhciBulkTransfer\n")); + return EFI_SUCCESS; +} + + +/** + + Submits an interrupt transfer to an interrupt endpoint of a USB device. + + @param Ohc Device private data + @param DeviceAddress Represents the address of the target device on the USB, + which is assigned during USB enumeration. + @param EndPointAddress The combination of an endpoint number and an endpoint + direction of the target USB device. Each endpoint address + supports data transfer in one direction except the + control endpoint (whose default endpoint address is 0). + It is the caller's responsibility to make sure that + the EndPointAddress represents an interrupt endpoint. + @param IsSlowDevice Indicates whether the target device is slow device + or full-speed device. + @param MaxPacketLength Indicates the maximum packet size the target endpoint + is capable of sending or receiving. + @param IsNewTransfer If TRUE, an asynchronous interrupt pipe is built between + the host and the target interrupt endpoint. + If FALSE, the specified asynchronous interrupt pipe + is canceled. + @param DataToggle A pointer to the data toggle value. On input, it is valid + when IsNewTransfer is TRUE, and it indicates the initial + data toggle value the asynchronous interrupt transfer + should adopt. + On output, it is valid when IsNewTransfer is FALSE, + and it is updated to indicate the data toggle value of + the subsequent asynchronous interrupt transfer. + @param PollingInterval Indicates the interval, in milliseconds, that the + asynchronous interrupt transfer is polled. + This parameter is required when IsNewTransfer is TRUE. + @param UCBuffer Uncacheable buffer + @param DataLength Indicates the length of data to be received at the + rate specified by PollingInterval from the target + asynchronous interrupt endpoint. This parameter + is only required when IsNewTransfer is TRUE. + @param CallBackFunction The Callback function.This function is called at the + rate specified by PollingInterval.This parameter is + only required when IsNewTransfer is TRUE. + @param Context The context that is passed to the CallBackFunction. + This is an optional parameter and may be NULL. + @param IsPeriodic Periodic interrupt or not + @param OutputED The correspoding ED carried out + @param OutputTD The correspoding TD carried out + + + @retval EFI_SUCCESS The asynchronous interrupt transfer request has been successfully + submitted or canceled. + @retval EFI_INVALID_PARAMETER Some parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ + +EFI_STATUS +OhciInterruptTransfer ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN BOOLEAN IsSlowDevice, + IN UINT8 MaxPacketLength, + IN BOOLEAN IsNewTransfer, + IN OUT UINT8 *DataToggle OPTIONAL, + IN UINTN PollingInterval OPTIONAL, + IN VOID *UCBuffer OPTIONAL, + IN UINTN DataLength OPTIONAL, + IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction OPTIONAL, + IN VOID *Context OPTIONAL, + IN BOOLEAN IsPeriodic OPTIONAL, + OUT VOID **OutputED OPTIONAL, + OUT VOID **OutputTD OPTIONAL + ) +{ + DEBUG ((EFI_D_ERROR, "USB: OhciInterruptTransfer\n")); + return EFI_SUCCESS; +} + +/** + + Submits an asynchronous interrupt transfer to an interrupt endpoint of a USB device. + + @param This A pointer to the EFI_USB_HC_PROTOCOL instance. + @param DeviceAddress Represents the address of the target device on the USB, + which is assigned during USB enumeration. + @param EndPointAddress The combination of an endpoint number and an endpoint + direction of the target USB device. Each endpoint address + supports data transfer in one direction except the + control endpoint (whose default endpoint address is 0). + It is the caller's responsibility to make sure that + the EndPointAddress represents an interrupt endpoint. + @param IsSlowDevice Indicates whether the target device is slow device + or full-speed device. + @param MaxiumPacketLength Indicates the maximum packet size the target endpoint + is capable of sending or receiving. + @param IsNewTransfer If TRUE, an asynchronous interrupt pipe is built between + the host and the target interrupt endpoint. + If FALSE, the specified asynchronous interrupt pipe + is canceled. + @param DataToggle A pointer to the data toggle value. On input, it is valid + when IsNewTransfer is TRUE, and it indicates the initial + data toggle value the asynchronous interrupt transfer + should adopt. + On output, it is valid when IsNewTransfer is FALSE, + and it is updated to indicate the data toggle value of + the subsequent asynchronous interrupt transfer. + @param PollingInterval Indicates the interval, in milliseconds, that the + asynchronous interrupt transfer is polled. + This parameter is required when IsNewTransfer is TRUE. + @param DataLength Indicates the length of data to be received at the + rate specified by PollingInterval from the target + asynchronous interrupt endpoint. This parameter + is only required when IsNewTransfer is TRUE. + @param CallBackFunction The Callback function.This function is called at the + rate specified by PollingInterval.This parameter is + only required when IsNewTransfer is TRUE. + @param Context The context that is passed to the CallBackFunction. + This is an optional parameter and may be NULL. + + @retval EFI_SUCCESS The asynchronous interrupt transfer request has been successfully + submitted or canceled. + @retval EFI_INVALID_PARAMETER Some parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ + + +EFI_STATUS +EFIAPI +OhciAsyncInterruptTransfer ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN BOOLEAN IsSlowDevice, + IN UINT8 MaxPacketLength, + IN BOOLEAN IsNewTransfer, + IN OUT UINT8 *DataToggle OPTIONAL, + IN UINTN PollingInterval OPTIONAL, + IN UINTN DataLength OPTIONAL, + IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction OPTIONAL, + IN VOID *Context OPTIONAL + ) +{ + DEBUG ((EFI_D_ERROR, "USB: OhciAsyncInterruptTransfer\n")); + return EFI_SUCCESS; +} + +/** + + Submits synchronous interrupt transfer to an interrupt endpoint + of a USB device. + + @param This A pointer to the EFI_USB_HC_PROTOCOL instance. + @param DeviceAddress Represents the address of the target device on the USB, + which is assigned during USB enumeration. + @param EndPointAddress The combination of an endpoint number and an endpoint + direction of the target USB device. Each endpoint + address supports data transfer in one direction + except the control endpoint (whose default + endpoint address is 0). It is the caller's responsibility + to make sure that the EndPointAddress represents + an interrupt endpoint. + @param IsSlowDevice Indicates whether the target device is slow device + or full-speed device. + @param MaxPacketLength Indicates the maximum packet size the target endpoint + is capable of sending or receiving. + @param Data A pointer to the buffer of data that will be transmitted + to USB device or received from USB device. + @param DataLength On input, the size, in bytes, of the data buffer specified + by Data. On output, the number of bytes transferred. + @param DataToggle A pointer to the data toggle value. On input, it indicates + the initial data toggle value the synchronous interrupt + transfer should adopt; + on output, it is updated to indicate the data toggle value + of the subsequent synchronous interrupt transfer. + @param TimeOut Indicates the maximum time, in microseconds, which the + transfer is allowed to complete. + @param TransferResult A pointer to the detailed result information from + the synchronous interrupt transfer. + + @retval EFI_UNSUPPORTED This interface not available. + @retval EFI_INVALID_PARAMETER Parameters not follow spec + +**/ + + +EFI_STATUS +EFIAPI +OhciSyncInterruptTransfer ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN BOOLEAN IsSlowDevice, + IN UINT8 MaxPacketLength, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN OUT UINT8 *DataToggle, + IN UINTN TimeOut, + OUT UINT32 *TransferResult + ) +{ + DEBUG ((EFI_D_ERROR, "USB: OhciSyncInterruptTransfer\n")); + return EFI_SUCCESS; +} + +/** + + Submits isochronous transfer to a target USB device. + + @param This A pointer to the EFI_USB_HC_PROTOCOL instance. + @param DeviceAddress Represents the address of the target device on the USB, + which is assigned during USB enumeration. + @param EndPointAddress End point address + @param MaximumPacketLength Indicates the maximum packet size that the + default control transfer endpoint is capable of + sending or receiving. + @param Data A pointer to the buffer of data that will be transmitted + to USB device or received from USB device. + @param DataLength Indicates the size, in bytes, of the data buffer + specified by Data. + @param TransferResult A pointer to the detailed result information generated + by this control transfer. + + @retval EFI_UNSUPPORTED This interface not available + @retval EFI_INVALID_PARAMETER Data is NULL or DataLength is 0 or TransferResult is NULL + +**/ + + +EFI_STATUS +EFIAPI +OhciIsochronousTransfer ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN UINT8 MaximumPacketLength, + IN OUT VOID *Data, + IN OUT UINTN DataLength, + OUT UINT32 *TransferResult + ) +{ + DEBUG ((EFI_D_ERROR, "USB: OhciIsochronousTransfer\n")); + if (Data == NULL || DataLength == 0 || TransferResult == NULL) { + return EFI_INVALID_PARAMETER; + } + + return EFI_UNSUPPORTED; +} + + +/** + + Submits Async isochronous transfer to a target USB device. + + @param his A pointer to the EFI_USB_HC_PROTOCOL instance. + @param DeviceAddress Represents the address of the target device on the USB, + which is assigned during USB enumeration. + @param EndPointAddress End point address + @param MaximumPacketLength Indicates the maximum packet size that the + default control transfer endpoint is capable of + sending or receiving. + @param Data A pointer to the buffer of data that will be transmitted + to USB device or received from USB device. + @param IsochronousCallBack When the transfer complete, the call back function will be called + @param Context Pass to the call back function as parameter + + @retval EFI_UNSUPPORTED This interface not available + @retval EFI_INVALID_PARAMETER Data is NULL or Datalength is 0 + +**/ + +EFI_STATUS +EFIAPI +OhciAsyncIsochronousTransfer ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN UINT8 MaximumPacketLength, + IN OUT VOID *Data, + IN OUT UINTN DataLength, + IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack, + IN VOID *Context OPTIONAL + ) +{ + DEBUG ((EFI_D_ERROR, "USB: OhciAsyncIsochronousTransfer\n")); + if (Data == NULL || DataLength == 0) { + return EFI_INVALID_PARAMETER; + } + + return EFI_UNSUPPORTED; +} + +/** + + Retrieves the number of root hub ports. + + @param This A pointer to the EFI_USB_HC_PROTOCOL instance. + @param NumOfPorts A pointer to the number of the root hub ports. + + @retval EFI_SUCCESS The port number was retrieved successfully. +**/ +EFI_STATUS +EFIAPI +OhciGetRootHubNumOfPorts ( + IN EFI_USB_HC_PROTOCOL *This, + OUT UINT8 *NumOfPorts + ) +{ + DEBUG ((EFI_D_ERROR, "USB: OhciGetRootHubNumOfPorts\n")); + //TODO, so apparently this devices root port can't be probed? + // default to one port, and simulate it? + *NumOfPorts = 1; + return EFI_SUCCESS; +} + +#define MAXPORTS 4; + +/** + + Retrieves the current status of a USB root hub port. + + @param This A pointer to the EFI_USB_HC_PROTOCOL. + @param PortNumber Specifies the root hub port from which the status + is to be retrieved. This value is zero-based. For example, + if a root hub has two ports, then the first port is numbered 0, + and the second port is numbered 1. + @param PortStatus A pointer to the current port status bits and + port status change bits. + + @retval EFI_SUCCESS The status of the USB root hub port specified by PortNumber + was returned in PortStatus. + @retval EFI_INVALID_PARAMETER Port number not valid +**/ + + +EFI_STATUS +EFIAPI +OhciGetRootHubPortStatus ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 PortNumber, + OUT EFI_USB_PORT_STATUS *PortStatus + ) +{ + USB_OHCI_HC_DEV *Ehc; + +// DEBUG ((EFI_D_ERROR, "USB: OhciGetRootHubPortStatus %d\n",PortNumber)); + if (PortStatus == NULL) { + return EFI_INVALID_PARAMETER; + } + + Ehc = USB_OHCI_HC_DEV_FROM_THIS (This); + + //TODO more faked status? + // The HPRT register contains the host status + // indicating speed/power etc + PortStatus->PortStatus = 0; + PortStatus->PortChangeStatus = 0; + PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED; + PortStatus->PortStatus |= USB_PORT_STAT_ENABLE; + PortStatus->PortStatus |= USB_PORT_STAT_POWER; + PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION; + + // on first status (reset/whatever) describe a new connection + if (Ehc->PortStatus) { + DEBUG ((EFI_D_ERROR, "USB: OhciGetRootHubPortStatus %d change to connected\n",PortNumber)); + DEBUG ((EFI_D_ERROR, "USB: OhciGetRootHubPortStatus actual hport status %X\n",READ_REG32(HPRT))); + Ehc->PortStatus = 0; + PortStatus->PortChangeStatus |= USB_PORT_STAT_CONNECTION; + } + + return EFI_SUCCESS; +} + +/** + + Sets a feature for the specified root hub port. + + @param This A pointer to the EFI_USB_HC_PROTOCOL. + @param PortNumber Specifies the root hub port whose feature + is requested to be set. + @param PortFeature Indicates the feature selector associated + with the feature set request. + + @retval EFI_SUCCESS The feature specified by PortFeature was set for the + USB root hub port specified by PortNumber. + @retval EFI_DEVICE_ERROR Set feature failed because of hardware issue + @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid. +**/ +EFI_STATUS +EFIAPI +OhciSetRootHubPortFeature ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 PortNumber, + IN EFI_USB_PORT_FEATURE PortFeature + ) +{ + DEBUG ((EFI_D_ERROR, "USB: OhciSetRootHubPortFeature port(%d) -> %d\n",PortNumber,PortFeature)); + switch (PortFeature) { + case EfiUsbPortReset: + DEBUG ((EFI_D_ERROR, "USB: OhciSetRootHubPortFeature reset\n")); + break; + case EfiUsbPortEnable: + DEBUG ((EFI_D_ERROR, "USB: OhciSetRootHubPortFeature enable\n")); + break; + default: + DEBUG ((EFI_D_ERROR, "USB: OhciSetRootHubPortFeature (other)\n")); + } + return EFI_SUCCESS; +} + + +/** + + Clears a feature for the specified root hub port. + + @param This A pointer to the EFI_USB_HC_PROTOCOL instance. + @param PortNumber Specifies the root hub port whose feature + is requested to be cleared. + @param PortFeature Indicates the feature selector associated with the + feature clear request. + + @retval EFI_SUCCESS The feature specified by PortFeature was cleared for the + USB root hub port specified by PortNumber. + @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid. + @retval EFI_DEVICE_ERROR Some error happened when clearing feature +**/ +EFI_STATUS +EFIAPI +OhciClearRootHubPortFeature ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 PortNumber, + IN EFI_USB_PORT_FEATURE PortFeature + ) +{ + DEBUG ((EFI_D_ERROR, "USB: OhciClearRootHubPortFeature port(%d) -> %d\n",PortNumber,PortFeature)); + return EFI_SUCCESS; +} + +USB_OHCI_HC_DEV * +OhciAllocateDev ( + IN EFI_PCI_IO_PROTOCOL *PciIo + ) +{ + USB_OHCI_HC_DEV *Ohc; +// EFI_STATUS Status; +// VOID *Buf; +// EFI_PHYSICAL_ADDRESS PhyAddr; +// VOID *Map; + UINTN Pages; + UINTN Bytes; + + Ohc = AllocateZeroPool (sizeof (USB_OHCI_HC_DEV)); + if (Ohc == NULL) { + return NULL; + } + + Ohc->Signature = USB_DW_HC_DEV_SIGNATURE; + Ohc->PciIo = PciIo; + + Ohc->UsbHc.Reset = OhciReset; + Ohc->UsbHc.GetState = OhciGetState; + Ohc->UsbHc.SetState = OhciSetState; + Ohc->UsbHc.ControlTransfer = OhciControlTransfer; + Ohc->UsbHc.BulkTransfer = OhciBulkTransfer; + Ohc->UsbHc.AsyncInterruptTransfer = OhciAsyncInterruptTransfer; + Ohc->UsbHc.SyncInterruptTransfer = OhciSyncInterruptTransfer; + Ohc->UsbHc.IsochronousTransfer = OhciIsochronousTransfer; + Ohc->UsbHc.AsyncIsochronousTransfer = OhciAsyncIsochronousTransfer; + Ohc->UsbHc.GetRootHubPortNumber = OhciGetRootHubNumOfPorts; + Ohc->UsbHc.GetRootHubPortStatus = OhciGetRootHubPortStatus; + Ohc->UsbHc.SetRootHubPortFeature = OhciSetRootHubPortFeature; + Ohc->UsbHc.ClearRootHubPortFeature = OhciClearRootHubPortFeature; + Ohc->UsbHc.MajorRevision = 0x1; + Ohc->UsbHc.MinorRevision = 0x1; + +// Ohc->HccaMemoryBlock = NULL; + Ohc->HccaMemoryMapping = NULL; + Ohc->HccaMemoryBuf = NULL; + Ohc->HccaMemoryPages = 0; +// Ohc->InterruptContextList = NULL; + Ohc->ControllerNameTable = NULL; + Ohc->HouseKeeperTimer = NULL; + +/* Ohc->MemPool = UsbHcInitMemPool(PciIo, TRUE, 0); + if(Ohc->MemPool == NULL) { + goto FREE_DEV_BUFFER; + }*/ + + Bytes = 4096; + Pages = EFI_SIZE_TO_PAGES (Bytes); + +/* Status = PciIo->AllocateBuffer ( + PciIo, + AllocateAnyPages, + EfiBootServicesData, + Pages, + &Buf, + 0 + ); + + if (EFI_ERROR (Status)) { + goto FREE_MEM_POOL; + } + + Status = PciIo->Map ( + PciIo, + EfiPciIoOperationBusMasterCommonBuffer, + Buf, + &Bytes, + &PhyAddr, + &Map + ); + + if (EFI_ERROR (Status) || (Bytes != 4096)) { + goto FREE_MEM_PAGE; + }*/ + +// Ohc->HccaMemoryBlock = (HCCA_MEMORY_BLOCK *)(UINTN)PhyAddr; +// Ohc->HccaMemoryMapping = Map; +// Ohc->HccaMemoryBuf = (VOID *)(UINTN)Buf; + Ohc->HccaMemoryPages = Pages; + Ohc->PortStatus = 1; + + return Ohc; + +//FREE_MEM_PAGE: +// PciIo->FreeBuffer (PciIo, Pages, Buf); +//FREE_MEM_POOL: +// UsbHcFreeMemPool (Ohc->MemPool); +//FREE_DEV_BUFFER: +// FreePool(Ohc); + + return NULL; +} + +/** + + One notified function to stop the Host Controller when gBS->ExitBootServices() called. + + @param Event Pointer to this event + @param Context Event handler private data +**/ +VOID +EFIAPI +DwHcExitBootService ( + EFI_EVENT Event, + VOID *Context + ) +{ + DEBUG ((EFI_D_ERROR, "DwUsbExitBootService!\n")); +} + + +#pragma pack(1) +typedef struct { + UINT8 ProgInterface; + UINT8 SubClassCode; + UINT8 BaseCode; +} USB_CLASSC; +#pragma pack() +//typedef struct _USB2_HC_DEV USB2_HC_DEV; + +/** + Test to see if this driver supports ControllerHandle. Any + ControllerHandle that has Usb2HcProtocol installed will + be supported. + + @param This Protocol instance pointer. + @param Controller Handle of device to test. + @param RemainingDevicePath Not used. + + @return EFI_SUCCESS This driver supports this device. + @return EFI_UNSUPPORTED This driver does not support this device. + +**/ +EFI_STATUS +EFIAPI +DwUsbDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + USB_CLASSC UsbClassCReg; + +// DEBUG ((EFI_D_ERROR, "DwUsbDriverBindingSupported\n")); + // + // Test whether there is PCI IO Protocol attached on the controller handle. + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Status = PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint8, + PCI_CLASSCODE_OFFSET, + sizeof (USB_CLASSC) / sizeof (UINT8), + &UsbClassCReg + ); + + if (EFI_ERROR (Status)) { + Status = EFI_UNSUPPORTED; + goto ON_EXIT; + } + + // + // Test whether the controller belongs to Usb class type + // + if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) || (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB)) { + Status = EFI_UNSUPPORTED; + } + else { + DEBUG ((EFI_D_ERROR, "DwUsbDriverBindingSupported found board!\n")); + } + +ON_EXIT: + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return Status; +} + +/** + Starting the Usb EHCI Driver. + + @param This Protocol instance pointer. + @param Controller Handle of device to test. + @param RemainingDevicePath Not used. + + @return EFI_SUCCESS supports this device. + @return EFI_UNSUPPORTED do not support this device. + @return EFI_DEVICE_ERROR cannot be started due to device Error. + @return EFI_OUT_OF_RESOURCES cannot allocate resources. + +**/ +EFI_STATUS +EFIAPI +DwUsbDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; +// USB2_HC_DEV *Ehc; + USB_OHCI_HC_DEV *Ehc; + EFI_PCI_IO_PROTOCOL *PciIo; + EFI_DEVICE_PATH_PROTOCOL *HcDevicePath; + + DEBUG ((EFI_D_ERROR, "DwUsbDriverBindingStart \n")); + // + // Open the PciIo Protocol, then enable the USB host controller + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (Status)) { + return Status; + } + DEBUG ((EFI_D_ERROR, "DwUsbDriverBindingStart2 \n")); + // + // Open Device Path Protocol for on USB host controller + // + HcDevicePath = NULL; + Status = gBS->OpenProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID **) &HcDevicePath, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + DEBUG ((EFI_D_ERROR, "DwUsbDriverBindingStart3 \n")); + // + // Create then install USB2_HC_PROTOCOL + // +// Ehc = EhcCreateUsb2Hc (PciIo, HcDevicePath, OriginalPciAttributes); +// Ehc = EhcCreateUsb2Hc (PciIo, HcDevicePath, 0); + Ehc = OhciAllocateDev(PciIo); + DEBUG ((EFI_D_ERROR, "DwUsbDriverBindingStart4 \n")); + if (Ehc == NULL) { + DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to create USB2_HC\n")); + + Status = EFI_OUT_OF_RESOURCES; + goto CLOSE_PCIIO; + } + Status = gBS->InstallProtocolInterface ( + &Controller, +// &gEfiUsb2HcProtocolGuid, + &gEfiUsbHcProtocolGuid, + EFI_NATIVE_INTERFACE, + &Ehc->UsbHc + ); + DEBUG ((EFI_D_ERROR, "DwUsbDriverBindingStart5 \n")); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to install USB2_HC Protocol\n")); + goto FREE_POOL; + } + // + // Start the asynchronous interrupt monitor + // +/* Status = gBS->SetTimer (Ehc->PollTimer, TimerPeriodic, EHC_ASYNC_POLL_INTERVAL); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to start async interrupt monitor\n")); + + EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT); + goto UNINSTALL_USBHC; + } +*/ + // + // Create event to stop the HC when exit boot service. + // + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + DwHcExitBootService, + Ehc, + &gEfiEventExitBootServicesGuid, + &Ehc->ExitBootServiceEvent + ); + if (EFI_ERROR (Status)) { + goto UNINSTALL_USBHC; + } + + // + // Install the component name protocol, don't fail the start + // because of something for display. + // + DEBUG ((EFI_D_ERROR, "DwUsbDriverBindingStart6 \n")); + AddUnicodeString2 ( + "eng", + gOhciComponentName.SupportedLanguages, + &Ehc->ControllerNameTable, + L"Designware Host Controller (USB 2.0)", + TRUE + ); + AddUnicodeString2 ( + "en", + gOhciComponentName2.SupportedLanguages, + &Ehc->ControllerNameTable, + L"Designware Host Controller (USB 2.0)", + FALSE + ); + DEBUG ((EFI_D_ERROR, "DwUsbDriverBindingStart7 \n")); + phy_init(Ehc); //TODO these need the pci protocol so they talk to the right device... + DEBUG ((EFI_D_ERROR, "DwUsbDriverBindingStart8 \n")); + DwHostInit(Ehc); + +UNINSTALL_USBHC: +CLOSE_PCIIO: +FREE_POOL: + + DEBUG ((EFI_D_INFO, "EhcDriverBindingStart: EHCI started for controller @ %p\n", Controller)); + DEBUG ((EFI_D_ERROR, "DwUsbDriverBindingStart9 \n")); + return EFI_SUCCESS; + +} + +/** + Stop this driver on ControllerHandle. Support stopping any child handles + created by this driver. + + @param This Protocol instance pointer. + @param Controller Handle of device to stop driver on. + @param NumberOfChildren Number of Children in the ChildHandleBuffer. + @param ChildHandleBuffer List of handles for the children we need to stop. + + @return EFI_SUCCESS Success. + @return EFI_DEVICE_ERROR Fail. + +**/ +EFI_STATUS +EFIAPI +DwUsbDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +{ + EFI_STATUS Status; + EFI_USB2_HC_PROTOCOL *Usb2Hc; +// EFI_PCI_IO_PROTOCOL *PciIo; + USB_OHCI_HC_DEV *Ehc; + + DEBUG ((EFI_D_ERROR, "DwUsbDriverBindingStop \n")); + // + // Test whether the Controller handler passed in is a valid + // Usb controller handle that should be supported, if not, + // return the error status directly + // + Status = gBS->OpenProtocol ( + Controller, +// &gEfiUsb2HcProtocolGuid, + &gEfiUsbHcProtocolGuid, + (VOID **) &Usb2Hc, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return Status; + } + +// Ehc = EHC_FROM_THIS (Usb2Hc); + Ehc = USB_OHCI_HC_DEV_FROM_THIS (This); +// PciIo = Ehc->PciIo; + + Status = gBS->UninstallProtocolInterface ( + Controller, +// &gEfiUsb2HcProtocolGuid, + &gEfiUsbHcProtocolGuid, + Usb2Hc + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Stop AsyncRequest Polling timer then stop the EHCI driver + // and uninstall the EHCI protocl. + // +/* gBS->SetTimer (Ehc->PollTimer, TimerCancel, EHC_ASYNC_POLL_INTERVAL); + EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT); + + if (Ehc->PollTimer != NULL) { + gBS->CloseEvent (Ehc->PollTimer); + } +*/ + if (Ehc->ExitBootServiceEvent != NULL) { + gBS->CloseEvent (Ehc->ExitBootServiceEvent); + } +/* + EhcFreeSched (Ehc); + + if (Ehc->ControllerNameTable != NULL) { + FreeUnicodeStringTable (Ehc->ControllerNameTable); + } +*/ + // + // Disable routing of all ports to EHCI controller, so all ports are + // routed back to the UHCI or OHCI controller. + // + /*EhcClearOpRegBit (Ehc, EHC_CONFIG_FLAG_OFFSET, CONFIGFLAG_ROUTE_EHC); + + // + // Restore original PCI attributes + // + PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationSet, + Ehc->OriginalPciAttributes, + NULL + ); + */ + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + FreePool (Ehc); + + return EFI_SUCCESS; +} + + + +EFI_DRIVER_BINDING_PROTOCOL +gOhciDriverBinding = { + DwUsbDriverBindingSupported, + DwUsbDriverBindingStart, + DwUsbDriverBindingStop, + 0x30, + NULL, + NULL +}; + +EFI_STATUS +EFIAPI +DwUsbEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + DEBUG ((EFI_D_ERROR, "DwUsbEntryPoint \n")); + return EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gOhciDriverBinding, + ImageHandle, + &gOhciComponentName, + &gOhciComponentName2 + ); +} diff --git a/Silicon/Synopsys/Usb/DwUsbDxe/DwUsbDxe.dec b/Silicon/Synopsys/Usb/DwUsbDxe/DwUsbDxe.dec new file mode 100644 index 000000000..860da80bd --- /dev/null +++ b/Silicon/Synopsys/Usb/DwUsbDxe/DwUsbDxe.dec @@ -0,0 +1,42 @@ +#/** @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) 2015-2017, 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 = DwUsbDxePkg + PACKAGE_GUID = 6c9afc9afb83-e3cd-4453-9b3f-78ffba3e67af + 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] + gDwUsbDxeTokenSpaceGuid = { 0x6fdd76a9, 0xf220, 0x4f1d, { 0x9c, 0xcf, 0xbc, 0x2d, 0x68, 0x29, 0xab, 0x9d }} + +[PcdsFixedAtBuild.common] + # DwEmmc Driver PCDs + gDwUsbDxeTokenSpaceGuid.PcdDwUsbBaseAddress|0x0|UINT32|0x00000001 + gDwUsbDxeTokenSpaceGuid.PcdDwUsbSysCtrlBaseAddress|0x0|UINT32|0x0000002 diff --git a/Silicon/Synopsys/Usb/DwUsbDxe/DwUsbDxe.h b/Silicon/Synopsys/Usb/DwUsbDxe/DwUsbDxe.h new file mode 100644 index 000000000..95ee0a5ee --- /dev/null +++ b/Silicon/Synopsys/Usb/DwUsbDxe/DwUsbDxe.h @@ -0,0 +1,534 @@ +/** @file + + Copyright (c) 2015, Linaro Limited. All rights reserved. + Copyright (c) 2015, Hisilicon Limited. All rights reserved. + Copyright (c) 2017, Jeremy Linton. 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_USB_DXE_H__ +#define __DW_USB_DXE_H__ + +#define DW_USB_BASE FixedPcdGet32 (PcdDwUsbBaseAddress) +#define USB_PHY_BASE FixedPcdGet32 (PcdDwUsbSysCtrlBaseAddress) + +// This stuff is a verbatim copy of the linux phy-hi6220-usb.c driver +// Its also in the linaro hikey edk2 git tree. +// No real explanation of what these do beyond that file. +/*#define SC_PERIPH_CTRL4 0x00c + +#define CTRL4_PICO_SIDDQ BIT6 +#define CTRL4_PICO_OGDISABLE BIT8 +#define CTRL4_PICO_VBUSVLDEXT BIT10 +#define CTRL4_PICO_VBUSVLDEXTSEL BIT11 +#define CTRL4_OTG_PHY_SEL BIT21 + +#define SC_PERIPH_CTRL5 0x010 + +#define CTRL5_USBOTG_RES_SEL BIT3 +#define CTRL5_PICOPHY_ACAENB BIT4 +#define CTRL5_PICOPHY_BC_MODE BIT5 +#define CTRL5_PICOPHY_CHRGSEL BIT6 +#define CTRL5_PICOPHY_VDATSRCEND BIT7 +#define CTRL5_PICOPHY_VDATDETENB BIT8 +#define CTRL5_PICOPHY_DCDENB BIT9 +#define CTRL5_PICOPHY_IDDIG BIT10 + +#define SC_PERIPH_CTRL8 0x018 +#define SC_PERIPH_RSTEN0 0x300 +#define SC_PERIPH_RSTDIS0 0x304 + +#define RST0_USBOTG_BUS BIT4 +#define RST0_POR_PICOPHY BIT5 +#define RST0_USBOTG BIT6 +#define RST0_USBOTG_32K BIT7 + +#define EYE_PATTERN_PARA 0x7053348c*/ + +// GPIO pins to enable hub and turn on host mode +#define GPIODATA_3 0x0020 +#define GPIODATA_7 0x0200 +#define GPIODIR 0x0400 +#define GPIOAFSEL 0x0420 + +#define USB_SEL_GPIO0_3 3 // GPIO 0_3 +#define USB_5V_HUB_EN 7 // GPIO 0_7 +#define USB_ID_DET_GPIO2_5 21 // GPIO 2_5 +#define USB_VBUS_DET_GPIO2_6 22 // GPIO 2_6 + + +#define PHY_READ_REG32(Offset) MmioRead32 (USB_PHY_BASE + Offset) +#define PHY_WRITE_REG32(Offset, Val) MmioWrite32 (USB_PHY_BASE + Offset, Val) +#define GPIO_READ_REG32(Offset) MmioRead32(0xf8011000+Offset) +#define GPIO_WRITE_REG32(Offset, Val) MmioWrite32(0xf8011000+Offset,Val) + +#define READ_REG64(Offset) MmioRead64 (DW_USB_BASE + Offset) +#define READ_REG32(Offset) MmioRead32 (DW_USB_BASE + Offset) +#define READ_REG16(Offset) (UINT16) READ_REG32 (Offset) +#define WRITE_REG64(Offset, Val) MmioWrite64 (DW_USB_BASE + Offset, Val) +#define WRITE_REG32(Offset, Val) MmioWrite32 (DW_USB_BASE + Offset, Val) +#define WRITE_REG16(Offset, Val) MmioWrite32 (DW_USB_BASE + Offset, (UINT32) Val) +#define WRITE_REG8(Offset, Val) MmioWrite32 (DW_USB_BASE + Offset, (UINT32) Val) + +// Max packet size in bytes (For Full Speed USB 64 is the only valid value) +#define MAX_PACKET_SIZE_CONTROL 64 + +#define MAX_PACKET_SIZE_BULK 512 + +// 8 Endpoints, in and out. Don't count the Endpoint 0 setup buffer +#define DW_NUM_ENDPOINTS 16 + +// Endpoint Indexes +#define DW_EP0SETUP 0x20 +#define DW_EP0RX 0x00 +#define DW_EP0TX 0x01 +#define DW_EP1RX 0x02 +#define DW_EP1TX 0x03 + +// DcInterrupt bits +#define DW_DC_INTERRUPT_BRESET BIT0 +#define DW_DC_INTERRUPT_SOF BIT1 +#define DW_DC_INTERRUPT_PSOF BIT2 +#define DW_DC_INTERRUPT_SUSP BIT3 +#define DW_DC_INTERRUPT_RESUME BIT4 +#define DW_DC_INTERRUPT_HS_STAT BIT5 +#define DW_DC_INTERRUPT_DMA BIT6 +#define DW_DC_INTERRUPT_VBUS BIT7 +#define DW_DC_INTERRUPT_EP0SETUP BIT8 +#define DW_DC_INTERRUPT_EP0RX BIT10 +#define DW_DC_INTERRUPT_EP0TX BIT11 +#define DW_DC_INTERRUPT_EP1RX BIT12 +#define DW_DC_INTERRUPT_EP1TX BIT13 +// All valid peripheral controller interrupts +#define DW_DC_INTERRUPT_MASK 0x003FFFDFF + +#define DW_ADDRESS 0x200 +#define DW_ADDRESS_DEVEN BIT7 + +#define DW_MODE 0x20C +#define DW_MODE_DATA_BUS_WIDTH BIT8 +#define DW_MODE_CLKAON BIT7 +#define DW_MODE_SFRESET BIT4 +#define DW_MODE_WKUPCS BIT2 + +#define DW_ENDPOINT_MAX_PACKET_SIZE 0x204 + +#define DW_ENDPOINT_TYPE 0x208 +#define DW_ENDPOINT_TYPE_NOEMPKT BIT4 +#define DW_ENDPOINT_TYPE_ENABLE BIT3 + +#define DW_INTERRUPT_CONFIG 0x210 +// Interrupt config value to only interrupt on ACK of IN and OUT tokens +#define DW_INTERRUPT_CONFIG_ACK_ONLY BIT2 | BIT5 | BIT6 + +#define DW_DC_INTERRUPT 0x218 +#define DW_DC_INTERRUPT_ENABLE 0x214 + +#define DW_CTRL_FUNCTION 0x228 +#define DW_CTRL_FUNCTION_VENDP BIT3 +#define DW_CTRL_FUNCTION_DSEN BIT2 +#define DW_CTRL_FUNCTION_STATUS BIT1 + +#define DW_DEVICE_UNLOCK 0x27C +#define DW_DEVICE_UNLOCK_MAGIC 0xAA37 + +#define DW_SW_RESET_REG 0x30C +#define DW_SW_RESET_ALL BIT0 + +#define DW_DEVICE_ID 0x370 + +#define DW_OTG_CTRL_SET 0x374 +#define DW_OTG_CTRL_CLR OTG_CTRL_SET + 2 +#define DW_OTG_CTRL_OTG_DISABLE BIT10 +#define DW_OTG_CTRL_VBUS_CHRG BIT6 +#define DW_OTG_CTRL_VBUS_DISCHRG BIT5 +#define DW_OTG_CTRL_DM_PULLDOWN BIT2 +#define DW_OTG_CTRL_DP_PULLDOWN BIT1 +#define DW_OTG_CTRL_DP_PULLUP BIT0 + +#define DW_OTG_STATUS 0x378 +#define DW_OTG_STATUS_B_SESS_END BIT7 +#define DW_OTG_STATUS_A_B_SESS_VLD BIT1 + +#define DW_OTG_INTERRUPT_LATCH_SET 0x37C +#define DW_OTG_INTERRUPT_LATCH_CLR 0x37E +#define DW_OTG_INTERRUPT_ENABLE_RISE 0x384 + +#define DW_DMA_ENDPOINT_INDEX 0x258 + +#define DW_ENDPOINT_INDEX 0x22c +#define DW_DATA_PORT 0x220 +#define DW_BUFFER_LENGTH 0x21c + +// Device ID Values +#define PHILLIPS_VENDOR_ID_VAL 0x04cc +#define DW_PRODUCT_ID_VAL 0x1761 +#define DW_DEVICE_ID_VAL ((ISP1761_PRODUCT_ID_VAL << 16) |\ + PHILLIPS_VENDOR_ID_VAL) + +#define DWC_OTG_BASE DW_USB_BASE + +#define USB_NUM_ENDPOINTS 2 +#define MAX_EPS_CHANNELS 16 + +#define BULK_OUT_EP 1 +#define BULK_IN_EP 1 + +#define RX_REQ_LEN 512 +#define MAX_PACKET_LEN 512 + +#define DATA_FIFO_CONFIG 0x0F801000 +/* RX FIFO: 2048 bytes */ +#define RX_SIZE 0x00000200 +/* Non-periodic TX FIFO: 128 bytes. start address: 0x200 * 4. */ +#define ENDPOINT_TX_SIZE 0x01000200 + +/* EP1 TX FIFO: 1024 bytes. start address: 0x300 * 4. */ +/* EP2 TX FIFO: 1024 bytes. start address: 0x400 * 4. */ +/* EP3 TX FIFO: 1024 bytes. start address: 0x500 * 4. */ +/* EP4 TX FIFO: 1024 bytes. start address: 0x600 * 4. */ +/* EP5 TX FIFO: 1024 bytes. start address: 0x700 * 4. */ +/* EP6 TX FIFO: 1024 bytes. start address: 0x800 * 4. */ +/* EP7 TX FIFO: 1024 bytes. start address: 0x900 * 4. */ +/* EP8 TX FIFO: 1024 bytes. start address: 0xA00 * 4. */ +/* EP9 TX FIFO: 1024 bytes. start address: 0xB00 * 4. */ +/* EP10 TX FIFO: 1024 bytes. start address: 0xC00 * 4. */ +/* EP11 TX FIFO: 512 bytes. start address: 0xD00 * 4. */ +/* EP12 TX FIFO: 512 bytes. start address: 0xD80 * 4. */ +/* EP13 TX FIFO: 512 bytes. start address: 0xE00 * 4. */ +/* EP14 TX FIFO: 512 bytes. start address: 0xE80 * 4. */ +/* EP15 TX FIFO: 512 bytes. start address: 0xF00 * 4. */ + +#define DATA_IN_ENDPOINT_TX_FIFO1 0x01000300 +#define DATA_IN_ENDPOINT_TX_FIFO2 0x01000400 +#define DATA_IN_ENDPOINT_TX_FIFO3 0x01000500 +#define DATA_IN_ENDPOINT_TX_FIFO4 0x01000600 +#define DATA_IN_ENDPOINT_TX_FIFO5 0x01000700 +#define DATA_IN_ENDPOINT_TX_FIFO6 0x01000800 +#define DATA_IN_ENDPOINT_TX_FIFO7 0x01000900 +#define DATA_IN_ENDPOINT_TX_FIFO8 0x01000A00 +#define DATA_IN_ENDPOINT_TX_FIFO9 0x01000B00 +#define DATA_IN_ENDPOINT_TX_FIFO10 0x01000C00 +#define DATA_IN_ENDPOINT_TX_FIFO11 0x00800D00 +#define DATA_IN_ENDPOINT_TX_FIFO12 0x00800D80 +#define DATA_IN_ENDPOINT_TX_FIFO13 0x00800E00 +#define DATA_IN_ENDPOINT_TX_FIFO14 0x00800E80 +#define DATA_IN_ENDPOINT_TX_FIFO15 0x00800F00 + +/*DWC_OTG regsiter descriptor*/ +/*Device mode CSR MAP*/ +#define DEVICE_CSR_BASE (0x800) +/*Device mode CSR MAP*/ +#define DEVICE_INEP_BASE (0x900) +/*Device mode CSR MAP*/ +#define DEVICE_OUTEP_BASE (0xB00) + +/*** OTG LINK CORE REGISTERS ***/ +/* Core Global Registers */ +#define GOTGCTL (0x000) +#define GOTGINT (0x004) +#define GAHBCFG (0x008) //Global AHB Config +#define GAHBCFG_AHB_SINGLE (1 << 23) +#define GAHBCFG_NOTI_ALL_DMA_WRIT (1 << 22) +#define GAHBCFG_REM_MEM_SUPP (1 << 21) +#define GAHBCFG_P_TXF_EMP_LVL (1 << 8) +#define GAHBCFG_NP_TXF_EMP_LVL (1 << 7) +#define GAHBCFG_DMA_EN (1 << 5) +#define GAHBCFG_HBSTLEN_MASK (0xf << 1) +#define GAHBCFG_HBSTLEN_SHIFT 1 +#define GAHBCFG_HBSTLEN_SINGLE 0 +#define GAHBCFG_HBSTLEN_INCR 1 +#define GAHBCFG_HBSTLEN_INCR4 3 +#define GAHBCFG_HBSTLEN_INCR8 5 +#define GAHBCFG_HBSTLEN_INCR16 7 +#define GAHBCFG_GLBL_INTR_EN (1 << 0) +#define GAHBCFG_CTRL_MASK (GAHBCFG_P_TXF_EMP_LVL | \ + GAHBCFG_NP_TXF_EMP_LVL | \ + GAHBCFG_DMA_EN | \ + GAHBCFG_GLBL_INTR_EN) +#define GUSBCFG (0x00C) +#define GRSTCTL (0x010) //Global reset control +#define GRSTCTL_AHBIDLE (1 << 31) +#define GRSTCTL_DMAREQ (1 << 30) +#define GRSTCTL_TXFNUM_MASK (0x1f << 6) +#define GRSTCTL_TXFNUM_SHIFT 6 +#define GRSTCTL_TXFNUM_LIMIT 0x1f +#define GRSTCTL_TXFNUM(_x) ((_x) << 6) +#define GRSTCTL_TXFFLSH (1 << 5) +#define GRSTCTL_RXFFLSH (1 << 4) +#define GRSTCTL_IN_TKNQ_FLSH (1 << 3) +#define GRSTCTL_FRMCNTRRST (1 << 2) +#define GRSTCTL_HSFTRST (1 << 1) +#define GRSTCTL_CSFTRST (1 << 0) + +#define GINTSTS (0x014) +#define GINTMSK (0x018) +#define GRXSTSR (0x01C) +#define GRXSTSP (0x020) +#define GRXFSIZ (0x024) //Global RX FIFO Size +#define GNPTXFSIZ (0x028) //Global non periodic TX FIFO Size +#define GNPTXSTS (0x02C) //Global non periodic TX FIFO Status +#define GSNPSID (0x040) //looks like a chip version? + +#define GHWCFG1 (0x044) +#define GHWCFG2 (0x048) +#define GHWCFG3 (0x04c) +#define GHWCFG4 (0x050) +#define GLPMCFG (0x054) + +#define GDFIFOCFG (0x05c) + +#define HPTXFSIZ (0x100) +#define DIEPTXF(x) (0x100 + 4 * (x)) +#define DIEPTXF1 (0x104) +#define DIEPTXF2 (0x108) +#define DIEPTXF3 (0x10C) +#define DIEPTXF4 (0x110) +#define DIEPTXF5 (0x114) +#define DIEPTXF6 (0x118) +#define DIEPTXF7 (0x11C) +#define DIEPTXF8 (0x120) +#define DIEPTXF9 (0x124) +#define DIEPTXF10 (0x128) +#define DIEPTXF11 (0x12C) +#define DIEPTXF12 (0x130) +#define DIEPTXF13 (0x134) +#define DIEPTXF14 (0x138) +#define DIEPTXF15 (0x13C) + +/*** HOST MODE REGISTERS ***/ +/* Host Global Registers */ +#define HCFG (0x400) // host config +#define HFIR (0x404) // host frame interval +#define HFNUM (0x408) // host frame number +#define HFNUM_FRNUM_MASK (0xffff << 0) +#define HPTXSTS (0x410) // host tx fifo stats +#define HAINT (0x414) // host all channels interrupt flags +#define HAINTMSK (0x418) // host all channels interrupt mask + +/* Host Port Control and Status Registers */ +#define HPRT (0x440) +#define HPRT0_SPD_MASK (0x3 << 17) +#define HPRT0_SPD_SHIFT 17 +#define HPRT0_SPD_HIGH_SPEED 0 +#define HPRT0_SPD_FULL_SPEED 1 +#define HPRT0_SPD_LOW_SPEED 2 +#define HPRT0_TSTCTL_MASK (0xf << 13) +#define HPRT0_TSTCTL_SHIFT 13 +#define HPRT0_PWR (1 << 12) +#define HPRT0_LNSTS_MASK (0x3 << 10) +#define HPRT0_LNSTS_SHIFT 10 +#define HPRT0_RST (1 << 8) +#define HPRT0_SUSP (1 << 7) +#define HPRT0_RES (1 << 6) +#define HPRT0_OVRCURRCHG (1 << 5) +#define HPRT0_OVRCURRACT (1 << 4) +#define HPRT0_ENACHG (1 << 3) +#define HPRT0_ENA (1 << 2) +#define HPRT0_CONNDET (1 << 1) +#define HPRT0_CONNSTS (1 << 0) + +/* Host Channel-Specific Registers */ +#define HCCHAR(x) (0x500 + 0x20 * (x)) //channel characteristics +#define HCCHAR_CHENA (1 << 31) // channel enable +#define HCCHAR_CHDIS (1 << 30) // channel disable +#define HCCHAR_ODDFRM (1 << 29) +#define HCCHAR_DEVADDR_MASK (0x7f << 22) +#define HCCHAR_DEVADDR_SHIFT 22 +#define HCCHAR_MULTICNT_MASK (0x3 << 20) +#define HCCHAR_MULTICNT_SHIFT 20 +#define HCCHAR_EPTYPE_MASK (0x3 << 18) +#define HCCHAR_EPTYPE_SHIFT 18 +#define HCCHAR_LSPDDEV (1 << 17) +#define HCCHAR_EPDIR (1 << 15) +#define HCCHAR_EPNUM_MASK (0xf << 11) +#define HCCHAR_EPNUM_SHIFT 11 +#define HCCHAR_MPS_MASK (0x7ff << 0) +#define HCCHAR_MPS_SHIFT 0 +#define HCSPLT(x) (0x504 + 0x20 * (x)) +#define HCINT(x) (0x508 + 0x20 * (x)) +#define HCINTMSK(x) (0x50C + 0x20 * (x)) +#define HCINTMSK_RESERVED14_31 (0x3ffff << 14) +#define HCINTMSK_FRM_LIST_ROLL (1 << 13) +#define HCINTMSK_XCS_XACT (1 << 12) +#define HCINTMSK_BNA (1 << 11) +#define HCINTMSK_DATATGLERR (1 << 10) +#define HCINTMSK_FRMOVRUN (1 << 9) +#define HCINTMSK_BBLERR (1 << 8) +#define HCINTMSK_XACTERR (1 << 7) +#define HCINTMSK_NYET (1 << 6) +#define HCINTMSK_ACK (1 << 5) +#define HCINTMSK_NAK (1 << 4) +#define HCINTMSK_STALL (1 << 3) +#define HCINTMSK_AHBERR (1 << 2) +#define HCINTMSK_CHHLTD (1 << 1) //channel halted +#define HCINTMSK_XFERCOMPL (1 << 0) +#define HCTSIZ(x) (0x510 + 0x20 * (x)) //transfer size/packet reg +#define TSIZ_DOPNG (1 << 31) //do ping before transfer +#define TSIZ_SC_MC_PID_MASK (0x3 << 29) //USB packet id +#define TSIZ_SC_MC_PID_SHIFT 29 +#define TSIZ_SC_MC_PID_DATA0 0 +#define TSIZ_SC_MC_PID_DATA2 1 +#define TSIZ_SC_MC_PID_DATA1 2 +#define TSIZ_SC_MC_PID_MDATA 3 +#define TSIZ_SC_MC_PID_SETUP 3 +#define TSIZ_PKTCNT_MASK (0x3ff << 19) +#define TSIZ_PKTCNT_SHIFT 19 +#define TSIZ_NTD_MASK (0xff << 8) +#define TSIZ_NTD_SHIFT 8 +#define TSIZ_SCHINFO_MASK (0xff << 0) +#define TSIZ_SCHINFO_SHIFT 0 +#define TSIZ_XFERSIZE_MASK (0x7ffff << 0) +#define TSIZ_XFERSIZE_SHIFT 0 +#define HCDMA(x) (0x514 + 0x20 * (x)) + +/*** DEVICE MODE REGISTERS ***/ +/* Device Global Registers */ +#define DCFG (0x800) +#define DCTL (0x804) +#define DSTS (0x808) +#define DIEPMSK (0x810) +#define DOEPMSK (0x814) +#define DAINT (0x818) +#define DAINTMSK (0x81C) +#define DTKNQR1 (0x820) +#define DTKNQR2 (0x824) +#define DVBUSDIS (0x828) +#define DVBUSPULSE (0x82C) +#define DTHRCTL (0x830) + +/* Device Logical IN Endpoint-Specific Registers */ +#define DIEPCTL(x) (0x900 + 0x20 * (x)) +#define DIEPINT(x) (0x908 + 0x20 * (x)) +#define DIEPTSIZ(x) (0x910 + 0x20 * (x)) +#define DIEPDMA(x) (0x914 + 0x20 * (x)) +#define DTXFSTS(x) (0x918 + 0x20 * (x)) + +/* Device Logical OUT Endpoint-Specific Registers */ +#define DOEPCTL(x) (0xB00 + 0x20 * (x)) +#define DOEPINT(x) (0xB08 + 0x20 * (x)) +#define DOEPTSIZ(x) (0xB10 + 0x20 * (x)) +#define DOEPDMA(x) (0xB14 + 0x20 * (x)) + +/* Power and Clock Gating Register */ +#define PCGCCTL (0xE00) + +#define EP0FIFO (0x1000) + +#define USB_ENDPOINT_XFER_CONTROL 0 +#define USB_ENDPOINT_XFER_ISOC 1 +#define USB_ENDPOINT_XFER_BULK 2 +#define USB_ENDPOINT_XFER_INT 3 + +/** + * This union represents the bit fields in the DMA Descriptor + * status quadlet. Read the quadlet into the d32 member then + * set/clear the bits using the bit, b_iso_out and + * b_iso_in elements. + */ +typedef union dev_dma_desc_sts { + /** raw register data */ + unsigned int d32; + /** quadlet bits */ + struct { + /** Received number of bytes */ + unsigned bytes:16; + /** NAK bit - only for OUT EPs */ + unsigned nak:1; + unsigned reserved17_22:6; + /** Multiple Transfer - only for OUT EPs */ + unsigned mtrf:1; + /** Setup Packet received - only for OUT EPs */ + unsigned sr:1; + /** Interrupt On Complete */ + unsigned ioc:1; + /** Short Packet */ + unsigned sp:1; + /** Last */ + unsigned l:1; + /** Receive Status */ + unsigned sts:2; + /** Buffer Status */ + unsigned bs:2; + } b; +} dev_dma_desc_sts_t; + +/** + * DMA Descriptor structure + * + * DMA Descriptor structure contains two quadlets: + * Status quadlet and Data buffer pointer. + */ +typedef struct dwc_otg_dev_dma_desc { + /** DMA Descriptor status quadlet */ + dev_dma_desc_sts_t status; + /** DMA Descriptor data buffer pointer */ + UINT32 buf; +} dwc_otg_dev_dma_desc_t; + + + + + + + + + + + + + + +typedef struct _USB_OHCI_HC_DEV USB_OHCI_HC_DEV; + +struct _USB_OHCI_HC_DEV { + UINTN Signature; + EFI_USB_HC_PROTOCOL UsbHc; + EFI_USB2_HC_PROTOCOL Usb2Hc; + EFI_PCI_IO_PROTOCOL *PciIo; + UINT64 OriginalPciAttributes; + +// HCCA_MEMORY_BLOCK *HccaMemoryBlock; + VOID *HccaMemoryBuf; + VOID *HccaMemoryMapping; + UINTN HccaMemoryPages; + +// ED_DESCRIPTOR *IntervalList[6][32]; +// INTERRUPT_CONTEXT_ENTRY *InterruptContextList; + VOID *MemPool; + + UINT32 ToggleFlag; + + EFI_EVENT HouseKeeperTimer; + // + // ExitBootServicesEvent is used to stop the OHC DMA operation + // after exit boot service. + // + EFI_EVENT ExitBootServiceEvent; + + EFI_UNICODE_STRING_TABLE *ControllerNameTable; + + UINT32 PortStatus; +}; + +#define USB_DW_HC_DEV_SIGNATURE SIGNATURE_32('d','u','s','b') +extern EFI_DRIVER_BINDING_PROTOCOL gOhciDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gOhciComponentName; +extern EFI_COMPONENT_NAME2_PROTOCOL gOhciComponentName2; + +#define USB_OHCI_HC_DEV_FROM_THIS(a) CR(a, USB_OHCI_HC_DEV, UsbHc, USB_DW_HC_DEV_SIGNATURE) +#define USB2_OHCI_HC_DEV_FROM_THIS(a) CR(a, USB_OHCI_HC_DEV, Usb2Hc, USB_DW_HC_DEV_SIGNATURE) + + + + + +#endif //ifndef __DW_USB_DXE_H__ diff --git a/Silicon/Synopsys/Usb/DwUsbDxe/DwUsbDxe.inf b/Silicon/Synopsys/Usb/DwUsbDxe/DwUsbDxe.inf new file mode 100644 index 000000000..e733e1172 --- /dev/null +++ b/Silicon/Synopsys/Usb/DwUsbDxe/DwUsbDxe.inf @@ -0,0 +1,60 @@ +#/** @file +# +# Copyright (c) 2015, Linaro Limited. All rights reserved. +# Copyright (c) 2015, Hisilicon Limited. All rights reserved. +# Copyright (c) 2017, Jeremy Linton +# +# 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 = 0x00010005 + BASE_NAME = DwUsbDxe + FILE_GUID = 72d78ea6-4dee-11e3-8100-f3842a48d0a0 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = DwUsbEntryPoint + +[Sources.common] + DwUsbDxe.c + ComponentName.c + +[LibraryClasses] + DebugLib + IoLib + MemoryAllocationLib + TimerLib + UefiLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UncachedMemoryAllocationLib + CacheMaintenanceLib + +[Guids] + gEfiEventExitBootServicesGuid ## consume + +[Protocols] + gEfiDriverBindingProtocolGuid + gUsbDeviceProtocolGuid + gEfiUsbHcProtocolGuid ## produce + gEfiPciIoProtocolGuid ## TO_START + + +[Packages] + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + Platform/Drivers/Usb/DwUsbDxe/DwUsbDxe.dec + +[Pcd] + gDwUsbDxeTokenSpaceGuid.PcdDwUsbBaseAddress + gDwUsbDxeTokenSpaceGuid.PcdDwUsbSysCtrlBaseAddress diff --git a/Silicon/Synopsys/Usb/DwUsbHostDxe/ComponentName.c b/Silicon/Synopsys/Usb/DwUsbHostDxe/ComponentName.c new file mode 100644 index 000000000..4357e091c --- /dev/null +++ b/Silicon/Synopsys/Usb/DwUsbHostDxe/ComponentName.c @@ -0,0 +1,243 @@ +/** @file +UEFI Component Name and Name2 protocol for Designware USB driver. + +Copyright (c) 2013-2015 Intel Corporation. +Copyright (c) 2017 Jeremy Linton + +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 "ComponentName.h" +#include "DwUsbHostDxe.h" + +// +// EFI Component Name Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gDwUsbComponentName = { + DwUsbComponentNameGetDriverName, + DwUsbComponentNameGetControllerName, + "eng" +}; + +// +// EFI Component Name 2 Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gDwUsbComponentName2 = { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) DwUsbComponentNameGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) DwUsbComponentNameGetControllerName, + "en" +}; + + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mDwUsbDriverNameTable[] = { + { "eng;en", L"Designware Usb Driver" }, + { NULL, NULL } +}; + + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +DwUsbComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mDwUsbDriverNameTable, + DriverName, + (BOOLEAN)(This == &gDwUsbComponentName) + ); +} + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +DwUsbComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +{ + EFI_STATUS Status; + DWUSB_OTGHC_DEV *DwUsbDev; + EFI_USB2_HC_PROTOCOL *UsbHc; + + // + // This is a device driver, so ChildHandle must be NULL. + // + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + // + // Make sure this driver is currently managing ControllerHandle + // +/* Status = EfiTestManagedDevice ( + ControllerHandle, + gOhciDriverBinding.DriverBindingHandle, + &gEfiPciIoProtocolGuid + ); + if (EFI_ERROR (Status)) { + return Status; +}*/ + // + // Get the device context + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUsb2HcProtocolGuid, + (VOID **) &UsbHc, + gDwUsbDriverBinding.DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + DwUsbDev = DWHC_FROM_THIS(UsbHc); + + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + DwUsbDev->ControllerNameTable, + ControllerName, + (BOOLEAN)(This == &gDwUsbComponentName) + ); + +} diff --git a/Silicon/Synopsys/Usb/DwUsbHostDxe/ComponentName.h b/Silicon/Synopsys/Usb/DwUsbHostDxe/ComponentName.h new file mode 100644 index 000000000..814a8501d --- /dev/null +++ b/Silicon/Synopsys/Usb/DwUsbHostDxe/ComponentName.h @@ -0,0 +1,148 @@ +/** @file +UEFI Component Name and Name2 protocol for Designware USB driver. + +Copyright (c) 2013-2015 Intel Corporation. +Copyright (c) 2017 Jeremy Linton + +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 _COMPONENT_NAME_H_ +#define _COMPONENT_NAME_H_ + + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +DwUsbComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +DwUsbComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +#endif + diff --git a/Silicon/Synopsys/Usb/DwUsbHostDxe/DwUsbHostDxe.c b/Silicon/Synopsys/Usb/DwUsbHostDxe/DwUsbHostDxe.c new file mode 100644 index 000000000..28a3cde98 --- /dev/null +++ b/Silicon/Synopsys/Usb/DwUsbHostDxe/DwUsbHostDxe.c @@ -0,0 +1,2043 @@ +/** @file + + Copyright (c) 2015, Linaro Limited. All rights reserved. + Copyright (c) 2015, Hisilicon Limited. All rights reserved. + Copyright (c) 2017, Jeremy Linton + + 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. + +**/ + + +// Some notes about this driver: +// +// First as it stands all transfers are routed through the "nonperiodic" queues +// including interrupt transfers. This means we emulate interrupt transfers using +// the UEFI timer and a queue. All the fancy hardware scheduling is unused. +// +// This also means that there is absolutely no prioritization, bandwidth reservations +// or anything else that are generally required of interrupt/isochronous transfers. +// +// We no round robin the channels, this in theory allows us to have multiple commands +// outstanding, but due to the fact that we are either using a timer and mostly +// blocking thta timer during the command submission, its really unlikely that we +// have more than a single command outstanding. +// +// At the moment this is host only driver, and the phy config, which should be attached +// to the DW i2c channel likely isn't. +// +// This driver defaults to High speed, but if we detect split transaction problems with +// low/full speed devices then we reset the root port and everything attached, and restart +// at a lower speed. This allows us to transparently support high/full/low speed devices. +// That said, it seems low speed devices don't really work worth a darn on this controller. +// There are assorted knobs that can be tiwiddled to tweak the low speed bitstream, but +// my USB analyzer is truly just a protocol analyzer and is unable to tell me how far out +// of spec the physical singaling is, and I'm currently to lazy to try an analyze it +// with my scope/logic analyzer. +// + +#include "DwUsbHostDxe.h" +#include "DwcHw.h" + +// Enabling this, disables attempting split transactions, and +// sets the initial root port to full speed (rather than high) +// This option is less useful now that we detect full/low speed +// devices having split transaction problems and automatically +// reset to full speed +#define DW_AT_FULLSPEED 0 + +// Forcing host mode may allow HS/FS/LS devices? Nah, doesn't +// appear that way on the HiSi, but do it anyway for the time. +#define DW_FORCE_HOST 1 + +// This timer controls how frequently we wake up to service +// interrupt transfers (in milliseconds). +#define DW_USB_POLL_TIMER 50 + +// timeout for interrupt transfers +#define DW_USB_POLL_INTERRUPT 100 //100 ms +// We delay ops for a few poll intervals following bulk transfers +// in a lame (non USB standard) way to avoid burning bandwidth +// on interrupt transfers if bulk/setup is active. This also +// avoids colliding interrupts with bulk transfers although this +// seems to work fine now. +#define POLL_DELAY 10 + + +VOID DwHcInit (IN DWUSB_OTGHC_DEV *DwHc); +VOID DwCoreInit (IN DWUSB_OTGHC_DEV *DwHc); + + +#define HI6220_PERI_BASE 0xF7030000 +#define PERI_SC_PERIPH_CLK0_EN 0x200 +#define PERI_SC_PERIPH_CLK0_DIS 0x204 +#define PERI_SC_PERIPH_CLK0_STAT 0x208 +/* this routine is the only really HiKey specific routine + in the module, replace it with appropriate calls elsewhere */ +VOID +ConfigureUsbPhy ( + VOID + ) +{ + UINT32 Data; + DEBUG ((EFI_D_VERBOSE, "ConfigureUsbPhy \n",__func__)); + /*Enable USB clock*/ + Data = MmioRead32 (HI6220_PERI_BASE + PERI_SC_PERIPH_CLK0_EN); + Data |= 0x10; + MmioWrite32 (HI6220_PERI_BASE + PERI_SC_PERIPH_CLK0_EN, 0x10); + + do { + Data = MmioRead32 (HI6220_PERI_BASE + PERI_SC_PERIPH_CLK0_STAT); + } while ((Data & 0x10) == 0); + + /*Take USB IPs out of reset*/ + MmioWrite32 (0xF7030000 + 0x304, 0xF0); + + do { + Data = MmioRead32 (HI6220_PERI_BASE + 0x308); + Data &= 0xF0; + } while (Data); + + /*CTRL5*/ + Data = MmioRead32 (HI6220_PERI_BASE + 0x010); + Data &= ~0x20; + Data |= 0x318; + MmioWrite32 (HI6220_PERI_BASE + 0x010, Data); + + /*CTRL4*/ + /*Configure USB PHY*/ + Data = MmioRead32 (HI6220_PERI_BASE + 0x00C); + + /*make PHY out of low power mode*/ + Data &= ~0x40; + Data &= ~0x100; + Data |= 0xC00; + Data &= ~0x200000; + MmioWrite32 (HI6220_PERI_BASE + 0x00C, Data); + + MmioWrite32 (HI6220_PERI_BASE + 0x018, 0x70533483); //EYE_PATTERN + + MicroSecondDelay (5000); +} + +UINT32 +Wait4Bit ( + IN UINT32 Reg, + IN UINT32 Mask, + IN BOOLEAN Set + ) +{ + UINT32 Timeout = DW_USB_POLL_INTERRUPT; + UINT32 Value; + DEBUG ((EFI_D_VERBOSE, "Wait4Bit \n",__func__)); + + while (--Timeout) { + Value = MmioRead32 (Reg); + if (!Set) + Value = ~Value; + + if ((Value & Mask) == Mask) { + DEBUG ((EFI_D_VERBOSE, "Wait4Bit val=%X return\n",Value)); + return 0; + } + + MicroSecondDelay (1); + } + +// DEBUG ((EFI_D_ERROR, "Wait4Bit: Timeout (Reg:0x%x, mask:0x%x, wait_set:%d, val:0x%X)\n", Reg, Mask, Set, Value)); + + return 1; +} + + +UINT32 +Wait4AnyBit ( + IN UINT32 Reg, + IN UINT32 Mask, + IN UINT32 MaskFail, + IN UINT32 Timeout // in milliseconds + ) +{ + UINT32 Value = MmioRead32 (Reg); + Timeout *= 1000; // we want this in microseconds + DEBUG ((EFI_D_VERBOSE, "Wait4AnyBit \n")); + + while (--Timeout) { + Value = MmioRead32 (Reg); + + if (Value & Mask) { + DEBUG ((EFI_D_VERBOSE, "Wait4AnyBit val=%X return\n",Value)); + return 0; + } + // fail early + if ((Timeout < DW_USB_POLL_INTERRUPT/4) & (Value & MaskFail)) { + DEBUG ((EFI_D_ERROR, "Wait4AnyBit val=%X early fail return\n",Value)); + return 0; + } + + MicroSecondDelay (1); + } + + DEBUG ((EFI_D_VERBOSE, "Wait4AnyBit: Timeout (Reg:0x%x, mask:0x%x, val:0x%X)\n", Reg, Mask, Value)); + + return 1; +} + + +// The Num parameter corresponds to the FIFO being flushed +// 0000 Non periodic TX FIFO in host mode +// 0001 Periodic FIFO host mode +// xxx0 Device mode FIFO +// 10000 Flush all transmit FIFOs +VOID +DwFlushTxFifo ( + IN DWUSB_OTGHC_DEV *DwHc, + IN INT32 Num + ) +{ + UINT32 Status; + DEBUG ((EFI_D_VERBOSE, "DwFlushTxFifo \n",__func__)); + MmioWrite32 (DwHc->DwUsbBase + GRSTCTL, DWC2_GRSTCTL_TXFFLSH | (Num << DWC2_GRSTCTL_TXFNUM_OFFSET)); + + Status = Wait4Bit (DwHc->DwUsbBase + GRSTCTL, DWC2_GRSTCTL_TXFFLSH, 0); + if (Status) + DEBUG ((EFI_D_ERROR, "DwFlushTxFifo: Timeout!\n")); + + MicroSecondDelay (1); +} + +VOID +DwFlushRxFifo ( + IN DWUSB_OTGHC_DEV *DwHc + ) +{ + UINT32 Status; + DEBUG ((EFI_D_VERBOSE, "DwFlushRxFifo \n",__func__)); + MmioWrite32 (DwHc->DwUsbBase + GRSTCTL, DWC2_GRSTCTL_RXFFLSH); + + Status = Wait4Bit (DwHc->DwUsbBase + GRSTCTL, DWC2_GRSTCTL_RXFFLSH, 0); + if (Status) + DEBUG ((EFI_D_ERROR, "DwFlushRxFifo: Timeout!\n")); + + MicroSecondDelay (1); +} + +void DwUsbAttemptClear( + IN DWUSB_OTGHC_DEV *DwHc, + IN UINT32 Channel + ) +{ + + MmioWrite32 (DwHc->DwUsbBase + HCINT(Channel), 0x3FFF); + // disable channel + MmioAndThenOr32 (DwHc->DwUsbBase + HCCHAR(Channel), + ~(DWC2_HCCHAR_CHEN | DWC2_HCCHAR_EPDIR), + DWC2_HCCHAR_CHDIS); + + DwFlushTxFifo (DwHc, 0x00); //flush non periodic queue + DwFlushRxFifo (DwHc); + + MicroSecondDelay (50000); + + MmioWrite32 (DwHc->DwUsbBase + HCINT(Channel), 0x3FFF); + + MmioAndThenOr32 (DwHc->DwUsbBase + HCCHAR(Channel), + ~(DWC2_HCCHAR_EPDIR|DWC2_HCCHAR_CHDIS), + DWC2_HCCHAR_CHEN|DWC2_HCCHAR_CHDIS); + Wait4Bit (DwHc->DwUsbBase + HCCHAR(Channel), DWC2_HCCHAR_CHEN, 0); +} + + +UINT32 +Wait4Chhltd ( + IN DWUSB_OTGHC_DEV *DwHc, + IN UINT32 Channel, + IN UINT32 *Sub, + IN UINT32 *Toggle, + IN BOOLEAN IgnoreAck, + IN BOOLEAN IgnoreComplete, + IN UINT32 Timeout + ) +{ + UINT32 HcintCompHltAck = DWC2_HCINT_XFERCOMP | DWC2_HCINT_CHHLTD; + INT32 Ret; + UINT32 Hcint, Hctsiz; + DEBUG ((EFI_D_VERBOSE, "Wait4Chhltd \n",__func__)); + + MicroSecondDelay (100); +// Ret = Wait4Bit (DwHc->DwUsbBase + HCINT(Channel), DWC2_HCINT_CHHLTD, 1); //wait only for channel halt, cosider waiting for NAK/STALL too.... + +// Ret = Wait4AnyBit (DwHc->DwUsbBase + HCINT(Channel), DWC2_HCINT_CHHLTD|DWC2_HCINT_XFERCOMP, DWC2_HCINT_NAK|DWC2_HCINT_STALL); //Ok really the sequence should be wait for complete + // then halt the channel and wait for channel halt + Ret = Wait4AnyBit (DwHc->DwUsbBase + HCINT(Channel), DWC2_HCINT_CHHLTD, DWC2_HCINT_NAK|DWC2_HCINT_STALL, Timeout); //for whatever reason just waiting for halt tends to work + + MicroSecondDelay (100); + Hcint = MmioRead32 (DwHc->DwUsbBase + HCINT(Channel)); + if (Hcint & DWC2_HCINT_STALL) { + DEBUG ((EFI_D_ERROR, "Wait4Chhltd: STALL Hcint=%X\n", Hcint)); + DwUsbAttemptClear(DwHc, Channel); + return EFI_USB_ERR_STALL; + } + if (Hcint & DWC2_HCINT_BBLERR) { + DEBUG ((EFI_D_ERROR, "Wait4Chhltd: BABBLE Hcint=%X\n", Hcint)); + return EFI_USB_ERR_BABBLE; + } + if (Hcint & DWC2_HCINT_FRMOVRUN) { + DEBUG ((EFI_D_VERBOSE, "Wait4Chhltd: Overrun Hcint=%X\n", Hcint)); + return EFI_USB_ERR_SYSTEM+1; + } + + if (Hcint & DWC2_HCINT_XACTERR) { + DEBUG ((EFI_D_ERROR, "Wait4Chhltd: CRC/bitstuff/etc error Hcint=%X\n", Hcint)); + return EFI_USB_ERR_CRC; + } + + if (Hcint & DWC2_HCINT_NAK) { + //NAKs are part of the normal interrupt protocol + DEBUG ((EFI_D_VERBOSE, "Wait4Chhltd: NAK Hcint=%X\n", Hcint)); + return EFI_USB_ERR_NAK; + } + + if (Hcint & DWC2_HCINT_DATATGLERR) { + DEBUG ((EFI_D_ERROR, "Wait4Chhltd: DATA toggle Hcint=%X\n", Hcint)); + return EFI_USB_ERR_SYSTEM; //what is the correct return? + } + + // Moved this down here so that NAK & other error conditions are + // handled before timeout + if (Ret) { + DEBUG ((EFI_D_VERBOSE, "Wait4Chhltd ret\n")); + DwUsbAttemptClear(DwHc, Channel); + return EFI_USB_ERR_TIMEOUT; + } + + // A happy transfer is halted/complete/acked + // an ignore ack transaction is just complete/halted + if (IgnoreAck) { + Hcint &= ~DWC2_HCINT_ACK; + } + else { + HcintCompHltAck |= DWC2_HCINT_ACK; + } + if (IgnoreComplete) { + Hcint |= DWC2_HCINT_XFERCOMP; + } + + if (Hcint != HcintCompHltAck) { + DEBUG ((EFI_D_ERROR, "Wait4Chhltd: HCINT Error 0x%x\n", Hcint)); + return EFI_USB_ERR_STALL; //JL take this out to unstick device? + } + + Hctsiz = MmioRead32 (DwHc->DwUsbBase + HCTSIZ(Channel)); + *Sub = (Hctsiz & DWC2_HCTSIZ_XFERSIZE_MASK) >> DWC2_HCTSIZ_XFERSIZE_OFFSET; + *Toggle = (Hctsiz & DWC2_HCTSIZ_PID_MASK) >> DWC2_HCTSIZ_PID_OFFSET; + + return EFI_USB_NOERROR; +} + +VOID +DwOtgHcInit ( + IN DWUSB_OTGHC_DEV *DwHc, + IN UINT8 Channel, + IN UINT8 DevAddr, + IN UINT8 Endpoint, + IN UINT8 EpDir, + IN UINT8 EpType, + IN UINT16 MaxPacket, + IN UINT8 DeviceSpeed, + IN UINT8 TtPort, + IN UINT8 TtHub, + IN UINT8 DoComplete + ) +{ + UINT32 Split = 0; + UINT32 Hcchar = (DevAddr << DWC2_HCCHAR_DEVADDR_OFFSET) | + (Endpoint << DWC2_HCCHAR_EPNUM_OFFSET) | + (EpDir << DWC2_HCCHAR_EPDIR_OFFSET) | + (EpType << DWC2_HCCHAR_EPTYPE_OFFSET) | + (MaxPacket << DWC2_HCCHAR_MPS_OFFSET); + + if ((DeviceSpeed != EFI_USB_SPEED_HIGH) && (!DwHc->AtFullSpeed)) + { + DEBUG ((EFI_D_ERROR, "Split Message to %d speed device (%d,%d) \n", DeviceSpeed, TtPort, TtHub)); + Split = TtPort | (TtHub << DWC2_HCSPLT_HUBADDR_OFFSET); + Split |= DWC2_HCSPLT_XACTPOS_ALL << DWC2_HCSPLT_XACTPOS_OFFSET; //do all packets? Or just the data payload? +// Split |= DWC2_HCSPLT_XACTPOS_BEGIN << DWC2_HCSPLT_XACTPOS_OFFSET; + Split |= DoComplete?DWC2_HCSPLT_COMPSPLT:0; + //Split |= DWC2_HCSPLT_COMPSPLT; //do a complete split transaction? (docs aren't 100% clear on what this means, although maybe its because i'm in DMA mode (hint that splits may not work with DMA) + Split |= DWC2_HCSPLT_SPLTENA; + // Do we need to set lowspeed? I'm guessing this is only when the root port is full/low + // because the "speed" of a split transaction is still high to the TT.. + Hcchar |= DWC2_HCCHAR_LSPDDEV; + } + else if (DeviceSpeed == EFI_USB_SPEED_LOW) + { + Hcchar |= DWC2_HCCHAR_LSPDDEV; + } + + DEBUG ((EFI_D_VERBOSE, "DwOtgHcInit \n",__func__)); + + MmioWrite32 (DwHc->DwUsbBase + HCINT(Channel), 0x3FFF); + + MmioWrite32 (DwHc->DwUsbBase + HCCHAR(Channel), Hcchar); + + MmioWrite32 (DwHc->DwUsbBase + HCSPLT(Channel), Split); +} + +VOID +DwCoreReset ( + IN DWUSB_OTGHC_DEV *DwHc + ) +{ + UINT32 Status; + DEBUG ((EFI_D_VERBOSE, "DwCoreReset \n",__func__)); + + Status = Wait4Bit (DwHc->DwUsbBase + GRSTCTL, DWC2_GRSTCTL_AHBIDLE, 1); + if (Status) + DEBUG ((EFI_D_ERROR, "DwCoreReset: Timeout!\n")); + + MmioWrite32 (DwHc->DwUsbBase + GRSTCTL, DWC2_GRSTCTL_CSFTRST); + + Status = Wait4Bit (DwHc->DwUsbBase + GRSTCTL, DWC2_GRSTCTL_CSFTRST, 0); + if (Status) + DEBUG ((EFI_D_ERROR, "DwCoreReset: Timeout!\n")); + + MicroSecondDelay (100000); +} + +EFI_STATUS +DwHcTransfer ( + IN DWUSB_OTGHC_DEV *DwHc, + IN UINT8 DeviceAddress, + IN UINTN MaximumPacketLength, + IN OUT UINT32 *Pid, + IN UINT32 TransferDirection, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN UINT32 EpAddress, + IN UINT32 EpType, + OUT UINT32 *TransferResult, + IN BOOLEAN IgnoreAck, + IN BOOLEAN DoPing, + IN UINT8 DeviceSpeed, + IN UINT8 TtPort, + IN UINT8 TtHub, + IN UINT8 IgnoreComplete, + IN UINT32 Timeout + ) +{ + UINT32 TxferLen; + UINTN BufferLen; + UINT32 Done = 0; + UINT32 NumPackets; + UINT32 Sub; + UINT32 StopTransfer = 0; + EFI_STATUS Status = EFI_SUCCESS; + UINT32 SplitDone = 0; + EFI_PHYSICAL_ADDRESS BusPhysAddr; + VOID *Mapping = NULL; + // picking a channel based on EP works in this driver but doesn't seem to afford andy + // advantages (at the moment). +// UINT32 Channel = (EpAddress & 0x7F) % DWC2_MAX_CHANNELS; + EFI_TPL OriginalTPL; +// UINT32 Channel = DWC2_HC_CHANNEL; //just use channel 0 for everything +// UINT32 Channel = 0; + + static UINT32 StaticChannel = 0; + UINT32 Channel = (StaticChannel++) % DWC2_MAX_CHANNELS; + UINT32 ChannelRetries = DWC2_MAX_CHANNELS; + + OriginalTPL = gBS->RaiseTPL(TPL_HIGH_LEVEL); + for (ChannelRetries = 0 ; ChannelRetries < DWC2_MAX_CHANNELS; ChannelRetries++) + { + if (DwHc->ActiveChannel[Channel]) + { + Channel++; + DEBUG ((EFI_D_ERROR, "DwHcTransfer: Channel Collision\n")); + } + else + { + DwHc->ActiveChannel[Channel] = TRUE; + break; + } + } + gBS->RestoreTPL (OriginalTPL); + + if (ChannelRetries == DWC2_MAX_CHANNELS) + { + DEBUG ((EFI_D_ERROR, "DwHcTransfer: Out of channels\n")); + } + DEBUG ((EFI_D_VERBOSE, "DwHcTransfer channel=%d\n",Channel)); + + + OriginalTPL = gBS->RaiseTPL(TPL_NOTIFY); + + do { + DwOtgHcInit (DwHc, Channel, DeviceAddress, EpAddress, TransferDirection, EpType, MaximumPacketLength, DeviceSpeed, TtPort, TtHub, SplitDone); + + TxferLen = *DataLength - Done; + if (TxferLen > DWC2_MAX_TRANSFER_SIZE) + TxferLen = DWC2_MAX_TRANSFER_SIZE - MaximumPacketLength + 1; + if (TxferLen > DWC2_DATA_BUF_SIZE) + TxferLen = DWC2_DATA_BUF_SIZE - MaximumPacketLength + 1; + + if (TxferLen > 0) { + NumPackets = (TxferLen + MaximumPacketLength - 1) / MaximumPacketLength; + if (NumPackets > DWC2_MAX_PACKET_COUNT) { + NumPackets = DWC2_MAX_PACKET_COUNT; + TxferLen = NumPackets * MaximumPacketLength; + } + } else { + NumPackets = 1; + } + + if (TransferDirection) + TxferLen = NumPackets * MaximumPacketLength; + + MmioWrite32 (DwHc->DwUsbBase + HCTSIZ(Channel), (TxferLen << DWC2_HCTSIZ_XFERSIZE_OFFSET) | + (NumPackets << DWC2_HCTSIZ_PKTCNT_OFFSET) | (DoPing << DWC2_HCTSIZ_DOPNG_OFFSET) | + (*Pid << DWC2_HCTSIZ_PID_OFFSET)); + + DEBUG ((EFI_D_VERBOSE, "Usb: dma (%d) size %d %d\n",TransferDirection, *DataLength, TxferLen)); + + if (TransferDirection) // direction=1 IN from USB + { + if (*DataLength < TxferLen) + { + BufferLen = *DataLength; + } + else + { + BufferLen = TxferLen; + } + Status = DwHc->PciIo->Map (DwHc->PciIo, EfiPciIoOperationBusMasterWrite , Data+Done , &BufferLen, &BusPhysAddr, &Mapping); + } + else + { + BufferLen = TxferLen; + Status = DwHc->PciIo->Map (DwHc->PciIo, EfiPciIoOperationBusMasterRead , Data+Done , &BufferLen, &BusPhysAddr, &Mapping); + } + + // something is horribly wrong with the way i'm binding the PciIo if this stabilizes + // the transfers (and it removes nearly all the remaining stalls) + asm("dsb sy"); + asm("isb sy"); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Usb: Map DMA failed\n")); + } + + MmioWrite32 (DwHc->DwUsbBase + HCDMA(Channel), (UINTN)BusPhysAddr); + + MmioAndThenOr32 (DwHc->DwUsbBase + HCCHAR(Channel), ~(DWC2_HCCHAR_MULTICNT_MASK | + DWC2_HCCHAR_CHEN | + DWC2_HCCHAR_CHDIS), + ((1 << DWC2_HCCHAR_MULTICNT_OFFSET) | + DWC2_HCCHAR_CHEN)); + +// ArmDataSynchronizationBarrier(); + + *TransferResult = Wait4Chhltd (DwHc, Channel, &Sub, Pid, IgnoreAck, IgnoreComplete, Timeout); + if ((DeviceSpeed != EFI_USB_SPEED_HIGH) && (!SplitDone) && (!DwHc->AtFullSpeed)) + { + SplitDone++; + MmioWrite32 (DwHc->DwUsbBase + HCINT(Channel), 0x3FFF); + MmioAndThenOr32 (DwHc->DwUsbBase + HCCHAR(Channel), ~(DWC2_HCCHAR_MULTICNT_MASK | DWC2_HCCHAR_CHEN | DWC2_HCCHAR_CHDIS), + ((1 << DWC2_HCCHAR_MULTICNT_OFFSET) | DWC2_HCCHAR_CHEN | DWC2_HCSPLT_COMPSPLT)); + *TransferResult = Wait4Chhltd (DwHc, Channel, &Sub, Pid, IgnoreAck, IgnoreComplete, Timeout); +// continue; + } + + DwHc->PciIo->Flush(DwHc->PciIo); + + if (Mapping) + { + DwHc->PciIo->Unmap (DwHc->PciIo, Mapping); + Mapping = NULL; + } + + if (*TransferResult) { + DEBUG ((EFI_D_VERBOSE, "DwHcTransfer: failed\n")); + Status = EFI_DEVICE_ERROR; + break; + } + + if (TransferDirection) { + TxferLen -= Sub; + if (Sub) + StopTransfer = 1; + } + + + Done += TxferLen; + } while (Done < *DataLength && !StopTransfer); + + MmioWrite32 (DwHc->DwUsbBase + HCINTMSK(Channel), 0); + MmioWrite32 (DwHc->DwUsbBase + HCINT(Channel), 0xFFFFFFFF); + + *DataLength = Done; + + gBS->RestoreTPL (OriginalTPL); + + OriginalTPL = gBS->RaiseTPL(TPL_HIGH_LEVEL); + DwHc->ActiveChannel[Channel] = FALSE; + gBS->RestoreTPL (OriginalTPL); + + return Status; +} + +/** + EFI_USB2_HC_PROTOCOL APIs +**/ + +EFI_STATUS +EFIAPI +DwHcGetCapability ( + IN EFI_USB2_HC_PROTOCOL *This, + OUT UINT8 *MaxSpeed, + OUT UINT8 *PortNumber, + OUT UINT8 *Is64BitCapable + ) +{ + DWUSB_OTGHC_DEV *DwHc; + DEBUG ((EFI_D_VERBOSE, "DwHcGetCapability \n",__func__)); + + DwHc = DWHC_FROM_THIS (This); + + if ((MaxSpeed == NULL) || (PortNumber == NULL) || (Is64BitCapable == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (DwHc->AtFullSpeed) + { + *MaxSpeed = EFI_USB_SPEED_FULL; + } + else + { + *MaxSpeed = EFI_USB_SPEED_HIGH; + } + *PortNumber = 1; + *Is64BitCapable = 1; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +DwHcReset ( + IN EFI_USB2_HC_PROTOCOL *This, + IN UINT16 Attributes + ) +{ + DWUSB_OTGHC_DEV *DwHc; + DEBUG ((EFI_D_ERROR, "Designware HostController Reset\n")); + + DwHc = DWHC_FROM_THIS (This); + + ConfigureUsbPhy (); + DwCoreInit(DwHc); + DwHcInit(DwHc); + + MmioAndThenOr32 (DwHc->DwUsbBase + HPRT0, + ~(DWC2_HPRT0_PRTENA | DWC2_HPRT0_PRTCONNDET | + DWC2_HPRT0_PRTENCHNG | DWC2_HPRT0_PRTOVRCURRCHNG), + DWC2_HPRT0_PRTRST); + + MicroSecondDelay (50000); + + MmioAnd32 (DwHc->DwUsbBase + HPRT0, ~(DWC2_HPRT0_PRTENA | DWC2_HPRT0_PRTCONNDET | + DWC2_HPRT0_PRTENCHNG | DWC2_HPRT0_PRTOVRCURRCHNG | + DWC2_HPRT0_PRTRST)); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +DwHcGetState ( + IN EFI_USB2_HC_PROTOCOL *This, + OUT EFI_USB_HC_STATE *State + ) +{ + DWUSB_OTGHC_DEV *DwHc; + + DEBUG ((EFI_D_VERBOSE, "GetState \n",__func__)); + + DwHc = DWHC_FROM_THIS (This); + + *State = DwHc->DwHcState; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +DwHcSetState ( + IN EFI_USB2_HC_PROTOCOL *This, + IN EFI_USB_HC_STATE State + ) +{ + DWUSB_OTGHC_DEV *DwHc; + DEBUG ((EFI_D_VERBOSE, "DwHcSetState \n",__func__)); + + DwHc = DWHC_FROM_THIS (This); + + DwHc->DwHcState = State; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +DwHcGetRootHubPortStatus ( + IN EFI_USB2_HC_PROTOCOL *This, + IN UINT8 PortNumber, + OUT EFI_USB_PORT_STATUS *PortStatus + ) +{ + DWUSB_OTGHC_DEV *DwHc; + UINT32 Hprt0; + static int first = 1; +// DEBUG ((EFI_D_ERROR, "%s \n",L __func__)); +// DEBUG ((EFI_D_ERROR, "GetPortStatus \n")); + + if (first) + { + first = 0 ; + DEBUG ((EFI_D_ERROR, "DwHcReset first \n")); + DwHcReset(This,0); + } + + if (PortNumber > DWC2_HC_CHANNEL) + return EFI_INVALID_PARAMETER; + + if (PortStatus == NULL) + return EFI_INVALID_PARAMETER; + + DwHc = DWHC_FROM_THIS (This); + + PortStatus->PortStatus = 0; + PortStatus->PortChangeStatus = 0; + + Hprt0 = MmioRead32 (DwHc->DwUsbBase + HPRT0); + + if (Hprt0 & DWC2_HPRT0_PRTCONNSTS) { + PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION; + } + + if (Hprt0 & DWC2_HPRT0_PRTENA) { + PortStatus->PortStatus |= USB_PORT_STAT_ENABLE; + } + + if (Hprt0 & DWC2_HPRT0_PRTSUSP) { + PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND; + } + + if (Hprt0 & DWC2_HPRT0_PRTOVRCURRACT) { + PortStatus->PortStatus |= USB_PORT_STAT_OVERCURRENT; + } + + if (Hprt0 & DWC2_HPRT0_PRTRST) { + PortStatus->PortStatus |= USB_PORT_STAT_RESET; + } + + if (Hprt0 & DWC2_HPRT0_PRTPWR) { + PortStatus->PortStatus |= USB_PORT_STAT_POWER; + } + + if (!DwHc->AtFullSpeed) + { + PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED; + } + + if (Hprt0 & DWC2_HPRT0_PRTENCHNG) { +// PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE; + } + + if (Hprt0 & DWC2_HPRT0_PRTCONNDET) { + PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION; + } + + if (Hprt0 & DWC2_HPRT0_PRTOVRCURRCHNG) { + PortStatus->PortChangeStatus |= USB_PORT_STAT_C_OVERCURRENT; + } + +// DEBUG ((EFI_D_ERROR, "GetPortStatus %X %X\n",PortStatus->PortStatus,PortStatus->PortChangeStatus)); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +DwHcSetRootHubPortFeature ( + IN EFI_USB2_HC_PROTOCOL *This, + IN UINT8 PortNumber, + IN EFI_USB_PORT_FEATURE PortFeature + ) +{ + DWUSB_OTGHC_DEV *DwHc; + UINT32 Hprt0; + EFI_STATUS Status = EFI_SUCCESS; + + DEBUG ((EFI_D_ERROR, "DwHcSetRootHubPortFeature \n")); + + if (PortNumber > DWC2_HC_CHANNEL) { + Status = EFI_INVALID_PARAMETER; + goto End; + } + + DwHc = DWHC_FROM_THIS (This); + + switch (PortFeature) { + case EfiUsbPortEnable: + break; + case EfiUsbPortSuspend: + Hprt0 = MmioRead32 (DwHc->DwUsbBase + HPRT0); + Hprt0 &= ~(DWC2_HPRT0_PRTENA | DWC2_HPRT0_PRTCONNDET | + DWC2_HPRT0_PRTENCHNG | DWC2_HPRT0_PRTOVRCURRCHNG); + Hprt0 |= DWC2_HPRT0_PRTSUSP; + MmioWrite32 (DwHc->DwUsbBase + HPRT0, Hprt0); + break; + case EfiUsbPortReset: + MmioAndThenOr32 (DwHc->DwUsbBase + HPRT0, + ~(DWC2_HPRT0_PRTENA | DWC2_HPRT0_PRTCONNDET | + DWC2_HPRT0_PRTENCHNG | DWC2_HPRT0_PRTOVRCURRCHNG), + DWC2_HPRT0_PRTRST); + MicroSecondDelay (50000); + MmioAnd32 (DwHc->DwUsbBase + HPRT0, ~DWC2_HPRT0_PRTRST); + break; + case EfiUsbPortPower: + Hprt0 = MmioRead32 (DwHc->DwUsbBase + HPRT0); + Hprt0 &= ~(DWC2_HPRT0_PRTENA | DWC2_HPRT0_PRTCONNDET | + DWC2_HPRT0_PRTENCHNG | DWC2_HPRT0_PRTOVRCURRCHNG); + Hprt0 |= DWC2_HPRT0_PRTPWR; + MmioWrite32 (DwHc->DwUsbBase + HPRT0, Hprt0); + break; + case EfiUsbPortOwner: + break; + default: + Status = EFI_INVALID_PARAMETER; + break; + } + + End: + return Status; +} + +EFI_STATUS +EFIAPI +DwHcClearRootHubPortFeature ( + IN EFI_USB2_HC_PROTOCOL *This, + IN UINT8 PortNumber, + IN EFI_USB_PORT_FEATURE PortFeature + ) +{ + DWUSB_OTGHC_DEV *DwHc; + UINT32 Hprt0; + EFI_STATUS Status = EFI_SUCCESS; + + DEBUG ((EFI_D_ERROR, "DwHcClearRootHubPortFeature \n")); + + if (PortNumber > DWC2_HC_CHANNEL) { + Status = EFI_INVALID_PARAMETER; + goto End; + } + + DwHc = DWHC_FROM_THIS (This); + + switch (PortFeature) { + case EfiUsbPortEnable: + Hprt0 = MmioRead32 (DwHc->DwUsbBase + HPRT0); + Hprt0 &= ~(DWC2_HPRT0_PRTENA | DWC2_HPRT0_PRTCONNDET | + DWC2_HPRT0_PRTENCHNG | DWC2_HPRT0_PRTOVRCURRCHNG); + Hprt0 |= DWC2_HPRT0_PRTENA; + MmioWrite32 (DwHc->DwUsbBase + HPRT0, Hprt0); + break; + case EfiUsbPortReset: + MmioAndThenOr32 (DwHc->DwUsbBase + HPRT0, + ~(DWC2_HPRT0_PRTENA | DWC2_HPRT0_PRTCONNDET | + DWC2_HPRT0_PRTENCHNG | DWC2_HPRT0_PRTOVRCURRCHNG), + DWC2_HPRT0_PRTRST); + MicroSecondDelay (50000); + MmioAnd32 (DwHc->DwUsbBase + HPRT0, ~DWC2_HPRT0_PRTRST); + break; + case EfiUsbPortSuspend: + MmioWrite32 (DwHc->DwUsbBase + PCGCCTL, 0); + MicroSecondDelay (40000); + Hprt0 = MmioRead32 (DwHc->DwUsbBase + HPRT0); + Hprt0 &= ~(DWC2_HPRT0_PRTENA | DWC2_HPRT0_PRTCONNDET | + DWC2_HPRT0_PRTENCHNG | DWC2_HPRT0_PRTOVRCURRCHNG); + Hprt0 |= DWC2_HPRT0_PRTRES; + MmioWrite32 (DwHc->DwUsbBase + HPRT0, Hprt0); + Hprt0 &= ~DWC2_HPRT0_PRTSUSP; + MicroSecondDelay (150000); + Hprt0 &= ~DWC2_HPRT0_PRTRES; + MmioWrite32 (DwHc->DwUsbBase + HPRT0, Hprt0); + break; + case EfiUsbPortPower: + Hprt0 = MmioRead32 (DwHc->DwUsbBase + HPRT0); + Hprt0 &= ~(DWC2_HPRT0_PRTENA | DWC2_HPRT0_PRTCONNDET | + DWC2_HPRT0_PRTENCHNG | DWC2_HPRT0_PRTOVRCURRCHNG); + Hprt0 &= ~DWC2_HPRT0_PRTPWR; + MmioWrite32 (DwHc->DwUsbBase + HPRT0, Hprt0); + break; + case EfiUsbPortOwner: + break; + case EfiUsbPortConnectChange: + Hprt0 = MmioRead32 (DwHc->DwUsbBase + HPRT0); + Hprt0 &= ~DWC2_HPRT0_PRTCONNDET; + MmioWrite32 (DwHc->DwUsbBase + HPRT0, Hprt0); + break; + case EfiUsbPortResetChange: + break; + case EfiUsbPortEnableChange: + Hprt0 = MmioRead32 (DwHc->DwUsbBase + HPRT0); + Hprt0 &= ~DWC2_HPRT0_PRTENCHNG; + MmioWrite32 (DwHc->DwUsbBase + HPRT0, Hprt0); + break; + case EfiUsbPortSuspendChange: + break; + case EfiUsbPortOverCurrentChange: + Hprt0 = MmioRead32 (DwHc->DwUsbBase + HPRT0); + Hprt0 &= ~DWC2_HPRT0_PRTOVRCURRCHNG; + MmioWrite32 (DwHc->DwUsbBase + HPRT0, Hprt0); + break; + default: + Status = EFI_INVALID_PARAMETER; + break; + } + + End: + return Status; +} + +void DumpRequest(EFI_USB_DEVICE_REQUEST *Request) +{ + if (Request->RequestType & 0x80) { + DEBUG ((EFI_D_VERBOSE, "USB: RequestType %X -> Host\n",Request->RequestType)); + } + else { + DEBUG ((EFI_D_VERBOSE, "USB: RequestType %X -> Device\n",Request->RequestType)); + } + if (Request->RequestType & 0x60) { + DEBUG ((EFI_D_VERBOSE, "USB: -> CLS/VEND\n")); + } + else { + DEBUG ((EFI_D_VERBOSE, "USB: -> STD\n")); + } + switch (Request->RequestType & 0x03) { + case USB_TARGET_DEVICE: + DEBUG ((EFI_D_VERBOSE, "USB: -> DEVICE\n")); + break; + case USB_TARGET_INTERFACE: + DEBUG ((EFI_D_VERBOSE, "USB: -> ITERFACE\n")); + break; + case USB_TARGET_ENDPOINT: + DEBUG ((EFI_D_VERBOSE, "USB: -> ENDPOINT\n")); + break; + case USB_TARGET_OTHER: + DEBUG ((EFI_D_VERBOSE, "USB: -> OTHER\n")); + break; + } + DEBUG ((EFI_D_VERBOSE, "USB: RequestType 0x%X\n",Request->RequestType)); + switch (Request->Request) { + case USB_DEV_GET_STATUS: + DEBUG ((EFI_D_VERBOSE, "USB: GET STATUS\n")); + break; + case USB_DEV_CLEAR_FEATURE: + DEBUG ((EFI_D_VERBOSE, "USB: CLEAR FEATURE\n")); + break; + case USB_DEV_SET_FEATURE: + DEBUG ((EFI_D_VERBOSE, "USB: SET FEATURE\n")); + break; + case USB_DEV_SET_ADDRESS: + DEBUG ((EFI_D_VERBOSE, "USB: SET ADDRESS\n")); + break; + case USB_DEV_GET_DESCRIPTOR: + DEBUG ((EFI_D_VERBOSE, "USB: GET DESCRIPTOR\n")); + break; + case USB_DEV_SET_DESCRIPTOR: + DEBUG ((EFI_D_VERBOSE, "USB: SET DESCRIPTOR\n")); + break; + default: + break; + } + DEBUG ((EFI_D_VERBOSE, "USB: Request %d\n",Request->Request)); + DEBUG ((EFI_D_VERBOSE, "USB: Value 0x%X\n",Request->Value)); + DEBUG ((EFI_D_VERBOSE, "USB: Index 0x%X\n",Request->Index)); + DEBUG ((EFI_D_VERBOSE, "USB: Length %d\n",Request->Length)); +} + + +EFI_STATUS +EFIAPI +DwHcControlTransfer ( + IN EFI_USB2_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 DeviceSpeed, + IN UINTN MaximumPacketLength, + IN EFI_USB_DEVICE_REQUEST *Request, + IN EFI_USB_DATA_DIRECTION TransferDirection, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN UINTN TimeOut, + IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator, + OUT UINT32 *TransferResult + ) +{ + DWUSB_OTGHC_DEV *DwHc; + EFI_STATUS Status; + UINT32 Pid; + UINTN Length; + EFI_USB_DATA_DIRECTION StatusDirection; + UINT32 Direction; + UINT8 *StatusBuffer; + EFI_TPL OriginalTPL; + + DEBUG ((EFI_D_VERBOSE, "DwHcControlTranfer \n")); + DumpRequest(Request); + + if ((Request == NULL) || (TransferResult == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((TransferDirection != EfiUsbDataIn) && + (TransferDirection != EfiUsbDataOut) && + (TransferDirection != EfiUsbNoData)) { + return EFI_INVALID_PARAMETER; + } + + if ((TransferDirection == EfiUsbNoData) && + ((Data != NULL) || (*DataLength != 0))) { + return EFI_INVALID_PARAMETER; + } + + if ((TransferDirection != EfiUsbNoData) && + ((Data == NULL) || (*DataLength == 0))) { + return EFI_INVALID_PARAMETER; + } + + if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) && + (MaximumPacketLength != 32) && (MaximumPacketLength != 64)) { + return EFI_INVALID_PARAMETER; + } + + if ((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) { + return EFI_INVALID_PARAMETER; + } + + DwHc = DWHC_FROM_THIS(This); + + OriginalTPL = gBS->RaiseTPL(TPL_HIGH_LEVEL); + DwHc->BulkActive=POLL_DELAY; + gBS->RestoreTPL (OriginalTPL); + + *TransferResult = EFI_USB_ERR_SYSTEM; + Status = EFI_DEVICE_ERROR; + + Pid = DWC2_HC_PID_SETUP; + Length = 8; + Status = DwHcTransfer (DwHc, DeviceAddress, MaximumPacketLength, &Pid, 0, Request, &Length, + 0, DWC2_HCCHAR_EPTYPE_CONTROL, TransferResult, 1, 0, DeviceSpeed, + Translator->TranslatorPortNumber, Translator->TranslatorHubAddress, 0, TimeOut); + + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_ERROR, "DwHcControlTransfer: Setup Stage Error\n")); + if ((DeviceSpeed != EFI_USB_SPEED_HIGH) && (DwHc->AtFullSpeed == 0)) + { + DEBUG ((EFI_D_ERROR, "DwHcControlTransfer: Split transaction failed, reducing bus speed\n")); + DwHc->AtFullSpeed = 1; + DwHcReset(This, 0); + } + Status = EFI_USB_ERR_SYSTEM; + goto EXIT; + } + + if (Data) { + Pid = DWC2_HC_PID_DATA1; + + if (TransferDirection == EfiUsbDataIn) + Direction = 1; + else + Direction = 0; + + Status = DwHcTransfer (DwHc, DeviceAddress, MaximumPacketLength, &Pid, Direction, + Data, DataLength, 0, DWC2_HCCHAR_EPTYPE_CONTROL, TransferResult, 0, 0, DeviceSpeed, + Translator->TranslatorPortNumber, Translator->TranslatorHubAddress, 0, TimeOut); + + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_ERROR, "DwHcControlTransfer: Data Stage Error\n")); + goto EXIT; + } + } + + if ((TransferDirection == EfiUsbDataOut) || (TransferDirection == EfiUsbNoData)) + StatusDirection = 1; + else + StatusDirection = 0; + + Pid = DWC2_HC_PID_DATA1; + Length = 0; + + StatusBuffer = UncachedAllocatePages (EFI_SIZE_TO_PAGES (DWC2_STATUS_BUF_SIZE)); + if (StatusBuffer == NULL) { + DEBUG ((EFI_D_ERROR, "CreateDwUsbHc: No page availablefor StatusBuffer\n")); + goto EXIT; + } + + Status = DwHcTransfer (DwHc, DeviceAddress, MaximumPacketLength, &Pid, StatusDirection, StatusBuffer, + &Length, 0, DWC2_HCCHAR_EPTYPE_CONTROL, TransferResult, 0, 0, DeviceSpeed, + Translator->TranslatorPortNumber, Translator->TranslatorHubAddress, 0, TimeOut); + + UncachedFreePages (StatusBuffer, EFI_SIZE_TO_PAGES (DWC2_STATUS_BUF_SIZE)); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_ERROR, "DwHcControlTransfer: Status Stage Error\n")); + } + + EXIT: + return Status; +} + +EFI_STATUS +EFIAPI +DwHcBulkTransfer ( + IN EFI_USB2_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN UINT8 DeviceSpeed, + IN UINTN MaximumPacketLength, + IN UINT8 DataBuffersNumber, + IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM], + IN OUT UINTN *DataLength, + IN OUT UINT8 *DataToggle, + IN UINTN TimeOut, + IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator, + OUT UINT32 *TransferResult + ) +{ + DWUSB_OTGHC_DEV *DwHc; + EFI_STATUS Status; + UINT8 TransferDirection; + UINT8 EpAddress; + UINT32 Pid; + UINT8 Ping; + EFI_TPL OriginalTPL; + + DEBUG ((EFI_D_VERBOSE, "DwHcBulkTransfer DEV=%X EP=%X LEN=%X \n",DeviceAddress,EndPointAddress,*DataLength)); + if ((Data == NULL) || (Data[0] == NULL) || + (DataLength == NULL) || (*DataLength == 0) || + (TransferResult == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((*DataToggle != 0) && (*DataToggle != 1)) + return EFI_INVALID_PARAMETER; + + if ((DeviceSpeed == EFI_USB_SPEED_LOW) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) + return EFI_INVALID_PARAMETER; + + if (((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) || + ((DeviceSpeed == EFI_USB_SPEED_HIGH) && (MaximumPacketLength > 512))) + return EFI_INVALID_PARAMETER; + + DwHc = DWHC_FROM_THIS (This); + + *TransferResult = EFI_USB_ERR_SYSTEM; + Status = EFI_DEVICE_ERROR; + TransferDirection = (EndPointAddress >> 7) & 0x01; //IN = 1, OUT = 0 + EpAddress = EndPointAddress & 0x0F; + Pid = (*DataToggle << 1); + Ping = 0; +// Ping = TransferDirection; //for write do ping first + + OriginalTPL = gBS->RaiseTPL(TPL_HIGH_LEVEL); + DwHc->BulkActive=POLL_DELAY; + gBS->RestoreTPL (OriginalTPL); + + Status = DwHcTransfer (DwHc, DeviceAddress, MaximumPacketLength, &Pid, TransferDirection, Data[0], DataLength, + EpAddress, DWC2_HCCHAR_EPTYPE_BULK, TransferResult, 1, Ping, DeviceSpeed, + Translator->TranslatorPortNumber, Translator->TranslatorHubAddress, 0, TimeOut); + + *DataToggle = (Pid >> 1); + +// MicroSecondDelay (5000); +// DwHc->BulkActive=POLL_DELAY; + + return Status; +} + +EFI_STATUS +EFIAPI +DwHcAsyncInterruptTransfer ( + IN EFI_USB2_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN UINT8 DeviceSpeed, + IN UINTN MaximumPacketLength, + IN BOOLEAN IsNewTransfer, + IN OUT UINT8 *DataToggle, + IN UINTN PollingInterval, + IN UINTN DataLength, + IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator, + IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction, + IN VOID *Context OPTIONAL + ) +{ + DWUSB_OTGHC_DEV *DwHc; + EFI_STATUS Status; + EFI_TPL OriginalTPL; + DWUSB_INTERRUPT_QUEUE *CompletionEntry; + DEBUG ((EFI_D_VERBOSE, "DwHcAsyncInterruptTransfer Addr=%d, EP=%d len=%d new=%d Interval=%d(%d)\n",DeviceAddress, EndPointAddress, DataLength, IsNewTransfer, PollingInterval, PollingInterval/DW_USB_POLL_TIMER)); + + if (!(EndPointAddress & USB_ENDPOINT_DIR_IN)) { + DEBUG ((EFI_D_ERROR, "DwHcAsyncInterruptTransfer: endpoint direction not right\n")); + return EFI_INVALID_PARAMETER; + } + + DwHc = DWHC_FROM_THIS (This); + + if (IsNewTransfer) { + if (DataLength == 0) { + DEBUG ((EFI_D_ERROR, "DwHcAsyncInterruptTransfer: invalid len\n")); + return EFI_INVALID_PARAMETER; + } + + if ((*DataToggle != 1) && (*DataToggle != 0)) { + DEBUG ((EFI_D_ERROR, "DwHcAsyncInterruptTransfer: invalid datatoggle\n")); + return EFI_INVALID_PARAMETER; + } + + if ((PollingInterval > 255) || (PollingInterval < 1)) { + DEBUG ((EFI_D_ERROR, "DwHcAsyncInterruptTransfer: Invalid polling interval\n")); + return EFI_INVALID_PARAMETER; + } + } + else { + // The async nature of this callback is bonkers with + // relation to how it should work. So we do all the + // "scheduled" processing in the foreground and then + // just queue the results.. + OriginalTPL = gBS->RaiseTPL(TPL_HIGH_LEVEL); + // Which means we want to cancel any outstanding items here.. + CompletionEntry = DwHc->InterruptQueue; + while (CompletionEntry) { + if ((CompletionEntry->DeviceAddress == DeviceAddress) && (CompletionEntry->EndPointAddress == EndPointAddress)) { + CompletionEntry->Cancel = 1; + } + CompletionEntry = CompletionEntry->Next; + } + gBS->RestoreTPL (OriginalTPL); + return EFI_SUCCESS; + } + + CompletionEntry = AllocateZeroPool (sizeof(DWUSB_INTERRUPT_QUEUE)); + if (CompletionEntry == NULL) { + DEBUG ((EFI_D_ERROR, "DwHcAsyncInterruptTransfer: failed to allocate buffer\n")); + Status = EFI_OUT_OF_RESOURCES; + goto EXIT; + } + + CompletionEntry->Data = AllocateZeroPool (DataLength); + if (CompletionEntry->Data == NULL) { + FreePool(CompletionEntry); + DEBUG ((EFI_D_ERROR, "DwHcAsyncInterruptTransfer: failed to allocate buffer\n")); + Status = EFI_OUT_OF_RESOURCES; + goto EXIT; + } + + CompletionEntry->CallBackFunction = CallBackFunction; + CompletionEntry->DataLength = DataLength; + CompletionEntry->Context = Context; + CompletionEntry->TransferResult = EFI_USB_NOERROR; + CompletionEntry->DeviceAddress = DeviceAddress; + CompletionEntry->EndPointAddress = EndPointAddress; + CompletionEntry->Cancel = 0; + CompletionEntry->This = This; + CompletionEntry->DeviceSpeed = DeviceSpeed; + CompletionEntry->MaximumPacketLength = MaximumPacketLength; + CompletionEntry->Translator = Translator; + if (PollingInterval > DW_USB_POLL_TIMER) { + CompletionEntry->TicksBeforeActive = (PollingInterval/DW_USB_POLL_TIMER); + } else { + CompletionEntry->TicksBeforeActive = 1; + } + CompletionEntry->Ticks = -1; + + Status = EFI_SUCCESS; + + CompletionEntry->DataToggle = *DataToggle; + + DEBUG ((EFI_D_VERBOSE, "DwHcAsyncInterruptTransfer: Save off results of interrupt transfer\n")); + // queue the result to be reported on the timer + OriginalTPL = gBS->RaiseTPL(TPL_HIGH_LEVEL); + CompletionEntry->Next = DwHc->InterruptQueue; + DwHc->InterruptQueue = CompletionEntry; + gBS->RestoreTPL (OriginalTPL); + + + + EXIT: + return Status; +} + +EFI_STATUS +EFIAPI +DwHcSyncInterruptTransfer ( + IN EFI_USB2_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN UINT8 DeviceSpeed, + IN UINTN MaximumPacketLength, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN OUT UINT8 *DataToggle, + IN UINTN TimeOut, + IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator, + OUT UINT32 *TransferResult + ) +{ + DEBUG ((EFI_D_ERROR, "DwHcSyncInterruptTransfer Not Supported\n",__func__)); + return EFI_UNSUPPORTED; +} + +EFI_STATUS +EFIAPI +DwHcIsochronousTransfer ( + IN EFI_USB2_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN UINT8 DeviceSpeed, + IN UINTN MaximumPacketLength, + IN UINT8 DataBuffersNumber, + IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM], + IN UINTN DataLength, + IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator, + OUT UINT32 *TransferResult + ) +{ + DEBUG ((EFI_D_ERROR, "DwHcIsochronousTransfer Not Supported\n",__func__)); + return EFI_UNSUPPORTED; +} + +EFI_STATUS +EFIAPI +DwHcAsyncIsochronousTransfer ( + IN EFI_USB2_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN UINT8 DeviceSpeed, + IN UINTN MaximumPacketLength, + IN UINT8 DataBuffersNumber, + IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM], + IN UINTN DataLength, + IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator, + IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack, + IN VOID *Context + ) +{ + DEBUG ((EFI_D_ERROR, "DwHcAsyncIsochronousTransfer Not Supported\n",__func__)); + return EFI_UNSUPPORTED; +} + +/** + Supported Functions +**/ + +VOID +InitFslspClkSel ( + IN DWUSB_OTGHC_DEV *DwHc + ) +{ + UINT32 PhyClk; + DEBUG ((EFI_D_VERBOSE, "InitFslspClkSel \n",__func__)); + PhyClk = DWC2_HCFG_FSLSPCLKSEL_30_60_MHZ; + + MmioAndThenOr32 (DwHc->DwUsbBase + HCFG, + ~DWC2_HCFG_FSLSPCLKSEL_MASK, + PhyClk << DWC2_HCFG_FSLSPCLKSEL_OFFSET); + if (DwHc->AtFullSpeed) + { + MmioAndThenOr32 (DwHc->DwUsbBase + HCFG, + ~DWC2_HCFG_FSLSSUPP, + DWC2_HCFG_FSLSSUPP); + } +} + + +/** + + Timer to submit periodic interrupt transfer, and invoke callbacks + + @param Event Event handle + @param Context Device private data + +**/ + +VOID +EFIAPI +DwHcTimerCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + DWUSB_OTGHC_DEV *DwHc = (DWUSB_OTGHC_DEV *) Context; + EFI_TPL OriginalTPL; + DWUSB_INTERRUPT_QUEUE *CompletionEntry; + DWUSB_INTERRUPT_QUEUE *CompletionNext; + UINT32 ret = 0; + + OriginalTPL = gBS->RaiseTPL(TPL_HIGH_LEVEL); + if (DwHc->BulkActive>0) { + // This is a gentle hack + // to avoid colliding requests + // for now. + DwHc->BulkActive--; + ret = 1; + } + gBS->RestoreTPL (OriginalTPL); + + if (ret) + return; + +// DEBUG ((EFI_D_ERROR, "DwHcTimerCallback TPL=%dn\n",OriginalTPL)); + + // pick off all queued items. + OriginalTPL = gBS->RaiseTPL(TPL_HIGH_LEVEL); + CompletionNext = DwHc->InterruptQueue; + //DwHc->InterruptQueue = NULL; + gBS->RestoreTPL (OriginalTPL); + + // perform callbacks on queued interrupt status + while (CompletionNext) { + DEBUG ((EFI_D_VERBOSE, "DwHcTimerCallbackn\n")); + CompletionEntry = CompletionNext; + CompletionNext = CompletionEntry->Next; + CompletionEntry->Ticks++; + if ((CompletionEntry->CallBackFunction) && ( CompletionEntry->Cancel == 0 ) && (CompletionEntry->Ticks > CompletionEntry->TicksBeforeActive)) + { + UINT32 Pid; + UINT8 TransferDirection; + UINT8 EpAddress; + EFI_STATUS Status; + EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator = CompletionEntry->Translator; + UINTN DataLength; + UINT32 Timeout = DW_USB_POLL_INTERRUPT; + + if ( CompletionEntry->DeviceAddress == 1 ) + { + // fast timeouts on first hub port + Timeout = 10; + DEBUG ((EFI_D_VERBOSE, "DwHcTimerCallbackn Reset timer for addr1\n")); + } + + // ok execute thie + EpAddress = CompletionEntry->EndPointAddress & 0x0F; + TransferDirection = (CompletionEntry->EndPointAddress >> 7) & 0x01; + + Pid = CompletionEntry->DataToggle; + DataLength = CompletionEntry->DataLength; + + DEBUG ((EFI_D_VERBOSE, "DwHcTimerCallback message to addr=%d, EP=%d Pid=%d\n",CompletionEntry->DeviceAddress, EpAddress, Pid)); + + Status = DwHcTransfer (DwHc, CompletionEntry->DeviceAddress, CompletionEntry->MaximumPacketLength, &Pid, TransferDirection, + CompletionEntry->Data, &DataLength, + EpAddress, DWC2_HCCHAR_EPTYPE_INTR, &CompletionEntry->TransferResult, 1, 0, CompletionEntry->DeviceSpeed, + Translator->TranslatorPortNumber, Translator->TranslatorHubAddress, 1, Timeout); + + DEBUG ((EFI_D_VERBOSE, "DwHcTimerCallback Pid=%d\n", Pid)); + if (EFI_ERROR(Status)) + { + //DEBUG ((EFI_D_ERROR, "Consider canceling the transaction here?\n")); + if (CompletionEntry->TransferResult == EFI_USB_ERR_NAK ) { + // NAK's are still successful transmission + // particularly for interrupt transfers + Status = EFI_USB_NOERROR; + } + + if (CompletionEntry->TransferResult == (EFI_USB_ERR_SYSTEM+1) ) { + // overruns may still have data, lets pass it on + Status = EFI_USB_NOERROR; + //DataLength = CompletionEntry->DataLength; + //CompletionEntry->TransferResult = EFI_USB_NOERROR; + } + if (CompletionEntry->TransferResult == EFI_USB_ERR_TIMEOUT) + { + // This actually appears to recovery everything correctly + // but does it really need recovery, or just a retry? + //DEBUG ((EFI_D_ERROR, "Doing full reset\n")); + // doing full reset + DwHcReset(CompletionEntry->This,0); + } + + } + + CompletionEntry->DataToggle = Pid; + + // don't report NAK's and DATA Toggle errors, what the end user doesn't know won't kill them.. + if ((CompletionEntry->TransferResult != EFI_USB_ERR_SYSTEM) && (CompletionEntry->TransferResult != EFI_USB_ERR_NAK )) { + CompletionEntry->CallBackFunction (CompletionEntry->Data, DataLength, CompletionEntry->Context, CompletionEntry->TransferResult); + } + CompletionEntry->Ticks = 0; //reset the ticks + } + } + + { + // Nove canceled items to a cancel list + // and then delete all the entries on the canceled list + DWUSB_INTERRUPT_QUEUE *Canceled; + // now remove any canceled entries + OriginalTPL = gBS->RaiseTPL(TPL_HIGH_LEVEL); + CompletionNext = DwHc->InterruptQueue; + DwHc->InterruptQueue = NULL; + Canceled = NULL; + + while (CompletionNext) { + + CompletionEntry = CompletionNext; + CompletionNext = CompletionEntry->Next; + if (CompletionEntry->Cancel) + { + // toss it on the canceled queue + CompletionEntry->Next = Canceled; + Canceled = CompletionEntry->Next; + } + else + { + // toss it back on the pending queue + CompletionEntry->Next = DwHc->InterruptQueue; + DwHc->InterruptQueue = CompletionEntry; + } + } + gBS->RestoreTPL (OriginalTPL); + + while (Canceled) + { + DEBUG ((EFI_D_VERBOSE, "DwHcTimerCallback cancel\n")); + CompletionEntry = Canceled; + Canceled = CompletionEntry->Next; + FreePool(CompletionEntry->Data); + FreePool(CompletionEntry); + } + } + +} + +VOID +DwHcInit ( + IN DWUSB_OTGHC_DEV *DwHc + ) +{ + UINT32 NpTxFifoSz = 0; + UINT32 pTxFifoSz = 0; + UINT32 Hprt0 = 0; + INT32 i, Status, NumChannels; + DEBUG ((EFI_D_VERBOSE, "HwHcInit \n",__func__)); + + MmioWrite32 (DwHc->DwUsbBase + PCGCCTL, 0); + + InitFslspClkSel (DwHc); + + MmioWrite32 (DwHc->DwUsbBase + GRXFSIZ, DWC2_HOST_RX_FIFO_SIZE); + + NpTxFifoSz |= DWC2_HOST_NPERIO_TX_FIFO_SIZE << DWC2_FIFOSIZE_DEPTH_OFFSET; + NpTxFifoSz |= DWC2_HOST_RX_FIFO_SIZE << DWC2_FIFOSIZE_STARTADDR_OFFSET; + MmioWrite32 (DwHc->DwUsbBase + GNPTXFSIZ, NpTxFifoSz); + + pTxFifoSz |= DWC2_HOST_PERIO_TX_FIFO_SIZE << DWC2_FIFOSIZE_DEPTH_OFFSET; + pTxFifoSz |= (DWC2_HOST_RX_FIFO_SIZE + DWC2_HOST_NPERIO_TX_FIFO_SIZE) << + DWC2_FIFOSIZE_STARTADDR_OFFSET; + MmioWrite32 (DwHc->DwUsbBase + HPTXFSIZ, pTxFifoSz); + + MmioAnd32 (DwHc->DwUsbBase + GOTGCTL, ~(DWC2_GOTGCTL_HSTSETHNPEN)); + + DwFlushTxFifo (DwHc, 0x10); + DwFlushRxFifo (DwHc); + + NumChannels = MmioRead32 (DwHc->DwUsbBase + GHWCFG2); + NumChannels &= DWC2_HWCFG2_NUM_HOST_CHAN_MASK; + NumChannels >>= DWC2_HWCFG2_NUM_HOST_CHAN_OFFSET; + NumChannels += 1; + + for (i=0; iDwUsbBase + HCCHAR(i), + ~(DWC2_HCCHAR_CHEN | DWC2_HCCHAR_EPDIR), + DWC2_HCCHAR_CHDIS); + + for (i=0; iDwUsbBase + HCCHAR(i), + ~DWC2_HCCHAR_EPDIR, + (DWC2_HCCHAR_CHEN | DWC2_HCCHAR_CHDIS)); + Status = Wait4Bit (DwHc->DwUsbBase + HCCHAR(i), DWC2_HCCHAR_CHEN, 0); + if (Status) + DEBUG ((EFI_D_VERBOSE, "DwHcInit: Timeout!\n")); + } + + if (MmioRead32 (DwHc->DwUsbBase + GINTSTS) & DWC2_GINTSTS_CURMODE_HOST) { + Hprt0 = MmioRead32 (DwHc->DwUsbBase + HPRT0); + Hprt0 &= ~(DWC2_HPRT0_PRTENA | DWC2_HPRT0_PRTCONNDET); + Hprt0 &= ~(DWC2_HPRT0_PRTENCHNG | DWC2_HPRT0_PRTOVRCURRCHNG); + + if (!(Hprt0 & DWC2_HPRT0_PRTPWR)) { + Hprt0 |= DWC2_HPRT0_PRTPWR; + MmioWrite32 (DwHc->DwUsbBase + HPRT0, Hprt0); + } + } +} + +VOID +DwCoreInit ( + IN DWUSB_OTGHC_DEV *DwHc + ) +{ + UINT32 AhbCfg = 0; + UINT32 UsbCfg = 0; + DEBUG ((EFI_D_VERBOSE, "DwCoreInit \n")); + + UsbCfg = MmioRead32 (DwHc->DwUsbBase + GUSBCFG); + + UsbCfg |= DWC2_GUSBCFG_ULPI_EXT_VBUS_DRV; + UsbCfg &= ~DWC2_GUSBCFG_TERM_SEL_DL_PULSE; + + MmioWrite32 (DwHc->DwUsbBase + GUSBCFG, UsbCfg); + + DwCoreReset (DwHc); + + UsbCfg &= ~(DWC2_GUSBCFG_ULPI_UTMI_SEL | DWC2_GUSBCFG_PHYIF); + UsbCfg |= CONFIG_DWC2_PHY_TYPE << DWC2_GUSBCFG_ULPI_UTMI_SEL_OFFSET; + + UsbCfg &= ~DWC2_GUSBCFG_DDRSEL; + + MmioWrite32 (DwHc->DwUsbBase + GUSBCFG, UsbCfg); + + DwCoreReset (DwHc); + + UsbCfg = MmioRead32 (DwHc->DwUsbBase + GUSBCFG); + UsbCfg &= ~(DWC2_GUSBCFG_ULPI_FSLS | DWC2_GUSBCFG_ULPI_CLK_SUS_M); + if (DW_FORCE_HOST) { + UsbCfg |= DWC2_GUSBCFG_FORCEHOSTMODE; + } + UsbCfg &= ~(DWC2_GUSBCFG_HNPCAP | DWC2_GUSBCFG_SRPCAP); //disable host neg protocol and SRP + MmioWrite32 (DwHc->DwUsbBase + GUSBCFG, UsbCfg); + + DEBUG ((EFI_D_ERROR, "DwCoreInit USB cfg %X\n",UsbCfg)); + + AhbCfg |= DWC2_GAHBCFG_HBURSTLEN_INCR4; + AhbCfg |= DWC2_GAHBCFG_DMAENABLE; + + MmioWrite32 (DwHc->DwUsbBase + GAHBCFG, AhbCfg); +// MmioOr32 (DwHc->DwUsbBase + GUSBCFG, DWC2_GUSBCFG_HNPCAP | DWC2_GUSBCFG_SRPCAP); //enable host negotiation, and session request (not wanted for host mode) + +} + +DWUSB_OTGHC_DEV * +CreateDwUsbHc ( + IN EFI_PCI_IO_PROTOCOL *PciIo + ) +{ + DWUSB_OTGHC_DEV *DwHc; + UINT32 Channel; + DEBUG ((EFI_D_VERBOSE, "CreateDwUsbHc \n",__func__)); + + DwHc = AllocateZeroPool (sizeof(DWUSB_OTGHC_DEV)); + + if (DwHc == NULL) { + return NULL; + } + + DwHc->Signature = DWUSB_OTGHC_DEV_SIGNATURE; + DwHc->DwUsbOtgHc.GetCapability = DwHcGetCapability; + DwHc->DwUsbOtgHc.Reset = DwHcReset; + DwHc->DwUsbOtgHc.GetState = DwHcGetState; + DwHc->DwUsbOtgHc.SetState = DwHcSetState; + DwHc->DwUsbOtgHc.ControlTransfer = DwHcControlTransfer; + DwHc->DwUsbOtgHc.BulkTransfer = DwHcBulkTransfer; + DwHc->DwUsbOtgHc.AsyncInterruptTransfer = DwHcAsyncInterruptTransfer; + DwHc->DwUsbOtgHc.SyncInterruptTransfer = DwHcSyncInterruptTransfer; + DwHc->DwUsbOtgHc.IsochronousTransfer = DwHcIsochronousTransfer; + DwHc->DwUsbOtgHc.AsyncIsochronousTransfer = DwHcAsyncIsochronousTransfer; + DwHc->DwUsbOtgHc.GetRootHubPortStatus = DwHcGetRootHubPortStatus; + DwHc->DwUsbOtgHc.SetRootHubPortFeature = DwHcSetRootHubPortFeature; + DwHc->DwUsbOtgHc.ClearRootHubPortFeature = DwHcClearRootHubPortFeature; + DwHc->DwUsbOtgHc.MajorRevision = 0x02; + DwHc->DwUsbOtgHc.MinorRevision = 0x00; + DwHc->DwUsbBase = FixedPcdGet32 (PcdDwUsbBaseAddress); //TODO remove this and convert to Pci->Mem.Read/Write() calls + + DwHc->InterruptQueue = NULL; + DwHc->PciIo = PciIo; + DwHc->BulkActive = 0; + DwHc->AtFullSpeed = DW_AT_FULLSPEED; + + for (Channel = 0 ; Channel < DWC2_MAX_CHANNELS; Channel++) + { + DwHc->ActiveChannel[Channel] = FALSE; + } + + + return DwHc; +} + +VOID +EFIAPI +DwUsbHcExitBootService ( + EFI_EVENT Event, + VOID *Context + ) +{ + DWUSB_OTGHC_DEV *DwHc; + + DEBUG ((EFI_D_ERROR, "\n\n\nEXIT BOOT SERVICES!\n\n\n")); + + DwHc = (DWUSB_OTGHC_DEV *) Context; + + MmioAndThenOr32 (DwHc->DwUsbBase + HPRT0, + ~(DWC2_HPRT0_PRTENA | DWC2_HPRT0_PRTCONNDET | + DWC2_HPRT0_PRTENCHNG | DWC2_HPRT0_PRTOVRCURRCHNG), + DWC2_HPRT0_PRTRST); + + MicroSecondDelay (50000); + + DwCoreReset (DwHc); +} + +#pragma pack(1) +typedef struct { + UINT8 ProgInterface; + UINT8 SubClassCode; + UINT8 BaseCode; +} USB_CLASSC; +#pragma pack() + +/** + Test to see if this driver supports ControllerHandle. Any + ControllerHandle that has Usb2HcProtocol installed will + be supported. + + @param This Protocol instance pointer. + @param Controller Handle of device to test. + @param RemainingDevicePath Not used. + + @return EFI_SUCCESS This driver supports this device. + @return EFI_UNSUPPORTED This driver does not support this device. + +**/ +EFI_STATUS +EFIAPI +DwUsbDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + USB_CLASSC UsbClassCReg; + + // + // Test whether there is PCI IO Protocol attached on the controller handle. + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Status = PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint8, + PCI_CLASSCODE_OFFSET, + sizeof (USB_CLASSC) / sizeof (UINT8), + &UsbClassCReg + ); + + if (EFI_ERROR (Status)) { + Status = EFI_UNSUPPORTED; + goto ON_EXIT; + } + + // + // Test whether the controller belongs to Usb class type + // + if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) || (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB)) { + Status = EFI_UNSUPPORTED; + } + else { + DEBUG ((EFI_D_VERBOSE, "DwUsbDriverBindingSupported found board!\n")); + } + + ON_EXIT: + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return Status; +} + +EFI_STATUS +EFIAPI +DwUsbDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + DWUSB_OTGHC_DEV *DwHc; + EFI_PCI_IO_PROTOCOL *PciIo; + EFI_DEVICE_PATH_PROTOCOL *HcDevicePath; + + Status = EFI_SUCCESS; + + // + // Open the PciIo Protocol, then enable the USB host controller + // + Status = gBS->OpenProtocol ( Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER ); + + if (EFI_ERROR (Status)) { + return Status; + } + + DEBUG ((EFI_D_VERBOSE, "DwUsbDriverBindingStart2 \n")); + // + // Open Device Path Protocol for on USB host controller + // + HcDevicePath = NULL; + Status = gBS->OpenProtocol ( Controller, + &gEfiDevicePathProtocolGuid, + (VOID **) &HcDevicePath, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL ); + DEBUG ((EFI_D_VERBOSE, "DwUsbDriverBindingStart3 \n")); + + if (EFI_ERROR (Status)) { + return Status; + } + + + DwHc = CreateDwUsbHc (PciIo); + + if (DwHc == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto EXIT; + } + + DEBUG ((EFI_D_VERBOSE, "DwUsbDriverBindingStart4 \n")); + Status = gBS->InstallProtocolInterface ( &Controller, + &gEfiUsb2HcProtocolGuid, + EFI_NATIVE_INTERFACE, + &DwHc->DwUsbOtgHc ); + + DEBUG ((EFI_D_VERBOSE, "DwUsbDriverBindingStart5 \n")); + if (EFI_ERROR (Status)) { + goto UNINSTALL_PROTOCOL; + } + + DEBUG ((EFI_D_VERBOSE, "DwUsbDriverBindingStart6 \n")); + // + // Start the asynchronous interrupt monitor + // + Status = gBS->CreateEvent (EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + DwHcTimerCallback, + DwHc, + &DwHc->PollTimer); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Failed to register DwUsbHostDxe Timer\n")); + } + + Status = gBS->SetTimer (DwHc->PollTimer, TimerPeriodic, EFI_TIMER_PERIOD_MILLISECONDS(DW_USB_POLL_TIMER)); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Failed to enable DwUsbHostDxe Timer\n")); + } + + + Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + DwUsbHcExitBootService, + DwHc, + &gEfiEventExitBootServicesGuid, + &DwHc->ExitBootServiceEvent ); + + if (EFI_ERROR (Status)) { + goto UNINSTALL_PROTOCOL; + } + + return Status; + + UNINSTALL_PROTOCOL: + FreePool (DwHc); + EXIT: + return Status; +} + +/** + Stop this driver on ControllerHandle. Support stopping any child handles + created by this driver. + + @param This Protocol instance pointer. + @param Controller Handle of device to stop driver on. + @param NumberOfChildren Number of Children in the ChildHandleBuffer. + @param ChildHandleBuffer List of handles for the children we need to stop. + + @return EFI_SUCCESS Success. + @return EFI_DEVICE_ERROR Fail. + +**/ +EFI_STATUS +EFIAPI +DwUsbDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +{ + EFI_STATUS Status; + EFI_USB2_HC_PROTOCOL *Usb2Hc; +// EFI_PCI_IO_PROTOCOL *PciIo; + DWUSB_OTGHC_DEV *DwHc; + + DEBUG ((EFI_D_ERROR, "DwUsbDriverBindingStop \n")); + // + // Test whether the Controller handler passed in is a valid + // Usb controller handle that should be supported, if not, + // return the error status directly + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiUsb2HcProtocolGuid, + (VOID **) &Usb2Hc, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + DwHc = DWHC_FROM_THIS (This); + + Status = gBS->UninstallProtocolInterface ( + Controller, + &gEfiUsb2HcProtocolGuid, + DwHc + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Stop AsyncRequest Polling timer then stop the EHCI driver + // and uninstall the EHCI protocl. + // + + // stop the interrupt handing + Status = gBS->SetTimer (DwHc->PollTimer, TimerCancel, 0 ); + if (DwHc->PollTimer != NULL) { + gBS->CloseEvent (DwHc->PollTimer); + } + + if (DwHc->ExitBootServiceEvent != NULL) { + gBS->CloseEvent (DwHc->ExitBootServiceEvent); + } + +/* + EhcFreeSched (Ehc); + + if (Ehc->ControllerNameTable != NULL) { + FreeUnicodeStringTable (Ehc->ControllerNameTable); + } +*/ + // + // Disable routing of all ports to EHCI controller, so all ports are + // routed back to the UHCI or OHCI controller. + // + /*EhcClearOpRegBit (Ehc, EHC_CONFIG_FLAG_OFFSET, CONFIGFLAG_ROUTE_EHC); + + // + // Restore original PCI attributes + // + PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationSet, + Ehc->OriginalPciAttributes, + NULL + ); + */ + + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + FreePool (DwHc); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +DwUsbHostExitPoint ( + IN EFI_HANDLE ImageHandle + ) +{ + EFI_STATUS Status; + + Status = EFI_SUCCESS; + + return Status; +} + + +EFI_DRIVER_BINDING_PROTOCOL +gDwUsbDriverBinding = { + DwUsbDriverBindingSupported, + DwUsbDriverBindingStart, + DwUsbDriverBindingStop, + 0x30, + NULL, + NULL +}; + +EFI_STATUS +EFIAPI +DwUsbHostEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + DEBUG ((EFI_D_ERROR, "DwUsbEntryPoint \n")); + return EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gDwUsbDriverBinding, + ImageHandle, + &gDwUsbComponentName, + &gDwUsbComponentName2 + ); +} diff --git a/Silicon/Synopsys/Usb/DwUsbHostDxe/DwUsbHostDxe.h b/Silicon/Synopsys/Usb/DwUsbHostDxe/DwUsbHostDxe.h new file mode 100644 index 000000000..e76094646 --- /dev/null +++ b/Silicon/Synopsys/Usb/DwUsbHostDxe/DwUsbHostDxe.h @@ -0,0 +1,121 @@ +/** @file + + Copyright (c) 2015-2016, Linaro Limited. All rights reserved. + Copyright (c) 2017, Jeremy Linton + + 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 _DWUSBHOSTDXE_H_ +#define _DWUSBHOSTDXE_H_ + +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "DwcHw.h" + +#define MAX_DEVICE 16 +#define MAX_ENDPOINT 16 + +typedef struct _DWUSB_OTGHC_DEV DWUSB_OTGHC_DEV; + +#define DWUSB_OTGHC_DEV_SIGNATURE SIGNATURE_32 ('d', 'w', 'h', 'c') +#define DWHC_FROM_THIS(a) CR(a, DWUSB_OTGHC_DEV, DwUsbOtgHc, DWUSB_OTGHC_DEV_SIGNATURE) + +extern EFI_DRIVER_BINDING_PROTOCOL gDwUsbDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gDwUsbComponentName; +extern EFI_COMPONENT_NAME2_PROTOCOL gDwUsbComponentName2; + +// +// The RequestType in EFI_USB_DEVICE_REQUEST is composed of +// three fields: One bit direction, 2 bit type, and 5 bit +// target. +// +#define USB_REQUEST_TYPE(Dir, Type, Target) \ + ((UINT8)((((Dir) == EfiUsbDataIn ? 0x01 : 0) << 7) | (Type) | (Target))) + +typedef struct { + ACPI_HID_DEVICE_PATH AcpiDevicePath; + PCI_DEVICE_PATH PciDevicePath; + EFI_DEVICE_PATH_PROTOCOL EndDevicePath; +} EFI_USB_PCIIO_DEVICE_PATH; + +typedef struct _DWUSB_INTERRUPT_QUEUE DWUSB_INTERRUPT_QUEUE; +struct _DWUSB_INTERRUPT_QUEUE { + DWUSB_INTERRUPT_QUEUE *Next; + EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction; + VOID *Data; + UINTN DataLength; + VOID *Context; + UINT32 TransferResult; + UINT8 DeviceAddress; //used for matching + UINT8 EndPointAddress; + UINT8 Cancel; +// Now everything needed to queue another interrupt transfer + EFI_USB2_HC_PROTOCOL *This; + UINT8 DeviceSpeed; + UINTN MaximumPacketLength; + EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator; + UINT8 DataToggle; + UINT32 TicksBeforeActive; + INT32 Ticks; +}; + +struct _DWUSB_OTGHC_DEV { + UINTN Signature; + EFI_HANDLE DeviceHandle; + + EFI_USB2_HC_PROTOCOL DwUsbOtgHc; + + EFI_USB_HC_STATE DwHcState; + + EFI_USB_PCIIO_DEVICE_PATH DevicePath; + + EFI_EVENT ExitBootServiceEvent; + + UINT64 DwUsbBase; + + UINT16 PortStatus; + UINT16 PortChangeStatus; + + UINT32 RhDevNum; + + EFI_EVENT PollTimer; //interrupt transfers require an async response model, use a timer to send the query/callback + DWUSB_INTERRUPT_QUEUE *InterruptQueue; //the queue of interrupt transfer results + EFI_PCI_IO_PROTOCOL *PciIo; + EFI_UNICODE_STRING_TABLE *ControllerNameTable; + UINT32 BulkActive; + BOOLEAN AtFullSpeed; + BOOLEAN ActiveChannel[DWC2_MAX_CHANNELS]; +}; + +#endif //_DWUSBHOSTDXE_H_ diff --git a/Silicon/Synopsys/Usb/DwUsbHostDxe/DwUsbHostDxe.inf b/Silicon/Synopsys/Usb/DwUsbHostDxe/DwUsbHostDxe.inf new file mode 100644 index 000000000..5a2109599 --- /dev/null +++ b/Silicon/Synopsys/Usb/DwUsbHostDxe/DwUsbHostDxe.inf @@ -0,0 +1,61 @@ +#/** @file +# +# Copyright (c) 2015-2016, Linaro Limited. All rights reserved. +# Copyright (c) 2017, Jeremy Linton +# +# 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 = 0x00010005 + BASE_NAME = DwUsbHostDxe + FILE_GUID = 4bf1704c-03f4-46d5-bca6-82fa580badfd + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = DwUsbHostEntryPoint +# UNLOAD_IMAGE = DwUsbHostExitPoint + +[Sources.common] + DwUsbHostDxe.c + ComponentName.c + +[Packages] + ArmPkg/ArmPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Synopsys/Usb/DwUsbDxe/DwUsbDxe.dec + +[LibraryClasses] + DmaLib + MemoryAllocationLib + BaseLib + UefiLib + UefiBootServicesTableLib + UefiDriverEntryPoint + BaseMemoryLib + DebugLib + PcdLib + ReportStatusCodeLib + TimerLib + IoLib + +[Guids] + gEfiEventExitBootServicesGuid + +[Protocols] + gEfiDriverBindingProtocolGuid + gEfiUsb2HcProtocolGuid + gEfiPciIoProtocolGuid ## TO_START + +[Pcd] + gDwUsbDxeTokenSpaceGuid.PcdDwUsbBaseAddress + gDwUsbDxeTokenSpaceGuid.PcdDwUsbSysCtrlBaseAddress + diff --git a/Silicon/Synopsys/Usb/DwUsbHostDxe/DwcHw.h b/Silicon/Synopsys/Usb/DwUsbHostDxe/DwcHw.h new file mode 100644 index 000000000..fbe07f64b --- /dev/null +++ b/Silicon/Synopsys/Usb/DwUsbHostDxe/DwcHw.h @@ -0,0 +1,792 @@ +/** @file + + Copyright (c) 2015-2016, Linaro Limited. All rights reserved. + Copyright (c) 2017, Jeremy Linton + + 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 __DWCHW_H__ +#define __DWCHW_H__ + +#define HSOTG_REG(x) (x) + +#define HCCHAR(_ch) HSOTG_REG(0x0500 + 0x20 * (_ch)) +#define HCSPLT(_ch) HSOTG_REG(0x0504 + 0x20 * (_ch)) +#define HCINT(_ch) HSOTG_REG(0x0508 + 0x20 * (_ch)) +#define HCINTMSK(_ch) HSOTG_REG(0x050c + 0x20 * (_ch)) +#define HCTSIZ(_ch) HSOTG_REG(0x0510 + 0x20 * (_ch)) +#define HCDMA(_ch) HSOTG_REG(0x0514 + 0x20 * (_ch)) +#define HCDMAB(_ch) HSOTG_REG(0x051c + 0x20 * (_ch)) + +#define HCFG HSOTG_REG(0x0400) //Host Config +#define HFIR HSOTG_REG(0x0404) //Host Frame interval register +#define HFNUM HSOTG_REG(0x0408) //Host Frame number/frame time +#define HPTXSTS HSOTG_REG(0x0410) //Host periodic transmit fifo queue status reg +#define HAINT HSOTG_REG(0x0414) //Host all channel interrupt register +#define HAINTMSK HSOTG_REG(0x0418) //Host all channel interrupt mask +#define HFLBADDR HSOTG_REG(0x041c) + +#define GOTGCTL HSOTG_REG(0x000) +#define GOTGINT HSOTG_REG(0x004) +#define GAHBCFG HSOTG_REG(0x008) +#define GUSBCFG HSOTG_REG(0x00C) //Global USB config +#define GRSTCTL HSOTG_REG(0x010) +#define GINTSTS HSOTG_REG(0x014) +#define GINTMSK HSOTG_REG(0x018) +#define GRXSTSR HSOTG_REG(0x01C) +#define GRXSTSP HSOTG_REG(0x020) +#define GRXFSIZ HSOTG_REG(0x024) +#define GNPTXFSIZ HSOTG_REG(0x028) +#define GNPTXSTS HSOTG_REG(0x02C) +#define GI2CCTL HSOTG_REG(0x0030) +#define GPVNDCTL HSOTG_REG(0x0034) +#define GGPIO HSOTG_REG(0x0038) +#define GUID HSOTG_REG(0x003c) +#define GSNPSID HSOTG_REG(0x0040) +#define GHWCFG1 HSOTG_REG(0x0044) +#define GHWCFG2 HSOTG_REG(0x0048) +#define GHWCFG3 HSOTG_REG(0x004c) +#define GHWCFG4 HSOTG_REG(0x0050) +#define GLPMCFG HSOTG_REG(0x0054) +#define HPTXFSIZ HSOTG_REG(0x100) +#define DPTXFSIZN(_a) HSOTG_REG(0x104 + (((_a) - 1) * 4)) +#define HPRT0 HSOTG_REG(0x0440) +#define PCGCCTL HSOTG_REG(0xE00) + +#define DWC2_GOTGCTL_SESREQSCS (1 << 0) +#define DWC2_GOTGCTL_SESREQSCS_OFFSET 0 +#define DWC2_GOTGCTL_SESREQ (1 << 1) +#define DWC2_GOTGCTL_SESREQ_OFFSET 1 +#define DWC2_GOTGCTL_HSTNEGSCS (1 << 8) +#define DWC2_GOTGCTL_HSTNEGSCS_OFFSET 8 +#define DWC2_GOTGCTL_HNPREQ (1 << 9) +#define DWC2_GOTGCTL_HNPREQ_OFFSET 9 +#define DWC2_GOTGCTL_HSTSETHNPEN (1 << 10) +#define DWC2_GOTGCTL_HSTSETHNPEN_OFFSET 10 +#define DWC2_GOTGCTL_DEVHNPEN (1 << 11) +#define DWC2_GOTGCTL_DEVHNPEN_OFFSET 11 +#define DWC2_GOTGCTL_CONIDSTS (1 << 16) +#define DWC2_GOTGCTL_CONIDSTS_OFFSET 16 +#define DWC2_GOTGCTL_DBNCTIME (1 << 17) +#define DWC2_GOTGCTL_DBNCTIME_OFFSET 17 +#define DWC2_GOTGCTL_ASESVLD (1 << 18) +#define DWC2_GOTGCTL_ASESVLD_OFFSET 18 +#define DWC2_GOTGCTL_BSESVLD (1 << 19) +#define DWC2_GOTGCTL_BSESVLD_OFFSET 19 +#define DWC2_GOTGCTL_OTGVER (1 << 20) +#define DWC2_GOTGCTL_OTGVER_OFFSET 20 +#define DWC2_GOTGINT_SESENDDET (1 << 2) +#define DWC2_GOTGINT_SESENDDET_OFFSET 2 +#define DWC2_GOTGINT_SESREQSUCSTSCHNG (1 << 8) +#define DWC2_GOTGINT_SESREQSUCSTSCHNG_OFFSET 8 +#define DWC2_GOTGINT_HSTNEGSUCSTSCHNG (1 << 9) +#define DWC2_GOTGINT_HSTNEGSUCSTSCHNG_OFFSET 9 +#define DWC2_GOTGINT_RESERVER10_16_MASK (0x7F << 10) +#define DWC2_GOTGINT_RESERVER10_16_OFFSET 10 +#define DWC2_GOTGINT_HSTNEGDET (1 << 17) +#define DWC2_GOTGINT_HSTNEGDET_OFFSET 17 +#define DWC2_GOTGINT_ADEVTOUTCHNG (1 << 18) +#define DWC2_GOTGINT_ADEVTOUTCHNG_OFFSET 18 +#define DWC2_GOTGINT_DEBDONE (1 << 19) +#define DWC2_GOTGINT_DEBDONE_OFFSET 19 +#define DWC2_GAHBCFG_GLBLINTRMSK (1 << 0) +#define DWC2_GAHBCFG_GLBLINTRMSK_OFFSET 0 +#define DWC2_GAHBCFG_HBURSTLEN_SINGLE (0 << 1) +#define DWC2_GAHBCFG_HBURSTLEN_INCR (1 << 1) +#define DWC2_GAHBCFG_HBURSTLEN_INCR4 (3 << 1) +#define DWC2_GAHBCFG_HBURSTLEN_INCR8 (5 << 1) +#define DWC2_GAHBCFG_HBURSTLEN_INCR16 (7 << 1) +#define DWC2_GAHBCFG_HBURSTLEN_MASK (0xF << 1) +#define DWC2_GAHBCFG_HBURSTLEN_OFFSET 1 +#define DWC2_GAHBCFG_DMAENABLE (1 << 5) +#define DWC2_GAHBCFG_DMAENABLE_OFFSET 5 +#define DWC2_GAHBCFG_NPTXFEMPLVL_TXFEMPLVL (1 << 7) +#define DWC2_GAHBCFG_NPTXFEMPLVL_TXFEMPLVL_OFFSET 7 +#define DWC2_GAHBCFG_PTXFEMPLVL (1 << 8) +#define DWC2_GAHBCFG_PTXFEMPLVL_OFFSET 8 +#define DWC2_GUSBCFG_TOUTCAL_MASK (0x7 << 0) +#define DWC2_GUSBCFG_TOUTCAL_OFFSET 0 +#define DWC2_GUSBCFG_PHYIF (1 << 3) +#define DWC2_GUSBCFG_PHYIF_OFFSET 3 +#define DWC2_GUSBCFG_ULPI_UTMI_SEL (1 << 4) +#define DWC2_GUSBCFG_ULPI_UTMI_SEL_OFFSET 4 +#define DWC2_GUSBCFG_FSINTF (1 << 5) +#define DWC2_GUSBCFG_FSINTF_OFFSET 5 +#define DWC2_GUSBCFG_PHYSEL (1 << 6) //Phy select (host only) 1 full speed phy, 0 external hign speed +#define DWC2_GUSBCFG_PHYSEL_OFFSET 6 +#define DWC2_GUSBCFG_DDRSEL (1 << 7) +#define DWC2_GUSBCFG_DDRSEL_OFFSET 7 +#define DWC2_GUSBCFG_SRPCAP (1 << 8) +#define DWC2_GUSBCFG_SRPCAP_OFFSET 8 +#define DWC2_GUSBCFG_HNPCAP (1 << 9) +#define DWC2_GUSBCFG_HNPCAP_OFFSET 9 +#define DWC2_GUSBCFG_USBTRDTIM_MASK (0xF << 10) +#define DWC2_GUSBCFG_USBTRDTIM_OFFSET 10 +#define DWC2_GUSBCFG_NPTXFRWNDEN (1 << 14) +#define DWC2_GUSBCFG_NPTXFRWNDEN_OFFSET 14 +#define DWC2_GUSBCFG_PHYLPWRCLKSEL (1 << 15) +#define DWC2_GUSBCFG_PHYLPWRCLKSEL_OFFSET 15 +#define DWC2_GUSBCFG_OTGUTMIFSSEL (1 << 16) +#define DWC2_GUSBCFG_OTGUTMIFSSEL_OFFSET 16 +#define DWC2_GUSBCFG_ULPI_FSLS (1 << 17) +#define DWC2_GUSBCFG_ULPI_FSLS_OFFSET 17 +#define DWC2_GUSBCFG_ULPI_AUTO_RES (1 << 18) +#define DWC2_GUSBCFG_ULPI_AUTO_RES_OFFSET 18 +#define DWC2_GUSBCFG_ULPI_CLK_SUS_M (1 << 19) +#define DWC2_GUSBCFG_ULPI_CLK_SUS_M_OFFSET 19 +#define DWC2_GUSBCFG_ULPI_EXT_VBUS_DRV (1 << 20) +#define DWC2_GUSBCFG_ULPI_EXT_VBUS_DRV_OFFSET 20 +#define DWC2_GUSBCFG_ULPI_INT_VBUS_INDICATOR (1 << 21) +#define DWC2_GUSBCFG_ULPI_INT_VBUS_INDICATOR_OFFSET 21 +#define DWC2_GUSBCFG_TERM_SEL_DL_PULSE (1 << 22) +#define DWC2_GUSBCFG_TERM_SEL_DL_PULSE_OFFSET 22 +#define DWC2_GUSBCFG_IC_USB_CAP (1 << 26) +#define DWC2_GUSBCFG_IC_USB_CAP_OFFSET 26 +#define DWC2_GUSBCFG_IC_TRAFFIC_PULL_REMOVE (1 << 27) +#define DWC2_GUSBCFG_IC_TRAFFIC_PULL_REMOVE_OFFSET 27 +#define DWC2_GUSBCFG_TX_END_DELAY (1 << 28) +#define DWC2_GUSBCFG_TX_END_DELAY_OFFSET 28 +#define DWC2_GUSBCFG_FORCEHOSTMODE (1 << 29) //force host mode +#define DWC2_GUSBCFG_FORCEHOSTMODE_OFFSET 29 +#define DWC2_GUSBCFG_FORCEDEVMODE (1 << 30) //force device mode +#define DWC2_GUSBCFG_FORCEDEVMODE_OFFSET 30 +#define DWC2_GLPMCTL_LPM_CAP_EN (1 << 0) +#define DWC2_GLPMCTL_LPM_CAP_EN_OFFSET 0 +#define DWC2_GLPMCTL_APPL_RESP (1 << 1) +#define DWC2_GLPMCTL_APPL_RESP_OFFSET 1 +#define DWC2_GLPMCTL_HIRD_MASK (0xF << 2) +#define DWC2_GLPMCTL_HIRD_OFFSET 2 +#define DWC2_GLPMCTL_REM_WKUP_EN (1 << 6) +#define DWC2_GLPMCTL_REM_WKUP_EN_OFFSET 6 +#define DWC2_GLPMCTL_EN_UTMI_SLEEP (1 << 7) +#define DWC2_GLPMCTL_EN_UTMI_SLEEP_OFFSET 7 +#define DWC2_GLPMCTL_HIRD_THRES_MASK (0x1F << 8) +#define DWC2_GLPMCTL_HIRD_THRES_OFFSET 8 +#define DWC2_GLPMCTL_LPM_RESP_MASK (0x3 << 13) +#define DWC2_GLPMCTL_LPM_RESP_OFFSET 13 +#define DWC2_GLPMCTL_PRT_SLEEP_STS (1 << 15) +#define DWC2_GLPMCTL_PRT_SLEEP_STS_OFFSET 15 +#define DWC2_GLPMCTL_SLEEP_STATE_RESUMEOK (1 << 16) +#define DWC2_GLPMCTL_SLEEP_STATE_RESUMEOK_OFFSET 16 +#define DWC2_GLPMCTL_LPM_CHAN_INDEX_MASK (0xF << 17) +#define DWC2_GLPMCTL_LPM_CHAN_INDEX_OFFSET 17 +#define DWC2_GLPMCTL_RETRY_COUNT_MASK (0x7 << 21) +#define DWC2_GLPMCTL_RETRY_COUNT_OFFSET 21 +#define DWC2_GLPMCTL_SEND_LPM (1 << 24) +#define DWC2_GLPMCTL_SEND_LPM_OFFSET 24 +#define DWC2_GLPMCTL_RETRY_COUNT_STS_MASK (0x7 << 25) +#define DWC2_GLPMCTL_RETRY_COUNT_STS_OFFSET 25 +#define DWC2_GLPMCTL_HSIC_CONNECT (1 << 30) +#define DWC2_GLPMCTL_HSIC_CONNECT_OFFSET 30 +#define DWC2_GLPMCTL_INV_SEL_HSIC (1 << 31) +#define DWC2_GLPMCTL_INV_SEL_HSIC_OFFSET 31 +#define DWC2_GRSTCTL_CSFTRST (1 << 0) +#define DWC2_GRSTCTL_CSFTRST_OFFSET 0 +#define DWC2_GRSTCTL_HSFTRST (1 << 1) +#define DWC2_GRSTCTL_HSFTRST_OFFSET 1 +#define DWC2_GRSTCTL_HSTFRM (1 << 2) +#define DWC2_GRSTCTL_HSTFRM_OFFSET 2 +#define DWC2_GRSTCTL_INTKNQFLSH (1 << 3) +#define DWC2_GRSTCTL_INTKNQFLSH_OFFSET 3 +#define DWC2_GRSTCTL_RXFFLSH (1 << 4) +#define DWC2_GRSTCTL_RXFFLSH_OFFSET 4 +#define DWC2_GRSTCTL_TXFFLSH (1 << 5) +#define DWC2_GRSTCTL_TXFFLSH_OFFSET 5 +#define DWC2_GRSTCTL_TXFNUM_MASK (0x1F << 6) +#define DWC2_GRSTCTL_TXFNUM_OFFSET 6 +#define DWC2_GRSTCTL_DMAREQ (1 << 30) +#define DWC2_GRSTCTL_DMAREQ_OFFSET 30 +#define DWC2_GRSTCTL_AHBIDLE (1 << 31) +#define DWC2_GRSTCTL_AHBIDLE_OFFSET 31 +#define DWC2_GINTMSK_MODEMISMATCH (1 << 1) +#define DWC2_GINTMSK_MODEMISMATCH_OFFSET 1 +#define DWC2_GINTMSK_OTGINTR (1 << 2) +#define DWC2_GINTMSK_OTGINTR_OFFSET 2 +#define DWC2_GINTMSK_SOFINTR (1 << 3) +#define DWC2_GINTMSK_SOFINTR_OFFSET 3 +#define DWC2_GINTMSK_RXSTSQLVL (1 << 4) +#define DWC2_GINTMSK_RXSTSQLVL_OFFSET 4 +#define DWC2_GINTMSK_NPTXFEMPTY (1 << 5) +#define DWC2_GINTMSK_NPTXFEMPTY_OFFSET 5 +#define DWC2_GINTMSK_GINNAKEFF (1 << 6) +#define DWC2_GINTMSK_GINNAKEFF_OFFSET 6 +#define DWC2_GINTMSK_GOUTNAKEFF (1 << 7) +#define DWC2_GINTMSK_GOUTNAKEFF_OFFSET 7 +#define DWC2_GINTMSK_I2CINTR (1 << 9) +#define DWC2_GINTMSK_I2CINTR_OFFSET 9 +#define DWC2_GINTMSK_ERLYSUSPEND (1 << 10) +#define DWC2_GINTMSK_ERLYSUSPEND_OFFSET 10 +#define DWC2_GINTMSK_USBSUSPEND (1 << 11) +#define DWC2_GINTMSK_USBSUSPEND_OFFSET 11 +#define DWC2_GINTMSK_USBRESET (1 << 12) +#define DWC2_GINTMSK_USBRESET_OFFSET 12 +#define DWC2_GINTMSK_ENUMDONE (1 << 13) +#define DWC2_GINTMSK_ENUMDONE_OFFSET 13 +#define DWC2_GINTMSK_ISOOUTDROP (1 << 14) +#define DWC2_GINTMSK_ISOOUTDROP_OFFSET 14 +#define DWC2_GINTMSK_EOPFRAME (1 << 15) +#define DWC2_GINTMSK_EOPFRAME_OFFSET 15 +#define DWC2_GINTMSK_EPMISMATCH (1 << 17) +#define DWC2_GINTMSK_EPMISMATCH_OFFSET 17 +#define DWC2_GINTMSK_INEPINTR (1 << 18) +#define DWC2_GINTMSK_INEPINTR_OFFSET 18 +#define DWC2_GINTMSK_OUTEPINTR (1 << 19) +#define DWC2_GINTMSK_OUTEPINTR_OFFSET 19 +#define DWC2_GINTMSK_INCOMPLISOIN (1 << 20) +#define DWC2_GINTMSK_INCOMPLISOIN_OFFSET 20 +#define DWC2_GINTMSK_INCOMPLISOOUT (1 << 21) +#define DWC2_GINTMSK_INCOMPLISOOUT_OFFSET 21 +#define DWC2_GINTMSK_PORTINTR (1 << 24) +#define DWC2_GINTMSK_PORTINTR_OFFSET 24 +#define DWC2_GINTMSK_HCINTR (1 << 25) +#define DWC2_GINTMSK_HCINTR_OFFSET 25 +#define DWC2_GINTMSK_PTXFEMPTY (1 << 26) +#define DWC2_GINTMSK_PTXFEMPTY_OFFSET 26 +#define DWC2_GINTMSK_LPMTRANRCVD (1 << 27) +#define DWC2_GINTMSK_LPMTRANRCVD_OFFSET 27 +#define DWC2_GINTMSK_CONIDSTSCHNG (1 << 28) +#define DWC2_GINTMSK_CONIDSTSCHNG_OFFSET 28 +#define DWC2_GINTMSK_DISCONNECT (1 << 29) +#define DWC2_GINTMSK_DISCONNECT_OFFSET 29 +#define DWC2_GINTMSK_SESSREQINTR (1 << 30) +#define DWC2_GINTMSK_SESSREQINTR_OFFSET 30 +#define DWC2_GINTMSK_WKUPINTR (1 << 31) +#define DWC2_GINTMSK_WKUPINTR_OFFSET 31 +#define DWC2_GINTSTS_CURMODE_DEVICE (0 << 0) +#define DWC2_GINTSTS_CURMODE_HOST (1 << 0) +#define DWC2_GINTSTS_CURMODE (1 << 0) +#define DWC2_GINTSTS_CURMODE_OFFSET 0 +#define DWC2_GINTSTS_MODEMISMATCH (1 << 1) +#define DWC2_GINTSTS_MODEMISMATCH_OFFSET 1 +#define DWC2_GINTSTS_OTGINTR (1 << 2) +#define DWC2_GINTSTS_OTGINTR_OFFSET 2 +#define DWC2_GINTSTS_SOFINTR (1 << 3) +#define DWC2_GINTSTS_SOFINTR_OFFSET 3 +#define DWC2_GINTSTS_RXSTSQLVL (1 << 4) +#define DWC2_GINTSTS_RXSTSQLVL_OFFSET 4 +#define DWC2_GINTSTS_NPTXFEMPTY (1 << 5) +#define DWC2_GINTSTS_NPTXFEMPTY_OFFSET 5 +#define DWC2_GINTSTS_GINNAKEFF (1 << 6) +#define DWC2_GINTSTS_GINNAKEFF_OFFSET 6 +#define DWC2_GINTSTS_GOUTNAKEFF (1 << 7) +#define DWC2_GINTSTS_GOUTNAKEFF_OFFSET 7 +#define DWC2_GINTSTS_I2CINTR (1 << 9) +#define DWC2_GINTSTS_I2CINTR_OFFSET 9 +#define DWC2_GINTSTS_ERLYSUSPEND (1 << 10) +#define DWC2_GINTSTS_ERLYSUSPEND_OFFSET 10 +#define DWC2_GINTSTS_USBSUSPEND (1 << 11) +#define DWC2_GINTSTS_USBSUSPEND_OFFSET 11 +#define DWC2_GINTSTS_USBRESET (1 << 12) +#define DWC2_GINTSTS_USBRESET_OFFSET 12 +#define DWC2_GINTSTS_ENUMDONE (1 << 13) +#define DWC2_GINTSTS_ENUMDONE_OFFSET 13 +#define DWC2_GINTSTS_ISOOUTDROP (1 << 14) +#define DWC2_GINTSTS_ISOOUTDROP_OFFSET 14 +#define DWC2_GINTSTS_EOPFRAME (1 << 15) +#define DWC2_GINTSTS_EOPFRAME_OFFSET 15 +#define DWC2_GINTSTS_INTOKENRX (1 << 16) +#define DWC2_GINTSTS_INTOKENRX_OFFSET 16 +#define DWC2_GINTSTS_EPMISMATCH (1 << 17) +#define DWC2_GINTSTS_EPMISMATCH_OFFSET 17 +#define DWC2_GINTSTS_INEPINT (1 << 18) +#define DWC2_GINTSTS_INEPINT_OFFSET 18 +#define DWC2_GINTSTS_OUTEPINTR (1 << 19) +#define DWC2_GINTSTS_OUTEPINTR_OFFSET 19 +#define DWC2_GINTSTS_INCOMPLISOIN (1 << 20) +#define DWC2_GINTSTS_INCOMPLISOIN_OFFSET 20 +#define DWC2_GINTSTS_INCOMPLISOOUT (1 << 21) +#define DWC2_GINTSTS_INCOMPLISOOUT_OFFSET 21 +#define DWC2_GINTSTS_PORTINTR (1 << 24) +#define DWC2_GINTSTS_PORTINTR_OFFSET 24 +#define DWC2_GINTSTS_HCINTR (1 << 25) +#define DWC2_GINTSTS_HCINTR_OFFSET 25 +#define DWC2_GINTSTS_PTXFEMPTY (1 << 26) +#define DWC2_GINTSTS_PTXFEMPTY_OFFSET 26 +#define DWC2_GINTSTS_LPMTRANRCVD (1 << 27) +#define DWC2_GINTSTS_LPMTRANRCVD_OFFSET 27 +#define DWC2_GINTSTS_CONIDSTSCHNG (1 << 28) +#define DWC2_GINTSTS_CONIDSTSCHNG_OFFSET 28 +#define DWC2_GINTSTS_DISCONNECT (1 << 29) +#define DWC2_GINTSTS_DISCONNECT_OFFSET 29 +#define DWC2_GINTSTS_SESSREQINTR (1 << 30) +#define DWC2_GINTSTS_SESSREQINTR_OFFSET 30 +#define DWC2_GINTSTS_WKUPINTR (1 << 31) +#define DWC2_GINTSTS_WKUPINTR_OFFSET 31 +#define DWC2_GRXSTS_EPNUM_MASK (0xF << 0) +#define DWC2_GRXSTS_EPNUM_OFFSET 0 +#define DWC2_GRXSTS_BCNT_MASK (0x7FF << 4) +#define DWC2_GRXSTS_BCNT_OFFSET 4 +#define DWC2_GRXSTS_DPID_MASK (0x3 << 15) +#define DWC2_GRXSTS_DPID_OFFSET 15 +#define DWC2_GRXSTS_PKTSTS_MASK (0xF << 17) +#define DWC2_GRXSTS_PKTSTS_OFFSET 17 +#define DWC2_GRXSTS_FN_MASK (0xF << 21) +#define DWC2_GRXSTS_FN_OFFSET 21 +#define DWC2_FIFOSIZE_STARTADDR_MASK (0xFFFF << 0) +#define DWC2_FIFOSIZE_STARTADDR_OFFSET 0 +#define DWC2_FIFOSIZE_DEPTH_MASK (0xFFFF << 16) +#define DWC2_FIFOSIZE_DEPTH_OFFSET 16 +#define DWC2_GNPTXSTS_NPTXFSPCAVAIL_MASK (0xFFFF << 0) +#define DWC2_GNPTXSTS_NPTXFSPCAVAIL_OFFSET 0 +#define DWC2_GNPTXSTS_NPTXQSPCAVAIL_MASK (0xFF << 16) +#define DWC2_GNPTXSTS_NPTXQSPCAVAIL_OFFSET 16 +#define DWC2_GNPTXSTS_NPTXQTOP_TERMINATE (1 << 24) +#define DWC2_GNPTXSTS_NPTXQTOP_TERMINATE_OFFSET 24 +#define DWC2_GNPTXSTS_NPTXQTOP_TOKEN_MASK (0x3 << 25) +#define DWC2_GNPTXSTS_NPTXQTOP_TOKEN_OFFSET 25 +#define DWC2_GNPTXSTS_NPTXQTOP_CHNEP_MASK (0xF << 27) +#define DWC2_GNPTXSTS_NPTXQTOP_CHNEP_OFFSET 27 +#define DWC2_DTXFSTS_TXFSPCAVAIL_MASK (0xFFFF << 0) +#define DWC2_DTXFSTS_TXFSPCAVAIL_OFFSET 0 +#define DWC2_GI2CCTL_RWDATA_MASK (0xFF << 0) +#define DWC2_GI2CCTL_RWDATA_OFFSET 0 +#define DWC2_GI2CCTL_REGADDR_MASK (0xFF << 8) +#define DWC2_GI2CCTL_REGADDR_OFFSET 8 +#define DWC2_GI2CCTL_ADDR_MASK (0x7F << 16) +#define DWC2_GI2CCTL_ADDR_OFFSET 16 +#define DWC2_GI2CCTL_I2CEN (1 << 23) +#define DWC2_GI2CCTL_I2CEN_OFFSET 23 +#define DWC2_GI2CCTL_ACK (1 << 24) +#define DWC2_GI2CCTL_ACK_OFFSET 24 +#define DWC2_GI2CCTL_I2CSUSPCTL (1 << 25) +#define DWC2_GI2CCTL_I2CSUSPCTL_OFFSET 25 +#define DWC2_GI2CCTL_I2CDEVADDR_MASK (0x3 << 26) +#define DWC2_GI2CCTL_I2CDEVADDR_OFFSET 26 +#define DWC2_GI2CCTL_RW (1 << 30) +#define DWC2_GI2CCTL_RW_OFFSET 30 +#define DWC2_GI2CCTL_BSYDNE (1 << 31) +#define DWC2_GI2CCTL_BSYDNE_OFFSET 31 +#define DWC2_HWCFG1_EP_DIR0_MASK (0x3 << 0) +#define DWC2_HWCFG1_EP_DIR0_OFFSET 0 +#define DWC2_HWCFG1_EP_DIR1_MASK (0x3 << 2) +#define DWC2_HWCFG1_EP_DIR1_OFFSET 2 +#define DWC2_HWCFG1_EP_DIR2_MASK (0x3 << 4) +#define DWC2_HWCFG1_EP_DIR2_OFFSET 4 +#define DWC2_HWCFG1_EP_DIR3_MASK (0x3 << 6) +#define DWC2_HWCFG1_EP_DIR3_OFFSET 6 +#define DWC2_HWCFG1_EP_DIR4_MASK (0x3 << 8) +#define DWC2_HWCFG1_EP_DIR4_OFFSET 8 +#define DWC2_HWCFG1_EP_DIR5_MASK (0x3 << 10) +#define DWC2_HWCFG1_EP_DIR5_OFFSET 10 +#define DWC2_HWCFG1_EP_DIR6_MASK (0x3 << 12) +#define DWC2_HWCFG1_EP_DIR6_OFFSET 12 +#define DWC2_HWCFG1_EP_DIR7_MASK (0x3 << 14) +#define DWC2_HWCFG1_EP_DIR7_OFFSET 14 +#define DWC2_HWCFG1_EP_DIR8_MASK (0x3 << 16) +#define DWC2_HWCFG1_EP_DIR8_OFFSET 16 +#define DWC2_HWCFG1_EP_DIR9_MASK (0x3 << 18) +#define DWC2_HWCFG1_EP_DIR9_OFFSET 18 +#define DWC2_HWCFG1_EP_DIR10_MASK (0x3 << 20) +#define DWC2_HWCFG1_EP_DIR10_OFFSET 20 +#define DWC2_HWCFG1_EP_DIR11_MASK (0x3 << 22) +#define DWC2_HWCFG1_EP_DIR11_OFFSET 22 +#define DWC2_HWCFG1_EP_DIR12_MASK (0x3 << 24) +#define DWC2_HWCFG1_EP_DIR12_OFFSET 24 +#define DWC2_HWCFG1_EP_DIR13_MASK (0x3 << 26) +#define DWC2_HWCFG1_EP_DIR13_OFFSET 26 +#define DWC2_HWCFG1_EP_DIR14_MASK (0x3 << 28) +#define DWC2_HWCFG1_EP_DIR14_OFFSET 28 +#define DWC2_HWCFG1_EP_DIR15_MASK (0x3 << 30) +#define DWC2_HWCFG1_EP_DIR15_OFFSET 30 +#define DWC2_HWCFG2_OP_MODE_MASK (0x7 << 0) +#define DWC2_HWCFG2_OP_MODE_OFFSET 0 +#define DWC2_HWCFG2_ARCHITECTURE_SLAVE_ONLY (0x0 << 3) +#define DWC2_HWCFG2_ARCHITECTURE_EXT_DMA (0x1 << 3) +#define DWC2_HWCFG2_ARCHITECTURE_INT_DMA (0x2 << 3) +#define DWC2_HWCFG2_ARCHITECTURE_MASK (0x3 << 3) +#define DWC2_HWCFG2_ARCHITECTURE_OFFSET 3 +#define DWC2_HWCFG2_POINT2POINT (1 << 5) +#define DWC2_HWCFG2_POINT2POINT_OFFSET 5 +#define DWC2_HWCFG2_HS_PHY_TYPE_MASK (0x3 << 6) +#define DWC2_HWCFG2_HS_PHY_TYPE_OFFSET 6 +#define DWC2_HWCFG2_FS_PHY_TYPE_MASK (0x3 << 8) +#define DWC2_HWCFG2_FS_PHY_TYPE_OFFSET 8 +#define DWC2_HWCFG2_NUM_DEV_EP_MASK (0xF << 10) +#define DWC2_HWCFG2_NUM_DEV_EP_OFFSET 10 +#define DWC2_HWCFG2_NUM_HOST_CHAN_MASK (0xF << 14) +#define DWC2_HWCFG2_NUM_HOST_CHAN_OFFSET 14 +#define DWC2_HWCFG2_PERIO_EP_SUPPORTED (1 << 18) +#define DWC2_HWCFG2_PERIO_EP_SUPPORTED_OFFSET 18 +#define DWC2_HWCFG2_DYNAMIC_FIFO (1 << 19) +#define DWC2_HWCFG2_DYNAMIC_FIFO_OFFSET 19 +#define DWC2_HWCFG2_MULTI_PROC_INT (1 << 20) +#define DWC2_HWCFG2_MULTI_PROC_INT_OFFSET 20 +#define DWC2_HWCFG2_NONPERIO_TX_Q_DEPTH_MASK (0x3 << 22) +#define DWC2_HWCFG2_NONPERIO_TX_Q_DEPTH_OFFSET 22 +#define DWC2_HWCFG2_HOST_PERIO_TX_Q_DEPTH_MASK (0x3 << 24) +#define DWC2_HWCFG2_HOST_PERIO_TX_Q_DEPTH_OFFSET 24 +#define DWC2_HWCFG2_DEV_TOKEN_Q_DEPTH_MASK (0x1F << 26) +#define DWC2_HWCFG2_DEV_TOKEN_Q_DEPTH_OFFSET 26 +#define DWC2_HWCFG3_XFER_SIZE_CNTR_WIDTH_MASK (0xF << 0) +#define DWC2_HWCFG3_XFER_SIZE_CNTR_WIDTH_OFFSET 0 +#define DWC2_HWCFG3_PACKET_SIZE_CNTR_WIDTH_MASK (0x7 << 4) +#define DWC2_HWCFG3_PACKET_SIZE_CNTR_WIDTH_OFFSET 4 +#define DWC2_HWCFG3_OTG_FUNC (1 << 7) +#define DWC2_HWCFG3_OTG_FUNC_OFFSET 7 +#define DWC2_HWCFG3_I2C (1 << 8) +#define DWC2_HWCFG3_I2C_OFFSET 8 +#define DWC2_HWCFG3_VENDOR_CTRL_IF (1 << 9) +#define DWC2_HWCFG3_VENDOR_CTRL_IF_OFFSET 9 +#define DWC2_HWCFG3_OPTIONAL_FEATURES (1 << 10) +#define DWC2_HWCFG3_OPTIONAL_FEATURES_OFFSET 10 +#define DWC2_HWCFG3_SYNCH_RESET_TYPE (1 << 11) +#define DWC2_HWCFG3_SYNCH_RESET_TYPE_OFFSET 11 +#define DWC2_HWCFG3_OTG_ENABLE_IC_USB (1 << 12) +#define DWC2_HWCFG3_OTG_ENABLE_IC_USB_OFFSET 12 +#define DWC2_HWCFG3_OTG_ENABLE_HSIC (1 << 13) +#define DWC2_HWCFG3_OTG_ENABLE_HSIC_OFFSET 13 +#define DWC2_HWCFG3_OTG_LPM_EN (1 << 15) +#define DWC2_HWCFG3_OTG_LPM_EN_OFFSET 15 +#define DWC2_HWCFG3_DFIFO_DEPTH_MASK (0xFFFF << 16) +#define DWC2_HWCFG3_DFIFO_DEPTH_OFFSET 16 +#define DWC2_HWCFG4_NUM_DEV_PERIO_IN_EP_MASK (0xF << 0) +#define DWC2_HWCFG4_NUM_DEV_PERIO_IN_EP_OFFSET 0 +#define DWC2_HWCFG4_POWER_OPTIMIZ (1 << 4) +#define DWC2_HWCFG4_POWER_OPTIMIZ_OFFSET 4 +#define DWC2_HWCFG4_MIN_AHB_FREQ_MASK (0x1FF << 5) +#define DWC2_HWCFG4_MIN_AHB_FREQ_OFFSET 5 +#define DWC2_HWCFG4_UTMI_PHY_DATA_WIDTH_MASK (0x3 << 14) +#define DWC2_HWCFG4_UTMI_PHY_DATA_WIDTH_OFFSET 14 +#define DWC2_HWCFG4_NUM_DEV_MODE_CTRL_EP_MASK (0xF << 16) +#define DWC2_HWCFG4_NUM_DEV_MODE_CTRL_EP_OFFSET 16 +#define DWC2_HWCFG4_IDDIG_FILT_EN (1 << 20) +#define DWC2_HWCFG4_IDDIG_FILT_EN_OFFSET 20 +#define DWC2_HWCFG4_VBUS_VALID_FILT_EN (1 << 21) +#define DWC2_HWCFG4_VBUS_VALID_FILT_EN_OFFSET 21 +#define DWC2_HWCFG4_A_VALID_FILT_EN (1 << 22) +#define DWC2_HWCFG4_A_VALID_FILT_EN_OFFSET 22 +#define DWC2_HWCFG4_B_VALID_FILT_EN (1 << 23) +#define DWC2_HWCFG4_B_VALID_FILT_EN_OFFSET 23 +#define DWC2_HWCFG4_SESSION_END_FILT_EN (1 << 24) +#define DWC2_HWCFG4_SESSION_END_FILT_EN_OFFSET 24 +#define DWC2_HWCFG4_DED_FIFO_EN (1 << 25) +#define DWC2_HWCFG4_DED_FIFO_EN_OFFSET 25 +#define DWC2_HWCFG4_NUM_IN_EPS_MASK (0xF << 26) +#define DWC2_HWCFG4_NUM_IN_EPS_OFFSET 26 +#define DWC2_HWCFG4_DESC_DMA (1 << 30) +#define DWC2_HWCFG4_DESC_DMA_OFFSET 30 +#define DWC2_HWCFG4_DESC_DMA_DYN (1 << 31) +#define DWC2_HWCFG4_DESC_DMA_DYN_OFFSET 31 +#define DWC2_HCFG_FSLSPCLKSEL_30_60_MHZ 0 +#define DWC2_HCFG_FSLSPCLKSEL_48_MHZ 1 +#define DWC2_HCFG_FSLSPCLKSEL_6_MHZ 2 +#define DWC2_HCFG_FSLSPCLKSEL_MASK (0x3 << 0) +#define DWC2_HCFG_FSLSPCLKSEL_OFFSET 0 +#define DWC2_HCFG_FSLSSUPP (1 << 2) //Force core to enumerate at FS/LS mode +#define DWC2_HCFG_FSLSSUPP_OFFSET 2 +#define DWC2_HCFG_DESCDMA (1 << 23) +#define DWC2_HCFG_DESCDMA_OFFSET 23 +#define DWC2_HCFG_FRLISTEN_MASK (0x3 << 24) +#define DWC2_HCFG_FRLISTEN_OFFSET 24 +#define DWC2_HCFG_PERSCHEDENA (1 << 26) +#define DWC2_HCFG_PERSCHEDENA_OFFSET 26 +#define DWC2_HCFG_PERSCHEDSTAT (1 << 27) +#define DWC2_HCFG_PERSCHEDSTAT_OFFSET 27 +#define DWC2_HFIR_FRINT_MASK (0xFFFF << 0) +#define DWC2_HFIR_FRINT_OFFSET 0 +#define DWC2_HFNUM_FRNUM_MASK (0xFFFF << 0) +#define DWC2_HFNUM_FRNUM_OFFSET 0 +#define DWC2_HFNUM_FRREM_MASK (0xFFFF << 16) +#define DWC2_HFNUM_FRREM_OFFSET 16 +#define DWC2_HPTXSTS_PTXFSPCAVAIL_MASK (0xFFFF << 0) +#define DWC2_HPTXSTS_PTXFSPCAVAIL_OFFSET 0 +#define DWC2_HPTXSTS_PTXQSPCAVAIL_MASK (0xFF << 16) +#define DWC2_HPTXSTS_PTXQSPCAVAIL_OFFSET 16 +#define DWC2_HPTXSTS_PTXQTOP_TERMINATE (1 << 24) +#define DWC2_HPTXSTS_PTXQTOP_TERMINATE_OFFSET 24 +#define DWC2_HPTXSTS_PTXQTOP_TOKEN_MASK (0x3 << 25) +#define DWC2_HPTXSTS_PTXQTOP_TOKEN_OFFSET 25 +#define DWC2_HPTXSTS_PTXQTOP_CHNUM_MASK (0xF << 27) +#define DWC2_HPTXSTS_PTXQTOP_CHNUM_OFFSET 27 +#define DWC2_HPTXSTS_PTXQTOP_ODD (1 << 31) +#define DWC2_HPTXSTS_PTXQTOP_ODD_OFFSET 31 +#define DWC2_HPRT0_PRTCONNSTS (1 << 0) +#define DWC2_HPRT0_PRTCONNSTS_OFFSET 0 +#define DWC2_HPRT0_PRTCONNDET (1 << 1) +#define DWC2_HPRT0_PRTCONNDET_OFFSET 1 +#define DWC2_HPRT0_PRTENA (1 << 2) +#define DWC2_HPRT0_PRTENA_OFFSET 2 +#define DWC2_HPRT0_PRTENCHNG (1 << 3) +#define DWC2_HPRT0_PRTENCHNG_OFFSET 3 +#define DWC2_HPRT0_PRTOVRCURRACT (1 << 4) +#define DWC2_HPRT0_PRTOVRCURRACT_OFFSET 4 +#define DWC2_HPRT0_PRTOVRCURRCHNG (1 << 5) +#define DWC2_HPRT0_PRTOVRCURRCHNG_OFFSET 5 +#define DWC2_HPRT0_PRTRES (1 << 6) +#define DWC2_HPRT0_PRTRES_OFFSET 6 +#define DWC2_HPRT0_PRTSUSP (1 << 7) +#define DWC2_HPRT0_PRTSUSP_OFFSET 7 +#define DWC2_HPRT0_PRTRST (1 << 8) +#define DWC2_HPRT0_PRTRST_OFFSET 8 +#define DWC2_HPRT0_PRTLNSTS_MASK (0x3 << 10) +#define DWC2_HPRT0_PRTLNSTS_OFFSET 10 +#define DWC2_HPRT0_PRTPWR (1 << 12) +#define DWC2_HPRT0_PRTPWR_OFFSET 12 +#define DWC2_HPRT0_PRTTSTCTL_MASK (0xF << 13) +#define DWC2_HPRT0_PRTTSTCTL_OFFSET 13 +#define DWC2_HPRT0_PRTSPD_MASK (0x3 << 17) +#define DWC2_HPRT0_PRTSPD_OFFSET 17 +#define DWC2_HAINT_CH0 (1 << 0) +#define DWC2_HAINT_CH0_OFFSET 0 +#define DWC2_HAINT_CH1 (1 << 1) +#define DWC2_HAINT_CH1_OFFSET 1 +#define DWC2_HAINT_CH2 (1 << 2) +#define DWC2_HAINT_CH2_OFFSET 2 +#define DWC2_HAINT_CH3 (1 << 3) +#define DWC2_HAINT_CH3_OFFSET 3 +#define DWC2_HAINT_CH4 (1 << 4) +#define DWC2_HAINT_CH4_OFFSET 4 +#define DWC2_HAINT_CH5 (1 << 5) +#define DWC2_HAINT_CH5_OFFSET 5 +#define DWC2_HAINT_CH6 (1 << 6) +#define DWC2_HAINT_CH6_OFFSET 6 +#define DWC2_HAINT_CH7 (1 << 7) +#define DWC2_HAINT_CH7_OFFSET 7 +#define DWC2_HAINT_CH8 (1 << 8) +#define DWC2_HAINT_CH8_OFFSET 8 +#define DWC2_HAINT_CH9 (1 << 9) +#define DWC2_HAINT_CH9_OFFSET 9 +#define DWC2_HAINT_CH10 (1 << 10) +#define DWC2_HAINT_CH10_OFFSET 10 +#define DWC2_HAINT_CH11 (1 << 11) +#define DWC2_HAINT_CH11_OFFSET 11 +#define DWC2_HAINT_CH12 (1 << 12) +#define DWC2_HAINT_CH12_OFFSET 12 +#define DWC2_HAINT_CH13 (1 << 13) +#define DWC2_HAINT_CH13_OFFSET 13 +#define DWC2_HAINT_CH14 (1 << 14) +#define DWC2_HAINT_CH14_OFFSET 14 +#define DWC2_HAINT_CH15 (1 << 15) +#define DWC2_HAINT_CH15_OFFSET 15 +#define DWC2_HAINT_CHINT_MASK 0xffff +#define DWC2_HAINT_CHINT_OFFSET 0 +#define DWC2_HAINTMSK_CH0 (1 << 0) +#define DWC2_HAINTMSK_CH0_OFFSET 0 +#define DWC2_HAINTMSK_CH1 (1 << 1) +#define DWC2_HAINTMSK_CH1_OFFSET 1 +#define DWC2_HAINTMSK_CH2 (1 << 2) +#define DWC2_HAINTMSK_CH2_OFFSET 2 +#define DWC2_HAINTMSK_CH3 (1 << 3) +#define DWC2_HAINTMSK_CH3_OFFSET 3 +#define DWC2_HAINTMSK_CH4 (1 << 4) +#define DWC2_HAINTMSK_CH4_OFFSET 4 +#define DWC2_HAINTMSK_CH5 (1 << 5) +#define DWC2_HAINTMSK_CH5_OFFSET 5 +#define DWC2_HAINTMSK_CH6 (1 << 6) +#define DWC2_HAINTMSK_CH6_OFFSET 6 +#define DWC2_HAINTMSK_CH7 (1 << 7) +#define DWC2_HAINTMSK_CH7_OFFSET 7 +#define DWC2_HAINTMSK_CH8 (1 << 8) +#define DWC2_HAINTMSK_CH8_OFFSET 8 +#define DWC2_HAINTMSK_CH9 (1 << 9) +#define DWC2_HAINTMSK_CH9_OFFSET 9 +#define DWC2_HAINTMSK_CH10 (1 << 10) +#define DWC2_HAINTMSK_CH10_OFFSET 10 +#define DWC2_HAINTMSK_CH11 (1 << 11) +#define DWC2_HAINTMSK_CH11_OFFSET 11 +#define DWC2_HAINTMSK_CH12 (1 << 12) +#define DWC2_HAINTMSK_CH12_OFFSET 12 +#define DWC2_HAINTMSK_CH13 (1 << 13) +#define DWC2_HAINTMSK_CH13_OFFSET 13 +#define DWC2_HAINTMSK_CH14 (1 << 14) +#define DWC2_HAINTMSK_CH14_OFFSET 14 +#define DWC2_HAINTMSK_CH15 (1 << 15) +#define DWC2_HAINTMSK_CH15_OFFSET 15 +#define DWC2_HAINTMSK_CHINT_MASK 0xffff +#define DWC2_HAINTMSK_CHINT_OFFSET 0 +#define DWC2_HCCHAR_MPS_MASK (0x7FF << 0) +#define DWC2_HCCHAR_MPS_OFFSET 0 +#define DWC2_HCCHAR_EPNUM_MASK (0xF << 11) +#define DWC2_HCCHAR_EPNUM_OFFSET 11 +#define DWC2_HCCHAR_EPDIR (1 << 15) +#define DWC2_HCCHAR_EPDIR_OFFSET 15 +#define DWC2_HCCHAR_LSPDDEV (1 << 17) +#define DWC2_HCCHAR_LSPDDEV_OFFSET 17 +#define DWC2_HCCHAR_EPTYPE_CONTROL 0 +#define DWC2_HCCHAR_EPTYPE_ISOC 1 +#define DWC2_HCCHAR_EPTYPE_BULK 2 +#define DWC2_HCCHAR_EPTYPE_INTR 3 +#define DWC2_HCCHAR_EPTYPE_MASK (0x3 << 18) +#define DWC2_HCCHAR_EPTYPE_OFFSET 18 +#define DWC2_HCCHAR_MULTICNT_MASK (0x3 << 20) +#define DWC2_HCCHAR_MULTICNT_OFFSET 20 +#define DWC2_HCCHAR_DEVADDR_MASK (0x7F << 22) +#define DWC2_HCCHAR_DEVADDR_OFFSET 22 +#define DWC2_HCCHAR_ODDFRM (1 << 29) +#define DWC2_HCCHAR_ODDFRM_OFFSET 29 +#define DWC2_HCCHAR_CHDIS (1 << 30) +#define DWC2_HCCHAR_CHDIS_OFFSET 30 +#define DWC2_HCCHAR_CHEN (1 << 31) +#define DWC2_HCCHAR_CHEN_OFFSET 31 +#define DWC2_HCSPLT_PRTADDR_MASK (0x7F << 0) +#define DWC2_HCSPLT_PRTADDR_OFFSET 0 +#define DWC2_HCSPLT_HUBADDR_MASK (0x7F << 7) +#define DWC2_HCSPLT_HUBADDR_OFFSET 7 +#define DWC2_HCSPLT_XACTPOS_MASK (0x3 << 14) +#define DWC2_HCSPLT_XACTPOS_MID 0 +#define DWC2_HCSPLT_XACTPOS_END 1 //otherwise each transaction needs to indicate if its beginning/mid/end +#define DWC2_HCSPLT_XACTPOS_BEGIN 2 +#define DWC2_HCSPLT_XACTPOS_ALL 3 //Xact all, is for complete transactions < 188 bytes +#define DWC2_HCSPLT_XACTPOS_OFFSET 14 +#define DWC2_HCSPLT_COMPSPLT (1 << 16) //Do complete split, (request host to do the complete split transaction) +#define DWC2_HCSPLT_COMPSPLT_OFFSET 16 +#define DWC2_HCSPLT_SPLTENA (1 << 31) +#define DWC2_HCSPLT_SPLTENA_OFFSET 31 +#define DWC2_HCINT_XFERCOMP (1 << 0) +#define DWC2_HCINT_XFERCOMP_OFFSET 0 +#define DWC2_HCINT_CHHLTD (1 << 1) //Channel Halt +#define DWC2_HCINT_CHHLTD_OFFSET 1 +#define DWC2_HCINT_AHBERR (1 << 2) +#define DWC2_HCINT_AHBERR_OFFSET 2 +#define DWC2_HCINT_STALL (1 << 3) +#define DWC2_HCINT_STALL_OFFSET 3 +#define DWC2_HCINT_NAK (1 << 4) +#define DWC2_HCINT_NAK_OFFSET 4 +#define DWC2_HCINT_ACK (1 << 5) +#define DWC2_HCINT_ACK_OFFSET 5 +#define DWC2_HCINT_NYET (1 << 6) +#define DWC2_HCINT_NYET_OFFSET 6 +#define DWC2_HCINT_XACTERR (1 << 7) +#define DWC2_HCINT_XACTERR_OFFSET 7 +#define DWC2_HCINT_BBLERR (1 << 8) +#define DWC2_HCINT_BBLERR_OFFSET 8 +#define DWC2_HCINT_FRMOVRUN (1 << 9) +#define DWC2_HCINT_FRMOVRUN_OFFSET 9 +#define DWC2_HCINT_DATATGLERR (1 << 10) +#define DWC2_HCINT_DATATGLERR_OFFSET 10 +#define DWC2_HCINT_BNA (1 << 11) +#define DWC2_HCINT_BNA_OFFSET 11 +#define DWC2_HCINT_XCS_XACT (1 << 12) +#define DWC2_HCINT_XCS_XACT_OFFSET 12 +#define DWC2_HCINT_FRM_LIST_ROLL (1 << 13) +#define DWC2_HCINT_FRM_LIST_ROLL_OFFSET 13 +#define DWC2_HCINTMSK_XFERCOMPL (1 << 0) +#define DWC2_HCINTMSK_XFERCOMPL_OFFSET 0 +#define DWC2_HCINTMSK_CHHLTD (1 << 1) +#define DWC2_HCINTMSK_CHHLTD_OFFSET 1 +#define DWC2_HCINTMSK_AHBERR (1 << 2) +#define DWC2_HCINTMSK_AHBERR_OFFSET 2 +#define DWC2_HCINTMSK_STALL (1 << 3) +#define DWC2_HCINTMSK_STALL_OFFSET 3 +#define DWC2_HCINTMSK_NAK (1 << 4) +#define DWC2_HCINTMSK_NAK_OFFSET 4 +#define DWC2_HCINTMSK_ACK (1 << 5) +#define DWC2_HCINTMSK_ACK_OFFSET 5 +#define DWC2_HCINTMSK_NYET (1 << 6) +#define DWC2_HCINTMSK_NYET_OFFSET 6 +#define DWC2_HCINTMSK_XACTERR (1 << 7) +#define DWC2_HCINTMSK_XACTERR_OFFSET 7 +#define DWC2_HCINTMSK_BBLERR (1 << 8) +#define DWC2_HCINTMSK_BBLERR_OFFSET 8 +#define DWC2_HCINTMSK_FRMOVRUN (1 << 9) +#define DWC2_HCINTMSK_FRMOVRUN_OFFSET 9 +#define DWC2_HCINTMSK_DATATGLERR (1 << 10) +#define DWC2_HCINTMSK_DATATGLERR_OFFSET 10 +#define DWC2_HCINTMSK_BNA (1 << 11) +#define DWC2_HCINTMSK_BNA_OFFSET 11 +#define DWC2_HCINTMSK_XCS_XACT (1 << 12) +#define DWC2_HCINTMSK_XCS_XACT_OFFSET 12 +#define DWC2_HCINTMSK_FRM_LIST_ROLL (1 << 13) +#define DWC2_HCINTMSK_FRM_LIST_ROLL_OFFSET 13 +#define DWC2_HCTSIZ_XFERSIZE_MASK 0x7ffff +#define DWC2_HCTSIZ_XFERSIZE_OFFSET 0 +#define DWC2_HCTSIZ_SCHINFO_MASK 0xff +#define DWC2_HCTSIZ_SCHINFO_OFFSET 0 +#define DWC2_HCTSIZ_NTD_MASK (0xff << 8) +#define DWC2_HCTSIZ_NTD_OFFSET 8 +#define DWC2_HCTSIZ_PKTCNT_MASK (0x3ff << 19) +#define DWC2_HCTSIZ_PKTCNT_OFFSET 19 +#define DWC2_HCTSIZ_PID_MASK (0x3 << 29) +#define DWC2_HCTSIZ_PID_OFFSET 29 +#define DWC2_HCTSIZ_DOPNG (1 << 31) +#define DWC2_HCTSIZ_DOPNG_OFFSET 31 +#define DWC2_HCDMA_CTD_MASK (0xFF << 3) +#define DWC2_HCDMA_CTD_OFFSET 3 +#define DWC2_HCDMA_DMA_ADDR_MASK (0x1FFFFF << 11) +#define DWC2_HCDMA_DMA_ADDR_OFFSET 11 +#define DWC2_PCGCCTL_STOPPCLK (1 << 0) +#define DWC2_PCGCCTL_STOPPCLK_OFFSET 0 +#define DWC2_PCGCCTL_GATEHCLK (1 << 1) +#define DWC2_PCGCCTL_GATEHCLK_OFFSET 1 +#define DWC2_PCGCCTL_PWRCLMP (1 << 2) +#define DWC2_PCGCCTL_PWRCLMP_OFFSET 2 +#define DWC2_PCGCCTL_RSTPDWNMODULE (1 << 3) +#define DWC2_PCGCCTL_RSTPDWNMODULE_OFFSET 3 +#define DWC2_PCGCCTL_PHYSUSPENDED (1 << 4) +#define DWC2_PCGCCTL_PHYSUSPENDED_OFFSET 4 +#define DWC2_PCGCCTL_ENBL_SLEEP_GATING (1 << 5) +#define DWC2_PCGCCTL_ENBL_SLEEP_GATING_OFFSET 5 +#define DWC2_PCGCCTL_PHY_IN_SLEEP (1 << 6) +#define DWC2_PCGCCTL_PHY_IN_SLEEP_OFFSET 6 +#define DWC2_PCGCCTL_DEEP_SLEEP (1 << 7) +#define DWC2_PCGCCTL_DEEP_SLEEP_OFFSET 7 +#define DWC2_SNPSID_DEVID_VER_2xx (0x4f542 << 12) +#define DWC2_SNPSID_DEVID_VER_3xx (0x4f543 << 12) +#define DWC2_SNPSID_DEVID_MASK (0xfffff << 12) +#define DWC2_SNPSID_DEVID_OFFSET 12 + +/* Host controller specific */ +#define DWC2_HC_PID_DATA0 0 +#define DWC2_HC_PID_DATA2 1 +#define DWC2_HC_PID_DATA1 2 +#define DWC2_HC_PID_MDATA 3 +#define DWC2_HC_PID_SETUP 3 + +/* roothub.a masks */ +#define RH_A_NDP (0xff << 0) /* number of downstream ports */ +#define RH_A_PSM (1 << 8) /* power switching mode */ +#define RH_A_NPS (1 << 9) /* no power switching */ +#define RH_A_DT (1 << 10) /* device type (mbz) */ +#define RH_A_OCPM (1 << 11) /* over current protection mode */ +#define RH_A_NOCP (1 << 12) /* no over current protection */ +#define RH_A_POTPGT (0xff << 24) /* power on to power good time */ + +/* roothub.b masks */ +#define RH_B_DR 0x0000ffff /* device removable flags */ +#define RH_B_PPCM 0xffff0000 /* port power control mask */ + +#define DWC2_PHY_TYPE_FS 0 +#define DWC2_PHY_TYPE_UTMI 1 +#define DWC2_PHY_TYPE_ULPI 2 +#define CONFIG_DWC2_PHY_TYPE DWC2_PHY_TYPE_UTMI /* PHY type */ +#define CONFIG_DWC2_UTMI_WIDTH 8 /* UTMI bus width (8/16) */ + +#define DWC2_DMA_BURST_SIZE 32 /* DMA burst len */ +//#define DWC2_MAX_CHANNELS 16 /* Max # of EPs */ +#define DWC2_MAX_CHANNELS 12 /* Max # of EPs (12 for LS/FS)*/ +#define DWC2_HOST_RX_FIFO_SIZE (516 + DWC2_MAX_CHANNELS) +#define DWC2_HOST_NPERIO_TX_FIFO_SIZE 0x100 /* nPeriodic TX FIFO */ +#define DWC2_HOST_PERIO_TX_FIFO_SIZE 0x200 /* Periodic TX FIFO */ +#define DWC2_MAX_TRANSFER_SIZE 65535 +#define DWC2_MAX_PACKET_COUNT 511 + +#define DWC2_HC_CHANNEL 0 + +#define DWC2_STATUS_BUF_SIZE 64 +#define DWC2_DATA_BUF_SIZE (64 * 1024) + + +#define USB_PORT_FEAT_CONNECTION 0 +#define USB_PORT_FEAT_ENABLE 1 +#define USB_PORT_FEAT_SUSPEND 2 +#define USB_PORT_FEAT_OVER_CURRENT 3 +#define USB_PORT_FEAT_RESET 4 +#define USB_PORT_FEAT_POWER 8 +#define USB_PORT_FEAT_LOWSPEED 9 +#define USB_PORT_FEAT_HIGHSPEED 10 +#define USB_PORT_FEAT_C_CONNECTION 16 +#define USB_PORT_FEAT_C_ENABLE 17 +#define USB_PORT_FEAT_C_SUSPEND 18 +#define USB_PORT_FEAT_C_OVER_CURRENT 19 +#define USB_PORT_FEAT_C_RESET 20 +#define USB_PORT_FEAT_TEST 21 + +#endif /* __DWCHW_H__ */